/// <summary> /// Starts proccessiong incoming connections (Accepts and queues connections). /// </summary> private void StartProcCons() { try{ CircleCollection <IPBindInfo> binds = new CircleCollection <IPBindInfo>(); foreach (IPBindInfo bindInfo in m_pBindInfo) { Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); s.Bind(new IPEndPoint(bindInfo.IP, bindInfo.Port)); s.Listen(500); bindInfo.Tag = s; binds.Add(bindInfo); } // Accept connections and queue them while (m_Running) { // We have reached maximum connection limit if (m_pSessions.Count > m_MaxConnections) { // Wait while some active connectins are closed while (m_pSessions.Count > m_MaxConnections) { Thread.Sleep(100); } } // Get incomong connection IPBindInfo bindInfo = binds.Next(); // There is waiting connection if (m_Running && ((Socket)bindInfo.Tag).Poll(0, SelectMode.SelectRead)) { // Accept incoming connection Socket s = ((Socket)bindInfo.Tag).Accept(); // Add session to queue lock (m_pQueuedConnections){ m_pQueuedConnections.Enqueue(new QueuedConnection(s, bindInfo)); } } Thread.Sleep(2); } } catch (SocketException x) { // Socket listening stopped, happens when StopServer is called. // We need just skip this error. if (x.ErrorCode == 10004) { } else { OnSysError("WE MUST NEVER REACH HERE !!! StartProcCons:", x); } } catch (Exception x) { OnSysError("WE MUST NEVER REACH HERE !!! StartProcCons:", x); } }
/// <summary> /// Smart host relay session constructor. /// </summary> /// <param name="server">Owner relay server.</param> /// <param name="localBindInfo">Local bind info.</param> /// <param name="realyItem">Relay item.</param> /// <param name="smartHosts">Smart hosts.</param> /// <exception cref="ArgumentNullException">Is raised when <b>server</b>,<b>localBindInfo</b>,<b>realyItem</b> or <b>smartHosts</b>is null.</exception> /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception> internal Relay_Session(Relay_Server server,IPBindInfo localBindInfo,Relay_QueueItem realyItem,Relay_SmartHost[] smartHosts) { if(server == null){ throw new ArgumentNullException("server"); } if(localBindInfo == null){ throw new ArgumentNullException("localBindInfo"); } if(realyItem == null){ throw new ArgumentNullException("realyItem"); } if(smartHosts == null){ throw new ArgumentNullException("smartHosts"); } m_pServer = server; m_pLocalBindInfo = localBindInfo; m_pRelayItem = realyItem; m_pSmartHosts = smartHosts; m_RelayMode = Relay_Mode.SmartHost; m_SessionID = Guid.NewGuid().ToString(); m_SessionCreateTime = DateTime.Now; m_pTargets = new List<Relay_Target>(); m_pSmtpClient = new SMTP_Client(); m_pSmtpClient.BdatEnabled = false; }
/// <summary> /// Default constructor. /// </summary> /// <param name="sessionID">Session ID.</param> /// <param name="socket">Server connected socket.</param> /// <param name="bindInfo">BindInfo what accepted socket.</param> /// <param name="server">Reference to server.</param> internal FTP_Session(string sessionID,SocketEx socket,IPBindInfo bindInfo,FTP_Server server) : base(sessionID,socket,bindInfo,server) { m_pServer = server; // Start session proccessing StartSession(); }
private string m_UserName = ""; // Holds USER command value #endregion Fields #region Constructors /// <summary> /// Default constructor. /// </summary> /// <param name="sessionID">Session ID.</param> /// <param name="socket">Server connected socket.</param> /// <param name="bindInfo">BindInfo what accepted socket.</param> /// <param name="server">Reference to server.</param> internal POP3_Session(string sessionID,SocketEx socket,IPBindInfo bindInfo,POP3_Server server) : base(sessionID,socket,bindInfo,server) { m_pServer = server; m_POP3_Messages = new POP3_MessageCollection(); // Start session proccessing StartSession(); }
/// <summary> /// Default constructor. /// </summary> /// <param name="sysSettings">Reference to system settings.</param> /// <param name="enabled">Specifies if SIP service is enabled.</param> /// <param name="proxyMode">Specifies SIP proxy server opearion mode.</param> /// <param name="minExpires">SIP minimum content expire time in seconds.</param> /// <param name="bindings">Specifies SIP listening info.</param> /// <param name="gateways">SIP gateways.</param> internal SIP_Settings(System_Settings sysSettings,bool enabled,SIP_ProxyMode proxyMode,int minExpires,IPBindInfo[] bindings,SIP_GatewayCollection gateways) { m_pSysSettings = sysSettings; m_Enabled = enabled; m_ProxyMode = proxyMode; m_MinExpires = minExpires; m_pBinds = bindings; m_pGateways = gateways; }
/// <summary> /// Default constructor. /// </summary> /// <param name="sessionID">Session ID.</param> /// <param name="socket">Server connected socket.</param> /// <param name="bindInfo">BindInfo what accepted socket.</param> /// <param name="server">Reference to server.</param> public SocketServerSession(string sessionID, SocketEx socket, IPBindInfo bindInfo, SocketServer server) { m_SessionID = sessionID; m_pSocket = socket; m_pBindInfo = bindInfo; m_pServer = server; m_SessionStartTime = DateTime.Now; }
/// <summary> /// Default constructor. /// </summary> /// <param name="sessionID">Session ID.</param> /// <param name="socket">Server connected socket.</param> /// <param name="bindInfo">BindInfo what accepted socket.</param> /// <param name="server">Reference to server.</param> public SocketServerSession(string sessionID,SocketEx socket,IPBindInfo bindInfo,SocketServer server) { m_SessionID = sessionID; m_pSocket = socket; m_pBindInfo = bindInfo; m_pServer = server; m_SessionStartTime = DateTime.Now; }
/// <summary> /// Default constructor. /// </summary> /// <param name="sessionID">Session ID.</param> /// <param name="socket">Server connected socket.</param> /// <param name="bindInfo">BindInfo what accepted socket.</param> /// <param name="server">Reference to server.</param> internal SMTP_Session(string sessionID,SocketEx socket,IPBindInfo bindInfo,SMTP_Server server) : base(sessionID,socket,bindInfo,server) { m_pServer = server; m_BodyType = BodyType.x7_bit; m_Forward_path = new Hashtable(); m_CmdValidator = new SMTP_Cmd_Validator(); // Start session proccessing StartSession(); }
/// <summary> /// Default constructor. /// </summary> /// <param name="sysSettings">Reference to system settings.</param> /// <param name="enabled">Specifies if IMAP service is enabled.</param> /// <param name="greeting">Greeting text.</param> /// <param name="idleTimeout">Session idle timeout seconds.</param> /// <param name="maxConnections">Maximum conncurent connections.</param> /// <param name="maxConnectionsPerIP">Maximum conncurent connections fro 1 IP address.</param> /// <param name="maxBadCommands">Maximum bad commands per session.</param> /// <param name="bindings">Specifies IMAP listening info.</param> internal IMAP_Settings(System_Settings sysSettings,bool enabled,string greeting,int idleTimeout,int maxConnections,int maxConnectionsPerIP,int maxBadCommands,IPBindInfo[] bindings) { m_pSysSettings = sysSettings; m_Enabled = enabled; m_Greeting = greeting; m_IdleTimeout = idleTimeout; m_MaxConnections = maxConnections; m_MaxConnsPerIP = maxConnectionsPerIP; m_MaxBadCommands = maxBadCommands; m_pBinds = bindings; }
/// <summary> /// Default constructor. /// </summary> /// <param name="sysSettings">Reference to system settings.</param> /// <param name="enabled">Specifies if SMTP service is enabled.</param> /// <param name="greeting">Greeting text.</param> /// <param name="defaultDomain">Default domain.</param> /// <param name="idleTimeOut">Session idle timeout seconds.</param> /// <param name="maxConnections">Maximum conncurent connections.</param> /// <param name="maxConnectionsPerIP">Maximum conncurent connections fro 1 IP address.</param> /// <param name="maxBadCommands">Maximum bad commands per session.</param> /// <param name="maxRecipients">Maximum recipients per message.</param> /// <param name="maxMessageSize">Maximum allowed message size.</param> /// <param name="maxTransactions">Maximum mail transactions per session.</param> /// <param name="requireAuth">Specifies if SMTP server is private server and requires authentication.</param> /// <param name="bindings">Specifies SMTP listening info.</param> internal SMTP_Settings(System_Settings sysSettings,bool enabled,string greeting,string defaultDomain,int idleTimeOut,int maxConnections,int maxConnectionsPerIP,int maxBadCommands,int maxRecipients,int maxMessageSize,int maxTransactions,bool requireAuth,IPBindInfo[] bindings) { m_pSysSettings = sysSettings; m_Enabled = enabled; m_GreetingText = greeting; m_DefaultDomain = defaultDomain; m_SessionIdleTimeOut = idleTimeOut; m_MaxConnections = maxConnections; m_MaxConnsPerIP = maxConnectionsPerIP; m_MaxBadCommnads = maxBadCommands; m_MaxRecipientPerMsg = maxRecipients; m_MaxMessageSize = maxMessageSize; m_MaxTransactions = maxTransactions; m_RequireAuth = requireAuth; m_pBinds = bindings; }
/// <summary> /// Default constructor. /// </summary> /// <param name="sysSettings">Reference to system settings.</param> /// <param name="relayMode">Relay mode.</param> /// <param name="smartHostBalanceMode">Specifies how smart hosts will balance.</param> /// <param name="smartHosts">Smart hosts.</param> /// <param name="idleTimeout">Session idle timeout seconds.</param> /// <param name="maxConnections">Maximum conncurent conncetions.</param> /// <param name="maxConnectionsPerIP">Maximum conncurent conncetions to one IP address.</param> /// <param name="relayInterval">Relay messages interval seconds.</param> /// <param name="relayRetryInterval">Relay retry messages interval seconds.</param> /// <param name="undeliveredWarning">Specifies after how many minutes delayed delivery message is sent.</param> /// <param name="undelivered">Specifies after how many hours undelivered notification message is sent.</param> /// <param name="storeUndelivered">Specifies if undelivered messages are stored to "Undelivered" folder in mail store.</param> /// <param name="bindings">Specifies SMTP listening info.</param> internal Relay_Settings(System_Settings sysSettings,Relay_Mode relayMode,BalanceMode smartHostBalanceMode,Relay_SmartHost[] smartHosts,int idleTimeout,int maxConnections,int maxConnectionsPerIP,int relayInterval,int relayRetryInterval,int undeliveredWarning,int undelivered,bool storeUndelivered,IPBindInfo[] bindings) { m_pSysSettings = sysSettings; m_RelayMode = relayMode; m_SmartHostsBalanceMode = smartHostBalanceMode; m_pSmartHosts = smartHosts; m_IdleTimeout = idleTimeout; m_MaxConnections = maxConnections; m_MaxConnectionsPerIP = maxConnectionsPerIP; m_RelayInterval = relayInterval; m_RelayRetryInterval = relayRetryInterval; m_SendUndelWaringAfter = undeliveredWarning; m_SendUndeliveredAfter = undelivered; m_StoreUndeliveredMsgs = storeUndelivered; m_pBinds = bindings; }
/// <summary> /// Compares the current instance with another object of the same type. /// </summary> /// <param name="obj">An object to compare with this instance.</param> /// <returns>Returns true if two objects are equal.</returns> public override bool Equals(object obj) { if (obj == null) { return(false); } if (!(obj is IPBindInfo)) { return(false); } IPBindInfo bInfo = (IPBindInfo)obj; if (bInfo.HostName != m_HostName) { return(false); } if (bInfo.Protocol != m_Protocol) { return(false); } if (!bInfo.EndPoint.Equals(m_pEndPoint)) { return(false); } if (bInfo.SslMode != m_SslMode) { return(false); } if (!X509Certificate.Equals(bInfo.Certificate, m_pCertificate)) { return(false); } return(true); }
/// <summary> /// Initialize and start new session here. Session isn't added to session list automatically, /// session must add itself to server session list by calling AddSession(). /// </summary> /// <param name="socket">Connected client socket.</param> /// <param name="bindInfo">BindInfo what accepted socket.</param> protected override void InitNewSession(Socket socket,IPBindInfo bindInfo) { // Check maximum conncurent connections from 1 IP. if(m_MaxConnectionsPerIP > 0){ lock(this.Sessions){ int nSessions = 0; foreach(SocketServerSession s in this.Sessions){ IPEndPoint ipEndpoint = s.RemoteEndPoint; if(ipEndpoint != null){ if(ipEndpoint.Address.Equals(((IPEndPoint)socket.RemoteEndPoint).Address)){ nSessions++; } } // Maimum allowed exceeded if(nSessions >= m_MaxConnectionsPerIP){ socket.Send(System.Text.Encoding.ASCII.GetBytes("421 Maximum connections from your IP address is exceeded, try again later !\r\n")); socket.Shutdown(SocketShutdown.Both); socket.Close(); return; } } } } string sessionID = Guid.NewGuid().ToString(); SocketEx socketEx = new SocketEx(socket); if(LogCommands){ socketEx.Logger = new SocketLogger(socket,this.SessionLog); socketEx.Logger.SessionID = sessionID; } SMTP_Session session = new SMTP_Session(sessionID,socketEx,bindInfo,this); }
/// <summary> /// Processes relay queue. /// </summary> private void Run() { while(m_IsRunning){ try{ // Bind info has changed, create new local end points. if(m_HasBindingsChanged){ m_pLocalEndPointIPv4.Clear(); m_pLocalEndPointIPv6.Clear(); foreach(IPBindInfo binding in m_pBindings){ if(binding.IP == IPAddress.Any){ foreach(IPAddress ip in System.Net.Dns.GetHostAddresses("")){ if(ip.AddressFamily == AddressFamily.InterNetwork){ IPBindInfo b = new IPBindInfo(binding.HostName,binding.Protocol,ip,25); if(!m_pLocalEndPointIPv4.Contains(b)){ m_pLocalEndPointIPv4.Add(b); } } } } else if(binding.IP == IPAddress.IPv6Any){ foreach(IPAddress ip in System.Net.Dns.GetHostAddresses("")){ if(ip.AddressFamily == AddressFamily.InterNetworkV6){ IPBindInfo b = new IPBindInfo(binding.HostName,binding.Protocol,ip,25); if(!m_pLocalEndPointIPv6.Contains(b)){ m_pLocalEndPointIPv6.Add(b); } } } } else{ IPBindInfo b = new IPBindInfo(binding.HostName,binding.Protocol,binding.IP,25); if(binding.IP.AddressFamily == AddressFamily.InterNetwork){ if(!m_pLocalEndPointIPv4.Contains(b)){ m_pLocalEndPointIPv4.Add(b); } } else{ if(!m_pLocalEndPointIPv6.Contains(b)){ m_pLocalEndPointIPv6.Add(b); } } } } m_HasBindingsChanged = false; } // There are no local end points specified. if(m_pLocalEndPointIPv4.Count == 0 && m_pLocalEndPointIPv6.Count == 0){ Thread.Sleep(10); } // Maximum allowed relay sessions exceeded, skip adding new ones. else if(m_MaxConnections != 0 && m_pSessions.Count >= m_MaxConnections){ Thread.Sleep(10); } else{ Relay_QueueItem item = null; // Get next queued message from highest possible priority queue. foreach(Relay_Queue queue in m_pQueues){ item = queue.DequeueMessage(); // There is queued message. if(item != null){ break; } // No messages in this queue, see next lower priority queue. } // There are no messages in any queue. if(item == null){ Thread.Sleep(10); } // Create new session for queued relay item. else{ if(m_RelayMode == Relay_Mode.Dns){ Relay_Session session = new Relay_Session(this,item); m_pSessions.Add(session); ThreadPool.QueueUserWorkItem(new WaitCallback(session.Start)); } else if(m_RelayMode == Relay_Mode.SmartHost){ // Get smart hosts in balance mode order. Relay_SmartHost[] smartHosts = null; if(m_SmartHostsBalanceMode == BalanceMode.FailOver){ smartHosts = m_pSmartHosts.ToArray(); } else{ smartHosts = m_pSmartHosts.ToCurrentOrderArray(); } Relay_Session session = new Relay_Session(this,item,smartHosts); m_pSessions.Add(session); ThreadPool.QueueUserWorkItem(new WaitCallback(session.Start)); } } } } catch(Exception x){ OnError(x); } } }
/// <summary> /// Default constructor. /// </summary> /// <param name="server">Reference to server.</param> /// <param name="allowUDP">Specifies if UDP protocol is enabled.</param> /// <param name="defaultPort">Specifies default port.</param> /// <param name="defaultSSLPort">Specifies default SSL port.</param> /// <param name="bindInfo">Bind info.</param> public wfrm_sys_BindInfo(Server server,bool allowUDP,int defaultPort,int defaultSSLPort,IPBindInfo bindInfo) : this(server,allowUDP,true,true,defaultPort,defaultSSLPort,bindInfo) { }
public void start_server() { server = new TCP_Server<TCP_ServerSession>(); server.SessionCreated += server_SessionCreated; IPBindInfo x = new IPBindInfo("server", BindInfoProtocol.TCP, System.Net.IPAddress.Any, 8787); server.Bindings = new IPBindInfo[] { x }; server.Start(); Log.log_info("TCP Server Started"); }
/// <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); } } }
/// <summary> /// Initialize and start new session here. Session isn't added to session list automatically, /// session must add itself to server session list by calling AddSession(). /// </summary> /// <param name="socket">Connected client socket.</param> /// <param name="bindInfo">BindInfo what accepted socket.</param> protected virtual void InitNewSession(Socket socket, IPBindInfo bindInfo) { }
/// <summary> /// Default constructor. /// </summary> /// <param name="socket">Socket.</param> /// <param name="bindInfo">Bind info.</param> public QueuedConnection(Socket socket, IPBindInfo bindInfo) { m_pSocket = socket; m_pBindInfo = bindInfo; }
/// <summary> /// Default constructor. /// </summary> /// <param name="server">Reference to server.</param> /// <param name="allowUDP">Specifies if UDP protocol is enabled.</param> /// <param name="allowSSL">Specifies if SSL is enabled.</param> /// <param name="allowChangePort">Specifies if port can be changed.</param> /// <param name="defaultPort">Specifies default port.</param> /// <param name="defaultSSLPort">Specifies default SSL port.</param> /// <param name="bindInfo">Bind info.</param> public wfrm_sys_BindInfo(Server server,bool allowUDP,bool allowSSL,bool allowChangePort,int defaultPort,int defaultSSLPort,IPBindInfo bindInfo) { m_SslEnabled = allowSSL; m_DefaultPort = defaultPort; m_DefaultSSLPort = defaultSSLPort; InitUI(); m_pSslMode.SelectedIndex = 0; if(!allowSSL){ m_pSslMode.Enabled = false; } if(!allowChangePort){ m_pPort.Enabled = false; } if(bindInfo != null){ m_pHostName.Text = bindInfo.HostName; } m_pProtocol.Items.Add("TCP"); if(allowUDP){ m_pProtocol.Items.Add("UDP"); } if(bindInfo == null){ m_pProtocol.SelectedIndex = 0; } else{ m_pProtocol.Text = bindInfo.Protocol.ToString(); } foreach(IPAddress ip in server.IPAddresses){ m_pIP.Items.Add(new WComboBoxItem(IpToString(ip),ip)); } if(bindInfo == null){ m_pIP.SelectedIndex = 0; m_pPort.Value = defaultPort; } else{ m_pCert = bindInfo.Certificate; m_pIP.Text = IpToString(bindInfo.IP); m_pPort.Value = bindInfo.Port; m_pSslMode.Text = bindInfo.SslMode.ToString(); } UpdateCertStatus(); }