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
+
+
+
+
+
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
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+