Skip to content

Commit e9ac890

Browse files
committed
Fix buggy config string transmitting ('bcsN')
The bcs0, bcs1, and bcs2 commands are used to transmit an info string that has more than a certain length. The old code chopped them into pieces based on the original length rather than the escaped length and provided only a fixed amount of overhead for escape characters. Turns out the overhead wasn't enough for real-life use cases (there are a lot of backslashes due to infostring separators) and so the command to send the serverinfo configstring would sometimes overflow and be silently dropped. Fix this by chopping up the string based on the escaped length.
1 parent e58c771 commit e9ac890

File tree

1 file changed

+41
-39
lines changed

1 file changed

+41
-39
lines changed

src/engine/server/sv_init.cpp

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,49 @@ void SV_SetConfigstring( int index, const char *val )
8282
sv.configstringsmodified[ index ] = true;
8383
}
8484

85+
static void SendConfigStringToClient( int cs, client_t *cl )
86+
{
87+
char buf[ 1024 ]; // escaped characters, in a quoted context
88+
// max command size for SV_SendServerCommand is 1022, leave a little overhead for the command
89+
char *limit = buf + 990;
90+
91+
char *out = buf;
92+
bool first = true;
93+
94+
for ( const char *in = sv.configstrings[ cs ]; ; )
95+
{
96+
char c = *in++;
97+
98+
// '$' does not need to be escaped as it is not interpreted in the context of a server command
99+
if ( c == '\\' || c == '"' )
100+
{
101+
*out++ = '\\';
102+
}
103+
104+
*out++ = c;
105+
106+
if ( !*in )
107+
{
108+
break;
109+
}
110+
111+
if ( out >= limit )
112+
{
113+
*out = '\0';
114+
SV_SendServerCommand( cl, "%s %d \"%s\"", first ? "bcs0" : "bcs1", cs, buf );
115+
first = false;
116+
out = buf;
117+
}
118+
}
119+
120+
*out = '\0';
121+
SV_SendServerCommand( cl, "%s %d \"%s\"", first ? "cs" : "bcs2", cs, buf );
122+
}
123+
85124
void SV_UpdateConfigStrings()
86125
{
87-
int len, i, index;
126+
int i, index;
88127
client_t *client;
89-
int maxChunkSize = MAX_STRING_CHARS - 64;
90128

91129
for ( index = 0; index < MAX_CONFIGSTRINGS; index++ )
92130
{
@@ -101,8 +139,6 @@ void SV_UpdateConfigStrings()
101139
// spawning a new server
102140
if ( sv.state == serverState_t::SS_GAME || sv.restarting )
103141
{
104-
len = strlen( sv.configstrings[ index ] );
105-
106142
// send the data to all relevent clients
107143
for ( i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++ )
108144
{
@@ -117,41 +153,7 @@ void SV_UpdateConfigStrings()
117153
continue;
118154
}
119155

120-
if ( len >= maxChunkSize )
121-
{
122-
int sent = 0;
123-
int remaining = len;
124-
const char *cmd;
125-
char buf[ MAX_STRING_CHARS ];
126-
127-
while ( remaining > 0 )
128-
{
129-
if ( sent == 0 )
130-
{
131-
cmd = "bcs0";
132-
}
133-
else if ( remaining < maxChunkSize )
134-
{
135-
cmd = "bcs2";
136-
}
137-
else
138-
{
139-
cmd = "bcs1";
140-
}
141-
142-
Q_strncpyz( buf, &sv.configstrings[ index ][ sent ], maxChunkSize );
143-
144-
SV_SendServerCommand( client, "%s %i %s\n", cmd, index, Cmd_QuoteString( buf ) );
145-
146-
sent += ( maxChunkSize - 1 );
147-
remaining -= ( maxChunkSize - 1 );
148-
}
149-
}
150-
else
151-
{
152-
// standard cs, just send it
153-
SV_SendServerCommand( client, "cs %i %s\n", index, Cmd_QuoteString( sv.configstrings[ index ] ) );
154-
}
156+
SendConfigStringToClient( index, client );
155157
}
156158
}
157159
}

0 commit comments

Comments
 (0)