Пример #1
0
        /// <summary>
        /// This method is called when asynchronous Connect method completes.
        /// </summary>
        /// <param name="ar">An IAsyncResult that stores state information and any user defined data for this asynchronous operation.</param>
        private void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                m_pSmtpClient.EndConnect(ar);

                // Start TLS requested, start switching to SSL.
                if (m_pActiveTarget.SslMode == SslMode.TLS)
                {
                    m_pSmtpClient.BeginStartTLS(StartTlsCallback, null);
                }
                // Authentication requested, start authenticating.
                else if (!string.IsNullOrEmpty(m_pActiveTarget.UserName))
                {
                    m_pSmtpClient.BeginAuthenticate(m_pActiveTarget.UserName,
                                                    m_pActiveTarget.Password,
                                                    AuthenticateCallback,
                                                    null);
                }
                else
                {
                    long messageSize = -1;
                    try
                    {
                        messageSize = m_pRelayItem.MessageStream.Length - m_pRelayItem.MessageStream.Position;
                    }
                    catch
                    {
                        // Stream doesn't support seeking.
                    }

                    m_pSmtpClient.BeginMailFrom(From, messageSize, MailFromCallback, null);
                }
            }
            catch (Exception x)
            {
                try
                {
                    // Release IP usage.
                    m_pServer.RemoveIpUsage(m_pActiveTarget.Target.Address);
                    m_pActiveTarget = null;

                    // Connect failed, if there are more target IPs, try next one.
                    if (!IsDisposed && !IsConnected && m_pTargets.Count > 0)
                    {
                        BeginConnect();
                    }
                    else
                    {
                        Dispose(x);
                    }
                }
                catch (Exception xx)
                {
                    Dispose(xx);
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Starts connecting to best target.
        /// </summary>
        private void BeginConnect()
        {
            // No tagets, abort relay.
            if (m_pTargets.Count == 0)
            {
                LogText("No relay target(s) for '" + m_pRelayItem.To + "', aborting.");
                Dispose(new Exception("No relay target(s) for '" + m_pRelayItem.To + "', aborting."));
                return;
            }

            // If maximum connections to specified target exceeded and there are more targets, try to get limit free target.
            if (m_pServer.MaxConnectionsPerIP > 0)
            {
                // For DNS or load-balnced smart host relay, search free target if any.
                if (m_pServer.RelayMode == Relay_Mode.Dns || m_pServer.SmartHostsBalanceMode == BalanceMode.LoadBalance)
                {
                    foreach (Relay_Target t in m_pTargets)
                    {
                        // We found free target, stop searching.
                        if (m_pServer.TryAddIpUsage(m_pTargets[0].Target.Address))
                        {
                            m_pActiveTarget = t;
                            m_pTargets.Remove(t);
                            break;
                        }
                    }
                }
                // Smart host fail-over mode, just check if it's free.
                else
                {
                    // Smart host IP limit not reached.
                    if (m_pServer.TryAddIpUsage(m_pTargets[0].Target.Address))
                    {
                        m_pActiveTarget = m_pTargets[0];
                        m_pTargets.RemoveAt(0);
                    }
                }
            }
            // Just get first target.
            else
            {
                m_pActiveTarget = m_pTargets[0];
                m_pTargets.RemoveAt(0);
            }

            // If all targets has exeeded maximum allowed connection per IP address, end relay session,
            // next relay cycle will try to relay again.
            if (m_pActiveTarget == null)
            {
                LogText("All targets has exeeded maximum allowed connection per IP address, skip relay.");
                Dispose(new Exception("All targets has exeeded maximum allowed connection per IP address, skip relay."));
                return;
            }

            m_pSmtpClient.BeginConnect(new IPEndPoint(m_pLocalBindInfo.IP, 0), m_pActiveTarget.Target, false, new AsyncCallback(this.ConnectCallback), null);
        }
Пример #3
0
        /// <summary>
        /// Is called when EHLO/HELO command has completed.
        /// </summary>
        /// <param name="op">Asynchronous operation.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
        private void ConnectCompleted(TCP_Client.ConnectAsyncOP op)
        {
            if (op == null)
            {
                throw new ArgumentNullException("op");
            }

            try
            {
                // Connect failed.
                if (op.Error != null)
                {
                    try
                    {
                        // Release IP usage.
                        m_pServer.RemoveIpUsage(m_pActiveTarget.Target.Address);
                        m_pActiveTarget = null;

                        // Connect failed, if there are more target IPs, try next one.
                        if (!this.IsDisposed && !this.IsConnected && m_pTargets.Count > 0)
                        {
                            BeginConnect();
                        }
                        else
                        {
                            Dispose(op.Error);
                        }
                    }
                    catch (Exception x1)
                    {
                        Dispose(x1);
                    }
                }
                // Connect suceeded.
                else
                {
                    // Do EHLO/HELO.
                    string hostName = string.IsNullOrEmpty(m_pLocalBindInfo.HostName) ? Dns.GetHostName() : m_pLocalBindInfo.HostName;
                    SMTP_Client.EhloHeloAsyncOP ehloOP = new SMTP_Client.EhloHeloAsyncOP(hostName);
                    ehloOP.CompletedAsync += delegate(object s, EventArgs <SMTP_Client.EhloHeloAsyncOP> e)
                    {
                        EhloCommandCompleted(ehloOP);
                    };
                    if (!m_pSmtpClient.EhloHeloAsync(ehloOP))
                    {
                        EhloCommandCompleted(ehloOP);
                    }
                }
            }
            catch (Exception x)
            {
                Dispose(x);
            }
        }
Пример #4
0
        /// <summary>
        /// Completes relay session and does clean up. This method is thread-safe.
        /// </summary>
        /// <param name="exception">Exception happened or null if relay completed successfully.</param>
        public void Dispose(Exception exception)
        {
            try
            {
                lock (this)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    try
                    {
                        m_pServer.OnSessionCompleted(this, exception);
                    }
                    catch
                    {
                    }
                    m_pServer.Sessions.Remove(this);
                    m_IsDisposed = true;

                    m_pLocalBindInfo = null;
                    m_pRelayItem     = null;
                    m_pSmartHosts    = null;
                    if (m_pSmtpClient != null)
                    {
                        m_pSmtpClient.Dispose();
                        m_pSmtpClient = null;
                    }
                    m_pTargets = null;
                    if (m_pActiveTarget != null)
                    {
                        m_pServer.RemoveIpUsage(m_pActiveTarget.Target.Address);
                        m_pActiveTarget = null;
                    }
                    m_pServer = null;
                }
            }
            catch (Exception x)
            {
                if (m_pServer != null)
                {
                    m_pServer.OnError(x);
                }
            }
        }
Пример #5
0
        /// <summary>
        /// This method is called when asynchronous Connect method completes.
        /// </summary>
        /// <param name="ar">An IAsyncResult that stores state information and any user defined data for this asynchronous operation.</param>
        private void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                m_pSmtpClient.EndConnect(ar);

                // Start TLS requested, start switching to SSL.
                if (m_pActiveTarget.SslMode == SslMode.TLS)
                {
                    m_pSmtpClient.BeginStartTLS(StartTlsCallback, null);
                }
                    // Authentication requested, start authenticating.
                else if (!string.IsNullOrEmpty(m_pActiveTarget.UserName))
                {
                    m_pSmtpClient.BeginAuthenticate(m_pActiveTarget.UserName,
                                                    m_pActiveTarget.Password,
                                                    AuthenticateCallback,
                                                    null);
                }
                else
                {
                    long messageSize = -1;
                    try
                    {
                        messageSize = m_pRelayItem.MessageStream.Length - m_pRelayItem.MessageStream.Position;
                    }
                    catch
                    {
                        // Stream doesn't support seeking.
                    }

                    m_pSmtpClient.BeginMailFrom(From, messageSize, MailFromCallback, null);
                }
            }
            catch (Exception x)
            {
                try
                {
                    // Release IP usage.
                    m_pServer.RemoveIpUsage(m_pActiveTarget.Target.Address);
                    m_pActiveTarget = null;

                    // Connect failed, if there are more target IPs, try next one.
                    if (!IsDisposed && !IsConnected && m_pTargets.Count > 0)
                    {
                        BeginConnect();
                    }
                    else
                    {
                        Dispose(x);
                    }
                }
                catch (Exception xx)
                {
                    Dispose(xx);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Starts connecting to best target. 
        /// </summary>
        private void BeginConnect()
        {
            // No tagets, abort relay.
            if (m_pTargets.Count == 0)
            {
                LogText("No relay target(s) for '" + m_pRelayItem.To + "', aborting.");
                Dispose(new Exception("No relay target(s) for '" + m_pRelayItem.To + "', aborting."));
                return;
            }

            // If maximum connections to specified target exceeded and there are more targets, try to get limit free target.            
            if (m_pServer.MaxConnectionsPerIP > 0)
            {
                // For DNS or load-balnced smart host relay, search free target if any.
                if (m_pServer.RelayMode == Relay_Mode.Dns ||
                    m_pServer.SmartHostsBalanceMode == BalanceMode.LoadBalance)
                {
                    foreach (Relay_Target t in m_pTargets)
                    {
                        // We found free target, stop searching.
                        if (m_pServer.TryAddIpUsage(m_pTargets[0].Target.Address))
                        {
                            m_pActiveTarget = t;
                            m_pTargets.Remove(t);
                            break;
                        }
                    }
                }
                    // Smart host fail-over mode, just check if it's free.
                else
                {
                    // Smart host IP limit not reached.
                    if (m_pServer.TryAddIpUsage(m_pTargets[0].Target.Address))
                    {
                        m_pActiveTarget = m_pTargets[0];
                        m_pTargets.RemoveAt(0);
                    }
                }
            }
                // Just get first target.
            else
            {
                m_pActiveTarget = m_pTargets[0];
                m_pTargets.RemoveAt(0);
            }

            // If all targets has exeeded maximum allowed connection per IP address, end relay session, 
            // next relay cycle will try to relay again.
            if (m_pActiveTarget == null)
            {
                LogText("All targets has exeeded maximum allowed connection per IP address, skip relay.");
                Dispose(
                    new Exception(
                        "All targets has exeeded maximum allowed connection per IP address, skip relay."));
                return;
            }

            m_pSmtpClient.BeginConnect(new IPEndPoint(m_pLocalBindInfo.IP, 0),
                                       m_pActiveTarget.Target,
                                       false,
                                       ConnectCallback,
                                       null);
        }
Пример #7
0
        /// <summary>
        /// Completes relay session and does clean up. This method is thread-safe.
        /// </summary>
        /// <param name="exception">Exception happened or null if relay completed successfully.</param>
        public void Dispose(Exception exception)
        {
            try
            {
                lock (this)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    try
                    {
                        m_pServer.OnSessionCompleted(this, exception);
                    }
                    catch {}
                    m_pServer.Sessions.Remove(this);
                    m_IsDisposed = true;

                    m_pLocalBindInfo = null;
                    m_pRelayItem = null;
                    m_pSmartHosts = null;
                    if (m_pSmtpClient != null)
                    {
                        m_pSmtpClient.Dispose();
                        m_pSmtpClient = null;
                    }
                    m_pTargets = null;
                    if (m_pActiveTarget != null)
                    {
                        m_pServer.RemoveIpUsage(m_pActiveTarget.Target.Address);
                        m_pActiveTarget = null;
                    }
                    m_pServer = null;
                }
            }
            catch (Exception x)
            {
                if (m_pServer != null)
                {
                    m_pServer.OnError(x);
                }
            }
        }
        /// <summary>
        /// Starts connecting to best target.
        /// </summary>
        private void BeginConnect()
        {
            // No tagets, abort relay.
            if (m_pTargets.Count == 0)
            {
                LogText("No relay target(s) for '" + m_pRelayItem.To + "', aborting.");
                Dispose(new Exception("No relay target(s) for '" + m_pRelayItem.To + "', aborting."));

                return;
            }

            // Maximum connections per IP limited.
            if (m_pServer.MaxConnectionsPerIP > 0)
            {
                // For DNS or load-balnced smart host relay, search free target if any.
                if (m_pServer.RelayMode == Relay_Mode.Dns || m_pServer.SmartHostsBalanceMode == BalanceMode.LoadBalance)
                {
                    foreach (Relay_Target t in m_pTargets)
                    {
                        // Get local IP binding for remote IP.
                        m_pLocalBindInfo = m_pServer.GetLocalBinding(t.Target.Address);

                        // We have suitable local IP binding for the target.
                        if (m_pLocalBindInfo != null)
                        {
                            // We found free target, stop searching.
                            if (m_pServer.TryAddIpUsage(t.Target.Address))
                            {
                                m_pActiveTarget = t;
                                m_pTargets.Remove(t);

                                break;
                            }
                            // Connection per IP limit reached.
                            else
                            {
                                LogText("Skipping relay target (" + t.HostName + "->" + t.Target.Address + "), maximum connections to the specified IP has reached.");
                            }
                        }
                        // No suitable local IP binding, try next target.
                        else
                        {
                            LogText("Skipping relay target (" + t.HostName + "->" + t.Target.Address + "), no suitable local IPv4/IPv6 binding.");
                        }
                    }
                }
                // Smart host fail-over mode, just check if it's free.
                else
                {
                    // Get local IP binding for remote IP.
                    m_pLocalBindInfo = m_pServer.GetLocalBinding(m_pTargets[0].Target.Address);

                    // We have suitable local IP binding for the target.
                    if (m_pLocalBindInfo != null)
                    {
                        // Smart host IP limit not reached.
                        if (m_pServer.TryAddIpUsage(m_pTargets[0].Target.Address))
                        {
                            m_pActiveTarget = m_pTargets[0];
                            m_pTargets.RemoveAt(0);
                        }
                        // Connection per IP limit reached.
                        else
                        {
                            LogText("Skipping relay target (" + m_pTargets[0].HostName + "->" + m_pTargets[0].Target.Address + "), maximum connections to the specified IP has reached.");
                        }
                    }
                    // No suitable local IP binding, try next target.
                    else
                    {
                        LogText("Skipping relay target (" + m_pTargets[0].HostName + "->" + m_pTargets[0].Target.Address + "), no suitable local IPv4/IPv6 binding.");
                    }
                }
            }
            // Just get first target.
            else
            {
                // Get local IP binding for remote IP.
                m_pLocalBindInfo = m_pServer.GetLocalBinding(m_pTargets[0].Target.Address);

                // We have suitable local IP binding for the target.
                if (m_pLocalBindInfo != null)
                {
                    m_pActiveTarget = m_pTargets[0];
                    m_pTargets.RemoveAt(0);
                }
                // No suitable local IP binding, try next target.
                else
                {
                    LogText("Skipping relay target (" + m_pTargets[0].HostName + "->" + m_pTargets[0].Target.Address + "), no suitable local IPv4/IPv6 binding.");
                }
            }

            // We don't have suitable local IP end point for relay target.
            // This may heppen for example: if remote server supports only IPv6 and we don't have local IPv6 local end point.
            if (m_pLocalBindInfo == null)
            {
                LogText("No suitable IPv4/IPv6 local IP endpoint for relay target.");
                Dispose(new Exception("No suitable IPv4/IPv6 local IP endpoint for relay target."));

                return;
            }

            // If all targets has exeeded maximum allowed connection per IP address, end relay session,
            // next relay cycle will try to relay again.
            if (m_pActiveTarget == null)
            {
                LogText("All targets has exeeded maximum allowed connection per IP address, skip relay.");
                Dispose(new Exception("All targets has exeeded maximum allowed connection per IP address, skip relay."));

                return;
            }

            // Set SMTP host name.
            m_pSmtpClient.LocalHostName = m_pLocalBindInfo.HostName;

            // Start connecting to remote end point.
            TCP_Client.ConnectAsyncOP connectOP = new TCP_Client.ConnectAsyncOP(new IPEndPoint(m_pLocalBindInfo.IP, 0), m_pActiveTarget.Target, false, null);
            connectOP.CompletedAsync += delegate(object s, EventArgs <TCP_Client.ConnectAsyncOP> e){
                ConnectCompleted(connectOP);
            };
            if (!m_pSmtpClient.ConnectAsync(connectOP))
            {
                ConnectCompleted(connectOP);
            }
        }
Пример #9
0
        /// <summary>
        /// Is called when EHLO/HELO command has completed.
        /// </summary>
        /// <param name="op">Asynchronous operation.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
        private void ConnectCompleted(TCP_Client.ConnectAsyncOP op)
        {
            if(op == null){
                throw new ArgumentNullException("op");
            }

            try{
                // Connect failed.
                if(op.Error != null){
                    try{
                        // Release IP usage.
                        m_pServer.RemoveIpUsage(m_pActiveTarget.Target.Address);
                        m_pActiveTarget = null;

                        // Connect failed, if there are more target IPs, try next one.
                        if(!this.IsDisposed && !this.IsConnected && m_pTargets.Count > 0){
                            BeginConnect();
                        }
                        else{
                            Dispose(op.Error);
                        }
                    }
                    catch(Exception x1){
                        Dispose(x1);
                    }
                }
                // Connect suceeded.
                else{
                    // Do EHLO/HELO.
                    string hostName = string.IsNullOrEmpty(m_pLocalBindInfo.HostName) ? Dns.GetHostName() : m_pLocalBindInfo.HostName;
                    SMTP_Client.EhloHeloAsyncOP ehloOP = new SMTP_Client.EhloHeloAsyncOP(hostName);
                    ehloOP.CompletedAsync += delegate(object s,EventArgs<SMTP_Client.EhloHeloAsyncOP> e){
                        EhloCommandCompleted(ehloOP);
                    };
                    if(!m_pSmtpClient.EhloHeloAsync(ehloOP)){
                        EhloCommandCompleted(ehloOP);
                    }
                }
            }
            catch(Exception x){
                Dispose(x);
            }
        }
Пример #10
0
        /// <summary>
        /// Starts connecting to best target. 
        /// </summary>
        private void BeginConnect()
        {
            // No tagets, abort relay.
            if(m_pTargets.Count == 0){
                LogText("No relay target(s) for '" + m_pRelayItem.To + "', aborting.");
                Dispose(new Exception("No relay target(s) for '" + m_pRelayItem.To + "', aborting."));

                return;
            }

            // Maximum connections per IP limited.
            if(m_pServer.MaxConnectionsPerIP > 0){
                // For DNS or load-balnced smart host relay, search free target if any.
                if(m_pServer.RelayMode == Relay_Mode.Dns || m_pServer.SmartHostsBalanceMode == BalanceMode.LoadBalance){
                    foreach(Relay_Target t in m_pTargets){
                        // Get local IP binding for remote IP.
                        m_pLocalBindInfo = m_pServer.GetLocalBinding(t.Target.Address);

                        // We have suitable local IP binding for the target.
                        if(m_pLocalBindInfo != null){
                            // We found free target, stop searching.
                            if(m_pServer.TryAddIpUsage(t.Target.Address)){
                                m_pActiveTarget = t;
                                m_pTargets.Remove(t);

                                break;
                            }
                            // Connection per IP limit reached.
                            else{
                                LogText("Skipping relay target (" + t.HostName + "->" + t.Target.Address + "), maximum connections to the specified IP has reached.");
                            }
                        }
                        // No suitable local IP binding, try next target.
                        else{
                            LogText("Skipping relay target (" + t.HostName + "->" + t.Target.Address + "), no suitable local IPv4/IPv6 binding.");
                        }
                    }
                }
                // Smart host fail-over mode, just check if it's free.
                else{
                    // Get local IP binding for remote IP.
                    m_pLocalBindInfo = m_pServer.GetLocalBinding(m_pTargets[0].Target.Address);

                    // We have suitable local IP binding for the target.
                    if(m_pLocalBindInfo != null){
                        // Smart host IP limit not reached.
                        if(m_pServer.TryAddIpUsage(m_pTargets[0].Target.Address)){
                            m_pActiveTarget = m_pTargets[0];
                            m_pTargets.RemoveAt(0);
                        }
                        // Connection per IP limit reached.
                        else{
                            LogText("Skipping relay target (" + m_pTargets[0].HostName + "->" + m_pTargets[0].Target.Address + "), maximum connections to the specified IP has reached.");
                        }
                    }
                    // No suitable local IP binding, try next target.
                    else{
                        LogText("Skipping relay target (" + m_pTargets[0].HostName + "->" + m_pTargets[0].Target.Address + "), no suitable local IPv4/IPv6 binding.");
                    }
                }
            }
            // Just get first target.
            else{
                 // Get local IP binding for remote IP.
                 m_pLocalBindInfo = m_pServer.GetLocalBinding(m_pTargets[0].Target.Address);

                 // We have suitable local IP binding for the target.
                 if(m_pLocalBindInfo != null){
                    m_pActiveTarget = m_pTargets[0];
                    m_pTargets.RemoveAt(0);
                 }
                 // No suitable local IP binding, try next target.
                 else{
                    LogText("Skipping relay target (" + m_pTargets[0].HostName + "->" + m_pTargets[0].Target.Address + "), no suitable local IPv4/IPv6 binding.");
                 }
            }

            // We don't have suitable local IP end point for relay target.
            // This may heppen for example: if remote server supports only IPv6 and we don't have local IPv6 local end point.
            if(m_pLocalBindInfo == null){
                LogText("No suitable IPv4/IPv6 local IP endpoint for relay target.");
                Dispose(new Exception("No suitable IPv4/IPv6 local IP endpoint for relay target."));

                return;
            }

            // If all targets has exeeded maximum allowed connection per IP address, end relay session,
            // next relay cycle will try to relay again.
            if(m_pActiveTarget == null){
                LogText("All targets has exeeded maximum allowed connection per IP address, skip relay.");
                Dispose(new Exception("All targets has exeeded maximum allowed connection per IP address, skip relay."));

                return;
            }

            // Set SMTP host name.
            m_pSmtpClient.LocalHostName = m_pLocalBindInfo.HostName;

            // Start connecting to remote end point.
            TCP_Client.ConnectAsyncOP connectOP = new TCP_Client.ConnectAsyncOP(new IPEndPoint(m_pLocalBindInfo.IP,0),m_pActiveTarget.Target,false,null);
            connectOP.CompletedAsync += delegate(object s,EventArgs<TCP_Client.ConnectAsyncOP> e){
                ConnectCompleted(connectOP);
            };
            if(!m_pSmtpClient.ConnectAsync(connectOP)){
                ConnectCompleted(connectOP);
            }
        }