diff --git a/source/CubeMS/Admin/Default.aspx b/source/CubeMS/Admin/Default.aspx new file mode 100644 index 00000000..533446e0 --- /dev/null +++ b/source/CubeMS/Admin/Default.aspx @@ -0,0 +1,65 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Admin_Admin" %> + + + + + + AssaultCube Admin + + +
+
+

AssaultCube Admin

+ +

Server List

+ + + + + + + + + + + + + + + + + + + +

Log

+ + + + + + + + + + + + + + + +   + +
+ Logged in as: + +
+ + +
+
+ + diff --git a/source/CubeMS/Admin/Default.aspx.cs b/source/CubeMS/Admin/Default.aspx.cs new file mode 100644 index 00000000..f085c6f1 --- /dev/null +++ b/source/CubeMS/Admin/Default.aspx.cs @@ -0,0 +1,18 @@ +using System; +using System.Data; +using System.Configuration; +using System.Collections; +using System.Web; +using System.Web.Security; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Web.UI.WebControls.WebParts; +using System.Web.UI.HtmlControls; + +public partial class Admin_Admin : System.Web.UI.Page +{ + protected void Page_Load(object sender, EventArgs e) + { + + } +} diff --git a/source/CubeMS/App_Code/CubeMS.cs b/source/CubeMS/App_Code/CubeMS.cs new file mode 100644 index 00000000..ef1c45cf --- /dev/null +++ b/source/CubeMS/App_Code/CubeMS.cs @@ -0,0 +1,147 @@ +using System; +using System.Data; +using System.Configuration; +using System.Web; +using System.Web.Security; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Web.UI.WebControls.WebParts; +using System.Web.UI.HtmlControls; + +using System.Net; +using System.Xml; +using System.IO; +using System.Data.SqlClient; +using System.Text; + +using AHSoftware.CubeMon; +using AHSoftware.CubeMon.Games.ActionCube.v094; + +/// +/// Summary description for CubeMS +/// +public class CubeMS +{ + string connectionString; + + public string ConnectionString + { + get { return connectionString; } + set { connectionString = value; } + } + + private bool AddServer(IPEndPoint address, string name, string description) + { + SqlConnection con = new SqlConnection(connectionString); + SqlCommand cmd = new SqlCommand("AddServer", con); + cmd.CommandType = CommandType.StoredProcedure; + cmd.Parameters.AddWithValue("IP", IPTools.IPToInt(address.Address)); + cmd.Parameters.AddWithValue("Port", address.Port); + cmd.Parameters.AddWithValue("Name", name); + cmd.Parameters.AddWithValue("Description", description); + try + { + con.Open(); + cmd.ExecuteNonQuery(); + return true; + } + catch + { + return false; + } + finally + { + con.Close(); + } + } + + public bool Register(IPEndPoint address) + { + Client c = new Client(); + c.Socket = new IPEndPoint(address.Address, address.Port+1); + ServerInfo info = null; + try + { + info = (ServerInfo) c.RequestInfo(); + } + catch + { + return false; + } + + string name = string.Empty; + try + { + name = Dns.GetHostEntry(info.Socket.Address).HostName; + } + catch { }; + + return AddServer(address, name, info.Description); + } + + public string GetServers(bool xml) + { + SqlConnection con = new SqlConnection(connectionString); + SqlCommand cmd = new SqlCommand(xml ? "GetServersXML" : "GetServers", con); + cmd.CommandType = CommandType.StoredProcedure; + try + { + con.Open(); + SqlDataReader r = cmd.ExecuteReader(); + StringBuilder sb = new StringBuilder(); + + if(xml) + { + // sql server handles xml conversion for us, just embed in a new xmldoc + sb.AppendLine(""); + sb.AppendLine(""); + if(r.Read()) + { + sb.AppendLine(r[0] as string); + } + sb.AppendLine(""); + } + else + { + // construct server list as cubescript + while(r.Read()) + { + sb.AppendFormat("addserver {0} {1};{2}", IPTools.IntToIp((int)r["IP"]).ToString(), r["Port"], Environment.NewLine); + } + } + + return sb.ToString(); + } + catch + { + return null; + } + finally + { + con.Close(); + } + } + + public string GetClientScript(string HTTPAgent) + { + SqlConnection con = new SqlConnection(connectionString); + SqlCommand cmd = new SqlCommand("GetClientScript", con); + cmd.CommandType = CommandType.StoredProcedure; + cmd.Parameters.AddWithValue("HTTPAgent", HTTPAgent); + try + { + con.Open(); + SqlDataReader r = cmd.ExecuteReader(); + r.Read(); + return r["Script"] as string; + } + catch + { + return null; + } + finally + { + con.Close(); + } + } +} diff --git a/source/CubeMS/App_Code/CubeMsRequestHandler.cs b/source/CubeMS/App_Code/CubeMsRequestHandler.cs new file mode 100644 index 00000000..f8cf8c6a --- /dev/null +++ b/source/CubeMS/App_Code/CubeMsRequestHandler.cs @@ -0,0 +1,158 @@ +using System; +using System.Data; +using System.Configuration; +using System.Web; +using System.Web.Security; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Web.UI.WebControls.WebParts; +using System.Web.UI.HtmlControls; + +using System.Net; +using System.Xml; +using System.IO; +using System.Web.Configuration; +using System.Web.Caching; + +using AHSoftware.CubeMon; +using AHSoftware.CubeMon.Games.ActionCube.v094; + +/// +/// Summary description for RequestHandler +/// +public class CubeMsRequestHandler : IHttpHandler +{ + Log log = new Log(); + CubeMS master; + int serverListCacheMinutes; + + CubeMsRequestHandler() + { + master = new CubeMS(); + master.ConnectionString = WebConfigurationManager.ConnectionStrings["CubeMS"].ConnectionString; + serverListCacheMinutes = int.Parse(WebConfigurationManager.AppSettings["ServerListCacheMinutes"] ?? "0"); + } + + #region IHttpHandler Members + + public bool IsReusable + { + get { return false; } + } + + public void ProcessRequest(HttpContext context) + { + IPEndPoint address = new IPEndPoint(IPAddress.Parse(context.Request.UserHostAddress), 0); + string requestFile = Path.GetFileName(context.Request.FilePath); + + try + { + if(requestFile == "register.do" && context.Request.QueryString["action"] == "add") + { + context.Response.ContentType = "text/plain"; + + try + { + address.Port = int.Parse(context.Request.QueryString["port"]); + } + catch + { + context.Response.Write("Server not registered, invalid request. Maybe you use an older server version?"); + log.AddEvent(Log.EventType.RegistrationFailed, "invalid request", address); + return; + } + + if(master.Register(address)) + { + // TODO: *DOS safety + context.Response.Write("Registration successful. Due to caching it might take a few minutes to see the your server in the serverlist"); + log.AddEvent(Log.EventType.RegistrationSuceeeded, null, address); + } + else + { + context.Response.Write("Server not registered, could not ping you. Make sure your server is accessible from the internet."); + log.AddEvent(Log.EventType.RegistrationFailed, "ping", address); + } + } + else if(requestFile == "retrieve.do") + { + string type = context.Request.QueryString["item"]; + if(type == "list") + { + context.Response.ContentType = "text/plain"; + + try + { + + // send server list + string servers = context.Cache[type] as string; + if(servers == null || servers.Length == 0) // empty cache, or empty server list + { + servers = master.GetServers(false); + if(serverListCacheMinutes > 0) context.Cache.Add(type, servers, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, serverListCacheMinutes, 0), CacheItemPriority.Normal, null); + } + + context.Response.Write(servers); + context.Response.Flush(); + log.AddEvent(Log.EventType.RetrieveServers, "list", address); + + // append client script if its an older or unknown client + if(bool.Parse((WebConfigurationManager.AppSettings["EnableClientScripts"] ?? "false")) && context.Request.UserAgent != WebConfigurationManager.AppSettings["ClientAgent"]) + { + string script = context.Cache["script"] as string; + if(script == null) + { + if((script = master.GetClientScript(context.Request.UserAgent)) != null) + { + int cacheminutes = int.Parse(WebConfigurationManager.AppSettings["ClientScriptCacheMinutes"] ?? "0"); + context.Cache.Add("script", script, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, cacheminutes, 0), CacheItemPriority.Normal, null); + } + } + + if(script != null) + { + context.Response.Write(script); + context.Response.Flush(); + log.AddEvent(Log.EventType.RetrieveServers, "script", address); + } + } + } + catch + { + // send error to the client + context.Response.Write("echo [An error ocurred on the masterserver]"); + context.Response.Flush(); + throw; // log errors globally + } + } + else if(context.Request.QueryString["item"] == "xml") + { + context.Response.ContentType = "text/xml"; + + string serversXml = context.Cache[type] as string; + if(serversXml == null || serversXml.Length == 0) // empty cache, or empty server list + { + serversXml = master.GetServers(true); + if(serverListCacheMinutes > 0) context.Cache.Add(type, serversXml, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, serverListCacheMinutes, 0), CacheItemPriority.Normal, null); + } + + context.Response.Write(serversXml); + context.Response.Flush(); + + log.AddEvent(Log.EventType.RetrieveServers, "xml", address); + } + } + } + catch(Exception ex) + { + try + { + // TODO: log all uncaught exceptions + // log.AddEvent(Log.EventType.Exception, ex.Message, address); + } + catch { } + } + } + + #endregion +} diff --git a/source/CubeMS/App_Code/IPTools.cs b/source/CubeMS/App_Code/IPTools.cs new file mode 100644 index 00000000..9028a907 --- /dev/null +++ b/source/CubeMS/App_Code/IPTools.cs @@ -0,0 +1,30 @@ +using System; +using System.Data; +using System.Configuration; +using System.Web; +using System.Web.Security; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Web.UI.WebControls.WebParts; +using System.Web.UI.HtmlControls; + +using System.Net; + +/// +/// Summary description for IPTools +/// +public static class IPTools +{ + public static int IPToInt(IPAddress address) + { + byte[] ip = address.GetAddressBytes(); + if(ip.Length == 4) return (int)(ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24)); + else return 0; + } + + public static IPAddress IntToIp(int address) + { + byte[] octets = { (byte)(address & 0xFF), (byte)((address >> 8) & 0xFF), (byte)((address >> 16) & 0xFF), (byte)((address >> 24) & 0xFF) }; + return new IPAddress(octets); + } +} diff --git a/source/CubeMS/App_Code/Log.cs b/source/CubeMS/App_Code/Log.cs new file mode 100644 index 00000000..325a0475 --- /dev/null +++ b/source/CubeMS/App_Code/Log.cs @@ -0,0 +1,41 @@ +using System; +using System.Data; +using System.Configuration; +using System.Web; +using System.Web.Security; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Web.UI.WebControls.WebParts; +using System.Web.UI.HtmlControls; + +using System.IO; +using System.Xml; +using System.Net; +using System.Data.SqlClient; + +/// +/// Summary description for Log +/// +public class Log +{ + public enum EventType : int + { + RegistrationFailed = 0, + RegistrationSuceeeded, + RetrieveServers, + Exception, + } + + public void AddEvent(EventType type, string data, IPEndPoint address) + { + SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["CubeMS"].ConnectionString as string); + SqlCommand cmd = new SqlCommand("AddEvent", con); + cmd.CommandType = CommandType.StoredProcedure; + cmd.Parameters.AddWithValue("Type", type); + cmd.Parameters.AddWithValue("Data", data); + cmd.Parameters.AddWithValue("IP", IPTools.IPToInt(address.Address)); + con.Open(); + cmd.ExecuteNonQuery(); + con.Close(); + } +} diff --git a/source/CubeMS/App_Themes/Pro/StyleSheet.css b/source/CubeMS/App_Themes/Pro/StyleSheet.css new file mode 100644 index 00000000..0aa7b503 --- /dev/null +++ b/source/CubeMS/App_Themes/Pro/StyleSheet.css @@ -0,0 +1,9 @@ +body +{ + Font-family: "Bitstream Vera Serif", Cambria, Baskerville, Palatino, Georgia, Times, "Times New Roman", serif.; + font-size: 12px; +} + +h1 +{ +} diff --git a/source/CubeMS/Bin/API.dll b/source/CubeMS/Bin/API.dll new file mode 100644 index 00000000..6a88f7f4 Binary files /dev/null and b/source/CubeMS/Bin/API.dll differ diff --git a/source/CubeMS/Bin/ActionCube.dll b/source/CubeMS/Bin/ActionCube.dll new file mode 100644 index 00000000..3c3ada0a Binary files /dev/null and b/source/CubeMS/Bin/ActionCube.dll differ diff --git a/source/CubeMS/Bin/Cube.dll b/source/CubeMS/Bin/Cube.dll new file mode 100644 index 00000000..62598c18 Binary files /dev/null and b/source/CubeMS/Bin/Cube.dll differ diff --git a/source/CubeMS/Bin/CubeEngineBase.dll b/source/CubeMS/Bin/CubeEngineBase.dll new file mode 100644 index 00000000..ec3c1282 Binary files /dev/null and b/source/CubeMS/Bin/CubeEngineBase.dll differ diff --git a/source/CubeMS/Default.aspx b/source/CubeMS/Default.aspx new file mode 100644 index 00000000..0da56486 --- /dev/null +++ b/source/CubeMS/Default.aspx @@ -0,0 +1,52 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> + + + + + + AssaultCube Master Server + + +
+
+

AssaultCube Master Server

+

Server List

+   + + + + + + + + + + + + + + + + + + +

Interfaces

+

+ You can retrieve the server list data using those url's: +

+ + + +

Admin

+ +
+ +
+
+ + diff --git a/source/CubeMS/Default.aspx.cs b/source/CubeMS/Default.aspx.cs new file mode 100644 index 00000000..42c253c5 --- /dev/null +++ b/source/CubeMS/Default.aspx.cs @@ -0,0 +1,17 @@ +using System; +using System.Data; +using System.Configuration; +using System.Web; +using System.Web.Security; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Web.UI.WebControls.WebParts; +using System.Web.UI.HtmlControls; + +public partial class _Default : System.Web.UI.Page +{ + protected void Page_Load(object sender, EventArgs e) + { + + } +} diff --git a/source/CubeMS/README.txt b/source/CubeMS/README.txt new file mode 100644 index 00000000..2138638a --- /dev/null +++ b/source/CubeMS/README.txt @@ -0,0 +1,42 @@ +CubeMS -- masterserver for the AssaultCube v0.94 + + +License: +ZLIB +http://www.gzip.org/zlib/zlib_license.html + +Author: +Adrian 'driAn' Henke +root AT sprintf.org + +Version: +v0.3 +November 2007 + +About this Software: +The purpose of this software is to let AssaultCube gameservers register +themselves on a central location and distribute the list of available +servers to all requesting AssaultCube game clients. Also it provides +additional interfaces for external application and possbilities to +control the storage and monitor various events. +This software has been developed to replace other PHP/Perl/Java based +solutions that are not easily expandable for future AssaultCube features +that will require more interaction with the masterserver. +This software is implemented as IIS HTTP-Handler written in C#/ASP.NET +with a MSSQL backend. Integrating the masterserver as HTTP-Handler and using +various caching possiblities ensures good scalability on higher workload. + +Installation: +There is no streamlined installation procedure for this software, you +need some knowledge of IIS 5+, MSSQL and ASP.NET to make any use of it. +Here is a quick list of required steps: + +* In IIS, create a new (virtual) directory that points to the CubeMS + directory. Configure security, ASP.NET 2.0, etc. +* In IIS, configure the application assignement for your CubeMS app. + Assign the ".do" ending to your aspnet_isapi.dll, restrict to GET requests + and disable the optional checks for existing files. +* In MSSQL, create a new database as well as tables and stored procedures. + Use the provided scripts to get this done. +* In MSSQL, create a new user and configure the web.config file in the CubeMS + directory accordingly. diff --git a/source/CubeMS/web.config b/source/CubeMS/web.config new file mode 100644 index 00000000..f0e7a535 --- /dev/null +++ b/source/CubeMS/web.config @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + +