public static string LatencyDescription(Session.ClientPing ping) { if (ping == null) { return("Unknown"); } if (ping.Latency < 0) { return("Unknown"); } if (ping.Latency < 300) { return("Good"); } if (ping.Latency < 600) { return("Moderate"); } return("Poor"); }
public static Color LatencyColor(Session.ClientPing ping) { if (ping == null) { return(Color.Gray); } // Levels set relative to the default order lag of 3 net ticks (360ms) // TODO: Adjust this once dynamic lag is implemented if (ping.Latency < 0) { return(Color.Gray); } if (ping.Latency < 300) { return(Color.LimeGreen); } if (ping.Latency < 600) { return(Color.Orange); } return(Color.Red); }
void ValidateClient(Connection newConn, string data) { try { if (State == ServerState.GameStarted) { Log.Write("server", "Rejected connection from {0}; game is already started.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "The game has already started"); DropClient(newConn); return; } var handshake = HandshakeResponse.Deserialize(data); if (!string.IsNullOrEmpty(Settings.Password) && handshake.Password != Settings.Password) { var message = string.IsNullOrEmpty(handshake.Password) ? "Server requires a password" : "Incorrect password"; SendOrderTo(newConn, "AuthenticationError", message); DropClient(newConn); return; } var client = new Session.Client() { Name = handshake.Client.Name, IpAddress = ((IPEndPoint)newConn.Socket.RemoteEndPoint).Address.ToString(), Index = newConn.PlayerIndex, Slot = LobbyInfo.FirstEmptySlot(), PreferredColor = handshake.Client.Color, Color = handshake.Client.Color, Race = "Random", SpawnPoint = 0, Team = 0, State = Session.ClientState.Invalid, IsAdmin = !LobbyInfo.Clients.Any(c1 => c1.IsAdmin) }; if (client.IsObserver && !LobbyInfo.GlobalSettings.AllowSpectators) { SendOrderTo(newConn, "ServerError", "The game is full"); DropClient(newConn); return; } if (client.Slot != null) { SyncClientToPlayerReference(client, MapPlayers.Players[client.Slot]); } else { client.Color = HSLColor.FromRGB(255, 255, 255); } if (ModData.Manifest.Mod.Id != handshake.Mod) { Log.Write("server", "Rejected connection from {0}; mods do not match.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "Server is running an incompatible mod"); DropClient(newConn); return; } if (ModData.Manifest.Mod.Version != handshake.Version && !LobbyInfo.GlobalSettings.AllowVersionMismatch) { Log.Write("server", "Rejected connection from {0}; Not running the same version.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "Server is running an incompatible version"); DropClient(newConn); return; } // Check if IP is banned var bans = Settings.Ban.Union(TempBans); if (bans.Contains(client.IpAddress)) { Log.Write("server", "Rejected connection from {0}; Banned.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "You have been {0} from the server".F(Settings.Ban.Contains(client.IpAddress) ? "banned" : "temporarily banned")); DropClient(newConn); return; } // Promote connection to a valid client PreConns.Remove(newConn); Conns.Add(newConn); LobbyInfo.Clients.Add(client); var clientPing = new Session.ClientPing(); clientPing.Index = client.Index; LobbyInfo.ClientPings.Add(clientPing); Log.Write("server", "Client {0}: Accepted connection from {1}.", newConn.PlayerIndex, newConn.Socket.RemoteEndPoint); foreach (var t in serverTraits.WithInterface <IClientJoined>()) { t.ClientJoined(this, newConn); } SyncLobbyInfo(); SendMessage("{0} has joined the game.".F(client.Name)); // Send initial ping SendOrderTo(newConn, "Ping", Game.RunTime.ToString()); if (Settings.Dedicated) { var motdFile = Platform.ResolvePath("^", "motd.txt"); if (!File.Exists(motdFile)) { System.IO.File.WriteAllText(motdFile, "Welcome, have fun and good luck!"); } var motd = System.IO.File.ReadAllText(motdFile); if (!string.IsNullOrEmpty(motd)) { SendOrderTo(newConn, "Message", motd); } } if (handshake.Mod == "{DEV_VERSION}") { SendMessage("{0} is running an unversioned development build, ".F(client.Name) + "and may desynchronize the game state if they have incompatible rules."); } SetOrderLag(); } catch (Exception) { DropClient(newConn); } }
void ValidateClient(Connection newConn, string data) { try { if (State == ServerState.GameStarted) { Log.Write("server", "Rejected connection from {0}; game is already started.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "The game has already started"); DropClient(newConn); return; } var handshake = HandshakeResponse.Deserialize(data); if (!string.IsNullOrEmpty(Settings.Password) && handshake.Password != Settings.Password) { var message = string.IsNullOrEmpty(handshake.Password) ? "Server requires a password" : "Incorrect password"; SendOrderTo(newConn, "AuthenticationError", message); DropClient(newConn); return; } var ipAddress = ((IPEndPoint)newConn.Socket.RemoteEndPoint).Address; var client = new Session.Client { Name = OpenRA.Settings.SanitizedPlayerName(handshake.Client.Name), IPAddress = ipAddress.ToString(), AnonymizedIPAddress = Type != ServerType.Local && Settings.ShareAnonymizedIPs ? Session.AnonymizeIP(ipAddress) : null, Location = GeoIP.LookupCountry(ipAddress), Index = newConn.PlayerIndex, PreferredColor = handshake.Client.PreferredColor, Color = handshake.Client.Color, Faction = "Random", SpawnPoint = 0, Team = 0, State = Session.ClientState.Invalid, }; if (ModData.Manifest.Id != handshake.Mod) { Log.Write("server", "Rejected connection from {0}; mods do not match.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "Server is running an incompatible mod"); DropClient(newConn); return; } if (ModData.Manifest.Metadata.Version != handshake.Version) { Log.Write("server", "Rejected connection from {0}; Not running the same version.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "Server is running an incompatible version"); DropClient(newConn); return; } if (handshake.OrdersProtocol != ProtocolVersion.Orders) { Log.Write("server", "Rejected connection from {0}; incompatible Orders protocol version {1}.", newConn.Socket.RemoteEndPoint, handshake.OrdersProtocol); SendOrderTo(newConn, "ServerError", "Server is running an incompatible protocol"); DropClient(newConn); return; } // Check if IP is banned var bans = Settings.Ban.Union(TempBans); if (bans.Contains(client.IPAddress)) { Log.Write("server", "Rejected connection from {0}; Banned.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "You have been {0} from the server".F(Settings.Ban.Contains(client.IPAddress) ? "banned" : "temporarily banned")); DropClient(newConn); return; } Action completeConnection = () => { lock (LobbyInfo) { client.Slot = LobbyInfo.FirstEmptySlot(); client.IsAdmin = !LobbyInfo.Clients.Any(c1 => c1.IsAdmin); if (client.IsObserver && !LobbyInfo.GlobalSettings.AllowSpectators) { SendOrderTo(newConn, "ServerError", "The game is full"); DropClient(newConn); return; } if (client.Slot != null) { SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]); } else { client.Color = Color.White; } // Promote connection to a valid client PreConns.Remove(newConn); Conns.Add(newConn); LobbyInfo.Clients.Add(client); newConn.Validated = true; var clientPing = new Session.ClientPing { Index = client.Index }; LobbyInfo.ClientPings.Add(clientPing); Log.Write("server", "Client {0}: Accepted connection from {1}.", newConn.PlayerIndex, newConn.Socket.RemoteEndPoint); if (client.Fingerprint != null) { Log.Write("server", "Client {0}: Player fingerprint is {1}.", newConn.PlayerIndex, client.Fingerprint); } foreach (var t in serverTraits.WithInterface <IClientJoined>()) { t.ClientJoined(this, newConn); } SyncLobbyInfo(); Log.Write("server", "{0} ({1}) has joined the game.", client.Name, newConn.Socket.RemoteEndPoint); // Report to all other players SendMessage("{0} has joined the game.".F(client.Name), newConn); // Send initial ping SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture)); if (Type == ServerType.Dedicated) { var motdFile = Platform.ResolvePath(Platform.SupportDirPrefix, "motd.txt"); if (!File.Exists(motdFile)) { File.WriteAllText(motdFile, "Welcome, have fun and good luck!"); } var motd = File.ReadAllText(motdFile); if (!string.IsNullOrEmpty(motd)) { SendOrderTo(newConn, "Message", motd); } } if (Map.DefinesUnsafeCustomRules) { SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change."); } if (!LobbyInfo.GlobalSettings.EnableSingleplayer) { SendOrderTo(newConn, "Message", TwoHumansRequiredText); } else if (Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) { SendOrderTo(newConn, "Message", "Bots have been disabled on this map."); } } }; if (Type == ServerType.Local) { // Local servers can only be joined by the local client, so we can trust their identity without validation client.Fingerprint = handshake.Fingerprint; completeConnection(); } else if (!string.IsNullOrEmpty(handshake.Fingerprint) && !string.IsNullOrEmpty(handshake.AuthSignature)) { waitingForAuthenticationCallback++; Action <DownloadDataCompletedEventArgs> onQueryComplete = i => { PlayerProfile profile = null; if (i.Error == null) { try { var yaml = MiniYaml.FromString(Encoding.UTF8.GetString(i.Result)).First(); if (yaml.Key == "Player") { profile = FieldLoader.Load <PlayerProfile>(yaml.Value); var publicKey = Encoding.ASCII.GetString(Convert.FromBase64String(profile.PublicKey)); var parameters = CryptoUtil.DecodePEMPublicKey(publicKey); if (!profile.KeyRevoked && CryptoUtil.VerifySignature(parameters, newConn.AuthToken, handshake.AuthSignature)) { client.Fingerprint = handshake.Fingerprint; Log.Write("server", "{0} authenticated as {1} (UID {2})", newConn.Socket.RemoteEndPoint, profile.ProfileName, profile.ProfileID); } else if (profile.KeyRevoked) { profile = null; Log.Write("server", "{0} failed to authenticate as {1} (key revoked)", newConn.Socket.RemoteEndPoint, handshake.Fingerprint); } else { profile = null; Log.Write("server", "{0} failed to authenticate as {1} (signature verification failed)", newConn.Socket.RemoteEndPoint, handshake.Fingerprint); } } else { Log.Write("server", "{0} failed to authenticate as {1} (invalid server response: `{2}` is not `Player`)", newConn.Socket.RemoteEndPoint, handshake.Fingerprint, yaml.Key); } } catch (Exception ex) { Log.Write("server", "{0} failed to authenticate as {1} (exception occurred)", newConn.Socket.RemoteEndPoint, handshake.Fingerprint); Log.Write("server", ex.ToString()); } } else { Log.Write("server", "{0} failed to authenticate as {1} (server error: `{2}`)", newConn.Socket.RemoteEndPoint, handshake.Fingerprint, i.Error); } delayedActions.Add(() => { var notAuthenticated = Type == ServerType.Dedicated && profile == null && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any()); var blacklisted = Type == ServerType.Dedicated && profile != null && Settings.ProfileIDBlacklist.Contains(profile.ProfileID); var notWhitelisted = Type == ServerType.Dedicated && Settings.ProfileIDWhitelist.Any() && (profile == null || !Settings.ProfileIDWhitelist.Contains(profile.ProfileID)); if (notAuthenticated) { Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account"); DropClient(newConn); } else if (blacklisted || notWhitelisted) { if (blacklisted) { Log.Write("server", "Rejected connection from {0}; In server blacklist.", newConn.Socket.RemoteEndPoint); } else { Log.Write("server", "Rejected connection from {0}; Not in server whitelist.", newConn.Socket.RemoteEndPoint); } SendOrderTo(newConn, "ServerError", "You do not have permission to join this server"); DropClient(newConn); } else { completeConnection(); } waitingForAuthenticationCallback--; }, 0); }; new Download(playerDatabase.Profile + handshake.Fingerprint, _ => { }, onQueryComplete); } else { if (Type == ServerType.Dedicated && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any())) { Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account"); DropClient(newConn); } else { completeConnection(); } } } catch (Exception ex) { Log.Write("server", "Dropping connection {0} because an error occurred:", newConn.Socket.RemoteEndPoint); Log.Write("server", ex.ToString()); DropClient(newConn); } }
void ValidateClient(Connection newConn, string data) { try { if (State == ServerState.GameStarted) { Log.Write("server", "Rejected connection from {0}; game is already started.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "The game has already started"); DropClient(newConn); return; } var handshake = HandshakeResponse.Deserialize(data); if (!string.IsNullOrEmpty(Settings.Password) && handshake.Password != Settings.Password) { var message = string.IsNullOrEmpty(handshake.Password) ? "Server requires a password" : "Incorrect password"; SendOrderTo(newConn, "AuthenticationError", message); DropClient(newConn); return; } var client = new Session.Client { Name = OpenRA.Settings.SanitizedPlayerName(handshake.Client.Name), IpAddress = ((IPEndPoint)newConn.Socket.RemoteEndPoint).Address.ToString(), Index = newConn.PlayerIndex, Slot = LobbyInfo.FirstEmptySlot(), PreferredColor = handshake.Client.PreferredColor, Color = handshake.Client.Color, Faction = "Random", SpawnPoint = 0, Team = 0, State = Session.ClientState.Invalid, IsAdmin = !LobbyInfo.Clients.Any(c1 => c1.IsAdmin) }; if (client.IsObserver && !LobbyInfo.GlobalSettings.AllowSpectators) { SendOrderTo(newConn, "ServerError", "The game is full"); DropClient(newConn); return; } if (client.Slot != null) { SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]); } else { client.Color = HSLColor.FromRGB(255, 255, 255); } if (ModData.Manifest.Id != handshake.Mod) { Log.Write("server", "Rejected connection from {0}; mods do not match.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "Server is running an incompatible mod"); DropClient(newConn); return; } if (ModData.Manifest.Metadata.Version != handshake.Version && !LobbyInfo.GlobalSettings.AllowVersionMismatch) { Log.Write("server", "Rejected connection from {0}; Not running the same version.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "Server is running an incompatible version"); DropClient(newConn); return; } // Check if IP is banned var bans = Settings.Ban.Union(TempBans); if (bans.Contains(client.IpAddress)) { Log.Write("server", "Rejected connection from {0}; Banned.", newConn.Socket.RemoteEndPoint); SendOrderTo(newConn, "ServerError", "You have been {0} from the server".F(Settings.Ban.Contains(client.IpAddress) ? "banned" : "temporarily banned")); DropClient(newConn); return; } // Promote connection to a valid client PreConns.Remove(newConn); Conns.Add(newConn); LobbyInfo.Clients.Add(client); newConn.Validated = true; var clientPing = new Session.ClientPing { Index = client.Index }; LobbyInfo.ClientPings.Add(clientPing); Log.Write("server", "Client {0}: Accepted connection from {1}.", newConn.PlayerIndex, newConn.Socket.RemoteEndPoint); foreach (var t in serverTraits.WithInterface <IClientJoined>()) { t.ClientJoined(this, newConn); } SyncLobbyInfo(); Log.Write("server", "{0} ({1}) has joined the game.", client.Name, newConn.Socket.RemoteEndPoint); if (LobbyInfo.NonBotClients.Count() > 1) { SendMessage("{0} has joined the game.".F(client.Name)); } // Send initial ping SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture)); if (Dedicated) { var motdFile = Platform.ResolvePath(Platform.SupportDirPrefix, "motd.txt"); if (!File.Exists(motdFile)) { File.WriteAllText(motdFile, "Welcome, have fun and good luck!"); } var motd = File.ReadAllText(motdFile); if (!string.IsNullOrEmpty(motd)) { SendOrderTo(newConn, "Message", motd); } } if (Map.DefinesUnsafeCustomRules) { SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change."); } if (!LobbyInfo.GlobalSettings.EnableSingleplayer) { SendOrderTo(newConn, "Message", TwoHumansRequiredText); } else if (Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) { SendOrderTo(newConn, "Message", "Bots have been disabled on this map."); } if (handshake.Mod == "{DEV_VERSION}") { SendMessage("{0} is running an unversioned development build, ".F(client.Name) + "and may desynchronize the game state if they have incompatible rules."); } } catch (Exception ex) { Log.Write("server", "Dropping connection {0} because an error occurred:", newConn.Socket.RemoteEndPoint); Log.Write("server", ex.ToString()); DropClient(newConn); } }
void ValidateClient(Connection newConn, string data) { try { if (State == ServerState.GameStarted) { SendOrderTo(newConn, "ServerError", "The game has already started"); DropClient(newConn); return; } var handshake = HandshakeResponse.Deserialize(data); if (!string.IsNullOrEmpty(Settings.Password) && handshake.Password != Settings.Password) { var message = string.IsNullOrEmpty(handshake.Password) ? "Server requires a password" : "Incorrect password"; SendOrderTo(newConn, "AuthenticationError", message); DropClient(newConn); return; } var client = new Session.Client { Name = EW.Settings.SanitizedPlayerName(handshake.Client.Name), IpAddress = ((IPEndPoint)newConn.Socket.RemoteEndPoint).Address.ToString(), Index = newConn.PlayerIndex, Slot = LobbyInfo.FirstEmptySlot(), PreferredColor = handshake.Client.PreferredColor, Color = handshake.Client.Color, Faction = "Random", SpawnPoint = 0, Team = 0, State = Session.ClientState.Invalid, IsAdmin = !LobbyInfo.Clients.Any(cl => cl.IsAdmin) }; if (client.IsObserver && !LobbyInfo.GlobalSettings.AllowSpectators) { SendOrderTo(newConn, "ServerError", "The game is full"); DropClient(newConn); return; } if (client.Slot != null) { SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]); } else { client.Color = HSLColor.FromRGB(255, 255, 255); } if (ModData.Manifest.Id != handshake.Mod) { SendOrderTo(newConn, "ServerError", "Server is running an incompatible mod"); DropClient(newConn); return; } if (ModData.Manifest.Metadata.Version != handshake.Version && !LobbyInfo.GlobalSettings.AllowVersionMismatch) { SendOrderTo(newConn, "ServerError", "Server is running an incompatible version"); DropClient(newConn); return; } //Check if IP is banned var bans = Settings.Ban.Union(TempBans); if (bans.Contains(client.IpAddress)) { SendOrderTo(newConn, "ServerError", "You have been {0} from the server".F(Settings.Ban.Contains(client.IpAddress) ? "banned" : "temporarily banned")); DropClient(newConn); return; } //Promote connection to a valid client PreConns.Remove(newConn); Conns.Add(newConn); LobbyInfo.Clients.Add(client); newConn.Validated = true; var clientPing = new Session.ClientPing { Index = client.Index }; LobbyInfo.ClientPings.Add(clientPing); foreach (var t in serverTraits.WithInterface <IClientJoined>()) { t.ClientJoined(this, newConn); } SyncLobbyInfo(); if (LobbyInfo.NonBotClients.Count() > 1) { SendMessage("{0} has joined the game".F(client.Name)); } SendOrderTo(newConn, "Ping", WarGame.RunTime.ToString(CultureInfo.InvariantCulture)); if (Dedicated) { } if (Map.DefinesUnsafeCustomRules) { SendOrderTo(newConn, "Message", "This map contains custom rules.Game experience may change."); } if (!LobbyInfo.GlobalSettings.EnableSinglePlayer) { SendOrderTo(newConn, "Message", TwoHumansRequiredText); } else if (Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) { SendOrderTo(newConn, "Message", "Bots have been disabled on this map"); } } catch (Exception ex) { DropClient(newConn); } }