/// <summary> /// Called when the connection receives a hello packet during initial handshake /// </summary> /// <param name="hello"></param> public void HandleHello(ServerInfoPacket hello) { ServerBehindNAT = hello.ServerBehindNAT; UplinkToGamespy = hello.UplinkToGamespy; this.LastUpdate = DateTime.Now; }
/// <summary> /// Handle a server greeting "HELLO" /// </summary> /// <param name="serverInfo"></param> protected virtual void HandleHello(ServerInfoPacket serverInfo) { if (serverInfo.ProcessHello()) { ConnectionLog("HELLO SERVERBEHINDNAT={0} UPLINKTOGAMESPY={1}", serverInfo.ServerBehindNAT, serverInfo.UplinkToGamespy); MasterServer.Log("[{0}] sent greeting. ServerBehindNAT={1}", server.Address, serverInfo.ServerBehindNAT); server.HandleHello(serverInfo); SendHeartbeatRequest(HeartbeatType.QueryInterface, server.HeartbeatCode); SendHeartbeatRequest(HeartbeatType.GamePort, server.HeartbeatCode); if (server.UplinkToGamespy) { SendHeartbeatRequest(HeartbeatType.GamespyQueryPort, server.HeartbeatCode); } waitingHeartbeatTime = DateTime.Now; State = ConnectionState.WaitingHeartbeat; } else { ConnectionLog("HELLO INVALID"); MasterServer.Log("[{0}] Invalid greeting received, closing connection", server.Address); Abort(); } }
/// <summary> /// Update information for a local server using the supplied gamestate packet /// </summary> /// <param name="server">Server to update</param> /// <param name="serverInfo">Gamestate packet</param> public void UpdateServer(Server server, ServerInfoPacket serverInfo) { // Update the server server.Update(serverInfo); // Remove duplicate servers List <Server> pendingRemoval = new List <Server>(); lock (serverListLock) { foreach (Server otherServer in servers) { if (otherServer != server && otherServer.IsDuplicateOf(server)) { // Can't modify the collection here pendingRemoval.Add(otherServer); } } } foreach (Server removeServer in pendingRemoval) { MasterServer.Log("[{0}] Removing duplicate server record.", removeServer); Remove(removeServer); } #if !WCF #warning "WCF functionality disabled - ServerList RPC will not function" #else // Propogate server information to remote master servers foreach (RemoteMasterServer remoteMaster in remoteMasters) { try { remoteMaster.Update( server.Active, server.Address, server.CDKey, server.Name, server.Country, server.Locale, server.Port, server.QueryPort, server.Map, server.GameType, server.MaxPlayers, server.CurrentPlayers, server.Properties, server.Players ); } catch (MessageSecurityException) { MasterServer.Log("[RPC] Credentials rejected by remote server at {0}", remoteMaster.InnerChannel.RemoteAddress.Uri.Host); } catch (CommunicationException) { } } #endif }
/// <summary> /// Handle a player disconnect failed response /// </summary> /// <param name="serverInfo"></param> protected virtual void HandleClientDisconnectFailed(ServerInfoPacket serverInfo) { ConnectionLog("STM_CLIENTDISCONNECTFAILED"); if (serverInfo.ProcessClientDisconnectFailed()) { MasterServer.Log("[{0}] Disconnect client {1} failed", server, serverInfo.ClientIP); } }
/// <summary> /// Handle stats information from a server /// </summary> /// <param name="serverInfo"></param> protected virtual void HandleStats(ServerInfoPacket serverInfo) { ConnectionLog("STM_STATS BTSTATLOGGING={0}", server.EnableStatLogging); if (server.EnableStatLogging && serverInfo.ProcessGameStats() && gameStats != null) { gameStats.Log(DateTime.Now, server, serverInfo.StatLine); } }
/// <summary> /// Update this server instance with information from the supplied packet /// </summary> /// <param name="data"></param> public void Update(ServerInfoPacket data) { this.Active = true; this.Name = data.Name; this.Port = data.Port; this.Map = data.Map; this.GameType = data.GameType; this.MaxPlayers = data.MaxPlayers; this.CurrentPlayers = data.NumPlayers; this.Properties = data.Info; this.Players = data.Players; this.LastUpdate = DateTime.Now; this.listEntry = new ServerListEntry(Address, (ushort)Port, (ushort)QueryPort, Name, Map, GameType, (byte)CurrentPlayers, (byte)MaxPlayers, Flags); }
/// <summary> /// Handle a player challenge response /// </summary> /// <param name="serverInfo"></param> protected virtual void HandleClientChallengeResponse(ServerInfoPacket serverInfo) { MasterServer.Log("[{0}] Received STM_ClientResponse", server); if (serverInfo.ProcessClientResponse()) { ConnectionLog("STM_CLIENTRESPONSE MD5={0} MD5={1}", serverInfo.ClientCDKey, serverInfo.ClientCDKeySalted); MasterServer.Log("{0} MD5={1}", serverInfo.ClientIP, serverInfo.ClientCDKey); MasterServer.Log("{0} MD5={1}", serverInfo.ClientIP, serverInfo.ClientCDKeySalted); if (validationContexts.ContainsKey(serverInfo.ClientIP)) { ValidationContext clientValidationContext = validationContexts[serverInfo.ClientIP]; validationContexts.Remove(serverInfo.ClientIP); clientValidationContext.SetClientInfo(serverInfo.ClientCDKey, serverInfo.ClientCDKeySalted, outerConnection.Type, outerConnection.Version); // Check player CD key is valid? if (!cdKeyValidator.ValidateKey(clientValidationContext)) { MasterServer.Log("Client {0} CD key invalid. Disconnecting client.", serverInfo.ClientIP); DisconnectClient(serverInfo.ClientIP); } else if (!cdKeyValidator.ValidateSaltedKey(clientValidationContext)) { MasterServer.Log("Client {0} failed challenge. Disconnecting client.", serverInfo.ClientIP); DisconnectClient(serverInfo.ClientIP); } else { MasterServer.Log("Client {0} challenge succeeded.", serverInfo.ClientIP); } cdKeyValidator.EndValidation(clientValidationContext); } else { MasterServer.Log("Client {0} challenge unverified. No matching context found!"); } } else { ConnectionLog("STM_CLIENTRESPONSE BAD: {0}", serverInfo.Print()); } }
public void GetServerInfo() { if (_client.Connected) { using (ServerInfoPacket _serverInfoP = new ServerInfoPacket(_stream)) { _serverInfoP.ReceivePacket(_aes); serverHeader = Encoding.Unicode.GetString(_serverInfoP.serverHeader); serverVersion = Encoding.Unicode.GetString(_serverInfoP.serverVersion); } } else { throw new Exception("Not connected!"); } }
/// <summary> /// Handle an MD5 version packet /// </summary> /// <param name="serverInfo"></param> protected virtual void HandleMD5Version(ServerInfoPacket serverInfo) { if (serverInfo.ProcessMD5Version()) { ConnectionLog("STM_MD5VERSION VERSION={0}", serverInfo.MD5Version); MasterServer.Log("[{0}] STM_MD5Version with: {1}", server, serverInfo.MD5Version); List <MD5Entry> updates = md5Manager.Get(serverInfo.MD5Version); if (updates.Count > 0) { SendMD5Updates(updates); } } else { ConnectionLog("STM_MD5VERSION BAD: {0}", serverInfo.Print()); } }
protected override object HandleClient(object clientObject) { IPEndPoint _clientEndPoint = null; try { TcpClient _client = (TcpClient)clientObject; NetworkStream _stream = _client.GetStream(); _clientEndPoint = (IPEndPoint)_client.Client.RemoteEndPoint; Console.WriteLine("[" + MadNetHelper.GetTimeStamp() + "] Client (" + _clientEndPoint.Address + ") connected."); Logger.Log("Client (" + _clientEndPoint.Address + ") connected.", Logger.MessageType.INFORM); using (ServerInfoPacket _serverInfoP = new ServerInfoPacket(_stream)) { _serverInfoP.serverHeader = Encoding.Unicode.GetBytes(_serverHeader); _serverInfoP.serverVersion = Encoding.Unicode.GetBytes(_serverVer); _serverInfoP.SendPacket(_aes); } CLISession _session = new CLISession(_stream, _aes, _js, _dhcpReader, _db); _session.InitCommands(); _session.Start(); } catch (Exception e) { if (_listenThreadRunning) { Console.WriteLine("[" + MadNetHelper.GetTimeStamp() + "] Execption: " + e.Message); Logger.Log(" Execption: " + e.Message, Logger.MessageType.ERROR); } } finally { if (_listenThreadRunning) { Console.WriteLine("[" + MadNetHelper.GetTimeStamp() + "] Client (" + _clientEndPoint.Address + ") disconnected."); Logger.Log("Client (" + _clientEndPoint.Address + ") disconnected.", Logger.MessageType.INFORM); } } return(null); }
/// <summary> /// Handle a CheckOption reply packet. Displays the value on screen /// </summary> /// <param name="serverInfo"></param> protected virtual void HandleCheckOptionReply(ServerInfoPacket serverInfo) { if (serverInfo.ProcessCheckOptionResponse()) { ConnectionLog("STM_CHECKOPTIONREPLY PKG={0} VAR={1} VALUE=\"{2}\"", serverInfo.OptionPackageName, serverInfo.OptionVariableName, serverInfo.OptionVariableValue); MasterServer.LogMessage("[{0}] {1} {2}=\"{3}\"", server, serverInfo.OptionPackageName, serverInfo.OptionVariableName, serverInfo.OptionVariableValue); CheckOptionReplyEventHandler checkOptionReply = this.CheckOptionReply; if (checkOptionReply != null) { checkOptionReply(serverInfo.OptionPackageName, serverInfo.OptionVariableName, serverInfo.OptionVariableValue); } } else { ConnectionLog("STM_CHECKOPTIONREPLY BAD: {0}", serverInfo.Print()); } }
/// <summary> /// Handle a gamestate packet from a server /// </summary> /// <param name="serverInfo"></param> protected virtual void HandleGameState(ServerInfoPacket serverInfo) { // MasterServer.Log("[{0}] STM_GameState", server); if (serverInfo.ProcessGameState(server, logWriter)) { ConnectionLog("STM_GAMESTATE OK"); serverList.UpdateServer(server, serverInfo); SendMatchID(); } else { ConnectionLog("STM_GAMESTATE BAD: {0}", serverInfo.Print()); gameStateParseFailureCount++; } if (gameStateParseFailureCount > 5) { MasterServer.Log("[{0}] WARN: Invalid STM_GameState", server); gameStateParseFailureCount = 0; } }
void ServerConnection_OnPacket(ServerInfoPacket packet) { ServerInfoPacket data = (ServerInfoPacket)packet; ServerInfo info = new ServerInfo() { Active = packet.Active, Banned = packet.Banned, Clients = packet.Clients, Firewalled = packet.Firewalled, Items = packet.Items, ItemScripts = packet.ItemScripts, Memory = packet.Memory, Mobiles = packet.Mobiles, MobileScripts = packet.MobileScripts, DotNetVersion = packet.DotNetVersion, OperatingSystem = packet.OperatingSystem, UpSecs = packet.UpSecs, }; InvokeOnServerInfo(info); }
/// <summary> /// Handle the server connection /// </summary> protected override void Handle() { // Loop until connection is closed or forcibly aborted while (socket.Connected && !aborted) { try { // Read data from the socket InboundPacket packet = Receive(); if (!packet.Empty && packet.Valid) { ServerInfoPacket serverInfo = (ServerInfoPacket)packet; // Connection is considered "established" once the heartbeat has been established switch (State) { // Waiting for initial greeting from the server case ConnectionState.WaitingHello: HandleHello(serverInfo); break; // Waiting to receive heartbeat from the server case ConnectionState.WaitingHeartbeat: if ((DateTime.Now - waitingHeartbeatTime).TotalSeconds > waitForHeartbeatSeconds) { ConnectionLog("TIMEOUT WAITING HEARTBEAT IN STATE {0}", State); MasterServer.Log("[{0}] Timeout waiting for heartbeat response."); outerConnection.Abort(); } else { ConnectionLog("UNSOLICITED MESSAGE IN STATE {0}", State); } break; // Connection is established, process inbound packets as normal server conversation case ConnectionState.Established: switch (serverInfo.PacketCode) { case ServerToMaster.ClientResponse: HandleClientChallengeResponse(serverInfo); break; case ServerToMaster.GameState: HandleGameState(serverInfo); break; case ServerToMaster.Stats: HandleStats(serverInfo); break; case ServerToMaster.ClientDisconnectFailed: HandleClientDisconnectFailed(serverInfo); break; case ServerToMaster.MD5Version: HandleMD5Version(serverInfo); break; case ServerToMaster.CheckOptionReply: HandleCheckOptionReply(serverInfo); break; default: packet.Rewind(); ConnectionLog("INVALID MESSAGE STATE={0} CODE={1}", State, packet.PopByte()); break; } break; } } else if (socket.Connected) { ConnectionLog("INVALID PACKET STATE={0} DATA={1}", State, packet.PrintBytes(true)); Debug.WriteLine(String.Format("Invalid packet from server at {0} in state {1}", server.Address, State)); Debug.WriteLine(packet.Print()); if (State == ConnectionState.WaitingHeartbeat && (DateTime.Now - waitingHeartbeatTime).TotalSeconds > waitForHeartbeatSeconds) { MasterServer.Log("[{0}] Timeout waiting for heartbeat response.", server); ConnectionLog("TIMEOUT WAITING HEARTBEAT IN STATE {0}", State); outerConnection.Abort(); } } } catch (ThreadAbortException) { aborted = true; } catch (Exception ex) { if (!aborted) { ConnectionLog("ERROR: {0}", ex.Message); } break; } } if (!socket.Connected) { MasterServer.Log("[{0}] Connection closed", server); } serverList.Remove(server); server = null; }