diff --git a/config/servercmdline.txt b/config/servercmdline.txt index 436bb4a4..26f5bbab 100644 --- a/config/servercmdline.txt +++ b/config/servercmdline.txt @@ -22,6 +22,8 @@ // -f // port, 1..65534, default 28763 // -c // max client number, 1..16, default 6 // -D // number of demos to keep in RAM, default 5 +// -Y // 32-byte private server key (you should maybe include that from another config file and remove it from the server after startup) +// -m // masterserver URL (no parameter uses default URL), if not set, the server will be LAN-only // the switches o, n, n1 and n2 support coloring and character escaping; 'o' also supports escaped newlines // the available colors are: 0: green, 1: blue, 2: yellow, 3: red, 4: gray, 5: white, 6: dark brown, 7: dark red @@ -95,5 +97,4 @@ // -u // uprate // -i // ip, only for machines with multiple network interfaces -// -m // masterserver URL (exception: use "-m localhost", if you don't want AC to register at a masterserver at all) diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 010172ae..3b30f97d 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -45,15 +45,12 @@ void setskin(playerent *pl, int skin, int team) pl->setskin(team, skin); } -extern char *global_name; - bool duplicatename(playerent *d, char *name = NULL) { if(!name) name = d->name; if(d!=player1 && !strcmp(name, player1->name) && !watchingdemo) return true; if(!strcmp(name, "you")) return true; loopv(players) if(players[i] && d!=players[i] && !strcmp(name, players[i]->name)) return true; - global_name = player1->name; // this certainly is not the best place to put this return false; } diff --git a/source/src/main.cpp b/source/src/main.cpp index 6331e59d..46526c25 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -1012,6 +1012,7 @@ int main(int argc, char **argv) char *initscript = NULL; char *initdemo = NULL; + setlocale(LC_ALL, "POSIX"); if(bootclientlog) cvecprintf(*bootclientlog, "######## start logging: %s\n", timestring(true)); const char *initmap = rndmapname(); @@ -1134,8 +1135,8 @@ int main(int argc, char **argv) if(enet_initialize()<0) fatal("Unable to initialise network module"); if (!dedicated) initclient(); - //FIXME the server executed in this way does not catch the SIGTERM or ^C - initserver(dedicated,argc,argv); // never returns if dedicated + + initserver(dedicated); // never returns if dedicated initlog("world (" STRINGIFY(AC_VERSION) ")"); empty_world(7, true); @@ -1158,10 +1159,6 @@ int main(int argc, char **argv) int usedcolorbits = 0, useddepthbits = 0, usedfsaa = 0; setupscreen(usedcolorbits, useddepthbits, usedfsaa); - // no more TTF ATM. - //initlog("font"); - //initfont(); - initlog("video: misc"); SDL_WM_SetCaption("AssaultCube", NULL); diff --git a/source/src/platform.h b/source/src/platform.h index 78817729..44c43e64 100644 --- a/source/src/platform.h +++ b/source/src/platform.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #ifdef __GNUC__ #include diff --git a/source/src/protos.h b/source/src/protos.h index 85b318b9..bae58dfc 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -958,6 +958,9 @@ extern void tigerhash(uchar *hash, const uchar *msg, int len); extern void *tigerhash_init(uchar *hash); extern void tigerhash_add(uchar *hash, const void *msg, int len, void *state); extern void tigerhash_finish(uchar *hash, void *state); +extern const char *bin2hex(char *d, const uchar *s, int len); +extern int hex2bin(uchar *d, const char *s, int maxlen); +extern void ed25519_pubkey_from_private(uchar *pubkey, const uchar *privkey); extern void loadcertdir(); // load all certs in "config/certs" #if 0 // crypto // for AUTH @@ -1027,7 +1030,7 @@ extern const char *modestr(int n, bool acronyms = false); extern const char *voteerrorstr(int n); extern const char *mmfullname(int n); extern void fatal(const char *s, ...) PRINTFARGS(1, 2); -extern void initserver(bool dedicated, int argc = 0, char **argv = NULL); +extern void initserver(bool dedicated); extern void cleanupserver(); extern void localconnect(); extern void localdisconnect(); @@ -1067,7 +1070,7 @@ extern int masterport; extern ENetSocket connectmaster(); extern void serverms(int mode, int numplayers, int minremain, char *smapname, int millis, const ENetAddress &localaddr, int *mnum, int *msend, int *mrec, int *cnum, int *csend, int *crec, int protocol_version, const char *servdesccur, int _interm); extern const char *genpwdhash(const char *name, const char *pwd, int salt); -extern void servermsinit(const char *master, const char *ip, int serverport, bool listen); +extern void servermsinit(bool listen); extern bool serverpickup(int i, int sender); extern bool valid_client(int cn); extern void extinfo_cnbuf(ucharbuf &p, int cn); @@ -1127,7 +1130,8 @@ struct serverconfigfile struct servercommandline { int uprate, serverport, syslogfacility, filethres, syslogthres, maxdemos, maxclients, kickthreshold, banthreshold, verbose, incoming_limit, afk_limit, ban_time, demotimelocal; - const char *ip, *master, *logident, *serverpassword, *adminpasswd, *demopath, *maprot, *pwdfile, *blfile, *nbfile, *infopath, *motdpath, *forbidden, *demofilenameformat, *demotimestampformat; + const char *ip, *master, *logident, *serverpassword, *adminpasswd, *demopath, *maprot, *pwdfile, *blfile, *nbfile, *infopath, *motdpath, *forbidden, *demofilenameformat, *demotimestampformat, *service; + uchar *ssk; bool logtimestamp, demo_interm, loggamestatus; string motd, servdesc_full, servdesc_pre, servdesc_suf, voteperm, mapperm; int clfilenesting; @@ -1137,7 +1141,8 @@ struct servercommandline maxclients(DEFAULTCLIENTS), kickthreshold(-5), banthreshold(-6), verbose(0), incoming_limit(10), afk_limit(45000), ban_time(20*60*1000), demotimelocal(0), ip(""), master(NULL), logident(""), serverpassword(""), adminpasswd(""), demopath(""), maprot("config/maprot.cfg"), pwdfile("config/serverpwd.cfg"), blfile("config/serverblacklist.cfg"), nbfile("config/nicknameblacklist.cfg"), - infopath("config/serverinfo"), motdpath("config/motd"), forbidden("config/forbidden.cfg"), + infopath("config/serverinfo"), motdpath("config/motd"), forbidden("config/forbidden.cfg"), service(NULL), + ssk(NULL), logtimestamp(false), demo_interm(false), loggamestatus(true), clfilenesting(0) { @@ -1154,7 +1159,18 @@ struct servercommandline int ai = atoi(a); // client: dtwhzbsave switch(arg[1]) - { // todo: gjlqEGHJQUYZ + { // todo: gjlqEGHJQU + case 'Y': // private server key + { + uchar temp[64]; + if(hex2bin(temp, a, 32) == 32) + { + if(!ssk) ssk = new uchar[64]; + memcpy(ssk, temp, 32); + ed25519_pubkey_from_private(ssk + 32, ssk); + } + break; + } case '-': if(!strncmp(arg, "--demofilenameformat=", 21)) { @@ -1244,6 +1260,7 @@ struct servercommandline case 'P': concatstring(voteperm, a); break; case 'M': concatstring(mapperm, a); break; case 'Z': if(ai >= 0) incoming_limit = ai; break; + case 'S': service = a; break; case 'V': verbose++; break; case 'C': if(*a && clfilenesting < 3) { diff --git a/source/src/server.cpp b/source/src/server.cpp index 9ce01588..a4085cf8 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -99,7 +99,6 @@ vector demofiles; long int incoming_size = 0; // cmod -char *global_name; int totalclients = 0; int cn2boot; int servertime = 0, serverlagged = 0; @@ -4304,60 +4303,25 @@ void processmasterinput(const char *cmd, int cmdlen, const char *args) else if(sscanf(cmd, "addgban %s", val) == 1) addgban(val); } -string server_name = "unarmed server"; - void quitproc(int param) { // this triggers any "atexit"-calls: exit(param == 2 ? EXIT_SUCCESS : EXIT_FAILURE); // 3 is the only reply on Win32 apparently, SIGINT == 2 == Ctrl-C } -void initserver(bool dedicated, int argc, char **argv) +void initserver(bool dedicated) { - const char *service = NULL; - - for(int i = 1; iargc = argc; svcctrl->argv = argv; - svcctrl->start(); - } - } - - if ( strlen(scl.servdesc_full) ) global_name = scl.servdesc_full; - else global_name = server_name; - sg->smapname[0] = '\0'; + // start logging string identity; if(scl.logident[0]) filtertext(identity, scl.logident, FTXT__LOGIDENT); else formatstring(identity)("%s#%d", scl.ip[0] ? scl.ip : "local", scl.serverport); int conthres = scl.verbose > 1 ? ACLOG_DEBUG : (scl.verbose ? ACLOG_VERBOSE : ACLOG_INFO); - if(dedicated && !initlogging(identity, scl.syslogfacility, conthres, scl.filethres, scl.syslogthres, scl.logtimestamp)) - printf("WARNING: logging not started!\n"); + if(dedicated && !initlogging(identity, scl.syslogfacility, conthres, scl.filethres, scl.syslogthres, scl.logtimestamp)) printf("WARNING: logging not started!\n"); logline(ACLOG_INFO, "logging local AssaultCube server (version %d, protocol %d/%d) now..", AC_VERSION, SERVER_PROTOCOL_VERSION, EXT_VERSION); - copystring(sg->servdesc_current, scl.servdesc_full); - servermsinit(scl.master ? scl.master : AC_MASTER_URI, scl.ip, CUBE_SERVINFO_PORT(scl.serverport), dedicated); + servermsinit(dedicated); if((isdedicated = dedicated)) { @@ -4367,6 +4331,8 @@ void initserver(bool dedicated, int argc, char **argv) if(!serverhost) fatal("could not create server host"); loopi(scl.maxclients) serverhost->peers[i].data = (void *)-1; + string pubkey; + if(scl.ssk) logline(ACLOG_VERBOSE,"server public key: %s", bin2hex(pubkey, scl.ssk + 32, 32)); maprot.init(scl.maprot); // maprot.next(false, true); // ensure minimum maprot length of '1' passwords.init(scl.pwdfile, scl.adminpasswd); @@ -4446,13 +4412,27 @@ int main(int argc, char **argv) #endif #endif - for(int i = 1; istart(); + } + + if(enet_initialize() < 0) fatal("Unable to initialise network module"); + initserver(true); return EXIT_SUCCESS; #if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__) diff --git a/source/src/serverbrowser.cpp b/source/src/serverbrowser.cpp index 5ce3d614..0f07cb46 100644 --- a/source/src/serverbrowser.cpp +++ b/source/src/serverbrowser.cpp @@ -1306,7 +1306,6 @@ void clearservers() #define RETRIEVELIMIT 5000 -extern char *global_name; bool cllock = false, clfail = false; int progress_callback_retrieveservers(void *data, float progress) @@ -1330,7 +1329,7 @@ void retrieveservers(vector &data) if(h.set_host(mastername)) { formatstring(progresstext)("retrieving servers from %s:%d... (esc to abort)", mastername, masterport); - defformatstring(url)("/retrieve.do?action=list&name=%s&version=%d&build=%d", urlencode(global_name, true), AC_VERSION, getbuildtype()|(1<<16)); + defformatstring(url)("/retrieve.do?action=list&name=%s&version=%d&build=%d", urlencode(player1->name, true), AC_VERSION, getbuildtype()|(1<<16)); h.outvec = (vector *) &data; // ouch... show_out_of_renderloop_progress(0, progresstext); int got = h.get(url, RETRIEVELIMIT, RETRIEVELIMIT); @@ -1358,7 +1357,7 @@ void retrieveservers(vector &data) defformatstring(text)("retrieving servers from %s:%d... (esc to abort)", mastername, masterport); show_out_of_renderloop_progress(0, text); int starttime = SDL_GetTicks(), timeout = 0; - defformatstring(request)("list %s %d %d\n", global_name, AC_VERSION, getbuildtype()); + defformatstring(request)("list %s %d %d\n", player1->name, AC_VERSION, getbuildtype()); const char *req = request; int reqlen = strlen(req); ENetBuffer buf; diff --git a/source/src/servercontroller.h b/source/src/servercontroller.h index 911e1655..44b729bd 100644 --- a/source/src/servercontroller.h +++ b/source/src/servercontroller.h @@ -19,11 +19,13 @@ struct winservice : servercontroller HANDLE stopevent; const char *name; - winservice(const char *name) : name(name) + winservice(const char *name, int _argc, char **_argv) : name(name) { - callbacks::svc = this; + callbacks::svc = this; statushandle = 0; - }; + argc = _argc; + argv = _argv; + } ~winservice() { @@ -109,25 +111,12 @@ struct winservice : servercontroller return main(argc, argv); } - struct callbacks { static winservice *svc; static int WINAPI main() { return svc->svcmain(); }; static void WINAPI requesthandler(DWORD request) { svc->requesthandler(request); }; }; - - /*void log(const char *msg, bool error) - { - HANDLE eventsrc = RegisterEventSource(NULL, "AC Server"); - if(eventsrc) - { - int eventid = ((error ? 0x11 : 0x1) << 10) & (0x1 << 9) & (FACILITY_NULL << 6) & 0x1; // TODO: create event definitions - LPCTSTR msgs[1] = { msg }; - int r = ReportEvent(eventsrc, error ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, 0, 4, NULL, 1, 0, msgs, NULL); - DeregisterEventSource(eventsrc); - } - }*/ }; winservice *winservice::callbacks::svc = (winservice *)NULL; diff --git a/source/src/serverms.cpp b/source/src/serverms.cpp index 5d335097..ea94fd76 100644 --- a/source/src/serverms.cpp +++ b/source/src/serverms.cpp @@ -16,6 +16,8 @@ int connectwithtimeout(ENetSocket sock, const char *hostname, ENetAddress &remot } #endif +extern struct servercommandline scl; +bool usemaster = false; ENetSocket mastersock = ENET_SOCKET_NULL; ENetAddress masteraddress = { ENET_HOST_ANY, ENET_PORT_ANY }, serveraddress = { ENET_HOST_ANY, ENET_PORT_ANY }; string mastername = AC_MASTER_URI; @@ -43,9 +45,8 @@ void disconnectmaster() ENetSocket connectmaster() { - if(!mastername[0]) return ENET_SOCKET_NULL; - extern servercommandline scl; - if(scl.maxclients>MAXCL) { logline(ACLOG_WARNING, "maxclient exceeded: cannot register"); return ENET_SOCKET_NULL; } + if(!mastername[0] || !usemaster) return ENET_SOCKET_NULL; + if(scl.maxclients > MAXCL) { logline(ACLOG_WARNING, "maxclient exceeded: cannot register"); return ENET_SOCKET_NULL; } if(masteraddress.host == ENET_HOST_ANY) { @@ -160,7 +161,6 @@ void flushmasterinput() else disconnectmaster(); } -extern char *global_name; extern int totalclients; // send alive signal to masterserver after 40 minutes of uptime and if currently in intermission (so theoretically <= 1 hour) @@ -169,8 +169,9 @@ static inline void updatemasterserver(int millis, int port, int _interm) { if(!lastupdatemaster || ((millis-lastupdatemaster)>40*60*1000 && (_interm || !totalclients))) { - char servername[30]; memset(servername,'\0',30); filtertext(servername, global_name, FTXT__GLOBALNAME, 20); - if(mastername[0]) requestmasterf("regserv %d %s %d\n", port, servername[0] ? servername : "noname", AC_VERSION); + string servdesc, pubkey; + filtertext(servdesc, scl.servdesc_full[0] ? scl.servdesc_full : "noname", FTXT__GLOBALNAME, 20); + if(mastername[0]) requestmasterf("regserv %d %s-%s %d\n", port, servdesc, scl.ssk ? bin2hex(pubkey, scl.ssk + 32, 32) : "nokey", AC_VERSION); lastupdatemaster = millis + 1; } } @@ -325,20 +326,21 @@ void serverms(int mode, int numplayers, int minremain, char *smapname, int milli if(mastersock != ENET_SOCKET_NULL && ENET_SOCKETSET_CHECK(sockset, mastersock)) flushmasterinput(); } -// this function should be made better, because it is used just ONCE (no need of so much parameters) -void servermsinit(const char *master, const char *ip, int infoport, bool listen) +void servermsinit(bool listen) { - copystring(mastername, master); + if(scl.master && *scl.master) copystring(mastername, scl.master); + usemaster = !listen || (listen && scl.master && scl.ssk); // true: connect to master, false: LAN-only server disconnectmaster(); if(listen) { - ENetAddress address = { ENET_HOST_ANY, (enet_uint16)infoport }; - if(*ip) + ENetAddress address = { ENET_HOST_ANY, (enet_uint16) CUBE_SERVINFO_PORT(scl.serverport) }; + if(*scl.ip) { - if(enet_address_set_host(&address, ip)<0) logline(ACLOG_WARNING, "server ip not resolved"); + if(enet_address_set_host(&address, scl.ip) < 0) logline(ACLOG_WARNING, "server ip \"%s\" not resolved", scl.ip); else serveraddress.host = address.host; } + pongsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); if(pongsock != ENET_SOCKET_NULL && enet_socket_bind(pongsock, &address) < 0) { @@ -347,6 +349,7 @@ void servermsinit(const char *master, const char *ip, int infoport, bool listen) } if(pongsock == ENET_SOCKET_NULL) fatal("could not create server info socket"); else enet_socket_set_option(pongsock, ENET_SOCKOPT_NONBLOCK, 1); + address.port = CUBE_SERVINFO_PORT_LAN; 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)) @@ -357,4 +360,5 @@ void servermsinit(const char *master, const char *ip, int infoport, bool listen) if(lansock == ENET_SOCKET_NULL) logline(ACLOG_WARNING, "could not create LAN server info socket"); else enet_socket_set_option(lansock, ENET_SOCKOPT_NONBLOCK, 1); } + if(!usemaster) logline(ACLOG_INFO, "server is LAN-only - without connection to masterserver"); }