/// <summary> /// Asynchronously handles responding to a request. /// </summary> /// <param name="connection">The connection.</param> /// <param name="request">A request message.</param> /// <param name="responseHandler">A response handler.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <returns>A task that represents the asynchronous operation.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="connection" /> /// is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="request" /> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="responseHandler" /> /// is <c>null</c>.</exception> /// <exception cref="OperationCanceledException">Thrown if <paramref name="cancellationToken" /> /// is cancelled.</exception> public async Task HandleResponseAsync( IConnection connection, Message request, IResponseHandler responseHandler, CancellationToken cancellationToken) { if (connection == null) { throw new ArgumentNullException(nameof(connection)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } if (responseHandler == null) { throw new ArgumentNullException(nameof(responseHandler)); } cancellationToken.ThrowIfCancellationRequested(); var response = _handshakeFailedResponse; var handshakeRequest = MessageUtilities.DeserializePayload<HandshakeRequest>(request); if (handshakeRequest != null) { if (!(handshakeRequest.MinimumProtocolVersion > handshakeRequest.ProtocolVersion || handshakeRequest.ProtocolVersion < _minimumProtocolVersion || handshakeRequest.MinimumProtocolVersion > _protocolVersion)) { SemanticVersion negotiatedProtocolVersion; if (_protocolVersion <= handshakeRequest.ProtocolVersion) { negotiatedProtocolVersion = _protocolVersion; } else { negotiatedProtocolVersion = handshakeRequest.ProtocolVersion; } response = new HandshakeResponse(MessageResponseCode.Success, negotiatedProtocolVersion); } } await responseHandler.SendResponseAsync(request, response, cancellationToken) .ContinueWith(task => _responseSentTaskCompletionSource.TrySetResult(0)) .ConfigureAwait(false); }
/// <summary> /// Initializes a new instance of the <see cref="SymmetricHandshake" /> class. /// </summary> /// <param name="connection">A connection.</param> /// <param name="handshakeTimeout">The handshake timeout.</param> /// <param name="protocolVersion">The handshaker's protocol version.</param> /// <param name="minimumProtocolVersion">The handshaker's minimum protocol version.</param> public SymmetricHandshake( IConnection connection, TimeSpan handshakeTimeout, SemanticVersion protocolVersion, SemanticVersion minimumProtocolVersion) { if (connection == null) { throw new ArgumentNullException(nameof(connection)); } if (!TimeoutUtilities.IsValid(handshakeTimeout)) { throw new ArgumentOutOfRangeException( nameof(handshakeTimeout), handshakeTimeout, Strings.Plugin_TimeoutOutOfRange); } if (protocolVersion == null) { throw new ArgumentNullException(nameof(protocolVersion)); } if (minimumProtocolVersion == null) { throw new ArgumentNullException(nameof(minimumProtocolVersion)); } _connection = connection; _handshakeTimeout = handshakeTimeout; _protocolVersion = protocolVersion; _minimumProtocolVersion = minimumProtocolVersion; _handshakeFailedResponse = new HandshakeResponse(MessageResponseCode.Error, protocolVersion: null); _responseSentTaskCompletionSource = new TaskCompletionSource <int>(); _timeoutCancellationTokenSource = new CancellationTokenSource(handshakeTimeout); _timeoutCancellationTokenSource.Token.Register(() => { _responseSentTaskCompletionSource.TrySetCanceled(); }); CancellationToken = _timeoutCancellationTokenSource.Token; if (!_connection.MessageDispatcher.RequestHandlers.TryAdd(MessageMethod.Handshake, this)) { throw new ArgumentException(Strings.Plugin_HandshakeRequestHandlerAlreadyExists, nameof(connection)); } }