diff options
Diffstat (limited to 'src/engine/server.cpp')
| -rw-r--r-- | src/engine/server.cpp | 1128 |
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 |
