summaryrefslogtreecommitdiff
path: root/src/engine/master.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/master.cpp')
-rw-r--r--src/engine/master.cpp299
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;
}