From 18036b63d908c36a4731a704d822bcd2fecd8ca9 Mon Sep 17 00:00:00 2001 From: Adam Olsen Date: Thu, 18 Oct 2001 04:44:58 +0000 Subject: [PATCH] - change MSG_ReadString to return const char * and return a pointer directly into the packet data. - change a bunch of char *'s to const char *'s for the above. Only thing that had trouble was the cl_nofake handler, which I changed to use a local buffer. - add MSG_ReadStaticString which acts like the old MSG_ReadString, specifically that it uses a static buffer and tollerates unterminated strings. - add a Q_strnlen function, and make strnlen use it if strnlen is undefined. - Add a net_svc.h and net_svc.c which will preparse svc messages into structs, for easier handling. Currently only soundlist and modellist are done. --- include/QF/msg.h | 3 +- include/QF/string.h | 1 + include/compat.h | 4 ++ libs/util/msg.c | 32 +++++++++++++- libs/util/string.c | 15 ++++++- nq/source/cl_parse.c | 2 +- nq/source/net_dgrm.c | 4 +- nq/source/sv_user.c | 2 +- qw/include/net_svc.h | 54 ++++++++++++++++++++++++ qw/source/Makefile.am | 2 +- qw/source/cl_main.c | 10 ++--- qw/source/cl_parse.c | 80 ++++++++++++++++++----------------- qw/source/net_packetlog.c | 4 +- qw/source/net_svc.c | 87 +++++++++++++++++++++++++++++++++++++++ qw/source/sv_user.c | 2 +- 15 files changed, 249 insertions(+), 53 deletions(-) create mode 100644 qw/include/net_svc.h create mode 100644 qw/source/net_svc.c diff --git a/include/QF/msg.h b/include/QF/msg.h index 45c98a018..d1b4a0b1f 100644 --- a/include/QF/msg.h +++ b/include/QF/msg.h @@ -53,7 +53,8 @@ int MSG_ReadByte (msg_t *msg); int MSG_ReadShort (msg_t *msg); int MSG_ReadLong (msg_t *msg); float MSG_ReadFloat (msg_t *msg); -char *MSG_ReadString (msg_t *msg); +const char *MSG_ReadString (msg_t *msg); +char *MSG_ReadStaticString (msg_t *msg); char *MSG_ReadStringLine (msg_t *msg); float MSG_ReadCoord (msg_t *msg); diff --git a/include/QF/string.h b/include/QF/string.h index 72eb97926..ee8b6f4c8 100644 --- a/include/QF/string.h +++ b/include/QF/string.h @@ -30,5 +30,6 @@ #define string_h const char * Q_strcasestr (const char *haystack, const char *needle); +size_t Q_strnlen (const char *s, size_t maxlen); #endif // string_h diff --git a/include/compat.h b/include/compat.h index 47919610e..ee808a502 100644 --- a/include/compat.h +++ b/include/compat.h @@ -93,6 +93,10 @@ extern int vsnprintf(char *s, size_t maxlen, const char *format, va_list arg); #if !defined(strcasestr) # define strcasestr Q_strcasestr #endif +// FIXME: same as above +#if !defined(strnlen) +# define strnlen Q_strnlen +#endif #undef field_offset #define field_offset(type,field) ((int)&(((type *)0)->field)) diff --git a/libs/util/msg.c b/libs/util/msg.c index 0335ca5f9..0d62b1a63 100644 --- a/libs/util/msg.c +++ b/libs/util/msg.c @@ -40,7 +40,9 @@ static const char rcsid[] = #include "QF/msg.h" #include "QF/qendian.h" #include "QF/sys.h" +#include "QF/string.h" +#include "compat.h" /* MESSAGE IO FUNCTIONS @@ -261,8 +263,36 @@ MSG_ReadFloat (msg_t *msg) return dat.f; } -char * +const char * MSG_ReadString (msg_t *msg) +{ + char *string; + int len, maxlen; + + if (msg->readcount + 1 > msg->message->cursize) { + msg->badread = true; + return ""; + } + + string = &msg->message->data[msg->readcount]; + + maxlen = msg->message->cursize - msg->readcount; + len = strnlen (string, maxlen); + if (len == maxlen) { + msg->badread = true; + return ""; + } + msg->readcount += len + 1; + + return string; +} + +// Netchan_OutOfBandPrint is broken such that it strips the +// terminating nul, which means connection packets (amoung others) +// aren't nul-terminated. So I provide the old string function for +// connectionless-packet parsers to use. +char * +MSG_ReadStaticString (msg_t *msg) { static char string[2048]; int l, c; diff --git a/libs/util/string.c b/libs/util/string.c index f46486511..fe218ff2a 100644 --- a/libs/util/string.c +++ b/libs/util/string.c @@ -45,7 +45,7 @@ static const char rcsid[] = const char * Q_strcasestr (const char *haystack, const char *needle) { - int len = strlen (needle); + size_t len = strlen (needle); while (*haystack) { if (!strncasecmp (haystack, needle, len)) return haystack; @@ -53,3 +53,16 @@ Q_strcasestr (const char *haystack, const char *needle) } return 0; } + +/* + Q_strnlen + + strlen with a cutoff +*/ +size_t +Q_strnlen (const char *s, size_t maxlen) +{ + size_t i; + for (i = 0; s[i] && i < maxlen; i++); + return i; +} diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index 9f30bf522..64481cd4e 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -222,7 +222,7 @@ CL_ParseServerInfo (void) { char model_precache[MAX_MODELS][MAX_QPATH]; char sound_precache[MAX_SOUNDS][MAX_QPATH]; - char *str; + const char *str; int nummodels, numsounds, i; Con_DPrintf ("Serverinfo packet received.\n"); diff --git a/nq/source/net_dgrm.c b/nq/source/net_dgrm.c index 60f98f776..048a6ee71 100644 --- a/nq/source/net_dgrm.c +++ b/nq/source/net_dgrm.c @@ -969,7 +969,7 @@ _Datagram_CheckNewConnections (void) } if (command == CCREQ_RULE_INFO) { - char *prevCvarName; + const char *prevCvarName; cvar_t *var; // find the search start location @@ -1277,7 +1277,7 @@ _Datagram_Connect (const char *host) int reps; double start_time; int control; - char *reason; + const char *reason; // see if we can resolve the host name if (dfunc.GetAddrFromName (host, &sendaddr) == -1) diff --git a/nq/source/sv_user.c b/nq/source/sv_user.c index 61587b5cf..fd3f3a986 100644 --- a/nq/source/sv_user.c +++ b/nq/source/sv_user.c @@ -448,7 +448,7 @@ qboolean SV_ReadClientMessage (void) { int cmd, ret; - char *s; + const char *s; do { nextmsg: diff --git a/qw/include/net_svc.h b/qw/include/net_svc.h new file mode 100644 index 000000000..864f80ddc --- /dev/null +++ b/qw/include/net_svc.h @@ -0,0 +1,54 @@ +/* + net_svc.h + + (description) + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifndef NET_SVC_H +#define NET_SVC_H + +#include "QF/mathlib.h" +#include "QF/msg.h" + +#include "bothdefs.h" + +typedef struct net_svc_soundlist_s +{ + byte startsound; + const char *sounds[MAX_SOUNDS + 1]; // space left for terminating empty string + byte nextsound; +} net_svc_soundlist_t; + +typedef struct net_svc_modellist_s +{ + byte startmodel; + const char *models[MAX_MODELS + 1]; // space left for terminating empty string + byte nextmodel; +} net_svc_modellist_t; + +void NET_SVC_Soundlist_Parse (net_svc_soundlist_t *soundlist, msg_t *message); +void NET_SVC_Modellist_Parse (net_svc_modellist_t *modellist, msg_t *message); + +#endif // NET_SVC_H diff --git a/qw/source/Makefile.am b/qw/source/Makefile.am index a42e86d00..e7b947e83 100644 --- a/qw/source/Makefile.am +++ b/qw/source/Makefile.am @@ -112,7 +112,7 @@ client_LIB_DEPS= libqfnet.la libasm.la $(qf_client_LIBS) client_sources= cl_cam.c cl_cmd.c cl_cvar.c cl_demo.c cl_ents.c cl_input.c \ cl_main.c cl_misc.c cl_ngraph.c cl_parse.c cl_pred.c \ cl_screen.c cl_skin.c cl_slist.c cl_tent.c cl_view.c \ - console.c locs.c sbar.c skin.c teamplay.c + console.c locs.c net_svc.c sbar.c skin.c teamplay.c # Software-rendering clients diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index e929ad429..70543b184 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -883,12 +883,12 @@ CL_ConnectionlessPacket (void) Con_Printf ("Command packet from remote host. Ignored.\n"); return; } - s = MSG_ReadString (net_message); + s = MSG_ReadStaticString (net_message); strncpy (cmdtext, s, sizeof (cmdtext) - 1); cmdtext[sizeof (cmdtext) - 1] = 0; - s = MSG_ReadString (net_message); + s = MSG_ReadStaticString (net_message); while (*s && isspace ((int) *s)) s++; @@ -923,7 +923,7 @@ CL_ConnectionlessPacket (void) } // print command from somewhere if (c == A2C_PRINT) { - s = MSG_ReadString (net_message); + s = MSG_ReadStaticString (net_message); if (SL_CheckStatus(NET_AdrToString (net_from), s)) { Con_Printf("status response\n"); @@ -952,7 +952,7 @@ CL_ConnectionlessPacket (void) if (c == S2C_CHALLENGE) { Con_Printf ("challenge\n"); - s = MSG_ReadString (net_message); + s = MSG_ReadStaticString (net_message); cls.challenge = atoi (s); if (strstr (s, "QF")) CL_AddQFInfoKeys (); @@ -964,7 +964,7 @@ CL_ConnectionlessPacket (void) { Con_Printf("Master Server Reply\n"); clcp_temp = MSG_ReadByte (net_message); - s = MSG_ReadString (net_message); + s = MSG_ReadStaticString (net_message); MSL_ParseServerList(s); return; } diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 8441f7c6a..534e8ee4a 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -64,6 +64,7 @@ static const char rcsid[] = #include "client.h" #include "compat.h" #include "host.h" +#include "net_svc.h" #include "pmove.h" #include "protocol.h" #include "sbar.h" @@ -427,7 +428,7 @@ CL_ParseDownload (void) } if (size == -2) { - char *newname = MSG_ReadString (net_message); + const char *newname = MSG_ReadString (net_message); if (strncmp (newname, cls.downloadname, strlen (cls.downloadname)) || strstr (newname + strlen (cls.downloadname), "/")) { @@ -612,7 +613,7 @@ void CL_ParseServerData (void) { char fn[MAX_OSPATH]; - char *str; + const char *str; int protover; qboolean cflag = false; @@ -724,16 +725,15 @@ CL_ClearBaselines (void) void CL_ParseSoundlist (void) { - char *str; - int numsounds, n; + const char *str; + int numsounds, i; + net_svc_soundlist_t soundlist; // precache sounds -// memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); + NET_SVC_Soundlist_Parse (&soundlist, net_message); - numsounds = MSG_ReadByte (net_message); - - for (;;) { - str = MSG_ReadString (net_message); + for (i = 0, numsounds = soundlist.startsound;; i++) { + str = soundlist.sounds[i]; if (!str[0]) break; numsounds++; @@ -742,12 +742,11 @@ CL_ParseSoundlist (void) strcpy (cl.sound_name[numsounds], str); } - n = MSG_ReadByte (net_message); - - if (n) { + if (soundlist.nextsound) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (soundlist_name, cl.servercount, n)); + va (soundlist_name, cl.servercount, + soundlist.nextsound)); return; } @@ -759,44 +758,45 @@ CL_ParseSoundlist (void) void CL_ParseModellist (void) { - int nummodels, n; - char *str; + int nummodels, i; + const char *str; + net_svc_modellist_t modellist; // precache models and note certain default indexes - nummodels = MSG_ReadByte (net_message); + NET_SVC_Modellist_Parse (&modellist, net_message); - for (;;) { - str = MSG_ReadString (net_message); + for (i = 0, nummodels = modellist.startmodel;; i++) { + str = modellist.models[i]; if (!str[0]) break; nummodels++; if (nummodels == MAX_MODELS) Host_EndGame ("Server sent too many model_precache"); - strcpy (cl.model_name[nummodels], str); + strncpy (cl.model_name[nummodels], str, MAX_QPATH - 1); + cl.model_name[nummodels][MAX_QPATH - 1] = '\0'; - if (!strcmp (cl.model_name[nummodels], "progs/spike.mdl")) + if (!strcmp (str, "progs/spike.mdl")) cl_spikeindex = nummodels; - else if (!strcmp (cl.model_name[nummodels], "progs/player.mdl")) + else if (!strcmp (str, "progs/player.mdl")) cl_playerindex = nummodels; - else if (!strcmp (cl.model_name[nummodels], "progs/flag.mdl")) + else if (!strcmp (str, "progs/flag.mdl")) cl_flagindex = nummodels; // for deadbodyfilter & gibfilter - else if (!strcmp (cl.model_name[nummodels], "progs/h_player.mdl")) + else if (!strcmp (str, "progs/h_player.mdl")) cl_h_playerindex = nummodels; - else if (!strcmp (cl.model_name[nummodels], "progs/gib1.mdl")) + else if (!strcmp (str, "progs/gib1.mdl")) cl_gib1index = nummodels; - else if (!strcmp (cl.model_name[nummodels], "progs/gib2.mdl")) + else if (!strcmp (str, "progs/gib2.mdl")) cl_gib2index = nummodels; - else if (!strcmp (cl.model_name[nummodels], "progs/gib3.mdl")) + else if (!strcmp (str, "progs/gib3.mdl")) cl_gib3index = nummodels; } - n = MSG_ReadByte (net_message); - - if (n) { + if (modellist.nextmodel) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (modellist_name, cl.servercount, n)); + va (modellist_name, cl.servercount, + modellist.nextmodel)); return; } @@ -1099,7 +1099,7 @@ int received_framecount; void CL_ParseServerMessage (void) { - char *s; + const char *s; int cmd, i, j; received_framecount = host_framecount; @@ -1151,18 +1151,24 @@ CL_ParseServerMessage (void) Host_EndGame ("Server disconnected"); break; - case svc_print: + case svc_print: { + char p[2048]; + int j; i = MSG_ReadByte (net_message); s = MSG_ReadString (net_message); if (i == PRINT_CHAT) { // TODO: cl_nofake 2 -- accept fake messages from // teammates - char *p; if (cl_nofake->int_val) { - for (p = s; *p; p++) - if (*p == 13) - *p = '#'; + do { + p[j] = (s[j] == 13) ? '#' : s[j]; + if (j == sizeof (p) - 1) { + p[j] = '\0'; + break; + } + } while (s[j++]); + s = p; } con_ormask = 128; S_LocalSound ("misc/talk.wav"); @@ -1170,7 +1176,7 @@ CL_ParseServerMessage (void) Con_Printf ("%s", s); con_ormask = 0; break; - + } case svc_centerprint: SCR_CenterPrint (MSG_ReadString (net_message)); break; diff --git a/qw/source/net_packetlog.c b/qw/source/net_packetlog.c index 3e0e20401..022c32cfb 100644 --- a/qw/source/net_packetlog.c +++ b/qw/source/net_packetlog.c @@ -411,7 +411,7 @@ Analyze_Server_Packet (const byte * data, int len) void Parse_Server_Packet () { - char *s; + const char *s; int c, i, ii, iii, mask1, mask2; long seq1, seq2; @@ -626,7 +626,7 @@ Parse_Server_Packet () Net_LogPrintf ("**QW OBSOLETE**"); break; case svc_centerprint: - Net_LogPrintf (MSG_ReadString (&packet)); + Net_LogPrintf ("%s", MSG_ReadString (&packet)); break; case svc_killedmonster: break; diff --git a/qw/source/net_svc.c b/qw/source/net_svc.c new file mode 100644 index 000000000..415484cab --- /dev/null +++ b/qw/source/net_svc.c @@ -0,0 +1,87 @@ +/* + net_svc.c + + (description) + + Copyright (C) 2001 Adam Olsen + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +static const char rcsid[] = + "$Id$"; + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifndef _WIN32 +# ifdef HAVE_UNISTD_H +# include +# endif +#else +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/msg.h" + +#include "compat.h" +#include "net_svc.h" + +void +NET_SVC_Soundlist_Parse (net_svc_soundlist_t *soundlist, msg_t *message) +{ + int i; + + soundlist->startsound = MSG_ReadByte (message); + + for (i = 0; i < MAX_MODELS; i++) { + soundlist->sounds[i] = MSG_ReadString (message); + if (!*soundlist->sounds[i]) + break; + } + // this is a bit redundant, but I think the robustness is a good thing + soundlist->sounds[MAX_SOUNDS] = ""; + + soundlist->nextsound = MSG_ReadByte (message); +} + +void +NET_SVC_Modellist_Parse (net_svc_modellist_t *modellist, msg_t *message) +{ + int i; + + modellist->startmodel = MSG_ReadByte (message); + + for (i = 0; i < MAX_MODELS; i++) { + modellist->models[i] = MSG_ReadString (message); + if (!*modellist->models[i]) + break; + } + // this is a bit redundant, but I think the robustness is a good thing + modellist->models[MAX_MODELS] = ""; + + modellist->nextmodel = MSG_ReadByte (message); +} + diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 2120b041d..e137af464 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -1673,7 +1673,7 @@ void SV_ExecuteClientMessage (client_t *cl) { int c; - char *s; + const char *s; usercmd_t oldest, oldcmd, newcmd; client_frame_t *frame; vec3_t o;