Inheritance: ISmtpSessionContext
Beispiel #1
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="options">The SMTP server options.</param>
 /// <param name="tcpClient">The TCP client to operate the session on.</param>
 internal SmtpSession(ISmtpServerOptions options, TcpClient tcpClient)
 {
     _options      = options;
     _tcpClient    = tcpClient;
     _context      = new SmtpSessionContext(tcpClient);
     _stateMachine = new SmtpStateMachine(options, _context);
 }
Beispiel #2
0
        /// <summary>
        /// Listen for SMTP traffic on the given endpoint.
        /// </summary>
        /// <param name="endpointDefinition">The definition of the endpoint to listen on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which performs the operation.</returns>
        async Task ListenAsync(IEndpointDefinition endpointDefinition, CancellationToken cancellationToken)
        {
            // The listener can be stopped either by the caller cancelling the CancellationToken used when starting the server, or when calling
            // the shutdown method. The Shutdown method will stop the listeners and allow any active sessions to finish gracefully.
            var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_shutdownTokenSource.Token, cancellationToken);

            using var endpointListener = _endpointListenerFactory.CreateListener(endpointDefinition);

            while (cancellationTokenSource.Token.IsCancellationRequested == false)
            {
                var sessionContext = new SmtpSessionContext(_serviceProvider, _options, endpointDefinition);

                try
                {
                    // wait for a client connection
                    sessionContext.Pipe = await GetPipeAsync(endpointListener, sessionContext, cancellationTokenSource.Token).ConfigureAwait(false);
                }
                catch (OperationCanceledException) { }
                catch (Exception ex)
                {
                    OnSessionFaulted(new SessionFaultedEventArgs(sessionContext, ex));
                    continue;
                }

                _sessions.Run(sessionContext, cancellationTokenSource.Token);
            }
        }
        /// <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>
        internal async Task ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            var retryCount = _maxRetries;

            while (retryCount-- > 0 && context.IsQuitRequested == false && cancellationToken.IsCancellationRequested == false)
            {
                var text = await context.Text.ReadLineAsync(cancellationToken).ConfigureAwait(false);

                SmtpCommand  command;
                SmtpResponse errorResponse;
                if (TryAccept(context, text, out command, out errorResponse) == false)
                {
                    var response = new SmtpResponse(errorResponse.ReplyCode, $"{errorResponse.Message}, {retryCount} retry(ies) remaining.");

                    await context.Text.ReplyAsync(response, cancellationToken);

                    continue;
                }

                // the command was a normal command so we can reset the retry count
                retryCount = _maxRetries;

                await ExecuteAsync(command, context, cancellationToken).ConfigureAwait(false);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Listen for SMTP traffic on the given endpoint.
        /// </summary>
        /// <param name="endpointDefinition">The definition of the endpoint to listen on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which performs the operation.</returns>
        async Task ListenAsync(IEndpointDefinition endpointDefinition, CancellationToken cancellationToken)
        {
            using (var endpointListener = _options.EndpointListenerFactory.CreateListener(endpointDefinition))
            {
                while (_shutdownTokenSource.Token.IsCancellationRequested == false && cancellationToken.IsCancellationRequested == false)
                {
                    var sessionContext = new SmtpSessionContext(_options, endpointDefinition);

                    try
                    {
                        await ListenAsync(sessionContext, endpointListener, cancellationToken);
                    }
                    catch (OperationCanceledException) when(_shutdownTokenSource.Token.IsCancellationRequested == false)
                    {
                        if (sessionContext.NetworkClient != null)
                        {
                            OnSessionCancelled(new SessionEventArgs(sessionContext));
                        }
                    }
                    catch (OperationCanceledException) { }
                    catch (Exception ex)
                    {
                        OnSessionFaulted(new SessionFaultedEventArgs(sessionContext, ex));
                    }
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Read the command input.
        /// </summary>
        /// <param name="context">The session context to execute the command handler against.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The input that was received from the client.</returns>
        async Task <IReadOnlyList <ArraySegment <byte> > > ReadCommandInputAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            var timeout = new CancellationTokenSource(_context.ServerOptions.CommandWaitTimeout);

            var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, cancellationToken);

            try
            {
                return(await context.NetworkClient.ReadLineAsync(cancellationTokenSource.Token).ConfigureAwait(false));
            }
            catch (OperationCanceledException)
            {
                if (timeout.IsCancellationRequested)
                {
                    await context.NetworkClient.ReplyAsync(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "Timeout whilst waiting for input."), cancellationToken).ConfigureAwait(false);

                    return(null);
                }

                await context.NetworkClient.ReplyAsync(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "The session has be cancelled."), CancellationToken.None).ConfigureAwait(false);

                return(null);
            }
            finally
            {
                timeout.Dispose();
                cancellationTokenSource.Dispose();
            }
        }
Beispiel #6
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 = _options.MaxRetryCount;

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

                if (TryAccept(context, text, out SmtpCommand command, out SmtpResponse response))
                {
                    try
                    {
                        await ExecuteAsync(command, context, cancellationToken).ReturnOnAnyThread();

                        retries = _options.MaxRetryCount;

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

                        response = responseException.Response;
                    }
                }

                await context.Client.ReplyAsync(CreateErrorResponse(response, retries), cancellationToken);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Listen for SMTP traffic on the given endpoint.
        /// </summary>
        /// <param name="endpointDefinition">The definition of the endpoint to listen on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which performs the operation.</returns>
        async Task ListenAsync(IEndpointDefinition endpointDefinition, CancellationToken cancellationToken)
        {
            // The listener can be stopped either by the caller cancelling the CancellationToken used when starting the server, or when calling
            // the shutdown method. The Shutdown method will stop the listeners and allow any active sessions to finish gracefully.
            var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_shutdownTokenSource.Token, cancellationToken);

            using var endpointListener = _endpointListenerFactory.CreateListener(endpointDefinition);

            while (cancellationTokenSource.Token.IsCancellationRequested == false)
            {
                var sessionContext = new SmtpSessionContext(_serviceProvider, _options, endpointDefinition);

                try
                {
                    // wait for a client connection
                    sessionContext.Pipe = await endpointListener.GetPipeAsync(sessionContext, cancellationTokenSource.Token).ConfigureAwait(false);

                    cancellationTokenSource.Token.ThrowIfCancellationRequested();

                    if (sessionContext.EndpointDefinition.IsSecure && _options.ServerCertificate != null)
                    {
                        await sessionContext.Pipe.UpgradeAsync(_options.ServerCertificate, _options.SupportedSslProtocols, cancellationToken).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested();
                    }

                    _sessions.Run(sessionContext, cancellationTokenSource.Token);
                }
                catch (OperationCanceledException) { }
            }
        }
Beispiel #8
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);
            }
        }
Beispiel #9
0
        /// <summary>
        /// Execute the command.
        /// </summary>
        /// <param name="command">The command to execute.</param>
        /// <param name="context">The execution context to operate on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which asynchronously performs the execution.</returns>
        static async Task <bool> ExecuteAsync(SmtpCommand command, SmtpSessionContext context, CancellationToken cancellationToken)
        {
            context.RaiseCommandExecuting(command);

            var result = await command.ExecuteAsync(context, cancellationToken);

            context.RaiseCommandExecuted(command);

            return(result);
        }
Beispiel #10
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="options">The SMTP server options.</param>
        /// <param name="tcpClient">The TCP client to operate the session on.</param>
        /// <param name="stateMachine">The SMTP state machine.</param>
        internal SmtpSession(ISmtpServerOptions options, TcpClient tcpClient, SmtpStateMachine stateMachine)
        {
            _options   = options;
            _tcpClient = tcpClient;

            Context = new SmtpSessionContext(new SmtpTransaction(), stateMachine, tcpClient.Client.RemoteEndPoint)
            {
                Text = new NetworkTextStream(tcpClient.GetStream())
            };
        }
Beispiel #11
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="options">The SMTP server options.</param>
        /// <param name="tcpClient">The TCP client to operate the session on.</param>
        /// <param name="stateMachine">The SMTP state machine.</param>
        internal SmtpSession(ISmtpServerOptions options, TcpClient tcpClient, SmtpStateMachine stateMachine)
        {
            _options = options;
            _tcpClient = tcpClient;
            _stateMachine = stateMachine;

            Context = new SmtpSessionContext(new SmtpTransaction(), stateMachine, tcpClient.Client.RemoteEndPoint)
            {
                Text = new NetworkTextStream(tcpClient)
            };
        }
Beispiel #12
0
        /// <summary>
        /// Listen for SMTP traffic on the given endpoint.
        /// </summary>
        /// <param name="endpointDefinition">The definition of the endpoint to listen on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which performs the operation.</returns>
        async Task ListenAsync(IEndpointDefinition endpointDefinition, CancellationToken cancellationToken)
        {
            // keep track of the running tasks for disposal
            var sessions = new ConcurrentDictionary <SmtpSession, SmtpSession>();

            using (var endpointListener = _options.EndpointListenerFactory.CreateListener(endpointDefinition))
            {
                while (cancellationToken.IsCancellationRequested == false)
                {
                    var sessionContext = new SmtpSessionContext(_options, endpointDefinition);

                    // wait for a client connection
                    var stream = await endpointListener.GetStreamAsync(sessionContext, cancellationToken).ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();

                    sessionContext.NetworkClient = new NetworkClient(stream, _options.NetworkBufferSize, _options.NetworkBufferReadTimeout);

                    if (endpointDefinition.IsSecure && _options.ServerCertificate != null)
                    {
                        await sessionContext.NetworkClient.UpgradeAsync(_options.ServerCertificate, _options.SupportedSslProtocols, cancellationToken);

                        cancellationToken.ThrowIfCancellationRequested();
                    }

                    // create a new session to handle the connection
                    var session = new SmtpSession(sessionContext);
                    sessions.TryAdd(session, session);

                    OnSessionCreated(new SessionEventArgs(sessionContext));

                    session.Run(cancellationToken);

                    #pragma warning disable 4014
                    session.Task
                    .ContinueWith(t =>
                    {
                        if (sessions.TryRemove(session, out var s))
                        {
                            sessionContext.NetworkClient.Dispose();
                        }

                        OnSessionCompleted(new SessionEventArgs(sessionContext));
                    },
                                  cancellationToken);
                    #pragma warning restore 4014
                }

                // the server has been cancelled, wait for the tasks to complete
                await Task.WhenAll(sessions.Keys.Select(s => s.Task)).ConfigureAwait(false);
            }
        }
Beispiel #13
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;
                }
            }
        }
        internal void Run(SmtpSessionContext sessionContext, CancellationToken cancellationToken)
        {
            var handle = new SmtpSessionHandle(new SmtpSession(sessionContext), sessionContext);

            Add(handle);

            handle.CompletionTask = RunAsync(handle, cancellationToken);

            // ReSharper disable once MethodSupportsCancellation
            handle.CompletionTask.ContinueWith(
                task =>
            {
                Remove(handle);
            });
        }
Beispiel #15
0
        /// <summary>
        /// Read the command input.
        /// </summary>
        /// <param name="context">The session context to execute the command handler against.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The input that was received from the client.</returns>
        async Task <IReadOnlyList <ArraySegment <byte> > > ReadCommandInputAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            try
            {
                return(await context.Client.ReadLineAsync(_options.CommandWaitTimeout, cancellationToken).ReturnOnAnyThread());
            }
            catch (TimeoutException)
            {
                await context.Client.ReplyAsync(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "Timeout whilst waiting for input."), cancellationToken);
            }
            catch (OperationCanceledException)
            {
                await context.Client.ReplyAsync(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "The session has be cancelled."), cancellationToken);
            }

            return(null);
        }
Beispiel #16
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);
                }
            }
        }
Beispiel #17
0
        async Task IngestProxyAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            var text = await ReadCommandInputAsync(context, cancellationToken);

            if (TryMake(context, text, out SmtpCommand command, out SmtpResponse response))
            {
                if (await ExecuteAsync(command, context, cancellationToken).ReturnOnAnyThread())
                {
                    await OutputGreetingAsync(cancellationToken).ReturnOnAnyThread();

                    await _context.NetworkClient.FlushAsync(cancellationToken).ReturnOnAnyThread();
                }
                else
                {
                    await _context.NetworkClient.FlushAsync(cancellationToken).ReturnOnAnyThread();
                }
            }
        }
Beispiel #18
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 = _options.MaxRetryCount;

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

                if (text == null)
                {
                    return;
                }

                if (TryAccept(context, text, out SmtpCommand command, out SmtpResponse response))
                {
                    try
                    {
                        await ExecuteAsync(command, context, cancellationToken).ReturnOnAnyThread();

                        retries = _options.MaxRetryCount;

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

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

                        return;
                    }
                }

                await context.Client.ReplyAsync(CreateErrorResponse(response, retries), cancellationToken);
            }
        }
Beispiel #19
0
        async Task ListenAsync(SmtpSessionContext sessionContext, IEndpointListener endpointListener, CancellationToken cancellationToken)
        {
            // The listener can be stopped either by the caller cancelling the CancellationToken used when starting the server, or when calling
            // the shutdown method. The Shutdown method will stop the listeners and allow any active sessions to finish gracefully.
            var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_shutdownTokenSource.Token, cancellationToken);

            // wait for a client connection
            var stream = await endpointListener.GetStreamAsync(sessionContext, cancellationTokenSource.Token).ConfigureAwait(false);

            cancellationTokenSource.Token.ThrowIfCancellationRequested();

            sessionContext.NetworkClient = new NetworkClient(stream, _options.NetworkBufferSize);

            if (sessionContext.EndpointDefinition.IsSecure && _options.ServerCertificate != null)
            {
                await sessionContext.NetworkClient.Stream.UpgradeAsync(_options.ServerCertificate, _options.SupportedSslProtocols, cancellationToken).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();
            }

            _sessions.Run(sessionContext, cancellationToken);
        }
Beispiel #20
0
            public void Run(SmtpSessionContext sessionContext, CancellationToken cancellationToken)
            {
                var session = new SmtpSession(sessionContext);

                Add(session);

                _smtpServer.OnSessionCreated(new SessionEventArgs(sessionContext));

                session.Run(
                    exception =>
                {
                    Remove(session);

                    sessionContext.NetworkClient.Dispose();

                    if (exception != null)
                    {
                        _smtpServer.OnSessionFaulted(new SessionFaultedEventArgs(sessionContext, exception));
                    }

                    _smtpServer.OnSessionCompleted(new SessionEventArgs(sessionContext));
                },
                    cancellationToken);
            }
 /// <summary>
 /// Advances the enumerator to the next command in the stream.
 /// </summary>
 /// <param name="context">The session context to execute the command handler against.</param>
 /// <param name="text">The text to return the commands from.</param>
 /// <param name="command">The command that was found.</param>
 /// <param name="errorResponse">The error response that indicates why a command could not be accepted.</param>
 /// <returns>true if a valid command was found, false if not.</returns>
 bool TryAccept(SmtpSessionContext context, string text, out SmtpCommand command, out SmtpResponse errorResponse)
 {
     return(context.StateMachine.TryAccept(new TokenEnumerator(new StringTokenReader(text)), out command, out errorResponse));
 }
Beispiel #22
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="context">The session context.</param>
 internal SmtpSession(SmtpSessionContext context)
 {
     _context      = context;
     _stateMachine = new SmtpStateMachine(_context);
 }
Beispiel #23
0
        /// <summary>
        /// Execute the command.
        /// </summary>
        /// <param name="command">The command to execute.</param>
        /// <param name="context">The execution context to operate on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which asynchronously performs the execution.</returns>
        Task <bool> ExecuteAsync(SmtpCommand command, SmtpSessionContext context, CancellationToken cancellationToken)
        {
            context.RaiseCommandExecuting(command);

            return(command.ExecuteAsync(context, cancellationToken));
        }
Beispiel #24
0
        /// <summary>
        /// Advances the enumerator to the next command in the stream.
        /// </summary>
        /// <param name="context">The session context to use when making session based transitions.</param>
        /// <param name="segments">The list of array segments to read the command from.</param>
        /// <param name="command">The command that was found.</param>
        /// <param name="errorResponse">The error response that indicates why a command could not be accepted.</param>
        /// <returns>true if a valid command was found, false if not.</returns>
        bool TryMake(SmtpSessionContext context, IReadOnlyList <ArraySegment <byte> > segments, out SmtpCommand command, out SmtpResponse errorResponse)
        {
            var tokenEnumerator = new TokenEnumerator(new ByteArrayTokenReader(segments));

            return(_stateMachine.TryMake(context, tokenEnumerator, out command, out errorResponse));
        }
 public SmtpSessionHandle(SmtpSession session, SmtpSessionContext sessionContext)
 {
     Session        = session;
     SessionContext = sessionContext;
 }
Beispiel #26
0
        async Task <ISecurableDuplexPipe> GetPipeAsync(IEndpointListener endpointListener, SmtpSessionContext sessionContext, CancellationToken cancellationToken)
        {
            var pipe = await endpointListener.GetPipeAsync(sessionContext, cancellationToken).ConfigureAwait(false);

            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (sessionContext.EndpointDefinition.IsSecure && _options.ServerCertificate != null)
                {
                    await pipe.UpgradeAsync(_options.ServerCertificate, _options.SupportedSslProtocols, cancellationToken).ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();
                }
            }
            catch
            {
                pipe.Dispose();

                throw;
            }

            return(pipe);
        }
Beispiel #27
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="context">The session context.</param>
 internal SmtpSession(SmtpSessionContext context)
 {
     _context        = context;
     _stateMachine   = new SmtpStateMachine(_context);
     _commandFactory = context.ServiceProvider.GetServiceOrDefault <ISmtpCommandFactory>(new SmtpCommandFactory());
 }