From f83ca01e7ab7e1e3b808c30c6be0c24de2c4891d Mon Sep 17 00:00:00 2001 From: driAn Date: Mon, 15 Sep 2008 17:02:13 +0000 Subject: [PATCH] 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 --- source/src/localserverms.cpp | 203 +++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 source/src/localserverms.cpp diff --git a/source/src/localserverms.cpp b/source/src/localserverms.cpp new file mode 100644 index 00000000..ed8c31b9 --- /dev/null +++ b/source/src/localserverms.cpp @@ -0,0 +1,203 @@ +// 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 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"); + } +} +