diff options
Diffstat (limited to 'src/engine/master.cpp')
| -rw-r--r-- | src/engine/master.cpp | 299 |
1 files changed, 91 insertions, 208 deletions
diff --git a/src/engine/master.cpp b/src/engine/master.cpp index 2bf1dba..c1d3e20 100644 --- a/src/engine/master.cpp +++ b/src/engine/master.cpp @@ -22,15 +22,13 @@ FILE *logfile = NULL; -struct userinfo -{ +struct userinfo { char *name; void *pubkey; }; hashnameset<userinfo> users; -void adduser(char *name, char *pubkey) -{ +void adduser(char *name, char *pubkey) { name = newstring(name); userinfo &u = users[name]; u.name = name; @@ -38,8 +36,7 @@ void adduser(char *name, char *pubkey) } COMMAND(adduser, "ss"); -void clearusers() -{ +void clearusers() { enumerate(users, userinfo, u, { delete[] u.name; freepubkey(u.pubkey); }); users.clear(); } @@ -47,16 +44,14 @@ COMMAND(clearusers, ""); vector<ipmask> bans, servbans, gbans; -void clearbans() -{ +void clearbans() { bans.shrink(0); servbans.shrink(0); gbans.shrink(0); } COMMAND(clearbans, ""); -void addban(vector<ipmask> &bans, const char *name) -{ +void addban(vector<ipmask> &bans, const char *name) { ipmask ban; ban.parse(name); bans.add(ban); @@ -65,21 +60,18 @@ ICOMMAND(ban, "s", (char *name), addban(bans, name)); ICOMMAND(servban, "s", (char *name), addban(servbans, name)); ICOMMAND(gban, "s", (char *name), addban(gbans, name)); -bool checkban(vector<ipmask> &bans, enet_uint32 host) -{ +bool checkban(vector<ipmask> &bans, enet_uint32 host) { loopv(bans) if(bans[i].check(host)) return true; return false; } -struct authreq -{ +struct authreq { enet_uint32 reqtime; uint id; void *answer; }; -struct gameserver -{ +struct gameserver { ENetAddress address; string ip; int port, numpings; @@ -87,30 +79,21 @@ struct gameserver }; vector<gameserver *> gameservers; -struct messagebuf -{ +struct messagebuf { vector<messagebuf *> &owner; vector<char> buf; int refs; - messagebuf(vector<messagebuf *> &owner) : owner(owner), refs(0) {} - const char *getbuf() { return buf.getbuf(); } int length() { return buf.length(); } void purge(); - - bool equals(const messagebuf &m) const - { + bool equals(const messagebuf &m) const { return buf.length() == m.buf.length() && !memcmp(buf.getbuf(), m.buf.getbuf(), buf.length()); } - - bool endswith(const messagebuf &m) const - { + bool endswith(const messagebuf &m) const { return buf.length() >= m.buf.length() && !memcmp(&buf[buf.length() - m.buf.length()], m.buf.getbuf(), m.buf.length()); } - - void concat(const messagebuf &m) - { + void concat(const messagebuf &m) { if(buf.length() && buf.last() == '\0') buf.pop(); buf.put(m.buf.getbuf(), m.buf.length()); } @@ -118,8 +101,7 @@ struct messagebuf vector<messagebuf *> gameserverlists, gbanlists; bool updateserverlist = true; -struct client -{ +struct client { ENetAddress address; ENetSocket socket; char input[INPUT_LIMIT]; @@ -132,7 +114,6 @@ struct client vector<authreq> authreqs; bool shouldpurge; bool registeredserver; - client() : message(NULL), inputpos(0), outputpos(0), servport(-1), lastauth(0), shouldpurge(false), registeredserver(false) {} }; vector<client *> clients; @@ -142,8 +123,7 @@ ENetSocket serversocket = ENET_SOCKET_NULL; time_t starttime; enet_uint32 servtime = 0; -void fatal(const char *fmt, ...) -{ +void fatal(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(logfile, fmt, args); @@ -152,14 +132,12 @@ void fatal(const char *fmt, ...) exit(EXIT_FAILURE); } -void conoutfv(int type, const char *fmt, va_list args) -{ +void conoutfv(int type, const char *fmt, va_list args) { vfprintf(logfile, fmt, args); fputc('\n', logfile); } -void purgeclient(int n) -{ +void purgeclient(int n) { client &c = *clients[n]; if(c.message) c.message->purge(); enet_socket_destroy(c.socket); @@ -167,27 +145,23 @@ void purgeclient(int n) clients.remove(n); } -void output(client &c, const char *msg, int len = 0) -{ +void output(client &c, const char *msg, int len = 0) { if(!len) len = strlen(msg); c.output.put(msg, len); } -void outputf(client &c, const char *fmt, ...) -{ +void outputf(client &c, const char *fmt, ...) { string msg; va_list args; va_start(args, fmt); vformatstring(msg, fmt, args); va_end(args); - output(c, msg); } ENetSocket pingsocket = ENET_SOCKET_NULL; -bool setuppingsocket(ENetAddress *address) -{ +bool setuppingsocket(ENetAddress *address) { if(pingsocket != ENET_SOCKET_NULL) return true; pingsocket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); if(pingsocket == ENET_SOCKET_NULL) return false; @@ -196,14 +170,11 @@ bool setuppingsocket(ENetAddress *address) return true; } -void setupserver(int port, const char *ip = NULL) -{ +void setupserver(int port, const char *ip = NULL) { ENetAddress address; address.host = ENET_HOST_ANY; address.port = port; - - if(ip) - { + if(ip) { if(enet_address_set_host(&address, ip)<0) fatal("failed to resolve server address: %s", ip); } @@ -217,23 +188,19 @@ void setupserver(int port, const char *ip = NULL) fatal("failed to make server socket non-blocking"); if(!setuppingsocket(&address)) fatal("failed to create ping socket"); - enet_time_set(0); - starttime = time(NULL); char *ct = ctime(&starttime); if(strchr(ct, '\n')) *strchr(ct, '\n') = '\0'; conoutf("*** Starting master server on %s %d at %s ***", ip ? ip : "localhost", port, ct); } -void genserverlist() -{ +void genserverlist() { if(!updateserverlist) return; while(gameserverlists.length() && gameserverlists.last()->refs<=0) delete gameserverlists.pop(); messagebuf *l = new messagebuf(gameserverlists); - loopv(gameservers) - { + loopv(gameservers) { gameserver &s = *gameservers[i]; if(!s.lastpong) continue; defformatstring(cmd, "addserver %s %d\n", s.ip, s.port); @@ -244,67 +211,56 @@ void genserverlist() updateserverlist = false; } -void gengbanlist() -{ +void gengbanlist() { messagebuf *l = new messagebuf(gbanlists); const char *header = "cleargbans\n"; l->buf.put(header, strlen(header)); string cmd = "addgban "; int cmdlen = strlen(cmd); - loopv(gbans) - { + loopv(gbans) { ipmask &b = gbans[i]; l->buf.put(cmd, cmdlen + b.print(&cmd[cmdlen])); l->buf.add('\n'); } - if(gbanlists.length() && gbanlists.last()->equals(*l)) - { + if(gbanlists.length() && gbanlists.last()->equals(*l)) { delete l; return; } while(gbanlists.length() && gbanlists.last()->refs<=0) delete gbanlists.pop(); - loopv(gbanlists) - { + loopv(gbanlists) { messagebuf *m = gbanlists[i]; if(m->refs > 0 && !m->endswith(*l)) m->concat(*l); } gbanlists.add(l); - loopv(clients) - { + loopv(clients) { client &c = *clients[i]; - if(c.servport >= 0 && !c.message) - { + if(c.servport >= 0 && !c.message) { c.message = l; c.message->refs++; } } } -void addgameserver(client &c) -{ +void addgameserver(client &c) { if(gameservers.length() >= SERVER_LIMIT) return; int dups = 0; - loopv(gameservers) - { + loopv(gameservers) { gameserver &s = *gameservers[i]; if(s.address.host != c.address.host) continue; ++dups; - if(s.port == c.servport) - { + if(s.port == c.servport) { s.lastping = 0; s.numpings = 0; return; } } - if(dups >= SERVER_DUP_LIMIT) - { + if(dups >= SERVER_DUP_LIMIT) { outputf(c, "failreg too many servers on ip\n"); return; } string hostname; - if(enet_address_get_host_ip(&c.address, hostname, sizeof(hostname)) < 0) - { + if(enet_address_get_host_ip(&c.address, hostname, sizeof(hostname)) < 0) { outputf(c, "failreg failed resolving ip\n"); return; } @@ -317,10 +273,8 @@ void addgameserver(client &c) s.lastping = s.lastpong = 0; } -client *findclient(gameserver &s) -{ - loopv(clients) - { +client *findclient(gameserver &s) { + loopv(clients) { client &c = *clients[i]; if(s.address.host == c.address.host && s.port == c.servport) return &c; @@ -328,37 +282,29 @@ client *findclient(gameserver &s) return NULL; } -void servermessage(gameserver &s, const char *msg) -{ +void servermessage(gameserver &s, const char *msg) { client *c = findclient(s); if(c) outputf(*c, msg); } -void checkserverpongs() -{ +void checkserverpongs() { ENetBuffer buf; ENetAddress addr; static uchar pong[MAXTRANS]; - for(;;) - { + for(;;) { buf.data = pong; buf.dataLength = sizeof(pong); int len = enet_socket_receive(pingsocket, &addr, &buf, 1); if(len <= 0) break; - loopv(gameservers) - { + loopv(gameservers) { gameserver &s = *gameservers[i]; - if(s.address.host == addr.host && s.address.port == addr.port) - { - if(s.lastping && (!s.lastpong || ENET_TIME_GREATER(s.lastping, s.lastpong))) - { + if(s.address.host == addr.host && s.address.port == addr.port) { + if(s.lastping && (!s.lastpong || ENET_TIME_GREATER(s.lastping, s.lastpong))) { client *c = findclient(s); - if(c) - { + if(c) { c->registeredserver = true; outputf(*c, "succreg\n"); - if(!c->message && gbanlists.length()) - { + if(!c->message && gbanlists.length()) { c->message = gbanlists.last(); c->message->refs++; } @@ -372,39 +318,30 @@ void checkserverpongs() } } -void bangameservers() -{ - loopvrev(gameservers) if(checkban(servbans, gameservers[i]->address.host)) - { +void bangameservers() { + loopvrev(gameservers) if(checkban(servbans, gameservers[i]->address.host)) { delete gameservers.remove(i); updateserverlist = true; } } -void checkgameservers() -{ +void checkgameservers() { ENetBuffer buf; - loopv(gameservers) - { + loopv(gameservers) { gameserver &s = *gameservers[i]; - if(s.lastping && s.lastpong && ENET_TIME_LESS_EQUAL(s.lastping, s.lastpong)) - { - if(ENET_TIME_DIFFERENCE(servtime, s.lastpong) > KEEPALIVE_TIME) - { + if(s.lastping && s.lastpong && ENET_TIME_LESS_EQUAL(s.lastping, s.lastpong)) { + if(ENET_TIME_DIFFERENCE(servtime, s.lastpong) > KEEPALIVE_TIME) { delete gameservers.remove(i--); updateserverlist = true; } } - else if(!s.lastping || ENET_TIME_DIFFERENCE(servtime, s.lastping) > PING_TIME) - { - if(s.numpings >= PING_RETRY) - { + else if(!s.lastping || ENET_TIME_DIFFERENCE(servtime, s.lastping) > PING_TIME) { + if(s.numpings >= PING_RETRY) { servermessage(s, "failreg failed pinging server\n"); delete gameservers.remove(i--); updateserverlist = true; } - else - { + else { static const uchar ping[] = { 1 }; buf.data = (void *)ping; buf.dataLength = sizeof(ping); @@ -416,23 +353,18 @@ void checkgameservers() } } -void messagebuf::purge() -{ +void messagebuf::purge() { refs = max(refs - 1, 0); - if(refs<=0 && owner.last()!=this) - { + if(refs<=0 && owner.last()!=this) { owner.removeobj(this); delete this; } } -void purgeauths(client &c) -{ +void purgeauths(client &c) { int expired = 0; - loopv(c.authreqs) - { - if(ENET_TIME_DIFFERENCE(servtime, c.authreqs[i].reqtime) >= AUTH_TIME) - { + loopv(c.authreqs) { + if(ENET_TIME_DIFFERENCE(servtime, c.authreqs[i].reqtime) >= AUTH_TIME) { outputf(c, "failauth %u\n", c.authreqs[i].id); freechallenge(c.authreqs[i].answer); expired = i + 1; @@ -442,40 +374,30 @@ void purgeauths(client &c) if(expired > 0) c.authreqs.remove(0, expired); } -void reqauth(client &c, uint id, char *name) -{ +void reqauth(client &c, uint id, char *name) { if(ENET_TIME_DIFFERENCE(servtime, c.lastauth) < AUTH_THROTTLE) return; - c.lastauth = servtime; - purgeauths(c); - time_t t = time(NULL); char *ct = ctime(&t); - if(ct) - { + if(ct) { char *newline = strchr(ct, '\n'); if(newline) *newline = '\0'; } string ip; if(enet_address_get_host_ip(&c.address, ip, sizeof(ip)) < 0) copystring(ip, "-"); conoutf("%s: attempting \"%s\" as %u from %s", ct ? ct : "-", name, id, ip); - userinfo *u = users.access(name); - if(!u) - { + if(!u) { outputf(c, "failauth %u\n", id); return; } - - if(c.authreqs.length() >= AUTH_LIMIT) - { + if(c.authreqs.length() >= AUTH_LIMIT) { outputf(c, "failauth %u\n", c.authreqs[0].id); freechallenge(c.authreqs[0].answer); c.authreqs.remove(0); } - authreq &a = c.authreqs.add(); a.reqtime = servtime; a.id = id; @@ -483,25 +405,19 @@ void reqauth(client &c, uint id, char *name) static vector<char> buf; buf.setsize(0); a.answer = genchallenge(u->pubkey, seed, sizeof(seed), buf); - outputf(c, "chalauth %u %s\n", id, buf.getbuf()); } -void confauth(client &c, uint id, const char *val) -{ +void confauth(client &c, uint id, const char *val) { purgeauths(c); - - loopv(c.authreqs) if(c.authreqs[i].id == id) - { + loopv(c.authreqs) if(c.authreqs[i].id == id) { string ip; if(enet_address_get_host_ip(&c.address, ip, sizeof(ip)) < 0) copystring(ip, "-"); - if(checkchallenge(val, c.authreqs[i].answer)) - { + if(checkchallenge(val, c.authreqs[i].answer)) { outputf(c, "succauth %u\n", id); conoutf("succeeded %u from %s", id, ip); } - else - { + else { outputf(c, "failauth %u\n", id); conoutf("failed %u from %s", id, ip); } @@ -512,20 +428,16 @@ void confauth(client &c, uint id, const char *val) outputf(c, "failauth %u\n", id); } -bool checkclientinput(client &c) -{ +bool checkclientinput(client &c) { if(c.inputpos<0) return true; char *end = (char *)memchr(c.input, '\n', c.inputpos); - while(end) - { + while(end) { *end++ = '\0'; c.lastinput = servtime; - int port; uint id; string user, val; - if(!strncmp(c.input, "list", 4) && (!c.input[4] || c.input[4] == '\n' || c.input[4] == '\r')) - { + if(!strncmp(c.input, "list", 4) && (!c.input[4] || c.input[4] == '\n' || c.input[4] == '\r')) { genserverlist(); if(gameserverlists.empty() || c.message) return false; c.message = gameserverlists.last(); @@ -535,27 +447,22 @@ bool checkclientinput(client &c) c.shouldpurge = true; return true; } - else if(sscanf(c.input, "regserv %d", &port) == 1) - { + else if(sscanf(c.input, "regserv %d", &port) == 1) { if(checkban(servbans, c.address.host)) return false; if(port < 0 || port > 0xFFFF-1 || (c.servport >= 0 && port != c.servport)) outputf(c, "failreg invalid port\n"); - else - { + else { c.servport = port; addgameserver(c); } } - else if(sscanf(c.input, "reqauth %u %100s", &id, user) == 2) - { + else if(sscanf(c.input, "reqauth %u %100s", &id, user) == 2) { reqauth(c, id, user); } - else if(sscanf(c.input, "confauth %u %100s", &id, val) == 2) - { + else if(sscanf(c.input, "confauth %u %100s", &id, val) == 2) { confauth(c, id, val); } c.inputpos = &c.input[c.inputpos] - end; memmove(c.input, end, c.inputpos); - end = (char *)memchr(c.input, '\n', c.inputpos); } return c.inputpos<(int)sizeof(c.input); @@ -563,16 +470,14 @@ bool checkclientinput(client &c) ENetSocketSet readset, writeset; -void checkclients() -{ +void checkclients() { ENetSocketSet readset, writeset; ENetSocket maxsock = max(serversocket, pingsocket); ENET_SOCKETSET_EMPTY(readset); ENET_SOCKETSET_EMPTY(writeset); ENET_SOCKETSET_ADD(readset, serversocket); ENET_SOCKETSET_ADD(readset, pingsocket); - loopv(clients) - { + loopv(clients) { client &c = *clients[i]; if(c.authreqs.length()) purgeauths(c); if(c.message || c.output.length()) ENET_SOCKETSET_ADD(writeset, c.socket); @@ -580,23 +485,18 @@ void checkclients() maxsock = max(maxsock, c.socket); } if(enet_socketset_select(maxsock, &readset, &writeset, 1000)<=0) return; - if(ENET_SOCKETSET_CHECK(readset, pingsocket)) checkserverpongs(); - if(ENET_SOCKETSET_CHECK(readset, serversocket)) - { + if(ENET_SOCKETSET_CHECK(readset, serversocket)) { ENetAddress address; ENetSocket clientsocket = enet_socket_accept(serversocket, &address); if(clients.length()>=CLIENT_LIMIT || checkban(bans, address.host)) enet_socket_destroy(clientsocket); - else if(clientsocket!=ENET_SOCKET_NULL) - { + else if(clientsocket!=ENET_SOCKET_NULL) { int dups = 0, oldest = -1; - loopv(clients) if(clients[i]->address.host == address.host) - { + loopv(clients) if(clients[i]->address.host == address.host) { dups++; if(oldest<0 || clients[i]->connecttime < clients[oldest]->connecttime) oldest = i; } if(dups >= DUP_LIMIT) purgeclient(oldest); - client *c = new client; c->address = address; c->socket = clientsocket; @@ -605,32 +505,25 @@ void checkclients() clients.add(c); } } - - loopv(clients) - { + loopv(clients) { client &c = *clients[i]; - if((c.message || c.output.length()) && ENET_SOCKETSET_CHECK(writeset, c.socket)) - { + if((c.message || c.output.length()) && ENET_SOCKETSET_CHECK(writeset, c.socket)) { const char *data = c.output.length() ? c.output.getbuf() : c.message->getbuf(); int len = c.output.length() ? c.output.length() : c.message->length(); ENetBuffer buf; buf.data = (void *)&data[c.outputpos]; buf.dataLength = len-c.outputpos; int res = enet_socket_send(c.socket, NULL, &buf, 1); - if(res>=0) - { + if(res>=0) { c.outputpos += res; - if(c.outputpos>=len) - { + if(c.outputpos>=len) { if(c.output.length()) c.output.setsize(0); - else - { + else { c.message->purge(); c.message = NULL; } c.outputpos = 0; - if(!c.message && c.output.empty() && c.shouldpurge) - { + if(!c.message && c.output.empty() && c.shouldpurge) { purgeclient(i--); continue; } @@ -638,14 +531,12 @@ void checkclients() } else { purgeclient(i--); continue; } } - if(ENET_SOCKETSET_CHECK(readset, c.socket)) - { + if(ENET_SOCKETSET_CHECK(readset, c.socket)) { ENetBuffer buf; buf.data = &c.input[c.inputpos]; buf.dataLength = sizeof(c.input) - c.inputpos; int res = enet_socket_receive(c.socket, NULL, &buf, 1); - if(res>0) - { + if(res>0) { c.inputpos += res; c.input[min(c.inputpos, (int)sizeof(c.input)-1)] = '\0'; if(!checkclientinput(c)) { purgeclient(i--); continue; } @@ -657,23 +548,19 @@ void checkclients() } } -void banclients() -{ +void banclients() { loopvrev(clients) if(checkban(bans, clients[i]->address.host)) purgeclient(i); } volatile int reloadcfg = 1; -void reloadsignal(int signum) -{ +void reloadsignal(int signum) { reloadcfg = 1; } -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { if(enet_initialize()<0) fatal("Unable to initialise network module"); atexit(enet_deinitialize); - const char *dir = "", *ip = NULL; int port = 28787; if(argc>=2) dir = argv[1]; @@ -688,10 +575,8 @@ int main(int argc, char **argv) setvbuf(logfile, NULL, _IOLBF, BUFSIZ); signal(SIGUSR1, reloadsignal); setupserver(port, ip); - for(;;) - { - if(reloadcfg) - { + for(;;) { + if(reloadcfg) { conoutf("reloading master.cfg"); execfile(cfgname); bangameservers(); @@ -699,12 +584,10 @@ int main(int argc, char **argv) gengbanlist(); reloadcfg = 0; } - servtime = enet_time_get(); checkclients(); checkgameservers(); } - return EXIT_SUCCESS; } |
