/// <summary> /// Print current server status to the interface /// </summary> private void ShowStatus() { MasterServer masterServer = MasterServer.Instance; if (connection != null && masterServer != null) { List <Server> servers = masterServer.ServerList.Query(); // Calculate number of local servers int localServerCount = 0; foreach (Server server in servers) { if (server.Local) { localServerCount++; } } connection.Send("\r\nMaster Server Status\r\n"); connection.Send(new String('-', 80) + "\r\n"); connection.Send(String.Format("Active Connections: {0,8}\r\n", localServerCount)); connection.Send(String.Format("Total Servers: {0,8}\r\n", servers.Count)); connection.Send(String.Format("Total Inbound Queries: {0,8}\r\n", masterServer.TotalQueries)); connection.Send(String.Format("Total Web Queries: {0,8}\r\n", masterServer.TotalWebQueries)); connection.Send("\r\nServer List\r\n"); connection.Send(new String('-', 80) + "\r\n"); // Server list if (servers.Count > 0) { for (int serverIndex = 0; serverIndex < servers.Count; serverIndex++) { Server server = servers[serverIndex]; connection.Send(String.Format("{0,-3}{1,-30}{2,-18}{3,-8}{4,-11}{5,-10}\r\n", server.Selected ? ">>" : "", ColourCodeParser.StripColourCodes(server.Name), server.Address.ToString(), server.Port > 0 ? server.Port.ToString() : "?", server.LastUpdate.ToString("HH:mm:ss"), server.Local ? "Local" : "RPC" )); } } else { connection.Send(" No connected servers\r\n"); } connection.Send(new String('-', 80) + "\r\n\r\n"); } }
/// <summary> /// List clients connected to this server to the console /// </summary> public void ListClients() { if (Players != null && Players.Count > 0) { foreach (Player player in Players) { MasterServer.LogMessage("{0,-22}{1,-20}{2,5}", player.Address, ColourCodeParser.StripColourCodes(player.Name), player.Ping); } } else { MasterServer.LogMessage("No clients connected"); } }
/// <summary> /// Get a reference to a connected player client /// </summary> /// <param name="clientAddress"></param> /// <returns></returns> public Player GetClientPlayer(string clientAddress) { if (Connection != null && Players != null) { foreach (Player player in Players) { if (player.Address == clientAddress || ColourCodeParser.StripColourCodes(player.Name).ToLower() == clientAddress.ToLower()) { return(player); } } } return(null); }
/// <summary> /// Attempt to handle a request, returns true if the request was handled and should not be passed /// to handlers with lower priority /// </summary> /// <param name="Request">HTTP Request</param> /// <param name="Response">HTTP Response</param> /// <returns>Bool indicating whether the request was handled or not</returns> public bool HandleRequest(HttpListenerRequest Request, HttpListenerResponse Response) { if (Request.HttpMethod.ToUpper() == "GET" && (Request.Url.LocalPath == "/server" || Request.Url.LocalPath == FRAMESRC) && pageFile.Exists && playerRowFile.Exists && infoRowFile.Exists) { // These GET vars contain the server address and port which the player wants to view string requestedIp = Request.QueryString["ip"]; string requestedPort = Request.QueryString["port"]; // Container variables for the parsed address and port IPAddress address; ushort port; string pageData = "Bad Query"; if (requestedIp != null && IPAddress.TryParse(requestedIp, out address) && requestedPort != null && ushort.TryParse(requestedPort, out port)) { // For stats masterServer.RegisterWebQuery(); // Get the server which the player has requested Server server = masterServer.ServerList.GetServer(address, port); variables["skin"] = WebServer.Skin; if (Request.Url.LocalPath == "/server") { pageData = ReadFile(pageFile); variables["title"] = String.Format("{0}{1}", MasterServer.Settings.WebServerServerHeader, server != null ? " - " + ColourCodeParser.StripColourCodes(server.Name) : ""); variables["framesrc"] = String.Format("{0}?ip={1}&port={2}", FRAMESRC, address, port); } else if (Request.Url.LocalPath == FRAMESRC) { pageData = ReadFile(doTemplateFile); if (server != null) { string playerList = ""; string infoList = ""; // Player list row template string playerListRow = ReadFile(playerRowFile); int playerIndex = 0; foreach (Player player in server.Players) { variables["playerindex"] = (playerIndex++).ToString(); variables["playername"] = ColourCodeParser.Colourise(player.Name); variables["playerping"] = player.Ping.ToString(); variables["playerscore"] = player.Score.ToString(); foreach (KeyValuePair <string, string> info in player.Info) { variables[String.Format("playerinfo[{0}]", info.Key.ToLower())] = ColourCodeParser.Colourise(info.Value); } playerList += ReplaceVariables(playerListRow); } // Info list row template string infoListRow = ReadFile(infoRowFile); foreach (KeyValuePair <string, string> property in server.Properties) { variables["key"] = property.Key; variables["value"] = property.Value; infoList += ReplaceVariables(infoListRow); } variables["headtitle"] = EncodeBrackets(ColourCodeParser.Colourise(server.Name)); variables["playerlistbody"] = EncodeBrackets(playerList); variables["serverinfobody"] = EncodeBrackets(infoList); variables["mapimage"] = String.Format("/img/maps/{0}.jpg", server.Map.ToLower()); variables["mapname"] = server.Map; } else { variables["headtitle"] = "Server offline"; variables["playerlistbody"] = ""; variables["serverinfobody"] = ""; variables["mapimage"] = "/img/maps/unknown.jpg"; variables["mapname"] = "Unknown Map"; } } else { pageData = "Bad Query"; } pageData = ReplaceVariables(pageData); } // Write the page to the output stream Response.OutputStream.Write(Encoding.ASCII.GetBytes(pageData), 0, pageData.Length); Response.OutputStream.Close(); return(true); } return(false); }
/// <summary> /// In-thread function called by UpdateDisplay, which updates the form elements with the current server status /// </summary> /// <param name="masterServer"></param> /// <param name="logText"></param> /// <param name="upTime"></param> private void UpdateForm(MasterServer masterServer, string logText, TimeSpan upTime) { // Update the log if the log has changed if (logText != txtConsole.Text) { txtConsole.Text = logText; txtConsole.Select(logText.LastIndexOf('\r') + 2, 1); txtConsole.ScrollToCaret(); } // Get servers from the server list List <Server> servers = masterServer.ServerList.Query(); // Calculate the number of local servers int localServerCount = 0; foreach (Server server in servers) { if (server.Local) { localServerCount++; } } // Set status label text lblActiveConnections.Text = localServerCount.ToString(); lblTotalServers.Text = servers.Count.ToString(); lblUpTime.Text = String.Format("{0} days {1} hours {2} minutes", upTime.Days, upTime.Hours, upTime.Minutes); lblQueries.Text = masterServer.TotalQueries.ToString(); lblWebQueries.Text = masterServer.TotalWebQueries.ToString(); lblTCPPorts.Text = MasterServer.ListenPorts; lblWebServerPort.Text = WebServer.ListenPorts; // Because there's so much to keep track of, and we only want to update the listview when something changes, the comparison // method I'm using is to serialise all the relevant data to a string and then use string comparison to determine whether an // update is required or not. Whilst this isn't pretty, it does work quite well. // Build the new serialised list string newServerList = ""; foreach (Server server in servers) { newServerList += server.Name + server.Selected.ToString() + server.Address.ToString() + server.Port.ToString() + server.LastUpdate.ToString("hhmmss") + server.Local.ToString(); } // Compare the new serialised list with the stored one and update if different if (newServerList != strServerList) { // Store the new serialised list for next time strServerList = newServerList; lstServers.Items.Clear(); // Refresh the server list foreach (Server server in servers) { ListViewItem serverItem = lstServers.Items.Add(ColourCodeParser.StripColourCodes(server.Name), server.Selected ? 1 : 0); serverItem.Tag = server; serverItem.SubItems.Add(server.Address.ToString()); serverItem.SubItems.Add(server.Port.ToString()); serverItem.SubItems.Add(server.LastUpdate.ToString("hh:mm:ss")); serverItem.SubItems.Add(server.Local ? "Yes" : "No"); } } }
/// <summary> /// Attempt to handle a request, returns true if the request was handled and should not be passed /// to handlers with lower priority /// </summary> /// <param name="Request">HTTP Request</param> /// <param name="Response">HTTP Response</param> /// <returns>Bool indicating whether the request was handled or not</returns> public bool HandleRequest(HttpListenerRequest Request, HttpListenerResponse Response) { if (Request.HttpMethod.ToUpper() == "GET" && Request.Url.LocalPath == "/serverlist.xml") { // For stats masterServer.RegisterWebQuery(); // Set up xml document and writer XmlDocument xmlDocument = new XmlDocument(); XmlWriter xml = xmlDocument.CreateNavigator().AppendChild(); // Write the XML declaration xml.WriteStartDocument(true); string xmlNamespaceServer = "http://" + Request.Url.Host + "/xmlns/server"; string xmlNamespaceServerProperties = "http://" + Request.Url.Host + "/xmlns/serverproperties"; string xmlNamespacePlayer = "http://" + Request.Url.Host + "/xmlns/player"; string xmlNamespacePlayerProperties = "http://" + Request.Url.Host + "/xmlns/playerproperties"; // Get current server list List <Server> servers = masterServer.ServerList.QueryGameType(MasterServer.Settings.WebServerGameTypeFilter, false); // Incremented for every active server int activeServerCount = servers.Count; xml.WriteStartElement("servers"); { xml.WriteAttributeString("xmlns", "s", null, xmlNamespaceServer); xml.WriteAttributeString("xmlns", "sp", null, xmlNamespaceServerProperties); xml.WriteAttributeString("xmlns", "p", null, xmlNamespacePlayer); xml.WriteAttributeString("xmlns", "pp", null, xmlNamespacePlayerProperties); // Stat information in the document element xml.WriteAttributeString("total", servers.Count.ToString()); xml.WriteAttributeString("active", "0"); xml.WriteAttributeString("pending", "0"); foreach (Server server in servers) { if (server.Active) { // This server is not busy activeServerCount--; xml.WriteStartElement("server", xmlNamespaceServer); { xml.WriteAttributeString("password", xmlNamespaceServer, server.Password.ToString()); xml.WriteAttributeString("listen", xmlNamespaceServer, server.Listen.ToString()); xml.WriteElementString("ip", xmlNamespaceServer, server.Address.ToString()); xml.WriteElementString("port", xmlNamespaceServer, server.Port.ToString()); xml.WriteElementString("queryport", xmlNamespaceServer, server.QueryPort.ToString()); xml.WriteElementString("country", xmlNamespaceServer, server.Country); xml.WriteStartElement("name", xmlNamespaceServer); { xml.WriteElementString("basic", xmlNamespaceServer, ColourCodeParser.StripColourCodes(server.Name)); xml.WriteElementString("html", xmlNamespaceServer, ColourCodeParser.ColouriseConditional(server.Name)); } xml.WriteEndElement(); // name xml.WriteElementString("gametype", xmlNamespaceServer, server.GameType); xml.WriteElementString("map", xmlNamespaceServer, server.Map); xml.WriteStartElement("players", xmlNamespaceServer); { xml.WriteAttributeString("current", xmlNamespaceServer, server.CurrentPlayers.ToString()); xml.WriteAttributeString("max", xmlNamespaceServer, server.MaxPlayers.ToString()); foreach (Player player in server.Players) { xml.WriteStartElement("player", xmlNamespacePlayer); xml.WriteStartElement("name", xmlNamespacePlayer); { xml.WriteElementString("basic", xmlNamespacePlayer, ColourCodeParser.StripColourCodes(player.Name)); xml.WriteElementString("html", xmlNamespacePlayer, ColourCodeParser.ColouriseConditional(player.Name)); } xml.WriteEndElement(); // name xml.WriteElementString("ping", xmlNamespacePlayer, player.Ping.ToString()); xml.WriteElementString("score", xmlNamespacePlayer, player.Score.ToString()); foreach (KeyValuePair <string, string> info in player.Info) { xml.WriteElementString(info.Key.ToLower(), xmlNamespacePlayerProperties, ColourCodeParser.StripColourCodes(info.Value)); } xml.WriteEndElement(); } } xml.WriteEndElement(); // players xml.WriteStartElement("properties", xmlNamespaceServerProperties); { foreach (KeyValuePair <string, string> property in server.Properties) { xml.WriteElementString(property.Key.ToLower(), xmlNamespaceServerProperties, ColourCodeParser.StripColourCodes(property.Value)); } } xml.WriteEndElement(); // properties } xml.WriteEndElement(); // server } } } xml.WriteEndElement(); // servers xml.WriteEndDocument(); xml.Close(); xmlDocument.DocumentElement.Attributes["active"].Value = activeServerCount.ToString(); xmlDocument.DocumentElement.Attributes["pending"].Value = (servers.Count - activeServerCount).ToString(); Response.Headers["Content-type"] = "text/xml"; xmlDocument.Save(Response.OutputStream); Response.OutputStream.Close(); return(true); } return(false); }
/// <summary> /// Display the current status /// </summary> /// <param name="masterServer"></param> /// <param name="log"></param> /// <param name="upTime"></param> public void UpdateDisplay(MasterServer masterServer, string[] log, TimeSpan upTime) { if (shutdown || masterServer == null || masterServer.ServerList == null) { return; } // Query for all servers List <Server> servers = masterServer.ServerList.Query(); // Calculate number of local servers int localServerCount = 0; foreach (Server server in servers) { if (server.Local) { localServerCount++; } } // Set up format strings to size of console string widthFormat1 = String.Format("{0}0,-{1}{2}", "{", Console.WindowWidth, "}"); string widthFormat2 = String.Empty; if (Console.WindowWidth < 88) { widthFormat2 = String.Format("{0}5,-{1}{2}", "{0,-3}{1,-30}{2,-18}{3,-8}{4,-11}{", Console.WindowWidth - 70, "}"); } else { widthFormat2 = String.Format("{0}7,-{1}{2}", "{0,-3}{1,-30}{2,-18}{3,-8}{4,-11}{5,-8}{6,2}/{", Console.WindowWidth - 81, "}"); } // Hide cursor whilst updating the screen Console.CursorVisible = false; Console.SetCursorPosition(0, 0); // Banner Reverse(HighlightColour); Console.Write(widthFormat1, String.Format("{0,-32} TCP Ports: {1} Web Server: {2}", MasterServer.Title, ListenPorts, WebServer.ListenPorts)); // Server information Normal(ForegroundColour); Console.Write(widthFormat1, String.Format(" Server uptime: {0} days {1} hours {2} minutes", upTime.Days, upTime.Hours, upTime.Minutes)); Console.Write(widthFormat1, String.Format(" Active Connections: {0,8} Total Servers: {1,8}", localServerCount, servers.Count)); Console.Write(widthFormat1, String.Format(" {0,-23}{1,8}{2,10}{3,-19}{4,8}", "Total Inbound Queries:", masterServer.TotalQueries, "", "Total Web Queries:", masterServer.TotalWebQueries)); // Server list header Reverse(HighlightColour); Console.Write(widthFormat1, "* Name IP Port Updated Type "); // Background colour for server list Normal(ForegroundColour); // Clamp list position within server list size while (listPos > servers.Count && listPos > 0) { listPos -= listCount; } // Server list if (servers.Count > 0) { for (int serverIndex = listPos; serverIndex < listPos + listCount; serverIndex++) { if (serverIndex < servers.Count) { Server server = servers[serverIndex]; string serverName = ColourCodeParser.StripColourCodes(server.Name); if (serverName.Length > 28) { serverName = serverName.Substring(0, 28); } Console.Write( widthFormat2, server.Selected ? ">>" : "", ColourCodeParser.StripColourCodes(server.Name), server.Address.ToString(), server.Port > 0 ? server.Port.ToString() : "?", server.LastUpdate.ToString("HH:mm:ss"), server.Local ? "Local" : "RPC", server.CurrentPlayers, server.MaxPlayers, server.GameType ); } else { // Pad the server list with blank rows Console.Write(widthFormat1, ""); } } } else { Console.Write(widthFormat1, " No connected servers"); for (int serverIndex = 1; serverIndex < listCount; serverIndex++) { Console.Write(widthFormat1, ""); } } Reverse(HighlightColour); Console.Write(widthFormat1, "Master Server Console"); Normal(LogColour); // Display log lines using remaining space int remainingLines = Console.BufferHeight - Console.CursorTop - 1; for (int i = log.Length - remainingLines; i < log.Length; i++) { Console.Write(widthFormat1, i >= 0 ? log[i].Substring(0, Math.Min(log[i].Length, Console.BufferWidth)) : ""); } Normal(ForegroundColour); Console.CursorVisible = true; }
/// <summary> /// Attempt to handle a request, returns true if the request was handled and should not be passed /// to handlers with lower priority /// </summary> /// <param name="Request">HTTP Request</param> /// <param name="Response">HTTP Response</param> /// <returns>Bool indicating whether the request was handled or not</returns> public bool HandleRequest(HttpListenerRequest Request, HttpListenerResponse Response) { if (Request.HttpMethod.ToUpper() == "GET") { // Get current server list List <Server> servers = masterServer.ServerList.QueryGameType(MasterServer.Settings.WebServerGameTypeFilter, false); if (Request.Url.LocalPath == "/" && indexFile.Exists) { // For stats masterServer.RegisterWebQuery(); // Set include variables variables["title"] = MasterServer.Settings.WebServerServerHeader; variables["skin"] = WebServer.Skin; variables["servercount"] = "0"; variables["busyservercount"] = "0"; variables["listspacer"] = ReadFile(serverSpacerRowFile);; variables["framesrc"] = FRAMESRC; // Substitute in server list and status line into index page template string indexPage = ReadFileAndParse(indexFile); Response.OutputStream.Write(Encoding.ASCII.GetBytes(indexPage), 0, indexPage.Length); Response.OutputStream.Close(); return(true); } else if (Request.Url.LocalPath == FRAMESRC && serverRowFile.Exists && serverSpacerRowFile.Exists && doTemplateFile.Exists) { // Set up page resources string serverListRow = ReadFile(serverRowFile); string serverSpacer = ReadFile(serverSpacerRowFile); string doTemplate = ReadFile(doTemplateFile); string serverList = ""; // Decremented for every active server, therefore this will count the "pending" servers in the list int busyServerCount = servers.Count; // Add server rows to server list foreach (Server server in servers) { if (server.Active) { busyServerCount--; variables["hrefserver"] = String.Format("server?ip={0}&port={1}", server.Address.ToString(), server.Port); variables["hrefmap"] = MapFileUrl(server.Map); variables["pwd"] = (server.Password) ? "Yes" : ""; variables["imgpwd"] = (server.Password) ? Image("lock.gif", "L", "Server is passworded", 13, 13) : ""; variables["listen"] = (server.Listen) ? "Yes" : ""; variables["imglisten"] = (server.Listen) ? Image("listen.gif", "P", "Server is a listen server (non-dedicated)", 13, 13) : ""; variables["name"] = ColourCodeParser.ColouriseConditional(server.Name); variables["map"] = server.Map; variables["gametype"] = server.GameType; variables["currentplayers"] = server.CurrentPlayers.ToString(); variables["maxplayers"] = server.MaxPlayers.ToString(); variables["flag"] = Image("img/flags/" + server.Country.ToLower() + ".gif", server.Country, server.Country, 18, 12); variables["country"] = server.Country; variables["ip"] = server.Address.ToString(); variables["port"] = server.Port.ToString(); variables["queryport"] = server.QueryPort.ToString(); // Add populated row to the server list serverList += ReplaceVariables(serverListRow); } } variables["serverlistbody"] = EncodeBrackets(serverSpacer + serverList + serverSpacer); variables["servercount"] = servers.Count.ToString(); variables["busyservercount"] = busyServerCount.ToString(); string doHtml = ReplaceVariables(doTemplate); Response.OutputStream.Write(Encoding.ASCII.GetBytes(doHtml), 0, doHtml.Length); Response.OutputStream.Close(); return(true); } } return(false); }