From 10c31b82cb2bdf65adc9cf1fc436a55824f1ca6c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 22 Feb 2009 05:05:58 +0000 Subject: [PATCH] - Added selective compression of network packets. Interestingly, most packets don't actually compress all that well, even the ones that aren't too short to possibly compress. (Maybe make the whole thing one long, never-ending zlib data stream with Z_SYNC_FLUSH used to chunk things at packet boundaries? That would probably help the compression ratio, but it would require changing the way the netcode determines sequence, which would be a much more invasive change.) SVN r1438 (trunk) --- docs/rh-log.txt | 11 +++++++- src/d_net.cpp | 29 ------------------- src/d_net.h | 32 ++++++++++++++++++++- src/i_net.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 108 insertions(+), 38 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 4eb084d48b..c50f7d8ed3 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,13 @@ -February 21, 2009 (Changes by Graf Zahl) +February 21, 2009 +- Added selective compression of network packets. Interestingly, most packets + don't actually compress all that well, even the ones that aren't too short + to possibly compress. (Maybe make the whole thing one long, never-ending + zlib data stream with Z_SYNC_FLUSH used to chunk things at packet + boundaries? That would probably help the compression ratio, but it would + require changing the way the netcode determines sequence, which would be + a much more invasive change.) + +February 21, 2009 (Changes by Graf Zahl) - Fixed: Heretic's fullscreen HUD crashed when the player had armor without a valid icon. - Fixed: The StrifePlayer was missing a RunHealth setting. diff --git a/src/d_net.cpp b/src/d_net.cpp index 3400e45da1..ce16d48d2a 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -67,35 +67,6 @@ EXTERN_CVAR (Int, autosavecount) //#define SIMULATEERRORS (RAND_MAX/3) #define SIMULATEERRORS 0 -#define NCMD_EXIT 0x80 -#define NCMD_RETRANSMIT 0x40 -#define NCMD_SETUP 0x20 -#define NCMD_MULTI 0x10 // multiple players in this packet -#define NCMD_QUITTERS 0x08 // one or more players just quit (packet server only) - -#define NCMD_XTICS 0x03 // packet contains >2 tics -#define NCMD_2TICS 0x02 // packet contains 2 tics -#define NCMD_1TICS 0x01 // packet contains 1 tic -#define NCMD_0TICS 0x00 // packet contains 0 tics - -// [RH] -// New generic packet structure: -// -// Header: -// One byte with above flags. -// One byte with starttic -// One byte with master's maketic (master -> slave only!) -// If NCMD_RETRANSMIT set, one byte with retransmitfrom -// If NCMD_XTICS set, one byte with number of tics (minus 3, so theoretically up to 258 tics in one packet) -// If NCMD_QUITTERS, one byte with number of players followed by one byte with each player's consolenum -// If NCMD_MULTI, one byte with number of players followed by one byte with each player's consolenum -// - The first player's consolenum is not included in this list, because it always matches the sender -// -// For each tic: -// Two bytes with consistancy check, followed by tic data -// -// Setup packets are different, and are described just before D_ArbitrateNetStart(). - extern BYTE *demo_p; // [RH] Special "ticcmds" get recorded in demos extern char savedescription[SAVESTRINGSIZE]; extern FString savegamefile; diff --git a/src/d_net.h b/src/d_net.h index 43be497102..3ad0bddede 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -48,7 +48,7 @@ // Probably not enough. #define MAX_MSGLEN (BACKUPTICS*10) #else -#define MAX_MSGLEN 1400 +#define MAX_MSGLEN 14000 #endif #define CMD_SEND 1 @@ -144,4 +144,34 @@ extern int nettics[MAXNETNODES]; extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; extern int ticdup; +// [RH] +// New generic packet structure: +// +// Header: +// One byte with following flags. +// One byte with starttic +// One byte with master's maketic (master -> slave only!) +// If NCMD_RETRANSMIT set, one byte with retransmitfrom +// If NCMD_XTICS set, one byte with number of tics (minus 3, so theoretically up to 258 tics in one packet) +// If NCMD_QUITTERS, one byte with number of players followed by one byte with each player's consolenum +// If NCMD_MULTI, one byte with number of players followed by one byte with each player's consolenum +// - The first player's consolenum is not included in this list, because it always matches the sender +// +// For each tic: +// Two bytes with consistancy check, followed by tic data +// +// Setup packets are different, and are described just before D_ArbitrateNetStart(). + +#define NCMD_EXIT 0x80 +#define NCMD_RETRANSMIT 0x40 +#define NCMD_SETUP 0x20 +#define NCMD_MULTI 0x10 // multiple players in this packet +#define NCMD_QUITTERS 0x08 // one or more players just quit (packet server only) +#define NCMD_COMPRESSED 0x04 // remainder of packet is compressed + +#define NCMD_XTICS 0x03 // packet contains >2 tics +#define NCMD_2TICS 0x02 // packet contains 2 tics +#define NCMD_1TICS 0x01 // packet contains 1 tic +#define NCMD_0TICS 0x00 // packet contains 0 tics + #endif diff --git a/src/i_net.cpp b/src/i_net.cpp index caa3a61fb8..7df97a76e3 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -64,7 +64,9 @@ #include "i_net.h" - +// As per http://support.microsoft.com/kb/q192599/ the standard +// size for network buffers is 8k. +#define TRANSMIT_SIZE 8000 /* [Petteri] Get more portable: */ #ifndef __WIN32__ @@ -133,6 +135,8 @@ struct PreGamePacket } machines[MAXNETNODES]; }; +BYTE TransmitBuffer[TRANSMIT_SIZE]; + // // UDPsocket // @@ -191,11 +195,47 @@ void PacketSend (void) { int c; - //printf ("sending %i\n",gametic); - c = sendto (mysocket , (const char*)doomcom.data, doomcom.datalength - ,0,(sockaddr *)&sendaddress[doomcom.remotenode] - ,sizeof(sendaddress[doomcom.remotenode])); + // FIXME: Catch this before we've overflown the buffer. With long chat + // text and lots of backup tics, it could conceivably happen. (Though + // apparently it hasn't yet, which is good.) + if (doomcom.datalength > MAX_MSGLEN) + { + I_FatalError("Netbuffer overflow!"); + } + uLong size = TRANSMIT_SIZE - 1; + if (doomcom.datalength >= 10) + { + assert(!(doomcom.data[0] & NCMD_COMPRESSED)); + TransmitBuffer[0] = doomcom.data[0] | NCMD_COMPRESSED; + c = compress2(TransmitBuffer + 1, &size, doomcom.data + 1, doomcom.datalength - 1, 9); + size += 1; + } + else + { + c = -1; // Just some random error code to avoid sending the compressed buffer. + } + if (c == Z_OK && size < (uLong)doomcom.datalength) + { +// Printf("send %lu/%d\n", size, doomcom.datalength); + c = sendto(mysocket, (char *)TransmitBuffer, size, + 0, (sockaddr *)&sendaddress[doomcom.remotenode], + sizeof(sendaddress[doomcom.remotenode])); + } + else + { + if (doomcom.datalength > TRANSMIT_SIZE) + { + I_Error("Net compression failed (zlib error %d)", c); + } + else + { +// Printf("send %d\n", doomcom.datalength); + c = sendto(mysocket, (char *)doomcom.data, doomcom.datalength, + 0, (sockaddr *)&sendaddress[doomcom.remotenode], + sizeof(sendaddress[doomcom.remotenode])); + } + } // if (c == -1) // I_Error ("SendPacket error: %s",strerror(errno)); } @@ -212,8 +252,8 @@ void PacketGet (void) int node; fromlen = sizeof(fromaddress); - c = recvfrom (mysocket, (char*)doomcom.data, MAX_MSGLEN, 0 - , (sockaddr *)&fromaddress, &fromlen); + c = recvfrom (mysocket, (char*)TransmitBuffer, TRANSMIT_SIZE, 0, + (sockaddr *)&fromaddress, &fromlen); node = FindNode (&fromaddress); if (node >= 0 && c == SOCKET_ERROR) @@ -239,6 +279,26 @@ void PacketGet (void) return; } } + else if (c > 0) + { + doomcom.data[0] = TransmitBuffer[0] & ~NCMD_COMPRESSED; + if (TransmitBuffer[0] & NCMD_COMPRESSED) + { + uLongf msgsize = MAX_MSGLEN - 1; + int err = uncompress(doomcom.data + 1, &msgsize, TransmitBuffer + 1, c - 1); +// Printf("recv %d/%lu\n", c, msgsize + 1); + if (err != Z_OK) + { + I_Error("Net decompression failed (zlib error %d)\n", err); + } + c = msgsize + 1; + } + else + { +// Printf("recv %d\n", c); + memcpy(doomcom.data + 1, TransmitBuffer + 1, c - 1); + } + } doomcom.remotenode = node; doomcom.datalength = (short)c;