masterserver

git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@1402 e016b1c5-ed68-44aa-a2f7-31cac88cffde
This commit is contained in:
driAn
2007-10-27 18:22:20 +00:00
parent 1c05664bbc
commit 8d65b707e6
15 changed files with 632 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Admin_Admin" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>AssaultCube Admin</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>AssaultCube Admin</h1>
<h2>Server List</h2>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4"
DataSourceID="XmlDataSource1" ForeColor="#333333" GridLines="Vertical" AllowPaging="True" DataKeyNames="address">
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<Columns>
<asp:BoundField DataField="address" HeaderText="address" SortExpression="address" />
<asp:BoundField DataField="port" HeaderText="port" SortExpression="port" />
<asp:BoundField DataField="added" HeaderText="added" SortExpression="added" />
<asp:BoundField DataField="name" HeaderText="name" SortExpression="name" />
<asp:BoundField DataField="description" HeaderText="description" SortExpression="description" />
</Columns>
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<EditRowStyle BackColor="#999999" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
</asp:GridView>
<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/App_Data/servers.xml"
XPath="//server"></asp:XmlDataSource>
<h2>Log</h2>
<asp:GridView ID="GridView2" runat="server" AllowPaging="True" AutoGenerateColumns="False"
CellPadding="4" DataSourceID="XmlDataSource2" ForeColor="#333333" GridLines="Vertical">
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<Columns>
<asp:BoundField DataField="action" HeaderText="Action" SortExpression="added" NullDisplayText="unknown" />
<asp:BoundField DataField="address" HeaderText="Client" SortExpression="address" />
<asp:BoundField DataField="added" HeaderText="Date" SortExpression="added" />
</Columns>
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<EditRowStyle BackColor="#999999" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
</asp:GridView>
&nbsp;
<asp:XmlDataSource ID="XmlDataSource2" runat="server" DataFile="~/App_Data/log.xml"
XPath="//LogEntry" ></asp:XmlDataSource>
<br />
Logged in as:
<asp:LoginName ID="LoginName1" runat="server" />
<br />
<asp:LoginStatus ID="LoginStatus1" runat="server" LogoutAction="Redirect" LogoutPageUrl="~/Default.aspx" />
</div>
</form>
</body>
</html>
+18
View File
@@ -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)
{
}
}
+147
View File
@@ -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>
/// Summary description for CubeMS
/// </summary>
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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.AppendLine("<Servers>");
if(r.Read())
{
sb.AppendLine(r[0] as string);
}
sb.AppendLine("</Servers>");
}
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();
}
}
}
@@ -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>
/// Summary description for RequestHandler
/// </summary>
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
}
+30
View File
@@ -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>
/// Summary description for IPTools
/// </summary>
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);
}
}
+41
View File
@@ -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>
/// Summary description for Log
/// </summary>
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();
}
}
@@ -0,0 +1,9 @@
body
{
Font-family: "Bitstream Vera Serif", Cambria, Baskerville, Palatino, Georgia, Times, "Times New Roman", serif.;
font-size: 12px;
}
h1
{
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+52
View File
@@ -0,0 +1,52 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>AssaultCube Master Server</title>
</head>
<body>
<form id="form1" runat="server">
<div title="AssaultCube Master Server">
<h1>AssaultCube Master Server</h1>
<h2>Server List</h2>
&nbsp;
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4"
DataKeyNames="IP" DataSourceID="SqlDataSource1" ForeColor="#333333" GridLines="None">
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<Columns>
<asp:BoundField DataField="IP" HeaderText="IP" ReadOnly="True" SortExpression="IP" />
<asp:BoundField DataField="Port" HeaderText="Port" SortExpression="Port" />
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
<asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" />
<asp:BoundField DataField="LastModified" HeaderText="LastModified" SortExpression="LastModified" />
</Columns>
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<EditRowStyle BackColor="#999999" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:CubeMS %>"
SelectCommand="GetServers" SelectCommandType="StoredProcedure"></asp:SqlDataSource>
<h2>Interfaces</h2>
<p>
You can retrieve the server list data using those url's:
</p>
<ul>
<li><a href="retrieve.do?item=xml">XML Server List (use for AJAX)</a></li>
<li><a href="retrieve.do?item=list">CubeScript Server List</a></li>
</ul>
<h2>Admin</h2>
<asp:Button ID="Button1" runat="server" PostBackUrl="~/Admin/Default.aspx" Text="Login" /><br />
</div>
</form>
</body>
</html>
+17
View File
@@ -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)
{
}
}
+42
View File
@@ -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.
+53
View File
@@ -0,0 +1,53 @@
<?xml version="1.0"?>
<!--
Note: As an alternative to hand editing this file you can use the
web admin tool to configure settings for your application. Use
the Website->Asp.Net Configuration option in Visual Studio.
A full list of settings and comments can be found in
machine.config.comments usually located in
\Windows\Microsoft.Net\Framework\v2.x\Config
-->
<configuration>
<appSettings>
<add key="ClientAgent" value="AssaultCube Client 940"/>
<add key="ServerAgent" value="AssaultCube Server 940"/>
<add key="EnableClientScripts" value="true"/>
<add key="ServerListCacheMinutes" value="0"/>
<add key="ClientScriptCacheMinutes" value="0"/>
</appSettings>
<connectionStrings>
<add name="CubeMS" connectionString="Data Source=ADRIAN\SQLEXPRESS;Initial Catalog=k0890;Integrated Security=True;Pooling=False"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<!--
Set compilation debug="true" to insert debugging
symbols into the compiled page. Because this
affects performance, set this value to true only
during development.
-->
<compilation debug="true"/>
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<authentication mode="Forms" />
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<httpHandlers>
<add verb="GET" path="*.do" type="CubeMsRequestHandler" validate="false"/>
</httpHandlers>
<pages theme="Pro"></pages>
</system.web>
</configuration>