using System; using System.Net; using System.Net.Sockets; using System.Collections.Generic; using Woodpecker.Core; using Woodpecker.Data; using Woodpecker.Net.Game.Messages; namespace Woodpecker.Net.Game { /// /// Provides management for connected game clients. /// public static class gameConnectionManager { #region Declares /// /// The Socket that listens for new game connections. /// private static Socket Listener; /// /// The max amount of connections. /// private static int maxConnections; /// /// The dictionary that contains the gameConnection objects for the connections. /// private static Dictionary Connections; /// /// A number that keeps the amount of accepted connections. Incremented by one at each request. /// private static int connectionCounter = 0; #endregion #region Methods /// /// Attempts to start listening on a certain port, with a certaint amount of max connections and a certain max length of connection queue. A boolean that indicates if the operation has succeeded is returned. /// /// The number of the TCP port to start listening on. /// The max amount of simultaneous connections. /// The max length of the connection queue. public static bool Listen(int Port, int MaxConnections, int backLog) { try { Logging.logHolyInfo("Starting up game connection listener on port " + Port + "..."); Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Listener.Bind(new IPEndPoint(IPAddress.Any, Port)); Listener.Listen(backLog); Connections = new Dictionary(); maxConnections = MaxConnections; Listener.BeginAccept(new AsyncCallback(connectionRequest), Listener); Logging.logHolyInfo("Game connection listener running on port " + Port + "."); Logging.logHolyInfo("Max simultaneous connections is " + MaxConnections + "."); Logging.logHolyInfo("Max length of connection request queue (backlog) is " + backLog + "."); return true; } catch { Logging.logWarning("Failed to set up game connection listener on port " + Port + ". Port could be in use etc."); return false; } } /// /// Invoked asynchronously when a new client requests connection. If the connection is not blacklisted and the max simultaenous connections amount isn't reached yet, then the connection will be processed and normal packet procedure will start. /// /// The IAsyncResult object of the asynchronous BeginAccept operation. private static void connectionRequest(IAsyncResult iAr) { try { Socket newClient = Listener.EndAccept(iAr); string newClientIP = newClient.RemoteEndPoint.ToString().Split(':')[0]; if (Connections.Count >= maxConnections) { newClient.Close(); Logging.logInfo("Refused connection request from " + newClientIP + ", because the max amount of simultaneous connections (" + maxConnections + ") has been reached."); } else if (Database.checkExists("woodpecker_connectionblacklist", "ipaddress", newClientIP)) { newClient.Close(); Logging.logInfo("Refused connection request from " + newClientIP + ", because this IP address is on the connection blacklist."); } else createConnection(newClient); } catch (Exception e) { Logging.logError(e.Message); } Listener.BeginAccept(new AsyncCallback(connectionRequest), Listener); } /// /// Creates a new gameConnection object for a new client connection, and starts up the packet routine. /// /// The Socket object of the new client connection. private static void createConnection(Socket newClient) { try { connectionCounter++; gameConnection Connection = new gameConnection(connectionCounter, newClient); Connections.Add(Connection.connectionID, Connection); Logging.logInfo("Created connection (" + Connection.connectionID + ") for " + Connection.IP + "."); Connection.sendMessage(new serverMessage(0)); } catch { } } /// /// Ends a certain connection to the game server and cleans up used resources. /// /// The gameConnection object of the connection to end. public static void endConnection(gameConnection Connection) { if (Connections.ContainsKey(Connection.connectionID)) { Logging.logInfo("Ended connection " + Connection.connectionID + "[" + Connection.IP + "]"); Connection.Close(SocketShutdown.Both); Connections.Remove(Connection.connectionID); } } #endregion } }