using System; using System.Net; using System.Net.Sockets; namespace Uber.Net { /// /// Listens for TCP connections at a given port, asynchronously accepting connections and optionally insert them in the Ion environment connection manager. /// public class TcpConnectionListener { #region Fields /// /// The maximum length of the connection request queue for the listener as an integer. /// private const int LISTENER_CONNECTIONREQUEST_QUEUE_LENGTH = 1; /// /// A System.Net.Sockets.TcpListener that listens for connections. /// private TcpListener mListener = null; private bool mIsListening = false; private AsyncCallback mConnectionRequestCallback = null; private TcpConnectionManager mManager; /// /// An IonTcpConnectionFactory instance that is capable of creating IonTcpConnections. /// private TcpConnectionFactory mFactory; #endregion #region Properties /// /// Gets whether the listener is listening for new connections or not. /// public bool isListening { get { return mIsListening; } } #endregion #region Constructors /// /// Constructs an IonTcpConnection listener and binds it to a given local IP address and TCP port. /// /// The IP address string to parse and bind the listener to. /// The TCP port number to parse the listener to. public TcpConnectionListener(string sLocalIP, int Port, TcpConnectionManager pManager) { IPAddress pIP = null; if (!IPAddress.TryParse(sLocalIP, out pIP)) { pIP = IPAddress.Loopback; UberEnvironment.GetLogging().WriteWarning(string.Format("Connection listener was unable to parse the given local IP address '{0}', now binding listener to '{1}'.", sLocalIP, pIP.ToString())); } mListener = new TcpListener(pIP, Port); mConnectionRequestCallback = new AsyncCallback(ConnectionRequest); mFactory = new TcpConnectionFactory(); mManager = pManager; UberEnvironment.GetLogging().WriteLine(string.Format("IonTcpConnectionListener initialized and bound to {0}:{1}.", pIP.ToString(), Port.ToString())); } #endregion #region Methods /// /// Starts listening for connections. /// public void Start() { if (mIsListening) return; mListener.Start(); mIsListening = true; WaitForNextConnection(); } /// /// Stops listening for connections. /// public void Stop() { if (!mIsListening) return; mIsListening = false; mListener.Stop(); } /// /// Destroys all resources in the connection listener. /// public void Destroy() { Stop(); mListener = null; mManager = null; mFactory = null; } /// /// Waits for the next connection request in it's own thread. /// private void WaitForNextConnection() { if (mIsListening) mListener.BeginAcceptSocket(mConnectionRequestCallback, null); } /// /// Invoked when the listener asynchronously accepts a new connection request. /// /// The IAsyncResult object holding the results of the asynchronous BeginAcceptSocket operation. private void ConnectionRequest(IAsyncResult iAr) { try { Socket pSocket = mListener.EndAcceptSocket(iAr); // TODO: IP blacklist TcpConnection connection = mFactory.CreateConnection(pSocket); if (connection != null) { mManager.HandleNewConnection(connection); } } catch { } // TODO: handle exceptions finally { if (mIsListening) WaitForNextConnection(); // Re-start the process for next connection } } #endregion } }