/// <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);
        }
Esempio n. 2
0
        /// <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));
            }
        }