/// <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); } }
/// <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); } }