Files
assaultcube-/source/src/localserverms.cpp
T
driAn f83ca01e7a find all AC servers in your LAN
git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@2633 e016b1c5-ed68-44aa-a2f7-31cac88cffde
2008-09-15 17:02:13 +00:00

204 lines
5.8 KiB
C++

// local master server used for LAN server-searching
#include "pch.h"
#include "cube.h"
extern int servmillis;
extern struct log *logger;
masterserver::masterserver() : created(false), lastpurge(0)
{
socket = ENET_SOCKET_NULL;
}
bool masterserver::addserver(ENetAddress &addr)
{
// update server if existing
loopv(servers)
{
server &s = servers[i];
if(s.addr.host==addr.host && s.addr.port==addr.port)
{
s.addmillis = servmillis;
logger->writeline(log::info, "local LAN masterserver: updated local server (port %d)", s.addr.port);
return true;
}
}
// add new entry
server s = { addr, servmillis };
servers.add(s);
logger->writeline(log::info, "local LAN masterserver: added local server (port %d) to the list", s.addr.port);
return true;
}
char *masterserver::getserverlist()
{
// construct cube-script serverlist
char *buf = newstring("// local servers\n", _MAXDEFSTR);
loopv(servers)
{
server &s = servers[i];
string host;
enet_address_get_host(&s.addr, host, _MAXDEFSTR);
s_sprintfd(serverline)("addserver %s %d;\n", host, s.addr.port);
s_strcat(buf, serverline);
}
return buf;
}
void masterserver::processrequests()
{
ENetAddress remoteaddr;
ENetBuffer requestbuf;
uchar data[MAXTRANS] = { 0 };
requestbuf.data = data;
int len;
enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
while(enet_socket_wait(socket, &events, 0) >= 0 && events)
{
requestbuf.dataLength = sizeof(data);
len = enet_socket_receive(socket, &remoteaddr, &requestbuf, 1);
// block all non-local connections
/*enet_uint32 loopback = 16777343;
if(address.host!=remoteaddr.host && !(address.host==ENET_HOST_ANY && remoteaddr.host==loopback))
{
enet_socket_destroy(datasocket);
datasocket = socket;
continue;
}*/
char *request = ((char *)requestbuf.data);
// split request string
hashtable<const char *, string> args;
char *argseparators = "?&";
char *t = strpbrk(request, argseparators);
while(t)
{
char *namebegin = t+1;
char *nameend = strchr(namebegin, '=');
char *valuebegin = nameend+1;
char *valueend = strpbrk(valuebegin, "& ");
if(namebegin < nameend && nameend < valuebegin && valuebegin < valueend)
{
char *name = newstring(namebegin, nameend-namebegin);
char *str = (char*)args[name];
s_strncpy(str, valuebegin, valueend-valuebegin+1);
}
t = strpbrk(t+1, argseparators);
}
// response buf
const string error400 = "HTTP/1.0 400 Bad Request\nContent-Type: text/plain\n\nBAD REQUEST\n\n";
const string error500 = "HTTP/1.0 500 Internal Server Error\nContent-Type: text/plain\n\nINTERNAL SERVER ERROR\n\n";
ENetBuffer responsebuf;
string response = { 0 };
responsebuf.data = response;
// process requests
char *action = (char *)args.access("action");
char *port = (char *)args.access("port");
char *item = (char *)args.access("item");
if(action)
{
if(!strcmp(action, "add") && port) // add requests
{
ENetAddress srvaddr = { remoteaddr.host, atoi(port) };
if(addserver(srvaddr))
{
//s_strcpy(response, "HTTP/1.0 200 OK\nContent-Type: text/plain\n\nServer was successfully added to the local LAN masterserver.\n\n");
}
else
{
s_strcpy(response, error500);
}
}
else
{
s_strcpy(response, error400);
}
}
else if(item)
{
if(!strcmp(item, "list")) // list requests
{
s_strcpy(response, "HTTP/1.0 200 OK\nContent-Type: text/plain\n\n");
char *servers = getserverlist();
s_strcat(response, servers);
s_strcat(response, "\n\n");
delete[] servers;
}
}
else
{
s_strcpy(response, error400);
}
size_t resplen = strlen(response);
if(resplen > 0)
{
responsebuf.dataLength = resplen;
enet_socket_send(socket, &remoteaddr, &responsebuf, 1);
}
args.clear();
}
}
void masterserver::purgeserverlist()
{
const int PURGEINTERVALMILLIS = 60*1000;
const int MAXAGEMILLIS = 60*60*1000;
if(!lastpurge || servmillis-lastpurge > PURGEINTERVALMILLIS)
{
loopv(servers)
{
server &s = servers[i];
int age = servmillis-s.addmillis;
if(age > MAXAGEMILLIS)
{
logger->writeline(log::info, "local LAN masterserver: removed local server (port %d) from list", s.addr.port);
servers.remove(i--);
}
}
lastpurge = servmillis;
}
}
void masterserver::update()
{
if(!created) return;
processrequests();
purgeserverlist();
}
void masterserver::create(ENetAddress &addr)
{
if(created) return;
socket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &addr);
if(socket == ENET_SOCKET_NULL)
{
logger->writeline(log::info, "local LAN masterserver: could not create masterserver instance, another server probably does the job already");
}
else
{
enet_socket_set_option(socket, ENET_SOCKOPT_NONBLOCK, 1);
address = addr;
created = true;
logger->writeline(log::info, "local LAN masterserver: created masterserver instance");
}
}