Skip to content

Commit

Permalink
client: send pending fragments before queueing new ones
Browse files Browse the repository at this point in the history
server: removed redundant sv.checksumFeedServerId
server: save latched sv_pure state to dedicated variable
  • Loading branch information
ec- committed Jun 26, 2024
1 parent ee60b5d commit 8d1636c
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 53 deletions.
8 changes: 7 additions & 1 deletion code/client/cl_net_chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,14 @@ CL_Netchan_Enqueue
void CL_Netchan_Enqueue( netchan_t *chan, msg_t* msg, int times ) {
int i;

if ( chan->compat )
// make sure we send all pending fragments to get correct chan->outgoingSequence
while ( CL_Netchan_TransmitNextFragment( chan ) ) {
;
}

if ( chan->compat ) {
CL_Netchan_Encode( msg );
}

for ( i = 0; i < times; i++ ) {
Netchan_Enqueue( chan, msg->cursize, msg->data );
Expand Down
41 changes: 17 additions & 24 deletions code/qcommon/net_chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,17 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) {
EnqueueFragments
=================
*/
void Netchan_EnqueueFragments( netchan_t *chan ) {
static void Netchan_EnqueueFragments( const netchan_t *chan, const int length, const byte *data ) {
msg_t send;
byte send_buf[MAX_PACKETLEN + 8];
int fragmentLength;
int outgoingSequence;
int unsentFragmentStart = 0;

for ( ;; ) {
// write the packet header
MSG_InitOOB( &send, send_buf, sizeof( send_buf ) - 8 );

outgoingSequence = chan->outgoingSequence | FRAGMENT_BIT;
MSG_WriteLong( &send, outgoingSequence );
MSG_WriteLong( &send, chan->outgoingSequence | FRAGMENT_BIT );

// send the qport if we are a client
if ( chan->sock == NS_CLIENT ) {
Expand All @@ -192,27 +191,26 @@ void Netchan_EnqueueFragments( netchan_t *chan ) {

// copy the reliable message to the packet first
fragmentLength = FRAGMENT_SIZE;
if ( chan->unsentFragmentStart + fragmentLength > chan->unsentLength ) {
fragmentLength = chan->unsentLength - chan->unsentFragmentStart;
if ( unsentFragmentStart + fragmentLength > length ) {
fragmentLength = length - unsentFragmentStart;
}

MSG_WriteShort( &send, chan->unsentFragmentStart );
MSG_WriteShort( &send, unsentFragmentStart );
MSG_WriteShort( &send, fragmentLength );
MSG_WriteData( &send, chan->unsentBuffer + chan->unsentFragmentStart, fragmentLength );
MSG_WriteData( &send, data + unsentFragmentStart, fragmentLength );

// enqueue the datagram
NET_QueuePacket( 1 /*queue index*/, chan->sock, send.cursize, send.data, &chan->remoteAddress, 0 /*offset*/ );

// TODO: add showpackets debug info

chan->unsentFragmentStart += fragmentLength;
unsentFragmentStart += fragmentLength;

// this exit condition is a little tricky, because a packet
// that is exactly the fragment length still needs to send
// a second packet of zero length so that the other side
// can tell there aren't more to follow
if ( chan->unsentFragmentStart == chan->unsentLength && fragmentLength != FRAGMENT_SIZE ) {
chan->unsentFragments = qfalse;
if ( unsentFragmentStart == length && fragmentLength != FRAGMENT_SIZE ) {
break;
}
}
Expand Down Expand Up @@ -297,15 +295,9 @@ void Netchan_Enqueue( netchan_t *chan, int length, const byte *data ) {
Com_Error( ERR_DROP, "%s: length = %i", __func__, length );
}

chan->unsentFragmentStart = 0;

// fragment large reliable messages
if ( length >= FRAGMENT_SIZE ) {
chan->unsentFragments = qtrue;
chan->unsentLength = length;
Com_Memcpy( chan->unsentBuffer, data, length );

Netchan_EnqueueFragments( chan );
Netchan_EnqueueFragments( chan, length, data );
return;
}

Expand Down Expand Up @@ -575,12 +567,13 @@ static void NET_SendLoopPacket( netsrc_t sock, int length, const void *data )
//=============================================================================

typedef struct packetQueue_s {
struct packetQueue_s *next;
int length;
byte *data;
netadr_t to;
netsrc_t sock;
int release;
struct packetQueue_s *next;
struct packetQueue_s *prev;
int length;
byte *data;
netadr_t to;
netsrc_t sock;
int release;
} packetQueue_t;

static packetQueue_t *packetQueue[2] = { NULL, NULL };
Expand Down
1 change: 0 additions & 1 deletion code/qcommon/qcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,6 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, const netadr_t *adr, int por
void Netchan_Transmit( netchan_t *chan, int length, const byte *data );
void Netchan_TransmitNextFragment( netchan_t *chan );
void Netchan_Enqueue( netchan_t *chan, int length, const byte *data );
void Netchan_EnqueueFragments( netchan_t *chan );

qboolean Netchan_Process( netchan_t *chan, msg_t *msg );

Expand Down
4 changes: 1 addition & 3 deletions code/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,10 @@ typedef struct snapshotFrame_s {
typedef struct {
serverState_t state;
qboolean restarting; // if true, send configstring changes during SS_LOADING
int pure;
int serverId; // changes each server start
int restartedServerId; // changes each map restart
int checksumFeed; // the feed key that we use to compute the pure checksum strings
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
// the serverId associated with the current checksumFeed (always <= serverId)
int checksumFeedServerId;
int snapshotCounter; // incremented for each snapshot built
int timeResidual; // <= 1000 / sv_frame->value
char *configstrings[MAX_CONFIGSTRINGS];
Expand Down
2 changes: 1 addition & 1 deletion code/server/sv_ccmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -1517,7 +1517,7 @@ SV_CompleteMapName
*/
static void SV_CompleteMapName( const char *args, int argNum ) {
if ( argNum == 2 ) {
if ( sv_pure->integer ) {
if ( sv.pure != 0 ) {
Field_CompleteFilename( "maps", "bsp", qtrue, FS_MATCH_PK3s | FS_MATCH_STICK );
} else {
Field_CompleteFilename( "maps", "bsp", qtrue, FS_MATCH_ANY | FS_MATCH_STICK );
Expand Down
35 changes: 16 additions & 19 deletions code/server/sv_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,15 @@ static void SV_SendClientGameState( client_t *client ) {
if ( *sv.configstrings[ start ] != '\0' ) {
MSG_WriteByte( &msg, svc_configstring );
MSG_WriteShort( &msg, start );
MSG_WriteBigString( &msg, sv.configstrings[ start ] );
if ( start == CS_SYSTEMINFO && sv.pure != sv_pure->integer ) {
// make sure we send latched sv.pure, not forced cvar value
char systemInfo[BIG_INFO_STRING];
Q_strncpyz( systemInfo, sv.configstrings[ start ], sizeof( systemInfo ) );
Info_SetValueForKey_s( systemInfo, sizeof( systemInfo ), "sv_pure", va( "%i", sv.pure ) );
MSG_WriteBigString( &msg, systemInfo );
} else {
MSG_WriteBigString( &msg, sv.configstrings[start] );
}
}
client->csUpdated[ start ] = qfalse;
}
Expand Down Expand Up @@ -1214,7 +1222,7 @@ static void SV_DoneDownload_f( client_t *cl ) {
if ( cl->state == CS_ACTIVE )
return;

Com_DPrintf( "clientDownload: %s Done\n", cl->name);
Com_DPrintf( "clientDownload: %s Done\n", cl->name );

// resend the game state to update any clients that entered during the download
SV_SendClientGameState( cl );
Expand Down Expand Up @@ -1359,7 +1367,7 @@ static int SV_WriteDownloadToClient( client_t *cl )
(sv_allowDownload->integer & DLF_NO_UDP) ) {

Com_Printf("clientDownload: %d : \"%s\" download disabled\n", (int) (cl - svs.clients), cl->downloadName);
if (sv_pure->integer) {
if ( sv.pure != 0 ) {
Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n"
"You will need to get this file elsewhere before you "
"can connect to this pure server.\n", cl->downloadName);
Expand Down Expand Up @@ -1578,7 +1586,7 @@ static void SV_VerifyPaks_f( client_t *cl ) {
// certain pk3 files, namely we want the client to have loaded the
// ui and cgame that we think should be loaded based on the pure setting
//
if ( sv_pure->integer != 0 ) {
if ( sv.pure != 0 ) {

nChkSum1 = nChkSum2 = 0;

Expand All @@ -1600,11 +1608,8 @@ static void SV_VerifyPaks_f( client_t *cl ) {
}
else
{
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
// we may get incoming cp sequences from a previous checksumFeed, which we need to ignore
// since serverId is a frame count, it always goes up
if ( atoi( pArg ) - sv.checksumFeedServerId < 0 )
{
// we may get incoming cp sequences from a previous serverId, which we need to ignore
if ( atoi( pArg ) != sv.serverId /* || !cl->gamestateAcked */ ) {
Com_DPrintf( "ignoring outdated cp command from client %s\n", cl->name );
return;
}
Expand Down Expand Up @@ -2149,7 +2154,7 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
// if this is the first usercmd we have received
// this gamestate, put the client into the world
if ( cl->state == CS_PRIMED ) {
if ( sv_pure->integer != 0 && !cl->gotCP ) {
if ( sv.pure != 0 && !cl->gotCP ) {
// we didn't get a cp yet, don't assume anything and just send the gamestate all over again
if ( !SVC_RateLimit( &cl->gamestate_rate, 2, 1000 ) ) {
Com_DPrintf( "%s: didn't get cp command, resending gamestate\n", cl->name );
Expand All @@ -2162,15 +2167,7 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
}

// a bad cp command was sent, drop the client
if ( sv_pure->integer != 0 && !cl->pureAuthentic ) {
#ifndef DEDICATED
if ( !cl->gotCP && cl->state == CS_ACTIVE && cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
// fix host player being dropped with ZTM' FlexibleHud at level end in TA SP
// FIXME: exact reason how cl->pureAuthentic being reset is unclear, should be investigated later
Com_DPrintf( "%s: didn't get cp command, resending gamestate\n", cl->name );
SV_SendClientGameState( cl );
} else
#endif
if ( sv.pure != 0 && !cl->pureAuthentic ) {
SV_DropClient( cl, "Cannot validate pure client!" );
return;
}
Expand Down
8 changes: 5 additions & 3 deletions code/server/sv_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,10 @@ void SV_SpawnServer( const char *mapname, qboolean killBots ) {
#endif

// get latched value
Cvar_Get( "sv_pure", "1", CVAR_SYSTEMINFO | CVAR_LATCH );
sv_pure = Cvar_Get( "sv_pure", "1", CVAR_SYSTEMINFO | CVAR_LATCH );

// VMs can change latched cvars instantly which could cause side-effects in SV_UserMove()
sv.pure = sv_pure->integer;

// get a new checksum feed and restart the file system
srand( Com_Milliseconds() );
Expand All @@ -512,7 +515,6 @@ void SV_SpawnServer( const char *mapname, qboolean killBots ) {
// serverid should be different each time
sv.serverId = com_frameTime;
sv.restartedServerId = sv.serverId;
sv.checksumFeedServerId = sv.serverId;
Cvar_SetIntegerValue( "sv_serverid", sv.serverId );

// clear physics interaction links
Expand Down Expand Up @@ -611,7 +613,7 @@ void SV_SpawnServer( const char *mapname, qboolean killBots ) {
Cvar_Set( "sv_paks", "" );
Cvar_Set( "sv_pakNames", "" ); // not used on client-side

if ( sv_pure->integer ) {
if ( sv.pure != 0 ) {
int freespace, pakslen, infolen;
qboolean overflowed = qfalse;
qboolean infoTruncated = qfalse;
Expand Down
2 changes: 1 addition & 1 deletion code/server/sv_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ static void SVC_Info( const netadr_t *from ) {
Info_SetValueForKey( infostring, "sv_maxclients",
va("%i", sv_maxclients->integer - sv_privateClients->integer ) );
Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) );
Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );
Info_SetValueForKey( infostring, "pure", va("%i", sv.pure) );
Info_SetValueForKey(infostring, "g_needpass", va("%d", Cvar_VariableIntegerValue("g_needpass")));
gamedir = Cvar_VariableString( "fs_game" );
if( *gamedir ) {
Expand Down

0 comments on commit 8d1636c

Please sign in to comment.