예제 #1
0
        /// <summary>
        /// Execute the command handler against the specified session context.
        /// </summary>
        /// <param name="context">The session context to execute the command handler against.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which asynchronously performs the execution.</returns>
        async Task ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            // The PROXY protocol requires that the receiver must wait for the
            // proxy command to be fully received before it starts processing the
            // session. Since the receiver is expected to speak first in SMTP,
            // i.e. sending the greeting on connect, we wait for the proxy
            // command to be consumed and processed before speaking to the
            // remote client.
            if (!_context.ServerOptions.Proxy)
            {
                await OutputGreetingAsync(cancellationToken).ReturnOnAnyThread();
            }

            if (_context.ServerOptions.Proxy)
            {
                await IngestProxyAsync(context, cancellationToken).ReturnOnAnyThread();
            }

            var retries = _context.ServerOptions.MaxRetryCount;

            while (retries-- > 0 && context.IsQuitRequested == false && cancellationToken.IsCancellationRequested == false)
            {
                var text = await ReadCommandInputAsync(context, cancellationToken);

                if (text == null)
                {
                    return;
                }

                if (TryMake(context, text, out var command, out var response))
                {
                    try
                    {
                        if (await ExecuteAsync(command, context, cancellationToken).ReturnOnAnyThread())
                        {
                            _stateMachine.Transition(context);
                        }

                        retries = _context.ServerOptions.MaxRetryCount;

                        continue;
                    }
                    catch (SmtpResponseException responseException)
                    {
                        context.IsQuitRequested = responseException.IsQuitRequested;

                        response = responseException.Response;
                    }
                    catch (OperationCanceledException)
                    {
                        await context.NetworkClient.ReplyAsync(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "The session has be cancelled."), cancellationToken);

                        return;
                    }
                }

                await context.NetworkClient.ReplyAsync(CreateErrorResponse(response, retries), cancellationToken);
            }
        }
예제 #2
0
        /// <summary>
        /// Execute the command handler against the specified session context.
        /// </summary>
        /// <param name="context">The session context to execute the command handler against.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which asynchronously performs the execution.</returns>
        async Task ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            var retries = _context.ServerOptions.MaxRetryCount;

            while (retries-- > 0 && context.IsQuitRequested == false && cancellationToken.IsCancellationRequested == false)
            {
                var text = await ReadCommandInputAsync(context, cancellationToken).ConfigureAwait(false);

                if (text == null)
                {
                    return;
                }

                if (TryMake(context, text, out var command, out var response) == false)
                {
                    await context.NetworkClient.ReplyAsync(CreateErrorResponse(response, retries), cancellationToken).ConfigureAwait(false);

                    continue;
                }

                try
                {
                    if (await ExecuteAsync(command, context, cancellationToken).ConfigureAwait(false))
                    {
                        _stateMachine.Transition(context);
                    }

                    retries = _context.ServerOptions.MaxRetryCount;
                }
                catch (SmtpResponseException responseException) when(responseException.IsQuitRequested)
                {
                    await context.NetworkClient.ReplyAsync(responseException.Response, cancellationToken).ConfigureAwait(false);

                    return;
                }
                catch (SmtpResponseException responseException)
                {
                    response = CreateErrorResponse(responseException.Response, retries);

                    await context.NetworkClient.ReplyAsync(response, cancellationToken).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                    await context.NetworkClient.ReplyAsync(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "The session has be cancelled."), cancellationToken).ConfigureAwait(false);

                    return;
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Execute the command handler against the specified session context.
        /// </summary>
        /// <param name="context">The session context to execute the command handler against.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which asynchronously performs the execution.</returns>
        async Task ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            var retries = _context.ServerOptions.MaxRetryCount;

            while (retries-- > 0 && context.IsQuitRequested == false && cancellationToken.IsCancellationRequested == false)
            {
                try
                {
                    var command = await ReadCommandAsync(context, cancellationToken).ConfigureAwait(false);

                    if (command == null)
                    {
                        return;
                    }

                    if (_stateMachine.TryAccept(command, out var errorResponse) == false)
                    {
                        throw new SmtpResponseException(errorResponse);
                    }

                    if (await ExecuteAsync(command, context, cancellationToken).ConfigureAwait(false))
                    {
                        _stateMachine.Transition(context);
                    }

                    retries = _context.ServerOptions.MaxRetryCount;
                }
                catch (SmtpResponseException responseException) when(responseException.IsQuitRequested)
                {
                    await context.Pipe.Output.WriteReplyAsync(responseException.Response, cancellationToken).ConfigureAwait(false);

                    context.IsQuitRequested = true;
                }
                catch (SmtpResponseException responseException)
                {
                    var response = CreateErrorResponse(responseException.Response, retries);

                    await context.Pipe.Output.WriteReplyAsync(response, cancellationToken).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                    await context.Pipe.Output.WriteReplyAsync(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "The session has be cancelled."), CancellationToken.None).ConfigureAwait(false);
                }
            }
        }