fix parsing of commandline switches for servers

also:
 * -Y now sets the private key for the server
 * -m without argument uses default masterserver URL
 * servers run LAN-only by default (set ms URL and private key to
   register with the master)
 * use generic locale "POSIX"
This commit is contained in:
ac-stef
2017-06-27 15:15:21 +02:00
parent 25deee5287
commit c8c310886a
9 changed files with 75 additions and 90 deletions
+2 -1
View File
@@ -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)
-3
View File
@@ -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;
}
+3 -6
View File
@@ -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);
+1
View File
@@ -12,6 +12,7 @@
#include <time.h>
#include <limits.h>
#include <math.h>
#include <locale.h>
#include <stdint.h>
#ifdef __GNUC__
#include <new>
+22 -5
View File
@@ -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)
{
+24 -44
View File
@@ -99,7 +99,6 @@ vector<demofile> 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; i<argc; i++)
{
if(!scl.checkarg(argv[i]))
{
char *a = &argv[i][2];
if(!scl.checkarg(argv[i]) && argv[i][0]=='-') switch(argv[i][1])
{
case '-': break;
case 'S': service = a; break;
default: break; /*printf("WARNING: unknown commandline option\n");*/ // less warnings - 2011feb05:ft: who disabled this - I think this should be on - more warnings == more clarity
}
else if (strncmp(argv[i], "assaultcube://", 13)) printf("WARNING: unknown commandline argument\n");
}
}
if(service && !svcctrl)
{
#ifdef WIN32
svcctrl = new winservice(service);
#endif
if(svcctrl)
{
svcctrl->argc = 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; i<argc; i++)
setlocale(LC_ALL, "POSIX");
for(int i = 1; i < argc; i++)
{
if (!strncmp(argv[i],"--wizard",8)) return wizardmain(argc, argv);
if(!scl.checkarg(argv[i]))
{
if (!strncmp(argv[i],"--wizard",8)) return wizardmain(argc, argv);
else printf("WARNING: unknown commandline argument \"%s\"\n", argv[i]);
}
}
if(enet_initialize()<0) fatal("Unable to initialise network module");
initserver(true, argc, argv);
if(scl.service && !svcctrl)
{
#ifdef WIN32
svcctrl = new winservice(scl.service, argc, argv);
#endif
if(svcctrl) svcctrl->start();
}
if(enet_initialize() < 0) fatal("Unable to initialise network module");
initserver(true);
return EXIT_SUCCESS;
#if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__)
+2 -3
View File
@@ -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<char> &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<uchar> *) &data; // ouch...
show_out_of_renderloop_progress(0, progresstext);
int got = h.get(url, RETRIEVELIMIT, RETRIEVELIMIT);
@@ -1358,7 +1357,7 @@ void retrieveservers(vector<char> &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;
+5 -16
View File
@@ -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;
+16 -12
View File
@@ -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");
}