Skip to content

Commit

Permalink
engine: server: pregenerate CRC table and testpacket data
Browse files Browse the repository at this point in the history
  • Loading branch information
a1batross committed Jun 13, 2023
1 parent 996897e commit 9c62fa9
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 25 deletions.
7 changes: 7 additions & 0 deletions engine/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,13 @@ typedef struct
entity_state_t *static_entities; // [MAX_STATIC_ENTITIES];

challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting

sizebuf_t testpacket; // pregenerataed testpacket, only needs CRC32 patching
byte *testpacket_buf; // check for NULL if testpacket is available
byte *testpacket_crcpos; // pointer to write pregenerated crc (unaligned!!!)
uint32_t *testpacket_crcs; // checksums lookup table
int testpacket_filepos; // file position (need to calculate lookup table pos)
int testpacket_filelen; // file and lookup table length
} server_static_t;

//=============================================================================
Expand Down
43 changes: 18 additions & 25 deletions engine/server/sv_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -832,14 +832,10 @@ SV_TestBandWidth
*/
void SV_TestBandWidth( netadr_t from )
{
int version = Q_atoi( Cmd_Argv( 1 ));
int packetsize = Q_atoi( Cmd_Argv( 2 ));
byte send_buf[FRAGMENT_MAX_SIZE];
dword crcValue = 0;
byte *filepos;
int crcpos;
file_t *test;
sizebuf_t send;
const int version = Q_atoi( Cmd_Argv( 1 ));
const int packetsize = Q_atoi( Cmd_Argv( 2 ));
uint32_t crc;
int ofs;

// don't waste time of protocol mismatched
if( version != PROTOCOL_VERSION )
Expand All @@ -848,32 +844,29 @@ void SV_TestBandWidth( netadr_t from )
return;
}

test = FS_Open( "gfx.wad", "rb", false );

if( FS_FileLength( test ) < sizeof( send_buf ))
// quickly reject invalid packets
if( !svs.testpacket_buf ||
( packetsize <= FRAGMENT_MIN_SIZE ) ||
( packetsize > FRAGMENT_MAX_SIZE ))
{
// skip the test and just get challenge
SV_GetChallenge( from );
return;
}

// write the packet header
MSG_Init( &send, "BandWidthPacket", send_buf, sizeof( send_buf ));
MSG_WriteLong( &send, -1 ); // -1 sequence means out of band
MSG_WriteString( &send, "testpacket" );
crcpos = MSG_GetNumBytesWritten( &send );
MSG_WriteLong( &send, 0 ); // reserve space for crc
filepos = send.pData + MSG_GetNumBytesWritten( &send );
packetsize = packetsize - MSG_GetNumBytesWritten( &send ); // adjust the packet size
FS_Read( test, filepos, packetsize );
FS_Close( test );
// don't go out of bounds
ofs = packetsize - svs.testpacket_filepos - 1;
if(( ofs < 0 ) || ( ofs > svs.testpacket_filelen ))
{
SV_GetChallenge( from );
return;
}

CRC32_ProcessBuffer( &crcValue, filepos, packetsize ); // calc CRC
MSG_SeekToBit( &send, packetsize << 3, SEEK_CUR );
*(uint *)&send.pData[crcpos] = crcValue;
crc = svs.testpacket_crcs[ofs];
memcpy( svs.testpacket_crcpos, &crc, sizeof( crc ));

// send the datagram
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), from );
NET_SendPacket( NS_SERVER, packetsize, MSG_GetData( &svs.testpacket ), from );
}

/*
Expand Down
74 changes: 74 additions & 0 deletions engine/server/sv_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,77 @@ static qboolean CRC32_MapFile( dword *crcvalue, const char *filename, qboolean m
return 1;
}

/*
================
SV_GenerateTestPacket
================
*/
static void SV_GenerateTestPacket( void )
{
const int maxsize = FRAGMENT_MAX_SIZE;
uint32_t crc;
file_t *file;
byte *filepos;
int i, filesize;

// testpacket already generated once, exit
// testpacket and lookup table takes ~300k of memory
// disable for low memory mode
if( svs.testpacket_buf || XASH_LOW_MEMORY >= 0 )
return;

// don't need in singleplayer with full client
if( svs.maxclients <= 1 && !Host_IsDedicated( ))
return;

file = FS_Open( "gfx.wad", "rb", false );
if( FS_FileLength( file ) < maxsize )
{
FS_Close( file );
return;
}

svs.testpacket_buf = Mem_Malloc( host.mempool, sizeof( *svs.testpacket_buf ) * maxsize );

// write packet base data
MSG_Init( &svs.testpacket, "BandWidthTest", svs.testpacket_buf, maxsize );
MSG_WriteLong( &svs.testpacket, -1 );
MSG_WriteString( &svs.testpacket, "testpacket" );
svs.testpacket_crcpos = svs.testpacket.pData + MSG_GetNumBytesWritten( &svs.testpacket );
MSG_WriteDword( &svs.testpacket, 0 ); // to be changed by crc

// time to read our file
svs.testpacket_filepos = MSG_GetNumBytesWritten( &svs.testpacket );
svs.testpacket_filelen = maxsize - svs.testpacket_filepos;

filepos = svs.testpacket.pData + svs.testpacket_filepos;
FS_Read( file, filepos, svs.testpacket_filelen );
FS_Close( file );

// now generate checksums lookup table
svs.testpacket_crcs = Mem_Malloc( host.mempool, sizeof( *svs.testpacket_crcs ) * svs.testpacket_filelen );
crc = 0; // intentional omit of CRC32_Init because of the client

// TODO: shrink to minimum!
for( i = 0; i < svs.testpacket_filelen; i++ )
{
uint32_t crc2;

CRC32_ProcessByte( &crc, filepos[i] );
svs.testpacket_crcs[i] = crc;
#if 0
// test
crc2 = 0;
CRC32_ProcessBuffer( &crc2, filepos, i + 1 );
if( svs.testpacket_crcs[i] != crc2 )
{
Con_Printf( "%d: 0x%x != 0x%x\n", i, svs.testpacket_crcs[i], crc2 );
svs.testpacket_crcs[i] = crc = crc2;
}
#endif
}
}

/*
================
SV_SpawnServer
Expand Down Expand Up @@ -1026,6 +1097,9 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
// clear physics interaction links
SV_ClearWorld();

// pregenerate test packet
SV_GenerateTestPacket();

return true;
}

Expand Down

0 comments on commit 9c62fa9

Please sign in to comment.