From 3e075e3e4e38779cc14c924ef0b5b1705704a4d9 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 9 Dec 2025 21:20:49 -0500 Subject: [PATCH] Port various netxcmd changes from SRB2Classic based on commits: Lift NetXCmd limits Fix segfault when sending excessively large netcmds Simplify NetXCmd client distribution try fixing some crash with bogus netxcmds --- src/d_clisrv.c | 134 ++++++++++++++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 53 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c0d2cf52f..911285a79 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -188,20 +188,23 @@ tic_t firstconnectattempttime = 0; // Must be a power of two #define TEXTCMD_HASH_SIZE 4 -typedef struct textcmdplayer_s -{ - INT32 playernum; - UINT8 cmd[MAXTEXTCMD]; - struct textcmdplayer_s *next; -} textcmdplayer_t; - typedef struct textcmdtic_s { tic_t tic; - textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE]; + UINT8 *playercmds[MAXPLAYERS]; struct textcmdtic_s *next; } textcmdtic_t; +typedef struct textcmdbuf_s textcmdbuf_t; + +struct textcmdbuf_s +{ + textcmdbuf_t *next; + UINT8 cmd[MAXTEXTCMD]; +}; + +static textcmdbuf_t *textcmdbuf[MAXSPLITSCREENPLAYERS]; + static ticcmd_t playercmds[MAXPLAYERS]; ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; @@ -287,23 +290,57 @@ void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)) listnetxcmd[id] = cmd_f; } +static void WriteNetXCmd(UINT8 *cmd, netxcmd_t id, const void *param, size_t nparam) +{ + cmd[0]++; + cmd[cmd[0]] = (UINT8)id; + if (param && nparam) + { + memcpy(&cmd[cmd[0]+1], param, nparam); + cmd[0] = (UINT8)(cmd[0] + (UINT8)nparam); + } +} + void SendNetXCmdForPlayer(UINT8 playerid, netxcmd_t id, const void *param, size_t nparam) { if (localtextcmd[playerid][0]+2+nparam > MAXTEXTCMD) { - // for future reference: if (cht_debug) != debug disabled. - CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[playerid][0], sizeu1(nparam)); + textcmdbuf_t *buf = textcmdbuf[playerid]; + + if (2+nparam > MAXTEXTCMD) + { + CONS_Alert(CONS_ERROR, M_GetText("packet too large to fit NetXCmd, cannot add netcmd %d! (size: %s, max: %d)\n"), id, sizeu1(2+nparam), MAXTEXTCMD); + return; + } + + // for future reference: if (cv_debug) != debug disabled. + CONS_Alert(CONS_NOTICE, M_GetText("NetXCmd buffer full, delaying netcmd %d... (size: %d, needed: %s)\n"), id, localtextcmd[playerid][0], sizeu1(nparam)); + if (buf == NULL) + { + textcmdbuf[playerid] = Z_Malloc(sizeof(textcmdbuf_t), PU_STATIC, NULL); + textcmdbuf[playerid]->cmd[0] = 0; + textcmdbuf[playerid]->next = NULL; + WriteNetXCmd(textcmdbuf[playerid]->cmd, id, param, nparam); + return; + } + + while (buf->next != NULL) + buf = buf->next; + + if (buf->cmd[0]+2+nparam > MAXTEXTCMD) + { + buf->next = Z_Malloc(sizeof(textcmdbuf_t), PU_STATIC, NULL); + buf->next->cmd[0] = 0; + buf->next->next = NULL; + WriteNetXCmd(buf->next->cmd, id, param, nparam); + } + else + { + WriteNetXCmd(buf->cmd, id, param, nparam); + } return; } - - localtextcmd[playerid][0]++; - localtextcmd[playerid][localtextcmd[playerid][0]] = (UINT8)id; - - if (param && nparam) - { - memcpy(&localtextcmd[playerid][localtextcmd[playerid][0] + 1], param, nparam); - localtextcmd[playerid][0] = (UINT8)(localtextcmd[playerid][0] + (UINT8)nparam); - } + WriteNetXCmd(localtextcmd[playerid], id, param, nparam); } UINT8 GetFreeXCmdSize(UINT8 playerid) @@ -326,22 +363,13 @@ static void D_FreeTextcmd(tic_t tic) if (textcmdtic) { - INT32 i; - // Remove this tic from the list. *tctprev = textcmdtic->next; // Free all players. - for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { - textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i]; - - while (textcmdplayer) - { - textcmdplayer_t *tcpnext = textcmdplayer->next; - Z_Free(textcmdplayer); - textcmdplayer = tcpnext; - } + Z_Free(textcmdtic->playercmds[i]); } // Free this tic's own memory. @@ -358,10 +386,8 @@ static UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum) // Do we have an entry for the tic? If so, look for player. if (textcmdtic) { - textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; - while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next; - - if (textcmdplayer) return textcmdplayer->cmd; + UINT8 *cmd = textcmdtic->playercmds[playernum]; + if (cmd) return cmd; } return NULL; @@ -372,7 +398,6 @@ static UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) { textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdplayer_t *textcmdplayer, **tcpprev; // Look for the tic. while (textcmdtic && textcmdtic->tic != tic) @@ -388,24 +413,11 @@ static UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) textcmdtic->tic = tic; } - tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; - textcmdplayer = *tcpprev; - - // Look for the player. - while (textcmdplayer && textcmdplayer->playernum != playernum) - { - tcpprev = &textcmdplayer->next; - textcmdplayer = textcmdplayer->next; - } - // If we don't have an entry for the player, make it. - if (!textcmdplayer) - { - textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL); - textcmdplayer->playernum = playernum; - } + if (!textcmdtic->playercmds[playernum]) + textcmdtic->playercmds[playernum] = Z_Calloc(MAXTEXTCMD, PU_STATIC, NULL); - return textcmdplayer->cmd; + return textcmdtic->playercmds[playernum]; } static boolean ExtraDataTicker(void) @@ -5061,11 +5073,17 @@ static void PT_ServerTics(SINT8 node, INT32 netconsole) numtxtpak = *txtpak++; for (j = 0; j < numtxtpak; j++) { - INT32 k = *txtpak++; // playernum + INT32 playernum = *txtpak++; // playernum const size_t txtsize = txtpak[0]+1; + if (playernum < 0 || playernum >= MAXPLAYERS) + { + CONS_Alert(CONS_WARNING, "Got bogus NetXCmd packet targetting player %d\n", playernum); + return; + } + if (i >= gametic) // Don't copy old net commands - memcpy(D_GetTextcmd(i, k), txtpak, txtsize); + memcpy(D_GetTextcmd(i, playernum), txtpak, txtsize); txtpak += txtsize; } } @@ -5774,7 +5792,17 @@ static void CL_SendClientCmd(void) memcpy(netbuffer->u.textcmd, localtextcmd[i], localtextcmd[i][0]+1); // All extra data have been sent if (HSendPacket(servernode, true, 0, localtextcmd[i][0]+1)) // Send can fail... + { localtextcmd[i][0] = 0; + + if (textcmdbuf[i] != NULL) + { + textcmdbuf_t *buf = textcmdbuf[i]; + memcpy(localtextcmd[i], textcmdbuf[i]->cmd, textcmdbuf[i]->cmd[0]+1); + textcmdbuf[i] = textcmdbuf[i]->next; + Z_Free(buf); + } + } } } }