summaryrefslogtreecommitdiff
path: root/src/engine/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/server.cpp')
-rw-r--r--src/engine/server.cpp1128
1 files changed, 564 insertions, 564 deletions
diff --git a/src/engine/server.cpp b/src/engine/server.cpp
index 9348b67..7e338b3 100644
--- a/src/engine/server.cpp
+++ b/src/engine/server.cpp
@@ -9,73 +9,73 @@ static FILE *logfile = NULL;
void closelogfile()
{
- if(logfile)
- {
- fclose(logfile);
- logfile = NULL;
- }
+ if(logfile)
+ {
+ fclose(logfile);
+ logfile = NULL;
+ }
}
FILE *getlogfile()
{
- return logfile ? logfile : stdout;
+ return logfile ? logfile : stdout;
}
void setlogfile(const char *fname)
{
- closelogfile();
- if(fname && fname[0])
- {
- fname = findfile(fname, "w");
- if(fname) logfile = fopen(fname, "w");
- }
- FILE *f = getlogfile();
- if(f) setvbuf(f, NULL, _IOLBF, BUFSIZ);
+ closelogfile();
+ if(fname && fname[0])
+ {
+ fname = findfile(fname, "w");
+ if(fname) logfile = fopen(fname, "w");
+ }
+ FILE *f = getlogfile();
+ if(f) setvbuf(f, NULL, _IOLBF, BUFSIZ);
}
void logoutf(const char *fmt, ...)
{
- va_list args;
- va_start(args, fmt);
- logoutfv(fmt, args);
- va_end(args);
+ va_list args;
+ va_start(args, fmt);
+ logoutfv(fmt, args);
+ va_end(args);
}
static void writelog(FILE *file, const char *buf)
{
- static uchar ubuf[512];
- size_t len = strlen(buf), carry = 0;
- while(carry < len)
- {
- size_t numu = encodeutf8(ubuf, sizeof(ubuf)-1, &((const uchar *)buf)[carry], len - carry, &carry);
- if(carry >= len) ubuf[numu++] = '\n';
- fwrite(ubuf, 1, numu, file);
- }
+ static uchar ubuf[512];
+ size_t len = strlen(buf), carry = 0;
+ while(carry < len)
+ {
+ size_t numu = encodeutf8(ubuf, sizeof(ubuf)-1, &((const uchar *)buf)[carry], len - carry, &carry);
+ if(carry >= len) ubuf[numu++] = '\n';
+ fwrite(ubuf, 1, numu, file);
+ }
}
static void writelogv(FILE *file, const char *fmt, va_list args)
{
- static char buf[LOGSTRLEN];
- vformatstring(buf, fmt, args, sizeof(buf));
- writelog(file, buf);
+ static char buf[LOGSTRLEN];
+ vformatstring(buf, fmt, args, sizeof(buf));
+ writelog(file, buf);
}
#ifdef STANDALONE
void fatal(const char *fmt, ...)
{
- void cleanupserver();
- cleanupserver();
+ void cleanupserver();
+ cleanupserver();
defvformatstring(msg,fmt,fmt);
if(logfile) logoutf("%s", msg);
- fprintf(stderr, "server error: %s\n", msg);
- closelogfile();
- exit(EXIT_FAILURE);
+ fprintf(stderr, "server error: %s\n", msg);
+ closelogfile();
+ exit(EXIT_FAILURE);
}
void conoutfv(int type, const char *fmt, va_list args)
{
- logoutfv(fmt, args);
+ logoutfv(fmt, args);
}
#endif
@@ -83,13 +83,13 @@ void conoutfv(int type, const char *fmt, va_list args)
enum { ST_EMPTY, ST_LOCAL, ST_TCPIP };
-struct client // server side version of "dynent" type
+struct client // server side version of "dynent" type
{
- int type;
- int num;
- ENetPeer *peer;
- string hostname;
- void *info;
+ int type;
+ int num;
+ ENetPeer *peer;
+ string hostname;
+ void *info;
};
vector<client *> clients;
@@ -105,54 +105,54 @@ bool haslocalclients() { return localclients!=0; }
client &addclient(int type)
{
- client *c = NULL;
- loopv(clients) if(clients[i]->type==ST_EMPTY)
- {
- c = clients[i];
- break;
- }
- if(!c)
- {
- c = new client;
- c->num = clients.length();
- clients.add(c);
- }
- c->info = server::newclientinfo();
- c->type = type;
- switch(type)
- {
- case ST_TCPIP: nonlocalclients++; break;
- case ST_LOCAL: localclients++; break;
- }
- return *c;
+ client *c = NULL;
+ loopv(clients) if(clients[i]->type==ST_EMPTY)
+ {
+ c = clients[i];
+ break;
+ }
+ if(!c)
+ {
+ c = new client;
+ c->num = clients.length();
+ clients.add(c);
+ }
+ c->info = server::newclientinfo();
+ c->type = type;
+ switch(type)
+ {
+ case ST_TCPIP: nonlocalclients++; break;
+ case ST_LOCAL: localclients++; break;
+ }
+ return *c;
}
void delclient(client *c)
{
- if(!c) return;
- switch(c->type)
- {
- case ST_TCPIP: nonlocalclients--; if(c->peer) c->peer->data = NULL; break;
- case ST_LOCAL: localclients--; break;
- case ST_EMPTY: return;
- }
- c->type = ST_EMPTY;
- c->peer = NULL;
- if(c->info)
- {
- server::deleteclientinfo(c->info);
- c->info = NULL;
- }
+ if(!c) return;
+ switch(c->type)
+ {
+ case ST_TCPIP: nonlocalclients--; if(c->peer) c->peer->data = NULL; break;
+ case ST_LOCAL: localclients--; break;
+ case ST_EMPTY: return;
+ }
+ c->type = ST_EMPTY;
+ c->peer = NULL;
+ if(c->info)
+ {
+ server::deleteclientinfo(c->info);
+ c->info = NULL;
+ }
}
void cleanupserver()
{
- if(serverhost) enet_host_destroy(serverhost);
- serverhost = NULL;
+ if(serverhost) enet_host_destroy(serverhost);
+ serverhost = NULL;
- if(pongsock != ENET_SOCKET_NULL) enet_socket_destroy(pongsock);
- if(lansock != ENET_SOCKET_NULL) enet_socket_destroy(lansock);
- pongsock = lansock = ENET_SOCKET_NULL;
+ if(pongsock != ENET_SOCKET_NULL) enet_socket_destroy(pongsock);
+ if(lansock != ENET_SOCKET_NULL) enet_socket_destroy(lansock);
+ pongsock = lansock = ENET_SOCKET_NULL;
}
VARF(maxclients, 0, DEFAULTCLIENTS, MAXCLIENTS, { if(!maxclients) maxclients = DEFAULTCLIENTS; });
@@ -164,181 +164,181 @@ void process(ENetPacket *packet, int sender, int chan);
int getservermtu() { return serverhost ? serverhost->mtu : -1; }
void *getclientinfo(int i) { return !clients.inrange(i) || clients[i]->type==ST_EMPTY ? NULL : clients[i]->info; }
ENetPeer *getclientpeer(int i) { return clients.inrange(i) && clients[i]->type==ST_TCPIP ? clients[i]->peer : NULL; }
-int getnumclients() { return clients.length(); }
-uint getclientip(int n) { return clients.inrange(n) && clients[n]->type==ST_TCPIP ? clients[n]->peer->address.host : 0; }
+int getnumclients() { return clients.length(); }
+uint getclientip(int n) { return clients.inrange(n) && clients[n]->type==ST_TCPIP ? clients[n]->peer->address.host : 0; }
void sendpacket(int n, int chan, ENetPacket *packet, int exclude)
{
- if(n<0)
- {
- server::recordpacket(chan, packet->data, packet->dataLength);
- loopv(clients) if(i!=exclude && server::allowbroadcast(i)) sendpacket(i, chan, packet);
- return;
- }
- switch(clients[n]->type)
- {
- case ST_TCPIP:
- {
- enet_peer_send(clients[n]->peer, chan, packet);
- break;
- }
+ if(n<0)
+ {
+ server::recordpacket(chan, packet->data, packet->dataLength);
+ loopv(clients) if(i!=exclude && server::allowbroadcast(i)) sendpacket(i, chan, packet);
+ return;
+ }
+ switch(clients[n]->type)
+ {
+ case ST_TCPIP:
+ {
+ enet_peer_send(clients[n]->peer, chan, packet);
+ break;
+ }
#ifndef STANDALONE
- case ST_LOCAL:
- localservertoclient(chan, packet);
- break;
+ case ST_LOCAL:
+ localservertoclient(chan, packet);
+ break;
#endif
- }
+ }
}
ENetPacket *sendf(int cn, int chan, const char *format, ...)
{
- int exclude = -1;
- bool reliable = false;
- if(*format=='r') { reliable = true; ++format; }
- packetbuf p(MAXTRANS, reliable ? ENET_PACKET_FLAG_RELIABLE : 0);
- va_list args;
- va_start(args, format);
- while(*format) switch(*format++)
- {
- case 'x':
- exclude = va_arg(args, int);
- break;
-
- case 'v':
- {
- int n = va_arg(args, int);
- int *v = va_arg(args, int *);
- loopi(n) putint(p, v[i]);
- break;
- }
-
- case 'i':
- {
- int n = isdigit(*format) ? *format++-'0' : 1;
- loopi(n) putint(p, va_arg(args, int));
- break;
- }
- case 'f':
- {
- int n = isdigit(*format) ? *format++-'0' : 1;
- loopi(n) putfloat(p, (float)va_arg(args, double));
- break;
- }
- case 's': sendstring(va_arg(args, const char *), p); break;
- case 'm':
- {
- int n = va_arg(args, int);
- p.put(va_arg(args, uchar *), n);
- break;
- }
- }
- va_end(args);
- ENetPacket *packet = p.finalize();
- sendpacket(cn, chan, packet, exclude);
- return packet->referenceCount > 0 ? packet : NULL;
+ int exclude = -1;
+ bool reliable = false;
+ if(*format=='r') { reliable = true; ++format; }
+ packetbuf p(MAXTRANS, reliable ? ENET_PACKET_FLAG_RELIABLE : 0);
+ va_list args;
+ va_start(args, format);
+ while(*format) switch(*format++)
+ {
+ case 'x':
+ exclude = va_arg(args, int);
+ break;
+
+ case 'v':
+ {
+ int n = va_arg(args, int);
+ int *v = va_arg(args, int *);
+ loopi(n) putint(p, v[i]);
+ break;
+ }
+
+ case 'i':
+ {
+ int n = isdigit(*format) ? *format++-'0' : 1;
+ loopi(n) putint(p, va_arg(args, int));
+ break;
+ }
+ case 'f':
+ {
+ int n = isdigit(*format) ? *format++-'0' : 1;
+ loopi(n) putfloat(p, (float)va_arg(args, double));
+ break;
+ }
+ case 's': sendstring(va_arg(args, const char *), p); break;
+ case 'm':
+ {
+ int n = va_arg(args, int);
+ p.put(va_arg(args, uchar *), n);
+ break;
+ }
+ }
+ va_end(args);
+ ENetPacket *packet = p.finalize();
+ sendpacket(cn, chan, packet, exclude);
+ return packet->referenceCount > 0 ? packet : NULL;
}
ENetPacket *sendfile(int cn, int chan, stream *file, const char *format, ...)
{
- if(cn < 0)
- {
+ if(cn < 0)
+ {
#ifdef STANDALONE
- return NULL;
+ return NULL;
#endif
- }
- else if(!clients.inrange(cn)) return NULL;
-
- int len = (int)min(file->size(), stream::offset(INT_MAX));
- if(len <= 0 || len > 16<<20) return NULL;
-
- packetbuf p(MAXTRANS+len, ENET_PACKET_FLAG_RELIABLE);
- va_list args;
- va_start(args, format);
- while(*format) switch(*format++)
- {
- case 'i':
- {
- int n = isdigit(*format) ? *format++-'0' : 1;
- loopi(n) putint(p, va_arg(args, int));
- break;
- }
- case 's': sendstring(va_arg(args, const char *), p); break;
- case 'l': putint(p, len); break;
- }
- va_end(args);
-
- file->seek(0, SEEK_SET);
- file->read(p.subbuf(len).buf, len);
-
- ENetPacket *packet = p.finalize();
- if(cn >= 0) sendpacket(cn, chan, packet, -1);
+ }
+ else if(!clients.inrange(cn)) return NULL;
+
+ int len = (int)min(file->size(), stream::offset(INT_MAX));
+ if(len <= 0 || len > 16<<20) return NULL;
+
+ packetbuf p(MAXTRANS+len, ENET_PACKET_FLAG_RELIABLE);
+ va_list args;
+ va_start(args, format);
+ while(*format) switch(*format++)
+ {
+ case 'i':
+ {
+ int n = isdigit(*format) ? *format++-'0' : 1;
+ loopi(n) putint(p, va_arg(args, int));
+ break;
+ }
+ case 's': sendstring(va_arg(args, const char *), p); break;
+ case 'l': putint(p, len); break;
+ }
+ va_end(args);
+
+ file->seek(0, SEEK_SET);
+ file->read(p.subbuf(len).buf, len);
+
+ ENetPacket *packet = p.finalize();
+ if(cn >= 0) sendpacket(cn, chan, packet, -1);
#ifndef STANDALONE
- else sendclientpacket(packet, chan);
+ else sendclientpacket(packet, chan);
#endif
- return packet->referenceCount > 0 ? packet : NULL;
+ return packet->referenceCount > 0 ? packet : NULL;
}
const char *disconnectreason(int reason)
{
- switch(reason)
- {
- case DISC_EOP: return "end of packet";
- case DISC_LOCAL: return "server is in local mode";
- case DISC_KICK: return "kicked/banned";
- case DISC_MSGERR: return "message error";
- case DISC_IPBAN: return "ip is banned";
- case DISC_PRIVATE: return "server is in private mode";
- case DISC_MAXCLIENTS: return "server FULL";
- case DISC_TIMEOUT: return "connection timed out";
- case DISC_OVERFLOW: return "overflow";
- case DISC_PASSWORD: return "invalid password";
- default: return NULL;
- }
+ switch(reason)
+ {
+ case DISC_EOP: return "end of packet";
+ case DISC_LOCAL: return "server is in local mode";
+ case DISC_KICK: return "kicked/banned";
+ case DISC_MSGERR: return "message error";
+ case DISC_IPBAN: return "ip is banned";
+ case DISC_PRIVATE: return "server is in private mode";
+ case DISC_MAXCLIENTS: return "server FULL";
+ case DISC_TIMEOUT: return "connection timed out";
+ case DISC_OVERFLOW: return "overflow";
+ case DISC_PASSWORD: return "invalid password";
+ default: return NULL;
+ }
}
void disconnect_client(int n, int reason)
{
- if(!clients.inrange(n) || clients[n]->type!=ST_TCPIP) return;
- enet_peer_disconnect(clients[n]->peer, reason);
- server::clientdisconnect(n);
- delclient(clients[n]);
- const char *msg = disconnectreason(reason);
- string s;
- if(msg) formatstring(s, "client (%s) disconnected because: %s", clients[n]->hostname, msg);
- else formatstring(s, "client (%s) disconnected", clients[n]->hostname);
- logoutf("%s", s);
- server::sendservmsg(s);
+ if(!clients.inrange(n) || clients[n]->type!=ST_TCPIP) return;
+ enet_peer_disconnect(clients[n]->peer, reason);
+ server::clientdisconnect(n);
+ delclient(clients[n]);
+ const char *msg = disconnectreason(reason);
+ string s;
+ if(msg) formatstring(s, "client (%s) disconnected because: %s", clients[n]->hostname, msg);
+ else formatstring(s, "client (%s) disconnected", clients[n]->hostname);
+ logoutf("%s", s);
+ server::sendservmsg(s);
}
void kicknonlocalclients(int reason)
{
- loopv(clients) if(clients[i]->type==ST_TCPIP) disconnect_client(i, reason);
+ loopv(clients) if(clients[i]->type==ST_TCPIP) disconnect_client(i, reason);
}
void process(ENetPacket *packet, int sender, int chan) // sender may be -1
{
- packetbuf p(packet);
- server::parsepacket(sender, chan, p);
- if(p.overread()) { disconnect_client(sender, DISC_EOP); return; }
+ packetbuf p(packet);
+ server::parsepacket(sender, chan, p);
+ if(p.overread()) { disconnect_client(sender, DISC_EOP); return; }
}
void localclienttoserver(int chan, ENetPacket *packet)
{
- client *c = NULL;
- loopv(clients) if(clients[i]->type==ST_LOCAL) { c = clients[i]; break; }
- if(c) process(packet, c->num, chan);
+ client *c = NULL;
+ loopv(clients) if(clients[i]->type==ST_LOCAL) { c = clients[i]; break; }
+ if(c) process(packet, c->num, chan);
}
#ifdef STANDALONE
bool resolverwait(const char *name, ENetAddress *address)
{
- return enet_address_set_host(address, name) >= 0;
+ return enet_address_set_host(address, name) >= 0;
}
int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &remoteaddress)
{
- return enet_socket_connect(sock, &remoteaddress);
+ return enet_socket_connect(sock, &remoteaddress);
}
#endif
@@ -351,21 +351,21 @@ VARN(updatemaster, allowupdatemaster, 0, 1, 1);
void disconnectmaster()
{
- if(mastersock != ENET_SOCKET_NULL)
- {
- server::masterdisconnected();
- enet_socket_destroy(mastersock);
- mastersock = ENET_SOCKET_NULL;
- }
+ if(mastersock != ENET_SOCKET_NULL)
+ {
+ server::masterdisconnected();
+ enet_socket_destroy(mastersock);
+ mastersock = ENET_SOCKET_NULL;
+ }
- masterout.setsize(0);
- masterin.setsize(0);
- masteroutpos = masterinpos = 0;
+ masterout.setsize(0);
+ masterin.setsize(0);
+ masteroutpos = masterinpos = 0;
- masteraddress.host = ENET_HOST_ANY;
- masteraddress.port = ENET_PORT_ANY;
+ masteraddress.host = ENET_HOST_ANY;
+ masteraddress.port = ENET_PORT_ANY;
- lastupdatemaster = masterconnecting = masterconnected = 0;
+ lastupdatemaster = masterconnecting = masterconnected = 0;
}
SVARF(mastername, server::defaultmaster(), disconnectmaster());
@@ -373,199 +373,199 @@ VARF(masterport, 1, server::masterport(), 0xFFFF, disconnectmaster());
ENetSocket connectmaster(bool wait)
{
- if(!mastername[0]) return ENET_SOCKET_NULL;
- if(masteraddress.host == ENET_HOST_ANY)
- {
- if(isdedicatedserver()) logoutf("looking up %s...", mastername);
- masteraddress.port = masterport;
- if(!resolverwait(mastername, &masteraddress)) return ENET_SOCKET_NULL;
- }
- ENetSocket sock = enet_socket_create(ENET_SOCKET_TYPE_STREAM);
- if(sock == ENET_SOCKET_NULL)
- {
- if(isdedicatedserver()) logoutf("could not open master server socket");
- return ENET_SOCKET_NULL;
- }
- if(wait || serveraddress.host == ENET_HOST_ANY || !enet_socket_bind(sock, &serveraddress))
- {
- enet_socket_set_option(sock, ENET_SOCKOPT_NONBLOCK, 1);
- if(wait)
- {
- if(!connectwithtimeout(sock, mastername, masteraddress)) return sock;
- }
- else if(!enet_socket_connect(sock, &masteraddress)) return sock;
- }
- enet_socket_destroy(sock);
- if(isdedicatedserver()) logoutf("could not connect to master server");
- return ENET_SOCKET_NULL;
+ if(!mastername[0]) return ENET_SOCKET_NULL;
+ if(masteraddress.host == ENET_HOST_ANY)
+ {
+ if(isdedicatedserver()) logoutf("looking up %s...", mastername);
+ masteraddress.port = masterport;
+ if(!resolverwait(mastername, &masteraddress)) return ENET_SOCKET_NULL;
+ }
+ ENetSocket sock = enet_socket_create(ENET_SOCKET_TYPE_STREAM);
+ if(sock == ENET_SOCKET_NULL)
+ {
+ if(isdedicatedserver()) logoutf("could not open master server socket");
+ return ENET_SOCKET_NULL;
+ }
+ if(wait || serveraddress.host == ENET_HOST_ANY || !enet_socket_bind(sock, &serveraddress))
+ {
+ enet_socket_set_option(sock, ENET_SOCKOPT_NONBLOCK, 1);
+ if(wait)
+ {
+ if(!connectwithtimeout(sock, mastername, masteraddress)) return sock;
+ }
+ else if(!enet_socket_connect(sock, &masteraddress)) return sock;
+ }
+ enet_socket_destroy(sock);
+ if(isdedicatedserver()) logoutf("could not connect to master server");
+ return ENET_SOCKET_NULL;
}
bool requestmaster(const char *req)
{
- if(mastersock == ENET_SOCKET_NULL)
- {
- mastersock = connectmaster(false);
- if(mastersock == ENET_SOCKET_NULL) return false;
- lastconnectmaster = masterconnecting = totalmillis ? totalmillis : 1;
- }
+ if(mastersock == ENET_SOCKET_NULL)
+ {
+ mastersock = connectmaster(false);
+ if(mastersock == ENET_SOCKET_NULL) return false;
+ lastconnectmaster = masterconnecting = totalmillis ? totalmillis : 1;
+ }
- if(masterout.length() >= 4096) return false;
+ if(masterout.length() >= 4096) return false;
- masterout.put(req, strlen(req));
- return true;
+ masterout.put(req, strlen(req));
+ return true;
}
bool requestmasterf(const char *fmt, ...)
{
- defvformatstring(req, fmt, fmt);
- return requestmaster(req);
+ defvformatstring(req, fmt, fmt);
+ return requestmaster(req);
}
void processmasterinput()
{
- if(masterinpos >= masterin.length()) return;
+ if(masterinpos >= masterin.length()) return;
- char *input = &masterin[masterinpos], *end = (char *)memchr(input, '\n', masterin.length() - masterinpos);
- while(end)
- {
- *end = '\0';
+ char *input = &masterin[masterinpos], *end = (char *)memchr(input, '\n', masterin.length() - masterinpos);
+ while(end)
+ {
+ *end = '\0';
- const char *args = input;
- while(args < end && !iscubespace(*args)) args++;
- int cmdlen = args - input;
- while(args < end && iscubespace(*args)) args++;
+ const char *args = input;
+ while(args < end && !iscubespace(*args)) args++;
+ int cmdlen = args - input;
+ while(args < end && iscubespace(*args)) args++;
- if(matchstring(input, cmdlen, "failreg"))
- conoutf(CON_ERROR, "master server registration failed: %s", args);
- else if(matchstring(input, cmdlen, "succreg"))
- conoutf("master server registration succeeded");
- else server::processmasterinput(input, cmdlen, args);
+ if(matchstring(input, cmdlen, "failreg"))
+ conoutf(CON_ERROR, "master server registration failed: %s", args);
+ else if(matchstring(input, cmdlen, "succreg"))
+ conoutf("master server registration succeeded");
+ else server::processmasterinput(input, cmdlen, args);
- end++;
- masterinpos = end - masterin.getbuf();
- input = end;
- end = (char *)memchr(input, '\n', masterin.length() - masterinpos);
- }
+ end++;
+ masterinpos = end - masterin.getbuf();
+ input = end;
+ end = (char *)memchr(input, '\n', masterin.length() - masterinpos);
+ }
- if(masterinpos >= masterin.length())
- {
- masterin.setsize(0);
- masterinpos = 0;
- }
+ if(masterinpos >= masterin.length())
+ {
+ masterin.setsize(0);
+ masterinpos = 0;
+ }
}
void flushmasteroutput()
{
- if(masterconnecting && totalmillis - masterconnecting >= 60000)
- {
- logoutf("could not connect to master server");
- disconnectmaster();
- }
- if(masterout.empty() || !masterconnected) return;
-
- ENetBuffer buf;
- buf.data = &masterout[masteroutpos];
- buf.dataLength = masterout.length() - masteroutpos;
- int sent = enet_socket_send(mastersock, NULL, &buf, 1);
- if(sent >= 0)
- {
- masteroutpos += sent;
- if(masteroutpos >= masterout.length())
- {
- masterout.setsize(0);
- masteroutpos = 0;
- }
- }
- else disconnectmaster();
+ if(masterconnecting && totalmillis - masterconnecting >= 60000)
+ {
+ logoutf("could not connect to master server");
+ disconnectmaster();
+ }
+ if(masterout.empty() || !masterconnected) return;
+
+ ENetBuffer buf;
+ buf.data = &masterout[masteroutpos];
+ buf.dataLength = masterout.length() - masteroutpos;
+ int sent = enet_socket_send(mastersock, NULL, &buf, 1);
+ if(sent >= 0)
+ {
+ masteroutpos += sent;
+ if(masteroutpos >= masterout.length())
+ {
+ masterout.setsize(0);
+ masteroutpos = 0;
+ }
+ }
+ else disconnectmaster();
}
void flushmasterinput()
{
- if(masterin.length() >= masterin.capacity())
- masterin.reserve(4096);
+ if(masterin.length() >= masterin.capacity())
+ masterin.reserve(4096);
- ENetBuffer buf;
- buf.data = masterin.getbuf() + masterin.length();
- buf.dataLength = masterin.capacity() - masterin.length();
- int recv = enet_socket_receive(mastersock, NULL, &buf, 1);
- if(recv > 0)
- {
- masterin.advance(recv);
- processmasterinput();
- }
- else disconnectmaster();
+ ENetBuffer buf;
+ buf.data = masterin.getbuf() + masterin.length();
+ buf.dataLength = masterin.capacity() - masterin.length();
+ int recv = enet_socket_receive(mastersock, NULL, &buf, 1);
+ if(recv > 0)
+ {
+ masterin.advance(recv);
+ processmasterinput();
+ }
+ else disconnectmaster();
}
static ENetAddress pongaddr;
void sendserverinforeply(ucharbuf &p)
{
- ENetBuffer buf;
- buf.data = p.buf;
- buf.dataLength = p.length();
- enet_socket_send(pongsock, &pongaddr, &buf, 1);
+ ENetBuffer buf;
+ buf.data = p.buf;
+ buf.dataLength = p.length();
+ enet_socket_send(pongsock, &pongaddr, &buf, 1);
}
#define MAXPINGDATA 32
-void checkserversockets() // reply all server info requests
-{
- static ENetSocketSet readset, writeset;
- ENET_SOCKETSET_EMPTY(readset);
- ENET_SOCKETSET_EMPTY(writeset);
- ENetSocket maxsock = pongsock;
- ENET_SOCKETSET_ADD(readset, pongsock);
- if(mastersock != ENET_SOCKET_NULL)
- {
- maxsock = max(maxsock, mastersock);
- ENET_SOCKETSET_ADD(readset, mastersock);
- if(!masterconnected) ENET_SOCKETSET_ADD(writeset, mastersock);
- }
- if(lansock != ENET_SOCKET_NULL)
- {
- maxsock = max(maxsock, lansock);
- ENET_SOCKETSET_ADD(readset, lansock);
- }
- if(enet_socketset_select(maxsock, &readset, &writeset, 0) <= 0) return;
-
- ENetBuffer buf;
- uchar pong[MAXTRANS];
- loopi(2)
- {
- ENetSocket sock = i ? lansock : pongsock;
- if(sock == ENET_SOCKET_NULL || !ENET_SOCKETSET_CHECK(readset, sock)) continue;
-
- buf.data = pong;
- buf.dataLength = sizeof(pong);
- int len = enet_socket_receive(sock, &pongaddr, &buf, 1);
- if(len < 0 || len > MAXPINGDATA) continue;
- ucharbuf req(pong, len), p(pong, sizeof(pong));
- p.len += len;
- server::serverinforeply(req, p);
- }
-
- if(mastersock != ENET_SOCKET_NULL)
- {
- if(!masterconnected)
- {
- if(ENET_SOCKETSET_CHECK(readset, mastersock) || ENET_SOCKETSET_CHECK(writeset, mastersock))
- {
- int error = 0;
- if(enet_socket_get_option(mastersock, ENET_SOCKOPT_ERROR, &error) < 0 || error)
- {
- logoutf("could not connect to master server");
- disconnectmaster();
- }
- else
- {
- masterconnecting = 0;
- masterconnected = totalmillis ? totalmillis : 1;
- server::masterconnected();
- }
- }
- }
- if(mastersock != ENET_SOCKET_NULL && ENET_SOCKETSET_CHECK(readset, mastersock)) flushmasterinput();
- }
+void checkserversockets() // reply all server info requests
+{
+ static ENetSocketSet readset, writeset;
+ ENET_SOCKETSET_EMPTY(readset);
+ ENET_SOCKETSET_EMPTY(writeset);
+ ENetSocket maxsock = pongsock;
+ ENET_SOCKETSET_ADD(readset, pongsock);
+ if(mastersock != ENET_SOCKET_NULL)
+ {
+ maxsock = max(maxsock, mastersock);
+ ENET_SOCKETSET_ADD(readset, mastersock);
+ if(!masterconnected) ENET_SOCKETSET_ADD(writeset, mastersock);
+ }
+ if(lansock != ENET_SOCKET_NULL)
+ {
+ maxsock = max(maxsock, lansock);
+ ENET_SOCKETSET_ADD(readset, lansock);
+ }
+ if(enet_socketset_select(maxsock, &readset, &writeset, 0) <= 0) return;
+
+ ENetBuffer buf;
+ uchar pong[MAXTRANS];
+ loopi(2)
+ {
+ ENetSocket sock = i ? lansock : pongsock;
+ if(sock == ENET_SOCKET_NULL || !ENET_SOCKETSET_CHECK(readset, sock)) continue;
+
+ buf.data = pong;
+ buf.dataLength = sizeof(pong);
+ int len = enet_socket_receive(sock, &pongaddr, &buf, 1);
+ if(len < 0 || len > MAXPINGDATA) continue;
+ ucharbuf req(pong, len), p(pong, sizeof(pong));
+ p.len += len;
+ server::serverinforeply(req, p);
+ }
+
+ if(mastersock != ENET_SOCKET_NULL)
+ {
+ if(!masterconnected)
+ {
+ if(ENET_SOCKETSET_CHECK(readset, mastersock) || ENET_SOCKETSET_CHECK(writeset, mastersock))
+ {
+ int error = 0;
+ if(enet_socket_get_option(mastersock, ENET_SOCKOPT_ERROR, &error) < 0 || error)
+ {
+ logoutf("could not connect to master server");
+ disconnectmaster();
+ }
+ else
+ {
+ masterconnecting = 0;
+ masterconnected = totalmillis ? totalmillis : 1;
+ server::masterconnected();
+ }
+ }
+ }
+ if(mastersock != ENET_SOCKET_NULL && ENET_SOCKETSET_CHECK(readset, mastersock)) flushmasterinput();
+ }
}
VAR(serveruprate, 0, 0, INT_MAX);
@@ -578,143 +578,143 @@ int curtime = 0, lastmillis = 0, elapsedtime = 0, totalmillis = 0;
void updatemasterserver()
{
- if(!masterconnected && lastconnectmaster && totalmillis-lastconnectmaster <= 5*60*1000) return;
- if(mastername[0] && allowupdatemaster) requestmasterf("regserv %d\n", serverport);
- lastupdatemaster = totalmillis ? totalmillis : 1;
+ if(!masterconnected && lastconnectmaster && totalmillis-lastconnectmaster <= 5*60*1000) return;
+ if(mastername[0] && allowupdatemaster) requestmasterf("regserv %d\n", serverport);
+ lastupdatemaster = totalmillis ? totalmillis : 1;
}
uint totalsecs = 0;
void updatetime()
{
- static int lastsec = 0;
- if(totalmillis - lastsec >= 1000)
- {
- int cursecs = (totalmillis - lastsec) / 1000;
- totalsecs += cursecs;
- lastsec += cursecs * 1000;
- }
+ static int lastsec = 0;
+ if(totalmillis - lastsec >= 1000)
+ {
+ int cursecs = (totalmillis - lastsec) / 1000;
+ totalsecs += cursecs;
+ lastsec += cursecs * 1000;
+ }
}
void serverslice(bool dedicated, uint timeout) // main server update, called from main loop in sp, or from below in dedicated server
{
- if(!serverhost)
- {
- server::serverupdate();
- server::sendpackets();
- return;
- }
-
- // below is network only
-
- if(dedicated)
- {
- int millis = (int)enet_time_get();
- elapsedtime = millis - totalmillis;
- static int timeerr = 0;
- int scaledtime = server::scaletime(elapsedtime) + timeerr;
- curtime = scaledtime/100;
- timeerr = scaledtime%100;
- if(server::ispaused()) curtime = 0;
- lastmillis += curtime;
- totalmillis = millis;
- updatetime();
- }
- server::serverupdate();
-
- flushmasteroutput();
- checkserversockets();
-
- if(!lastupdatemaster || totalmillis-lastupdatemaster>60*60*1000) // send alive signal to masterserver every hour of uptime
- updatemasterserver();
-
- if(totalmillis-laststatus>60*1000) // display bandwidth stats, useful for server ops
- {
- laststatus = totalmillis;
- if(nonlocalclients || serverhost->totalSentData || serverhost->totalReceivedData) logoutf("status: %d remote clients, %.1f send, %.1f rec (K/sec)", nonlocalclients, serverhost->totalSentData/60.0f/1024, serverhost->totalReceivedData/60.0f/1024);
- serverhost->totalSentData = serverhost->totalReceivedData = 0;
- }
-
- ENetEvent event;
- bool serviced = false;
- while(!serviced)
- {
- if(enet_host_check_events(serverhost, &event) <= 0)
- {
- if(enet_host_service(serverhost, &event, timeout) <= 0) break;
- serviced = true;
- }
- switch(event.type)
- {
- case ENET_EVENT_TYPE_CONNECT:
- {
- client &c = addclient(ST_TCPIP);
- c.peer = event.peer;
- c.peer->data = &c;
- string hn;
- copystring(c.hostname, (enet_address_get_host_ip(&c.peer->address, hn, sizeof(hn))==0) ? hn : "unknown");
- logoutf("client connected (%s)", c.hostname);
- int reason = server::clientconnect(c.num);
- if(reason) disconnect_client(c.num, reason);
- break;
- }
- case ENET_EVENT_TYPE_RECEIVE:
- {
- client *c = (client *)event.peer->data;
- if(c) process(event.packet, c->num, event.channelID);
- if(event.packet->referenceCount==0) enet_packet_destroy(event.packet);
- break;
- }
- case ENET_EVENT_TYPE_DISCONNECT:
- {
- client *c = (client *)event.peer->data;
- if(!c) break;
- logoutf("disconnected client (%s)", c->hostname);
- server::clientdisconnect(c->num);
- delclient(c);
- break;
- }
- default:
- break;
- }
- }
- if(server::sendpackets()) enet_host_flush(serverhost);
+ if(!serverhost)
+ {
+ server::serverupdate();
+ server::sendpackets();
+ return;
+ }
+
+ // below is network only
+
+ if(dedicated)
+ {
+ int millis = (int)enet_time_get();
+ elapsedtime = millis - totalmillis;
+ static int timeerr = 0;
+ int scaledtime = server::scaletime(elapsedtime) + timeerr;
+ curtime = scaledtime/100;
+ timeerr = scaledtime%100;
+ if(server::ispaused()) curtime = 0;
+ lastmillis += curtime;
+ totalmillis = millis;
+ updatetime();
+ }
+ server::serverupdate();
+
+ flushmasteroutput();
+ checkserversockets();
+
+ if(!lastupdatemaster || totalmillis-lastupdatemaster>60*60*1000) // send alive signal to masterserver every hour of uptime
+ updatemasterserver();
+
+ if(totalmillis-laststatus>60*1000) // display bandwidth stats, useful for server ops
+ {
+ laststatus = totalmillis;
+ if(nonlocalclients || serverhost->totalSentData || serverhost->totalReceivedData) logoutf("status: %d remote clients, %.1f send, %.1f rec (K/sec)", nonlocalclients, serverhost->totalSentData/60.0f/1024, serverhost->totalReceivedData/60.0f/1024);
+ serverhost->totalSentData = serverhost->totalReceivedData = 0;
+ }
+
+ ENetEvent event;
+ bool serviced = false;
+ while(!serviced)
+ {
+ if(enet_host_check_events(serverhost, &event) <= 0)
+ {
+ if(enet_host_service(serverhost, &event, timeout) <= 0) break;
+ serviced = true;
+ }
+ switch(event.type)
+ {
+ case ENET_EVENT_TYPE_CONNECT:
+ {
+ client &c = addclient(ST_TCPIP);
+ c.peer = event.peer;
+ c.peer->data = &c;
+ string hn;
+ copystring(c.hostname, (enet_address_get_host_ip(&c.peer->address, hn, sizeof(hn))==0) ? hn : "unknown");
+ logoutf("client connected (%s)", c.hostname);
+ int reason = server::clientconnect(c.num);
+ if(reason) disconnect_client(c.num, reason);
+ break;
+ }
+ case ENET_EVENT_TYPE_RECEIVE:
+ {
+ client *c = (client *)event.peer->data;
+ if(c) process(event.packet, c->num, event.channelID);
+ if(event.packet->referenceCount==0) enet_packet_destroy(event.packet);
+ break;
+ }
+ case ENET_EVENT_TYPE_DISCONNECT:
+ {
+ client *c = (client *)event.peer->data;
+ if(!c) break;
+ logoutf("disconnected client (%s)", c->hostname);
+ server::clientdisconnect(c->num);
+ delclient(c);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if(server::sendpackets()) enet_host_flush(serverhost);
}
void flushserver(bool force)
{
- if(server::sendpackets(force) && serverhost) enet_host_flush(serverhost);
+ if(server::sendpackets(force) && serverhost) enet_host_flush(serverhost);
}
#ifndef STANDALONE
void localdisconnect(bool cleanup)
{
- bool disconnected = false;
- loopv(clients) if(clients[i]->type==ST_LOCAL)
- {
- server::localdisconnect(i);
- delclient(clients[i]);
- disconnected = true;
- }
- if(!disconnected) return;
- game::gamedisconnect(cleanup);
- mainmenu = 1;
+ bool disconnected = false;
+ loopv(clients) if(clients[i]->type==ST_LOCAL)
+ {
+ server::localdisconnect(i);
+ delclient(clients[i]);
+ disconnected = true;
+ }
+ if(!disconnected) return;
+ game::gamedisconnect(cleanup);
+ mainmenu = 1;
}
void localconnect()
{
- if(initing) return;
- client &c = addclient(ST_LOCAL);
- copystring(c.hostname, "local");
- game::gameconnect(false);
- server::localconnect(c.num);
+ if(initing) return;
+ client &c = addclient(ST_LOCAL);
+ copystring(c.hostname, "local");
+ game::gameconnect(false);
+ server::localconnect(c.num);
}
#endif
void logoutfv(const char *fmt, va_list args)
{
- FILE *f = getlogfile();
- if(f) writelogv(f, fmt, args);
+ FILE *f = getlogfile();
+ if(f) writelogv(f, fmt, args);
}
static bool dedicatedserver = false;
@@ -723,121 +723,121 @@ bool isdedicatedserver() { return dedicatedserver; }
void rundedicatedserver()
{
- dedicatedserver = true;
- logoutf("dedicated server started, waiting for clients...");
- for(;;) serverslice(true, 5);
- dedicatedserver = false;
+ dedicatedserver = true;
+ logoutf("dedicated server started, waiting for clients...");
+ for(;;) serverslice(true, 5);
+ dedicatedserver = false;
}
bool servererror(bool dedicated, const char *desc)
{
#ifndef STANDALONE
- if(!dedicated)
- {
- conoutf(CON_ERROR, "%s", desc);
- cleanupserver();
- }
- else
+ if(!dedicated)
+ {
+ conoutf(CON_ERROR, "%s", desc);
+ cleanupserver();
+ }
+ else
#endif
- fatal("%s", desc);
- return false;
+ fatal("%s", desc);
+ return false;
}
bool setuplistenserver(bool dedicated)
{
- ENetAddress address = { ENET_HOST_ANY, enet_uint16(serverport <= 0 ? server::serverport() : serverport) };
- if(*serverip)
- {
- if(enet_address_set_host(&address, serverip)<0) conoutf(CON_WARN, "WARNING: server ip not resolved");
- else serveraddress.host = address.host;
- }
- serverhost = enet_host_create(&address, min(maxclients + server::reserveclients(), MAXCLIENTS), server::numchannels(), 0, serveruprate);
- if(!serverhost) return servererror(dedicated, "could not create server host");
- serverhost->duplicatePeers = maxdupclients ? maxdupclients : MAXCLIENTS;
- address.port = server::serverinfoport(serverport > 0 ? serverport : -1);
- pongsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
- if(pongsock != ENET_SOCKET_NULL && enet_socket_bind(pongsock, &address) < 0)
- {
- enet_socket_destroy(pongsock);
- pongsock = ENET_SOCKET_NULL;
- }
- if(pongsock == ENET_SOCKET_NULL) return servererror(dedicated, "could not create server info socket");
- else enet_socket_set_option(pongsock, ENET_SOCKOPT_NONBLOCK, 1);
- address.port = server::laninfoport();
- lansock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
- if(lansock != ENET_SOCKET_NULL && (enet_socket_set_option(lansock, ENET_SOCKOPT_REUSEADDR, 1) < 0 || enet_socket_bind(lansock, &address) < 0))
- {
- enet_socket_destroy(lansock);
- lansock = ENET_SOCKET_NULL;
- }
- if(lansock == ENET_SOCKET_NULL) conoutf(CON_WARN, "WARNING: could not create LAN server info socket");
- else enet_socket_set_option(lansock, ENET_SOCKOPT_NONBLOCK, 1);
- return true;
+ ENetAddress address = { ENET_HOST_ANY, enet_uint16(serverport <= 0 ? server::serverport() : serverport) };
+ if(*serverip)
+ {
+ if(enet_address_set_host(&address, serverip)<0) conoutf(CON_WARN, "WARNING: server ip not resolved");
+ else serveraddress.host = address.host;
+ }
+ serverhost = enet_host_create(&address, min(maxclients + server::reserveclients(), MAXCLIENTS), server::numchannels(), 0, serveruprate);
+ if(!serverhost) return servererror(dedicated, "could not create server host");
+ serverhost->duplicatePeers = maxdupclients ? maxdupclients : MAXCLIENTS;
+ address.port = server::serverinfoport(serverport > 0 ? serverport : -1);
+ pongsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
+ if(pongsock != ENET_SOCKET_NULL && enet_socket_bind(pongsock, &address) < 0)
+ {
+ enet_socket_destroy(pongsock);
+ pongsock = ENET_SOCKET_NULL;
+ }
+ if(pongsock == ENET_SOCKET_NULL) return servererror(dedicated, "could not create server info socket");
+ else enet_socket_set_option(pongsock, ENET_SOCKOPT_NONBLOCK, 1);
+ address.port = server::laninfoport();
+ lansock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
+ if(lansock != ENET_SOCKET_NULL && (enet_socket_set_option(lansock, ENET_SOCKOPT_REUSEADDR, 1) < 0 || enet_socket_bind(lansock, &address) < 0))
+ {
+ enet_socket_destroy(lansock);
+ lansock = ENET_SOCKET_NULL;
+ }
+ if(lansock == ENET_SOCKET_NULL) conoutf(CON_WARN, "WARNING: could not create LAN server info socket");
+ else enet_socket_set_option(lansock, ENET_SOCKOPT_NONBLOCK, 1);
+ return true;
}
void initserver(bool listen, bool dedicated)
{
- execfile("server-init.cfg", false);
+ execfile("server-init.cfg", false);
- if(listen) setuplistenserver(dedicated);
+ if(listen) setuplistenserver(dedicated);
- server::serverinit();
+ server::serverinit();
- if(listen)
- {
- dedicatedserver = dedicated;
- updatemasterserver();
- if(dedicated) rundedicatedserver(); // never returns
+ if(listen)
+ {
+ dedicatedserver = dedicated;
+ updatemasterserver();
+ if(dedicated) rundedicatedserver(); // never returns
#ifndef STANDALONE
- else conoutf("listen server started");
+ else conoutf("listen server started");
#endif
- }
+ }
}
#ifndef STANDALONE
void startlistenserver(int *usemaster)
{
- if(serverhost) { conoutf(CON_ERROR, "listen server is already running"); return; }
+ if(serverhost) { conoutf(CON_ERROR, "listen server is already running"); return; }
- allowupdatemaster = *usemaster>0 ? 1 : 0;
+ allowupdatemaster = *usemaster>0 ? 1 : 0;
- if(!setuplistenserver(false)) return;
+ if(!setuplistenserver(false)) return;
- updatemasterserver();
+ updatemasterserver();
- conoutf("listen server started for %d clients%s", maxclients, allowupdatemaster ? " and listed with master server" : "");
+ conoutf("listen server started for %d clients%s", maxclients, allowupdatemaster ? " and listed with master server" : "");
}
COMMAND(startlistenserver, "i");
void stoplistenserver()
{
- if(!serverhost) { conoutf(CON_ERROR, "listen server is not running"); return; }
+ if(!serverhost) { conoutf(CON_ERROR, "listen server is not running"); return; }
- kicknonlocalclients();
- enet_host_flush(serverhost);
- cleanupserver();
+ kicknonlocalclients();
+ enet_host_flush(serverhost);
+ cleanupserver();
- conoutf("listen server stopped");
+ conoutf("listen server stopped");
}
COMMAND(stoplistenserver, "");
#endif
bool serveroption(char *opt)
{
- switch(opt[1])
- {
- case 'u': setvar("serveruprate", atoi(opt+2)); return true;
- case 'c': setvar("maxclients", atoi(opt+2)); return true;
- case 'i': setsvar("serverip", opt+2); return true;
- case 'j': setvar("serverport", atoi(opt+2)); return true;
- case 'm': setsvar("mastername", opt+2); setvar("updatemaster", mastername[0] ? 1 : 0); return true;
+ switch(opt[1])
+ {
+ case 'u': setvar("serveruprate", atoi(opt+2)); return true;
+ case 'c': setvar("maxclients", atoi(opt+2)); return true;
+ case 'i': setsvar("serverip", opt+2); return true;
+ case 'j': setvar("serverport", atoi(opt+2)); return true;
+ case 'm': setsvar("mastername", opt+2); setvar("updatemaster", mastername[0] ? 1 : 0); return true;
#ifdef STANDALONE
- case 'q': logoutf("Using home directory: %s", opt); sethomedir(opt+2); return true;
- case 'k': logoutf("Adding package directory: %s", opt); addpackagedir(opt+2); return true;
- case 'g': logoutf("Setting log file: %s", opt); setlogfile(opt+2); return true;
+ case 'q': logoutf("Using home directory: %s", opt); sethomedir(opt+2); return true;
+ case 'k': logoutf("Adding package directory: %s", opt); addpackagedir(opt+2); return true;
+ case 'g': logoutf("Setting log file: %s", opt); setlogfile(opt+2); return true;
#endif
- default: return false;
- }
+ default: return false;
+ }
}
vector<const char *> gameargs;
@@ -845,13 +845,13 @@ vector<const char *> gameargs;
#ifdef STANDALONE
int main(int argc, char **argv)
{
- setlogfile(NULL);
- if(enet_initialize()<0) fatal("Unable to initialise network module");
- atexit(enet_deinitialize);
- enet_time_set(0);
- for(int i = 1; i<argc; i++) if(argv[i][0]!='-' || !serveroption(argv[i])) gameargs.add(argv[i]);
- game::parseoptions(gameargs);
- initserver(true, true);
- return EXIT_SUCCESS;
+ setlogfile(NULL);
+ if(enet_initialize()<0) fatal("Unable to initialise network module");
+ atexit(enet_deinitialize);
+ enet_time_set(0);
+ for(int i = 1; i<argc; i++) if(argv[i][0]!='-' || !serveroption(argv[i])) gameargs.add(argv[i]);
+ game::parseoptions(gameargs);
+ initserver(true, true);
+ return EXIT_SUCCESS;
}
#endif