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