From b1e3060648629f44eb544a648a592f8451d7c5bb Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 24 Jun 2014 03:02:32 +0000 Subject: [PATCH] tweaked download rules to match mvdsv, by adding an allow_download_other cvar. added log_enable_rcon (and enabled it by default), for feature parity with mvdsv. invalid requests, valid requests, and redirected prints are all logged. tweaked server-side download code to not bug out with downloads larger than 2gb. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4697 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/common/cmd.c | 4 + engine/common/cmd.h | 1 + engine/common/common.h | 1 + engine/common/fs.c | 6 +- engine/common/gl_q2bsp.c | 7 ++ engine/common/log.c | 10 ++- engine/common/vm.h | 7 +- engine/dotnet2005/ftequake.vcproj | 18 +++- engine/server/server.h | 10 +-- engine/server/sv_main.c | 38 ++++++--- engine/server/sv_send.c | 6 +- engine/server/sv_user.c | 132 ++++++++++++++++++------------ 12 files changed, 163 insertions(+), 77 deletions(-) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 14003e094..12558c303 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -26,6 +26,7 @@ cvar_t cmd_maxbuffersize = SCVAR("cmd_maxbuffersize", "65536"); cvar_t dpcompat_set = SCVAR("dpcompat_set", "0"); int Cmd_ExecLevel; qboolean cmd_didwait; +qboolean cmd_blockwait; void Cmd_ForwardToServer (void); @@ -161,6 +162,9 @@ bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" */ void Cmd_Wait_f (void) { + if (cmd_blockwait) + return; + #ifndef CLIENTONLY if (cmd_didwait && sv.state) Con_DPrintf("waits without server frames\n"); diff --git a/engine/common/cmd.h b/engine/common/cmd.h index 7a3e88b8a..c6b6e9104 100644 --- a/engine/common/cmd.h +++ b/engine/common/cmd.h @@ -55,6 +55,7 @@ void Cbuf_Execute (void); // Normally called once per frame, but may be explicitly invoked. // Do not call inside a command function! +extern qboolean cmd_blockwait; void Cbuf_ExecuteLevel(int level); //executes only a single cbuf level. can be used to restrict cbuf execution to some 'safe' set of commands, so there are no surprise 'map' commands. //will not magically make all commands safe to exec, but will prevent user commands slipping in too. diff --git a/engine/common/common.h b/engine/common/common.h index 9658874a9..cd8f4f31d 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -570,6 +570,7 @@ void PO_Close(struct po_s *po); typedef enum { LOG_CONSOLE, LOG_PLAYER, + LOG_RCON, LOG_TYPES } logtype_t; void Log_Dir_Callback (struct cvar_s *var, char *oldvalue); diff --git a/engine/common/fs.c b/engine/common/fs.c index 895a8e256..cd1677eb9 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1051,7 +1051,7 @@ qboolean FS_GetPackageDownloadable(const char *package) for (search = com_searchpaths ; search ; search = search->next) { - if (!strcmp(package, search->purepath)) + if (!Q_strcasecmp(package, search->purepath)) return !(search->flags & SPF_COPYPROTECTED); } return false; @@ -3944,6 +3944,10 @@ void FS_ChangeGame_f(void) int i; char *arg = Cmd_Argv(1); + //don't execute this if we're executing rcon commands, as this can change game directories. + if (cmd_blockwait) + return; + if (!*arg) { Con_Printf("Valid games are:\n"); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 001af5f2b..f074f53ae 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -5691,6 +5691,10 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, if (0) { //treat *ALL* tests against the actual geometry instead of using any brushes. //also ignores the bsp etc. not fast. testing only. + + trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 + && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0; + for (i = 0; i < mod->numsurfaces; i++) { CM_ClipBoxToMesh(trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, mod->surfaces[i].mesh); @@ -5699,6 +5703,9 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, else if (0) { + trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 + && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0; + for (i = 0; i < mod->numleafs; i++) CM_TraceToLeaf(&mod->leafs[i]); } diff --git a/engine/common/log.c b/engine/common/log.c index ca4daa5cd..65f0017b3 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -9,9 +9,12 @@ void Log_Name_Callback (struct cvar_s *var, char *oldvalue); // cvars #define CONLOGGROUP "Console logging" cvar_t log_enable[LOG_TYPES] = { CVARF("log_enable", "0", CVAR_NOTFROMSERVER), - CVARF("log_enable_players", "0", CVAR_NOTFROMSERVER)}; + CVARF("log_enable_players", "0", CVAR_NOTFROMSERVER), + CVARF("log_enable_rcon", "1", CVAR_NOTFROMSERVER) + }; cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_Name_Callback), - CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback)}; + CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback), + CVARFC("log_name_rcon", "", CVAR_NOTFROMSERVER, Log_Name_Callback)}; cvar_t log_dir = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback); cvar_t log_readable = CVARFD("log_readable", "7", CVAR_NOTFROMSERVER, "Bitfield describing what to convert/strip. If 0, exact byte representation will be used.\n&1: Dequakify text.\n&2: Strip special markup.\n&4: Strip ansi control codes."); cvar_t log_developer = CVARF("log_developer", "0", CVAR_NOTFROMSERVER); @@ -88,6 +91,9 @@ void Log_String (logtype_t lognum, char *s) case LOG_PLAYER: f = "players"; break; + case LOG_RCON: + f = "rcon"; + break; default: break; } diff --git a/engine/common/vm.h b/engine/common/vm.h index cdd6c2501..caf7040eb 100644 --- a/engine/common/vm.h +++ b/engine/common/vm.h @@ -19,8 +19,11 @@ #define FTE_WORDSIZE 64 #define quintptr_t unsigned qintptr_t #elif defined(_WIN32) - typedef __int32 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions - typedef unsigned __int32 quintptr_t; + #ifndef _MSC_VER + #define __w64 + #endif + typedef __int32 __w64 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions + typedef unsigned __int32 __w64 quintptr_t; // #define qintptr_t __int32 // #define quintptr_t unsigned qintptr_t #define FTE_WORDSIZE 32 diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 39cf8070e..6f8601a4e 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -8837,6 +8837,14 @@ + + + + + + datagram; - if (chunknum*CHUNKSIZE > host_client->downloadsize) + if (chunknum == -1) + error = 2; //silent, don't report it + else if (chunknum*CHUNKSIZE > host_client->downloadsize) { SV_ClientTPrintf (host_client, PRINT_HIGH, "Warning: Invalid file chunk requested %u to %u of %u.\n", chunknum*CHUNKSIZE, (chunknum+1)*CHUNKSIZE, host_client->downloadsize); error = 2; } - if (!error && VFS_SEEK (host_client->download, chunknum*CHUNKSIZE) == false) + if (!error && VFS_SEEK (host_client->download, (qofs_t)chunknum*CHUNKSIZE) == false) error = true; else { @@ -2032,58 +2036,63 @@ void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum) host_client->downloadcount = chunknum*CHUNKSIZE; } - if ((host_client->datagram.cursize + CHUNKSIZE+5+50 > host_client->datagram.maxsize) || (host_client->datagram.cursize + CHUNKSIZE+5 > 1400)) + + while (!error && chunks > 0) { - //would overflow the packet, or result in (ethernet) fragmentation and high packet loss. - msg = &msg_oob; + if ((host_client->datagram.cursize + CHUNKSIZE+5+50 > host_client->datagram.maxsize) || (host_client->datagram.cursize + CHUNKSIZE+5 > 1400)) + { + //would overflow the packet, or result in (ethernet) fragmentation and high packet loss. + msg = &msg_oob; - if (!ezfilenum) - return; + if (!ezfilenum) //can't oob it + return; - if (host_client->waschoked) - return; //don't let chunked downloads flood out the standard packets. + if (host_client->waschoked) + return; //don't let chunked downloads flood out the standard packets. - if (!Netchan_CanPacket(&host_client->netchan, SV_RateForClient(host_client))) - return; - } + if (!Netchan_CanPacket(&host_client->netchan, SV_RateForClient(host_client))) + return; + } - if (error) - i = 0; - else i = VFS_READ (host_client->download, buffer, CHUNKSIZE); - if (i > 0) - { - if (msg == &msg_oob) + if (i > 0) { - msg = &msg_oob; - msg->cursize = 0; - msg->maxsize = sizeof(oobdata); - msg->currentbit = 0; - msg->packing = SZ_RAWBYTES; - msg->allowoverflow = 0; - msg->overflowed = 0; - msg->data = oobdata; - MSG_WriteByte(msg, A2C_PRINT); - SZ_Write(msg, "\\chunk", 6); - MSG_WriteLong(msg, ezfilenum); //echoing the file num is used so the packets don't go out of sync. + if (msg == &msg_oob) + { + msg = &msg_oob; + msg->cursize = 0; + msg->maxsize = sizeof(oobdata); + msg->currentbit = 0; + msg->packing = SZ_RAWBYTES; + msg->allowoverflow = 0; + msg->overflowed = 0; + msg->data = oobdata; + MSG_WriteByte(msg, A2C_PRINT); + SZ_Write(msg, "\\chunk", 6); + MSG_WriteLong(msg, ezfilenum); //echoing the file num is used so the packets don't go out of sync. + } + + if (i != CHUNKSIZE) + memset(buffer+i, 0, CHUNKSIZE-i); + + MSG_WriteByte(msg, svc_download); + MSG_WriteLong(msg, chunknum); + SZ_Write(msg, buffer, CHUNKSIZE); + + if (msg == &msg_oob) + { + Netchan_OutOfBand(NS_SERVER, &host_client->netchan.remote_address, msg_oob.cursize, msg_oob.data); + Netchan_Block(&host_client->netchan, msg_oob.cursize, SV_RateForClient(host_client)); + host_client->netchan.bytesout += msg_oob.cursize; + } } + else if (i < 0) + error = true; - if (i != CHUNKSIZE) - memset(buffer+i, 0, CHUNKSIZE-i); - - MSG_WriteByte(msg, svc_download); - MSG_WriteLong(msg, chunknum); - SZ_Write(msg, buffer, CHUNKSIZE); - - if (msg == &msg_oob) - { - Netchan_OutOfBand(NS_SERVER, &host_client->netchan.remote_address, msg_oob.cursize, msg_oob.data); - Netchan_Block(&host_client->netchan, msg_oob.cursize, SV_RateForClient(host_client)); - } + chunks--; + chunknum++; } - else if (i < 0) - error = true; if (error) { @@ -2122,9 +2131,9 @@ void SV_NextDownload_f (void) if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) { if (Cmd_Argc() < 2) - SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3))); + SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3)), atoi(Cmd_Argv(4))); else - SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3))); + SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3)), atoi(Cmd_Argv(4))); return; } #endif @@ -2596,6 +2605,7 @@ qboolean SV_AllowDownload (const char *name) extern cvar_t allow_download_root; extern cvar_t allow_download_configs; extern cvar_t allow_download_copyrighted; + extern cvar_t allow_download_other; char cleanname[MAX_QPATH]; int i=0; if (strlen(name) >= MAX_QPATH) @@ -2620,6 +2630,9 @@ qboolean SV_AllowDownload (const char *name) if (strchr(name, '\\')) //no windows paths - grow up lame windows users. return false; + if (!Q_strcasecmp("log", COM_FileExtension(name))) + return false; + if (!strncmp(name, "package/", 8)) { if (!strcmp("pk4", COM_FileExtension(name)) || !strcmp("pk3", COM_FileExtension(name)) || !strcmp("pak", COM_FileExtension(name))) @@ -2677,12 +2690,13 @@ qboolean SV_AllowDownload (const char *name) //root of gamedir if (!strchr(name, '/') && !allow_download_root.value) { - if (strcmp(name, "csprogs.dat")) //we always allow csprogs.dat to be downloaded (if downloads are permitted). - return false; + if (!strcmp(name, "csprogs.dat")) //we always allow csprogs.dat to be downloaded (if downloads are permitted). + return true; + return false; } //any other subdirs are allowed - return true; + return !!allow_download_other.value;; } static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementname, qboolean redirectpaks) @@ -3036,9 +3050,16 @@ void SV_BeginDownload_f(void) host_client->download = tmp; } - ClientReliableWrite_Begin (host_client, svc_download, 10+strlen(host_client->downloadfn)); + ClientReliableWrite_Begin (host_client, svc_download, 18+strlen(host_client->downloadfn)); ClientReliableWrite_Long (host_client, -1); - ClientReliableWrite_Long (host_client, host_client->downloadsize); + if (host_client->downloadsize >= 0x7fffffff) + { //avoid unsigned values. + ClientReliableWrite_Long (host_client, 0x80000000); //signal that its 64bit + ClientReliableWrite_Long (host_client, qofs_Low(host_client->downloadsize)); + ClientReliableWrite_Long (host_client, qofs_High(host_client->downloadsize)); + } + else + ClientReliableWrite_Long (host_client, host_client->downloadsize); ClientReliableWrite_String (host_client, host_client->downloadfn); } else @@ -5333,8 +5354,11 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC) return; } + Log_String(LOG_RCON, va("cmd from %s - %s:\n%s\n" + , NET_AdrToString (adr, sizeof(adr), &net_from), host_client->name, s)); + Con_TPrintf ("cmd from %s:\n%s\n" - , host_client->name, net_message.data+4); + , host_client->name, s); SV_BeginRedirect (RD_CLIENT, host_client->language); @@ -5351,8 +5375,8 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC) , NET_AdrToString (adr, sizeof(adr), &net_from), "Was too long - possible buffer overflow attempt"); return; } - strcat (remaining, Cmd_Argv(i) ); - strcat (remaining, " "); + Q_strncatz(remaining, Cmd_Argv(i), sizeof(remaining)); + Q_strncatz(remaining, " ", sizeof(remaining)); } Cmd_ExecuteString (remaining, stats.trustlevel);