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
}
}