From f044a59984067f85c448b8ef3234a82c5bdbe4a9 Mon Sep 17 00:00:00 2001 From: mittorn Date: Tue, 29 Jan 2019 17:28:39 +0700 Subject: [PATCH] Port old netsplit implementation --- engine/common/net_chan.c | 135 +++++++++++++++++++++++++++++++++++++++ engine/common/netchan.h | 45 +++++++++++++ 2 files changed, 180 insertions(+) diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index a5c744c4..cabb0b1a 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -102,6 +102,141 @@ const char *ns_strings[NS_COUNT] = "Server", }; + +/* +================================= + +NETWORK PACKET SPLIT + +================================= +*/ + +/* +====================== +NetSplit_GetLong + +Collect fragmrnts with signature 0xFFFFFFFE to single packet +return true when got full packet +====================== +*/ +qboolean NetSplit_GetLong( netsplit_t *ns, netadr_t *from, byte *data, size_t *length ) +{ + netsplit_packet_t *packet = (netsplit_packet_t*)data; + netsplit_chain_packet_t * p; + + //ASSERT( *length > NETSPLIT_HEADER_SIZE ); + if( *length <= NETSPLIT_HEADER_SIZE ) return false; + + LittleLongSW(packet->id); + LittleLongSW(packet->length); + LittleLongSW(packet->part); + + p = &ns->packets[packet->id & NETSPLIT_BACKUP_MASK]; + // Con_Reportf( S_NOTE "NetSplit_GetLong: packet from %s, id %d, index %d length %d\n", NET_AdrToString( *from ), (int)packet->id, (int)packet->index, (int)*length ); + + // no packets with this id received + if( packet->id != p->id ) + { + // warn if previous packet not received + if( p->received < p->count ) + { + //CL_WarnLostSplitPacket(); + Con_Reportf( S_WARN "NetSplit_GetLong: lost packet %d\n", p->id ); + } + + p->id = packet->id; + p->count = packet->count; + p->received = 0; + memset( p->recieved_v, 0, 32 ); + } + + // use bool vector to detect dup packets + if( p->recieved_v[packet->index >> 5 ] & ( 1 << ( packet->index & 31 ) ) ) + { + Con_Reportf( S_WARN "NetSplit_GetLong: dup packet from %s\n", NET_AdrToString( *from ) ); + return false; + } + + p->received++; + + // mark as received + p->recieved_v[packet->index >> 5] |= 1 << ( packet->index & 31 ); + + // prevent overflow + if( packet->part * packet->index > NET_MAX_PAYLOAD ) + { + Con_Reportf( S_WARN "NetSplit_GetLong: packet out fo bounds from %s (part %d index %d)\n", NET_AdrToString( *from ), packet->part, packet->index ); + return false; + } + + if( packet->length > NET_MAX_PAYLOAD ) + { + Con_Reportf( S_WARN "NetSplit_GetLong: packet out fo bounds from %s (length %d)\n", NET_AdrToString( *from ), packet->length ); + return false; + } + + memcpy( p->data + packet->part * packet->index, packet->data, *length - 18 ); + + // rewrite results of NET_GetPacket + if( p->received == packet->count ) + { + //ASSERT( packet->length % packet->part == (*length - NETSPLIT_HEADER_SIZE) % packet->part ); + size_t len = packet->length; + + ns->total_received += len; + + ns->total_received_uncompressed += len; + *length = len; + + // Con_Reportf( S_NOTE "NetSplit_GetLong: packet from %s, id %d received %d length %d\n", NET_AdrToString( *from ), (int)packet->id, (int)p->received, (int)packet->length ); + memcpy( data, p->data, len ); + return true; + } + else + *length = NETSPLIT_HEADER_SIZE + packet->part; + + + return false; +} + +/* +====================== +NetSplit_SendLong + +Send parts that are less or equal maxpacket +====================== +*/ +void NetSplit_SendLong( netsrc_t sock, size_t length, void *data, netadr_t to, unsigned int maxpacket, unsigned int id) +{ + netsplit_packet_t packet = {0}; + unsigned int part = maxpacket - NETSPLIT_HEADER_SIZE; + + packet.signature = LittleLong(0xFFFFFFFE); + packet.id = LittleLong(id); + packet.length = LittleLong(length); + packet.part = LittleLong(part); + packet.count = ( length - 1 ) / part + 1; + + //Con_Reportf( S_NOTE "NetSplit_SendLong: packet to %s, count %d, length %d\n", NET_AdrToString( to ), (int)packet.count, (int)packet.length ); + + while( packet.index < packet.count ) + { + unsigned int size = part; + + if( size > length ) + size = length; + + length -= size; + + memcpy( packet.data, (const byte*)data + packet.index * part, size ); + //Con_Reportf( S_NOTE "NetSplit_SendLong: packet to %s, id %d, index %d\n", NET_AdrToString( to ), (int)packet.id, (int)packet.index ); + + NET_SendPacket( sock, size + NETSPLIT_HEADER_SIZE, &packet, to ); + packet.index++; + } + +} + /* =============== Netchan_Init diff --git a/engine/common/netchan.h b/engine/common/netchan.h index d1d60435..9d588faa 100644 --- a/engine/common/netchan.h +++ b/engine/common/netchan.h @@ -84,6 +84,47 @@ GNU General Public License for more details. #define NUM_PACKET_ENTITIES 256 // 170 Mb for multiplayer with 32 players #define MAX_CUSTOM_BASELINES 64 +#define NET_EXT_SPLIT (1U<<1) +#define NETSPLIT_BACKUP 8 +#define NETSPLIT_BACKUP_MASK (NETSPLIT_BACKUP - 1) +#define NETSPLIT_HEADER_SIZE 18 + +typedef struct netsplit_chain_packet_s +{ + // bool vector + unsigned int recieved_v[8]; + // serial number + unsigned int id; + byte data[NET_MAX_PAYLOAD]; + byte received; + byte count; +} netsplit_chain_packet_t; + +// raw packet format +typedef struct netsplit_packet_s +{ + unsigned int signature; // 0xFFFFFFFE + unsigned int length; + unsigned int part; + unsigned int id; + // max 256 parts + byte count; + byte index; + byte data[NET_MAX_PAYLOAD - NETSPLIT_HEADER_SIZE]; +} netsplit_packet_t; + + +typedef struct netsplit_s +{ + netsplit_chain_packet_t packets[NETSPLIT_BACKUP]; + integer64 total_received; + integer64 total_received_uncompressed; +} netsplit_t; + +// packet splitting +qboolean NetSplit_GetLong( netsplit_t *ns, netadr_t *from, byte *data, size_t *length ); + + /* ============================================================== @@ -203,6 +244,10 @@ typedef struct netchan_s // added for net_speeds size_t total_sended; size_t total_received; + qboolean split; + unsigned int maxpacket; + unsigned int splitid; + netsplit_t netsplit; } netchan_t; extern netadr_t net_from;