engine: server: pregenerate CRC table and testpacket data

This commit is contained in:
Alibek Omarov 2023-06-14 00:35:07 +03:00
parent 996897e30e
commit 9c62fa901f
3 changed files with 99 additions and 25 deletions

View File

@ -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;
//=============================================================================

View File

@ -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 )
@ -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 );
}
/*

View File

@ -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
@ -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;
}