Browse Source

Merge pull request #22 from FWGS/netsplit

Extended netsplit, network extensions
pull/2/head
Alibek Omarov 6 years ago committed by GitHub
parent
commit
6a6f341c07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 75
      engine/client/cl_main.c
  2. 3
      engine/client/client.h
  3. 34
      engine/common/net_chan.c
  4. 54
      engine/common/net_ws.c
  5. 2
      engine/common/net_ws.h
  6. 19
      engine/common/netchan.h
  7. 7
      engine/common/protocol.h
  8. 1
      engine/server/server.h
  9. 50
      engine/server/sv_client.c

75
engine/client/cl_main.c

@ -65,6 +65,8 @@ convar_t *cl_showevents;
convar_t *cl_cmdrate; convar_t *cl_cmdrate;
convar_t *cl_interp; convar_t *cl_interp;
convar_t *cl_dlmax; convar_t *cl_dlmax;
convar_t *cl_upmax;
convar_t *cl_lw; convar_t *cl_lw;
convar_t *cl_charset; convar_t *cl_charset;
convar_t *cl_trace_messages; convar_t *cl_trace_messages;
@ -197,12 +199,18 @@ void CL_CheckClientState( void )
} }
} }
int CL_GetFragmentSize( void *unused ) int CL_GetFragmentSize( void *unused, fragsize_t mode )
{ {
if( mode == FRAGSIZE_SPLIT )
return 0;
if( mode == FRAGSIZE_UNRELIABLE )
return NET_MAX_MESSAGE;
if( Netchan_IsLocal( &cls.netchan )) if( Netchan_IsLocal( &cls.netchan ))
return FRAGMENT_LOCAL_SIZE; return FRAGMENT_LOCAL_SIZE;
return FRAGMENT_MIN_SIZE; return cl_upmax->value;
} }
/* /*
@ -1017,10 +1025,12 @@ void CL_SendConnectPacket( void )
{ {
// set related userinfo keys // set related userinfo keys
if( cl_dlmax->value >= 40000 || cl_dlmax->value < 100 ) if( cl_dlmax->value >= 40000 || cl_dlmax->value < 100 )
Cvar_FullSet( "cl_maxpacket", "1400", FCVAR_USERINFO ); Info_SetValueForKey( cls.userinfo, "cl_maxpacket", "1400", sizeof( cls.userinfo ) );
else else
Cvar_FullSet( "cl_maxpacket", cl_dlmax->string, FCVAR_USERINFO ); Info_SetValueForKey( cls.userinfo, "cl_maxpacket", cl_dlmax->string, sizeof( cls.userinfo ) );
Cvar_FullSet( "cl_maxpayload", "1000", FCVAR_USERINFO );
if( !*Info_ValueForKey( cls.userinfo,"cl_maxpayload") )
Info_SetValueForKey( cls.userinfo, "cl_maxpayload", "1000", sizeof( cls.userinfo ) );
/// TODO: add input devices list /// TODO: add input devices list
//Info_SetValueForKey( protinfo, "d", va( "%d", input_devices ), sizeof( protinfo ) ); //Info_SetValueForKey( protinfo, "d", va( "%d", input_devices ), sizeof( protinfo ) );
@ -1030,17 +1040,24 @@ void CL_SendConnectPacket( void )
Info_SetValueForKey( protinfo, "a", Q_buildarch(), sizeof( protinfo ) ); Info_SetValueForKey( protinfo, "a", Q_buildarch(), sizeof( protinfo ) );
Info_SetValueForKey( protinfo, "i", ID_GetMD5(), sizeof( protinfo ) ); Info_SetValueForKey( protinfo, "i", ID_GetMD5(), sizeof( protinfo ) );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i %i \"%s\" 2 \"%s\"\n", Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i %i \"%s\" %d \"%s\"\n",
PROTOCOL_LEGACY_VERSION, Q_atoi( qport ), cls.challenge, cls.userinfo, protinfo ); PROTOCOL_LEGACY_VERSION, Q_atoi( qport ), cls.challenge, cls.userinfo, NET_LEGACY_EXT_SPLIT, protinfo );
Con_Printf( "Trying to connect by legacy protocol\n" ); Con_Printf( "Trying to connect by legacy protocol\n" );
} }
else else
{ {
// remove useless userinfo keys int extensions = NET_EXT_SPLITSIZE;
Cvar_FullSet( "cl_maxpacket", "0", 0 );
Cvar_FullSet( "cl_maxpayload", "1000", 0 ); if( cl_dlmax->value > FRAGMENT_MAX_SIZE || cl_dlmax->value < FRAGMENT_MIN_SIZE )
Cvar_SetValue( "cl_dlmax", FRAGMENT_DEFAULT_SIZE );
Info_RemoveKey( cls.userinfo,"cl_maxpacket" );
Info_RemoveKey( cls.userinfo, "cl_maxpayload" );
Info_SetValueForKey( protinfo, "uuid", key, sizeof( protinfo )); Info_SetValueForKey( protinfo, "uuid", key, sizeof( protinfo ));
Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo )); Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo ));
Info_SetValueForKey( protinfo, "ext", va("%d", extensions), sizeof( protinfo ));
Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, cls.challenge, protinfo, cls.userinfo ); Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, cls.challenge, protinfo, cls.userinfo );
Con_Printf( "Trying to connect by modern protocol\n" ); Con_Printf( "Trying to connect by modern protocol\n" );
} }
@ -1364,6 +1381,24 @@ void CL_SendDisconnectMessage( void )
Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf )); Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf ));
} }
int CL_GetSplitSize( void )
{
int splitsize;
if( Host_IsDedicated() )
return 0;
if( !(cls.extensions & NET_EXT_SPLITSIZE) )
return 1400;
splitsize = cl_dlmax->value;
if( splitsize < FRAGMENT_MIN_SIZE || splitsize > FRAGMENT_MAX_SIZE )
Cvar_SetValue( "cl_dlmax", FRAGMENT_DEFAULT_SIZE );
return cl_dlmax->value;
}
/* /*
===================== =====================
CL_Reconnect CL_Reconnect
@ -1381,13 +1416,22 @@ void CL_Reconnect( qboolean setup_netchan )
{ {
unsigned int extensions = Q_atoi( Cmd_Argv( 1 ) ); unsigned int extensions = Q_atoi( Cmd_Argv( 1 ) );
if( extensions & NET_EXT_SPLIT ) if( extensions & NET_LEGACY_EXT_SPLIT )
{ {
// only enable incoming split for legacy mode // only enable incoming split for legacy mode
cls.netchan.split = true; cls.netchan.split = true;
Con_Reportf( "^2NET_EXT_SPLIT enabled^7 (packet sizes is %d/%d)\n", (int)cl_dlmax->value, 65536 ); Con_Reportf( "^2NET_EXT_SPLIT enabled^7 (packet sizes is %d/%d)\n", (int)cl_dlmax->value, 65536 );
} }
} }
else
{
cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" ));
if( cls.extensions & NET_EXT_SPLITSIZE )
{
Con_Reportf( "^2NET_EXT_SPLITSIZE enabled^7 (packet size is %d)\n", (int)cl_dlmax->value );
}
}
} }
else else
@ -1892,7 +1936,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
// too many fails use default connection method // too many fails use default connection method
Con_Printf( "hi-speed connection is failed, use default method\n" ); Con_Printf( "hi-speed connection is failed, use default method\n" );
Netchan_OutOfBandPrint( NS_CLIENT, from, "getchallenge\n" ); Netchan_OutOfBandPrint( NS_CLIENT, from, "getchallenge\n" );
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE ); Cvar_SetValue( "cl_dlmax", FRAGMENT_DEFAULT_SIZE );
cls.connect_time = host.realtime; cls.connect_time = host.realtime;
return; return;
} }
@ -2698,7 +2742,8 @@ void CL_InitLocal( void )
name = Cvar_Get( "name", Sys_GetCurrentUser(), FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_PRINTABLEONLY, "player name" ); name = Cvar_Get( "name", Sys_GetCurrentUser(), FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_PRINTABLEONLY, "player name" );
model = Cvar_Get( "model", "", FCVAR_USERINFO|FCVAR_ARCHIVE, "player model ('player' is a singleplayer model)" ); model = Cvar_Get( "model", "", FCVAR_USERINFO|FCVAR_ARCHIVE, "player model ('player' is a singleplayer model)" );
cl_updaterate = Cvar_Get( "cl_updaterate", "20", FCVAR_USERINFO|FCVAR_ARCHIVE, "refresh rate of server messages" ); cl_updaterate = Cvar_Get( "cl_updaterate", "20", FCVAR_USERINFO|FCVAR_ARCHIVE, "refresh rate of server messages" );
cl_dlmax = Cvar_Get( "cl_dlmax", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "max allowed fragment size on download resources" ); cl_dlmax = Cvar_Get( "cl_dlmax", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "max allowed outcoming fragment size" );
cl_upmax = Cvar_Get( "cl_upmax", "1200", FCVAR_ARCHIVE, "max allowed incoming fragment size" );
rate = Cvar_Get( "rate", "3500", FCVAR_USERINFO|FCVAR_ARCHIVE, "player network rate" ); rate = Cvar_Get( "rate", "3500", FCVAR_USERINFO|FCVAR_ARCHIVE, "player network rate" );
topcolor = Cvar_Get( "topcolor", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "player top color" ); topcolor = Cvar_Get( "topcolor", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "player top color" );
bottomcolor = Cvar_Get( "bottomcolor", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "player bottom color" ); bottomcolor = Cvar_Get( "bottomcolor", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "player bottom color" );
@ -2708,10 +2753,6 @@ void CL_InitLocal( void )
Cvar_Get( "team", "", FCVAR_USERINFO, "player team" ); Cvar_Get( "team", "", FCVAR_USERINFO, "player team" );
Cvar_Get( "skin", "", FCVAR_USERINFO, "player skin" ); Cvar_Get( "skin", "", FCVAR_USERINFO, "player skin" );
// legacy mode cvars (need this to add it to userinfo)
Cvar_Get( "cl_maxpacket", "0", 0, "legacy server compatibility" );
Cvar_Get( "cl_maxpayload", "1000", 0, "legacy server compatibility" );
cl_showfps = Cvar_Get( "cl_showfps", "1", FCVAR_ARCHIVE, "show client fps" ); cl_showfps = Cvar_Get( "cl_showfps", "1", FCVAR_ARCHIVE, "show client fps" );
cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", FCVAR_ARCHIVE, "disable smooth up stair climbing and interpolate position in multiplayer" ); cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", FCVAR_ARCHIVE, "disable smooth up stair climbing and interpolate position in multiplayer" );
cl_smoothtime = Cvar_Get( "cl_smoothtime", "0", FCVAR_ARCHIVE, "time to smooth up" ); cl_smoothtime = Cvar_Get( "cl_smoothtime", "0", FCVAR_ARCHIVE, "time to smooth up" );

3
engine/client/client.h

@ -665,6 +665,7 @@ typedef struct
netadr_t legacyserver; netadr_t legacyserver;
netadr_t legacyservers[MAX_LEGACY_SERVERS]; netadr_t legacyservers[MAX_LEGACY_SERVERS];
int legacyservercount; int legacyservercount;
int extensions;
} client_static_t; } client_static_t;
#ifdef __cplusplus #ifdef __cplusplus
@ -778,7 +779,7 @@ void CL_SendCommand( void );
void CL_Disconnect_f( void ); void CL_Disconnect_f( void );
void CL_ProcessFile( qboolean successfully_received, const char *filename ); void CL_ProcessFile( qboolean successfully_received, const char *filename );
void CL_WriteUsercmd( sizebuf_t *msg, int from, int to ); void CL_WriteUsercmd( sizebuf_t *msg, int from, int to );
int CL_GetFragmentSize( void *unused ); int CL_GetFragmentSize( void *unused , fragsize_t mode );
qboolean CL_PrecacheResources( void ); qboolean CL_PrecacheResources( void );
void CL_SetupOverviewParams( void ); void CL_SetupOverviewParams( void );
void CL_UpdateFrameLerp( void ); void CL_UpdateFrameLerp( void );

34
engine/common/net_chan.c

@ -302,7 +302,7 @@ Netchan_Setup
called to open a channel to a remote system called to open a channel to a remote system
============== ==============
*/ */
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void * )) void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ))
{ {
Netchan_Clear( chan ); Netchan_Clear( chan );
@ -710,7 +710,7 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
return; return;
if( chan->pfnBlockSize != NULL ) if( chan->pfnBlockSize != NULL )
chunksize = chan->pfnBlockSize( chan->client ); chunksize = chan->pfnBlockSize( chan->client, FRAGSIZE_FRAG );
else chunksize = FRAGMENT_MAX_SIZE; // fallback else chunksize = FRAGMENT_MAX_SIZE; // fallback
wait = (fragbufwaiting_t *)Mem_Calloc( net_mempool, sizeof( fragbufwaiting_t )); wait = (fragbufwaiting_t *)Mem_Calloc( net_mempool, sizeof( fragbufwaiting_t ));
@ -871,7 +871,7 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, const char *filenam
if( !size ) return; if( !size ) return;
if( chan->pfnBlockSize != NULL ) if( chan->pfnBlockSize != NULL )
chunksize = chan->pfnBlockSize( chan->client ); chunksize = chan->pfnBlockSize( chan->client, FRAGSIZE_FRAG );
else chunksize = FRAGMENT_MAX_SIZE; // fallback else chunksize = FRAGMENT_MAX_SIZE; // fallback
if( !LZSS_IsCompressed( pbuf )) if( !LZSS_IsCompressed( pbuf ))
@ -969,7 +969,7 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
} }
if( chan->pfnBlockSize != NULL ) if( chan->pfnBlockSize != NULL )
chunksize = chan->pfnBlockSize( chan->client ); chunksize = chan->pfnBlockSize( chan->client, FRAGSIZE_FRAG );
else chunksize = FRAGMENT_MAX_SIZE; // fallback else chunksize = FRAGMENT_MAX_SIZE; // fallback
Q_strncpy( compressedfilename, filename, sizeof( compressedfilename )); Q_strncpy( compressedfilename, filename, sizeof( compressedfilename ));
@ -1458,9 +1458,15 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
if( send_from_regular && ( send_from_frag[FRAG_NORMAL_STREAM] )) if( send_from_regular && ( send_from_frag[FRAG_NORMAL_STREAM] ))
{ {
send_from_regular = false; send_from_regular = false;
int maxsize = MAX_RELIABLE_PAYLOAD;
if( chan->pfnBlockSize )
maxsize = chan->pfnBlockSize( chan->client, FRAGSIZE_SPLIT );
if( maxsize == 0 )
maxsize = MAX_RELIABLE_PAYLOAD;
// if the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer // if the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer
if( MSG_GetNumBytesWritten( &chan->message ) > MAX_RELIABLE_PAYLOAD ) if( MSG_GetNumBytesWritten( &chan->message ) + (((uint)length) >> 3) > maxsize )
{ {
Netchan_CreateFragments_( chan, &chan->message ); Netchan_CreateFragments_( chan, &chan->message );
MSG_Clear( &chan->message ); MSG_Clear( &chan->message );
@ -1627,9 +1633,16 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
chan->last_reliable_sequence = chan->outgoing_sequence - 1; chan->last_reliable_sequence = chan->outgoing_sequence - 1;
} }
if( MSG_GetNumBitsLeft( &send ) >= length ) if( length )
MSG_WriteBits( &send, data, length ); {
else Con_Printf( S_WARN "Netchan_Transmit: unreliable message overflow\n" ); int maxsize = NET_MAX_MESSAGE;
if( chan->pfnBlockSize )
maxsize = chan->pfnBlockSize( chan->client, FRAGSIZE_UNRELIABLE );
if( MSG_GetNumBytesWritten( &send ) + length >> 3 <= maxsize )
MSG_WriteBits( &send, data, length );
else Con_Printf( S_WARN "Netchan_Transmit: unreliable message overflow: %d\n", MSG_GetNumBytesWritten( &send ) );
}
// deal with packets that are too small for some networks // deal with packets that are too small for some networks
if( MSG_GetNumBytesWritten( &send ) < 16 && !NET_IsLocalAddress( chan->remote_address )) // packet too small for some networks if( MSG_GetNumBytesWritten( &send ) < 16 && !NET_IsLocalAddress( chan->remote_address )) // packet too small for some networks
@ -1658,7 +1671,10 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
// send the datagram // send the datagram
if( !CL_IsPlaybackDemo( )) if( !CL_IsPlaybackDemo( ))
{ {
NET_SendPacket( chan->sock, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), chan->remote_address ); int splitsize = 0;
if( chan->pfnBlockSize )
splitsize = chan->pfnBlockSize( chan->client, FRAGSIZE_SPLIT );
NET_SendPacketEx( chan->sock, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), chan->remote_address, splitsize );
} }
if( SV_Active() && sv_lan.value && sv_lan_rate.value > 1000.0 ) if( SV_Active() && sv_lan.value && sv_lan_rate.value > 1000.0 )

54
engine/common/net_ws.c

@ -35,15 +35,16 @@ GNU General Public License for more details.
#include "netchan.h" #include "netchan.h"
#include "mathlib.h" #include "mathlib.h"
// #define NET_USE_FRAGMENTS #define NET_USE_FRAGMENTS
#define PORT_ANY -1 #define PORT_ANY -1
#define MAX_LOOPBACK 4 #define MAX_LOOPBACK 4
#define MASK_LOOPBACK (MAX_LOOPBACK - 1) #define MASK_LOOPBACK (MAX_LOOPBACK - 1)
#define MAX_ROUTEABLE_PACKET 1400 #define MAX_ROUTEABLE_PACKET 1400
#define SPLIT_SIZE ( MAX_ROUTEABLE_PACKET - sizeof( SPLITPACKET )) #define SPLITPACKET_MIN_SIZE 508 // RFC 791: 576(min ip packet) - 60 (ip header) - 8 (udp header)
#define NET_MAX_FRAGMENTS ( NET_MAX_FRAGMENT / SPLIT_SIZE ) #define SPLITPACKET_MAX_SIZE 64000
#define NET_MAX_FRAGMENTS ( NET_MAX_FRAGMENT / (SPLITPACKET_MIN_SIZE - sizeof( SPLITPACKET )) )
#ifndef _WIN32 // it seems we need to use WS2 to support it #ifndef _WIN32 // it seems we need to use WS2 to support it
#define HAVE_GETADDRINFO #define HAVE_GETADDRINFO
@ -1105,13 +1106,17 @@ NET_GetLong
receive long packet from network receive long packet from network
================== ==================
*/ */
qboolean NET_GetLong( byte *pData, int size, int *outSize ) qboolean NET_GetLong( byte *pData, int size, int *outSize, int splitsize )
{ {
int i, sequence_number, offset; int i, sequence_number, offset;
SPLITPACKET *pHeader = (SPLITPACKET *)pData; SPLITPACKET *pHeader = (SPLITPACKET *)pData;
int packet_number; int packet_number;
int packet_count; int packet_count;
short packet_id; short packet_id;
int body_size = splitsize - sizeof( SPLITPACKET );
if( body_size < 0 )
return false;
if( size < sizeof( SPLITPACKET )) if( size < sizeof( SPLITPACKET ))
{ {
@ -1149,7 +1154,7 @@ qboolean NET_GetLong( byte *pData, int size, int *outSize )
if( net.split_flags[packet_number] != sequence_number ) if( net.split_flags[packet_number] != sequence_number )
{ {
if( packet_number == ( packet_count - 1 )) if( packet_number == ( packet_count - 1 ))
net.split.total_size = size + SPLIT_SIZE * ( packet_count - 1 ); net.split.total_size = size + body_size * ( packet_count - 1 );
net.split.split_count--; net.split.split_count--;
net.split_flags[packet_number] = sequence_number; net.split_flags[packet_number] = sequence_number;
@ -1162,7 +1167,7 @@ qboolean NET_GetLong( byte *pData, int size, int *outSize )
Con_DPrintf( "NET_GetLong: Ignoring duplicated split packet %i of %i ( %i bytes )\n", packet_number + 1, packet_count, size ); Con_DPrintf( "NET_GetLong: Ignoring duplicated split packet %i of %i ( %i bytes )\n", packet_number + 1, packet_count, size );
} }
offset = (packet_number * SPLIT_SIZE); offset = (packet_number * body_size);
memcpy( net.split.buffer + offset, pData + sizeof( SPLITPACKET ), size ); memcpy( net.split.buffer + offset, pData + sizeof( SPLITPACKET ), size );
// have we received all of the pieces to the packet? // have we received all of the pieces to the packet?
@ -1221,13 +1226,13 @@ qboolean NET_QueuePacket( netsrc_t sock, netadr_t *from, byte *data, size_t *len
#ifndef XASH_DEDICATED #ifndef XASH_DEDICATED
if( CL_LegacyMode() ) if( CL_LegacyMode() )
return NET_LagPacket( true, sock, from, length, data ); return NET_LagPacket( true, sock, from, length, data );
#endif
// check for split message // check for split message
if( *(int *)data == NET_HEADER_SPLITPACKET ) if( sock == NS_CLIENT && *(int *)data == NET_HEADER_SPLITPACKET )
{ {
return NET_GetLong( data, ret, length ); return NET_GetLong( data, ret, length, CL_GetSplitSize() );
} }
#endif
// lag the packet, if needed // lag the packet, if needed
return NET_LagPacket( true, sock, from, length, data ); return NET_LagPacket( true, sock, from, length, data );
} }
@ -1288,15 +1293,16 @@ NET_SendLong
Fragment long packets, send short directly Fragment long packets, send short directly
================== ==================
*/ */
int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, int len, int flags, const struct sockaddr *to, int tolen ) int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, size_t len, int flags, const struct sockaddr *to, size_t tolen, size_t splitsize )
{ {
#ifdef NET_USE_FRAGMENTS #ifdef NET_USE_FRAGMENTS
// do we need to break this packet up? // do we need to break this packet up?
if( sock == NS_SERVER && len > MAX_ROUTEABLE_PACKET ) if( splitsize > sizeof( SPLITPACKET ) && sock == NS_SERVER && len > splitsize )
{ {
char packet[MAX_ROUTEABLE_PACKET]; char packet[SPLITPACKET_MAX_SIZE];
int total_sent, size, packet_count; int total_sent, size, packet_count;
int ret, packet_number; int ret, packet_number;
int body_size = splitsize - sizeof( SPLITPACKET );
SPLITPACKET *pPacket; SPLITPACKET *pPacket;
net.sequence_number++; net.sequence_number++;
@ -1308,13 +1314,13 @@ int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, int len, int f
pPacket->net_id = NET_HEADER_SPLITPACKET; pPacket->net_id = NET_HEADER_SPLITPACKET;
packet_number = 0; packet_number = 0;
total_sent = 0; total_sent = 0;
packet_count = (len + SPLIT_SIZE - 1) / SPLIT_SIZE; packet_count = (len + body_size - 1) / body_size;
while( len > 0 ) while( len > 0 )
{ {
size = Q_min( SPLIT_SIZE, len ); size = Q_min( body_size, len );
pPacket->packet_id = (packet_number << 8) + packet_count; pPacket->packet_id = (packet_number << 8) + packet_count;
memcpy( packet + sizeof( SPLITPACKET ), buf + ( packet_number * SPLIT_SIZE ), size ); memcpy( packet + sizeof( SPLITPACKET ), buf + ( packet_number * body_size ), size );
if( net_showpackets && net_showpackets->value == 3.0f ) if( net_showpackets && net_showpackets->value == 3.0f )
{ {
@ -1349,10 +1355,10 @@ int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, int len, int f
/* /*
================== ==================
NET_SendPacket NET_SendPacketEx
================== ==================
*/ */
void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to ) void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t to, size_t splitsize )
{ {
int ret; int ret;
struct sockaddr addr; struct sockaddr addr;
@ -1382,7 +1388,7 @@ void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to
NET_NetadrToSockadr( &to, &addr ); NET_NetadrToSockadr( &to, &addr );
ret = NET_SendLong( sock, net_socket, data, length, 0, &addr, sizeof( addr )); ret = NET_SendLong( sock, net_socket, data, length, 0, &addr, sizeof( addr ), splitsize );
if( NET_IsSocketError( ret )) if( NET_IsSocketError( ret ))
{ {
@ -1412,6 +1418,16 @@ void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to
} }
/*
==================
NET_SendPacket
==================
*/
void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to )
{
return NET_SendPacketEx( sock, length, data, to, 0 );
}
/* /*
==================== ====================
NET_BufferToBufferCompress NET_BufferToBufferCompress

2
engine/common/net_ws.h

@ -61,10 +61,12 @@ qboolean NET_GetPacket( netsrc_t sock, netadr_t *from, byte *data, size_t *lengt
qboolean NET_BufferToBufferCompress( char *dest, uint *destLen, char *source, uint sourceLen ); qboolean NET_BufferToBufferCompress( char *dest, uint *destLen, char *source, uint sourceLen );
qboolean NET_BufferToBufferDecompress( char *dest, uint *destLen, char *source, uint sourceLen ); qboolean NET_BufferToBufferDecompress( char *dest, uint *destLen, char *source, uint sourceLen );
void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to ); void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to );
void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t to, size_t splitsize );
void NET_ClearLagData( qboolean bClient, qboolean bServer ); void NET_ClearLagData( qboolean bClient, qboolean bServer );
#ifndef XASH_DEDICATED #ifndef XASH_DEDICATED
qboolean CL_LegacyMode( void ); qboolean CL_LegacyMode( void );
int CL_GetSplitSize( void );
#endif #endif
void HTTP_AddCustomServer( const char *url ); void HTTP_AddCustomServer( const char *url );

19
engine/common/netchan.h

@ -59,10 +59,10 @@ GNU General Public License for more details.
// { // {
// byte (on/off) // byte (on/off)
// int (fragment id) // int (fragment id)
// short (startpos) // int (startpos)
// short (length) // int (length)
// } // }
#define HEADER_BYTES ( 8 + MAX_STREAMS * 9 ) #define HEADER_BYTES ( 8 + MAX_STREAMS * 13 )
// Pad this to next higher 16 byte boundary // Pad this to next higher 16 byte boundary
// This is the largest packet that can come in/out over the wire, before processing the header // This is the largest packet that can come in/out over the wire, before processing the header
@ -84,7 +84,7 @@ GNU General Public License for more details.
#define NUM_PACKET_ENTITIES 256 // 170 Mb for multiplayer with 32 players #define NUM_PACKET_ENTITIES 256 // 170 Mb for multiplayer with 32 players
#define MAX_CUSTOM_BASELINES 64 #define MAX_CUSTOM_BASELINES 64
#define NET_EXT_SPLIT (1U<<1) #define NET_LEGACY_EXT_SPLIT (1U<<1)
#define NETSPLIT_BACKUP 8 #define NETSPLIT_BACKUP 8
#define NETSPLIT_BACKUP_MASK (NETSPLIT_BACKUP - 1) #define NETSPLIT_BACKUP_MASK (NETSPLIT_BACKUP - 1)
#define NETSPLIT_HEADER_SIZE 18 #define NETSPLIT_HEADER_SIZE 18
@ -182,6 +182,13 @@ typedef struct fbufqueue_s
fragbuf_t *fragbufs; // the actual buffers fragbuf_t *fragbufs; // the actual buffers
} fragbufwaiting_t; } fragbufwaiting_t;
typedef enum fragsize_e
{
FRAGSIZE_FRAG,
FRAGSIZE_SPLIT,
FRAGSIZE_UNRELIABLE
} fragsize_t;
// Network Connection Channel // Network Connection Channel
typedef struct netchan_s typedef struct netchan_s
{ {
@ -205,7 +212,7 @@ typedef struct netchan_s
// callback to get actual framgment size // callback to get actual framgment size
void *client; void *client;
int (*pfnBlockSize)( void *cl ); int (*pfnBlockSize)( void *cl, fragsize_t mode );
// staging and holding areas // staging and holding areas
sizebuf_t message; sizebuf_t message;
@ -261,7 +268,7 @@ extern int net_drop;
void Netchan_Init( void ); void Netchan_Init( void );
void Netchan_Shutdown( void ); void Netchan_Shutdown( void );
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void * ) ); void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ) );
void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, const char *filename, byte *pbuf, int size ); void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, const char *filename, byte *pbuf, int size );
qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *length ); qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *length );
qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ); qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg );

7
engine/common/protocol.h

@ -174,8 +174,8 @@ GNU General Public License for more details.
#define MAX_RESOURCES (MAX_MODELS+MAX_SOUNDS+MAX_CUSTOM+MAX_EVENTS) #define MAX_RESOURCES (MAX_MODELS+MAX_SOUNDS+MAX_CUSTOM+MAX_EVENTS)
#define MAX_RESOURCE_BITS 13 // 13 bits 8192 resource (4096 models + 2048 sounds + 1024 events + 1024 files) #define MAX_RESOURCE_BITS 13 // 13 bits 8192 resource (4096 models + 2048 sounds + 1024 events + 1024 files)
#define FRAGMENT_MIN_SIZE 508 // RFC 791: 576(min ip packet) - 60 (ip header) - 8 (udp header)
#define FRAGMENT_MIN_SIZE 1200 // default MTU #define FRAGMENT_DEFAULT_SIZE 1200 // default MTU
#define FRAGMENT_MAX_SIZE 64000 // maximal fragment size #define FRAGMENT_MAX_SIZE 64000 // maximal fragment size
#define FRAGMENT_LOCAL_SIZE FRAGMENT_MAX_SIZE // local connection #define FRAGMENT_LOCAL_SIZE FRAGMENT_MAX_SIZE // local connection
@ -243,6 +243,9 @@ GNU General Public License for more details.
extern const char *svc_strings[svc_lastmsg+1]; extern const char *svc_strings[svc_lastmsg+1];
extern const char *clc_strings[clc_lastmsg+1]; extern const char *clc_strings[clc_lastmsg+1];
// FWGS extensions
#define NET_EXT_SPLITSIZE (1U<<0) // set splitsize by cl_dlmax
// legacy protocol definitons // legacy protocol definitons
#define PROTOCOL_LEGACY_VERSION 48 #define PROTOCOL_LEGACY_VERSION 48
#define svc_legacy_modelindex 31 // [index][modelpath] #define svc_legacy_modelindex 31 // [index][modelpath]

1
engine/server/server.h

@ -252,6 +252,7 @@ typedef struct sv_client_s
int challenge; // challenge of this user, randomly generated int challenge; // challenge of this user, randomly generated
int userid; // identifying number on server int userid; // identifying number on server
int extensions;
} sv_client_t; } sv_client_t;
/* /*

50
engine/server/sv_client.c

@ -87,7 +87,7 @@ void SV_GetChallenge( netadr_t from )
Netchan_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "challenge %i", svs.challenges[i].challenge ); Netchan_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "challenge %i", svs.challenges[i].challenge );
} }
int SV_GetFragmentSize( void *pcl ) int SV_GetFragmentSize( void *pcl, fragsize_t mode )
{ {
sv_client_t *cl = (sv_client_t*)pcl; sv_client_t *cl = (sv_client_t*)pcl;
int cl_frag_size; int cl_frag_size;
@ -95,10 +95,39 @@ int SV_GetFragmentSize( void *pcl )
if( Netchan_IsLocal( &cl->netchan )) if( Netchan_IsLocal( &cl->netchan ))
return FRAGMENT_LOCAL_SIZE; return FRAGMENT_LOCAL_SIZE;
if( mode == FRAGSIZE_UNRELIABLE )
{
// allow setting unreliable limit with "setinfo cl_urmax"
cl_frag_size = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_urmax" ));
if( cl_frag_size == 0 )
return NET_MAX_MESSAGE;
return bound( FRAGMENT_MAX_SIZE, cl_frag_size, NET_MAX_MESSAGE );
}
cl_frag_size = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_dlmax" )); cl_frag_size = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_dlmax" ));
cl_frag_size = bound( FRAGMENT_MIN_SIZE, cl_frag_size, FRAGMENT_MAX_SIZE ); cl_frag_size = bound( FRAGMENT_MIN_SIZE, cl_frag_size, FRAGMENT_MAX_SIZE );
return cl_frag_size; if( mode != FRAGSIZE_FRAG )
{
if( cl->extensions & NET_EXT_SPLITSIZE )
return cl_frag_size;
else
return 0; // original engine behaviour
}
// get in-game fragmentation size
if( cl->state == cs_spawned )
{
// allow setting in-game fragsize with "setinfo cl_frmax"
int frmax = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_frmax" ));
if( frmax < FRAGMENT_MIN_SIZE || frmax > FRAGMENT_MAX_SIZE )
cl_frag_size = frmax;
else
cl_frag_size /= 2;// add window for unreliable
}
return cl_frag_size - HEADER_BYTES;
} }
/* /*
@ -242,6 +271,7 @@ void SV_ConnectClient( netadr_t from )
int i, count = 0; int i, count = 0;
int challenge; int challenge;
const char *s; const char *s;
int extensions;
if( Cmd_Argc() < 5 ) if( Cmd_Argc() < 5 )
{ {
@ -283,6 +313,9 @@ void SV_ConnectClient( netadr_t from )
return; return;
} }
extensions = Q_atoi( Info_ValueForKey( protinfo, "ext" ) );
// LAN servers restrict to class b IP addresses // LAN servers restrict to class b IP addresses
if( !SV_CheckIPRestrictions( from )) if( !SV_CheckIPRestrictions( from ))
{ {
@ -346,6 +379,7 @@ void SV_ConnectClient( netadr_t from )
newcl->frames = (client_frame_t *)Z_Calloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP ); newcl->frames = (client_frame_t *)Z_Calloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
newcl->userid = g_userid++; // create unique userid newcl->userid = g_userid++; // create unique userid
newcl->state = cs_connected; newcl->state = cs_connected;
newcl->extensions = extensions & (NET_EXT_SPLITSIZE);
// reset viewentities (from previous level) // reset viewentities (from previous level)
memset( newcl->viewentity, 0, sizeof( newcl->viewentity )); memset( newcl->viewentity, 0, sizeof( newcl->viewentity ));
@ -356,8 +390,15 @@ void SV_ConnectClient( netadr_t from )
Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize ); Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize );
MSG_Init( &newcl->datagram, "Datagram", newcl->datagram_buf, sizeof( newcl->datagram_buf )); // datagram buf MSG_Init( &newcl->datagram, "Datagram", newcl->datagram_buf, sizeof( newcl->datagram_buf )); // datagram buf
Q_strncpy( newcl->hashedcdkey, Info_ValueForKey( protinfo, "uuid" ), 32 );
newcl->hashedcdkey[32] = '\0';
// build protinfo answer
protinfo[0] = '\0';
Info_SetValueForKey( protinfo, "ext", va( "%d",newcl->extensions ), sizeof( protinfo ) );
// send the connect packet to the client // send the connect packet to the client
Netchan_OutOfBandPrint( NS_SERVER, from, "client_connect" ); Netchan_OutOfBandPrint( NS_SERVER, from, "client_connect %s", protinfo );
newcl->upstate = us_inactive; newcl->upstate = us_inactive;
newcl->connection_started = host.realtime; newcl->connection_started = host.realtime;
@ -365,8 +406,7 @@ void SV_ConnectClient( netadr_t from )
newcl->delta_sequence = -1; newcl->delta_sequence = -1;
newcl->flags = 0; newcl->flags = 0;
Q_strncpy( newcl->hashedcdkey, Info_ValueForKey( protinfo, "uuid" ), 32 );
newcl->hashedcdkey[32] = '\0';
// reset any remaining events // reset any remaining events
memset( &newcl->events, 0, sizeof( newcl->events )); memset( &newcl->events, 0, sizeof( newcl->events ));

Loading…
Cancel
Save