/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : Command & Conquer * * * * $Archive:: /Commando/Code/wwnet/packetmgr.h $* * * * $Author:: Bhayes $* * * * $Modtime:: 2/18/02 10:48p $* * * * $Revision:: 16 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #pragma once #ifndef _PACKETMGR_H #define _PACKETMGR_H #include "mutex.h" #include "wwdebug.h" #include "vector.h" #include // for SOCKET #ifdef WWASSERT #ifndef pm_assert #define pm_assert WWASSERT #endif //pm_assert #else //WWASSERT #define pm_assert assert #endif //WWASSERT #pragma pack(push) #pragma pack(1) #define WRAPPER_CRC /* ** Header used at the beginning of a packet to identify the number of packets packed in this packet IYSWIM. */ struct PacketPackHeaderStruct { /* ** Number of same length packets in this block. */ unsigned short NumPackets : 5; /* ** Length of the packets. */ unsigned short PacketSize : 10; /* ** More packets of a different length after these ones? */ unsigned short MorePackets : 1; }; /* ** Header used at the beginning of every delta packet. */ struct PacketDeltaHeaderStruct { /* ** Chunk pack bits are present. */ unsigned char ChunkPack : 1; /* ** Byte pack bits are present. */ unsigned char BytePack : 1; }; #pragma pack(pop) /* ** Minimum MTU allowable on the internet is 576. IP Header is 20 bytes. UDP header is 8 bytes ** So our max packet size is 576 - 28 = 548 */ #ifdef WRAPPER_CRC #define PACKET_MANAGER_MTU 540 #else #define PACKET_MANAGER_MTU 544 #endif //WRAPPER_CRC #define PACKET_MANAGER_BUFFERS 256 #define PACKET_MANAGER_BUFFERS_WHEN_SERVER (32 * 32) #define PACKET_MANAGER_RECEIVE_BUFFERS 128 #define PACKET_MANAGER_RECEIVE_BUFFERS_AS_SERVER (64 * 32) #define PACKET_MANAGER_MAX_PACKETS 31 #define UDP_HEADER_SIZE 28 /* ** This class intercepts packets at the lowest level and applies delta based compression and packet combining to reduce ** low level bandwidth while being transparent to higher levels in the application. ** ** All packets are prefixed by a PacketHeaderStruct which is 2 bytes long. So sending a single packet incurs an extra ** overhead of two bytes. Normally, however, multiple small packets can be combined into a single large one which saves ** the IP and UDP overhead invlolved in sending the subsequent packets. ** */ class PacketManagerClass; class PacketManagerClass { public: /* ** Constructor. */ PacketManagerClass(void); ~PacketManagerClass(void); /* ** Application interface. */ bool Take_Packet(unsigned char *packet, int packet_len, unsigned char *dest_ip, unsigned short dest_port, SOCKET socket); int Get_Packet(SOCKET socket, unsigned char *packet_buffer, int packet_buffer_size, unsigned char *ip_address, unsigned short &port); void Flush(bool forced = false); void Set_Is_Server(bool is_server); /* ** Bandwidth Management. */ void Reset_Stats(void); void Update_Stats(bool forced = false); unsigned long Get_Total_Raw_Bandwidth_In(void); unsigned long Get_Total_Raw_Bandwidth_Out(void); unsigned long Get_Total_Compressed_Bandwidth_In(void); unsigned long Get_Total_Compressed_Bandwidth_Out(void); unsigned long Get_Raw_Bandwidth_In(SOCKADDR_IN *address); unsigned long Get_Raw_Bandwidth_Out(SOCKADDR_IN *address); unsigned long Get_Compressed_Bandwidth_In(SOCKADDR_IN *address); unsigned long Get_Compressed_Bandwidth_Out(SOCKADDR_IN *address); unsigned long Get_Raw_Bytes_Out(SOCKADDR_IN *address); void Set_Stats_Sampling_Frequency_Delay(unsigned long time_ms); unsigned long Get_Stats_Sampling_Frequency_Delay(void) {return(StatsFrequency);}; /* ** Class configuration. */ void Set_Flush_Frequency(unsigned long freq) {FlushFrequency = freq;}; bool Toggle_Allow_Deltas(void) { AllowDeltas = AllowDeltas ? false : true; return(AllowDeltas); }; bool Toggle_Allow_Combos(void) { AllowCombos = AllowCombos ? false : true; return(AllowCombos); }; // // TSS added 09/25/01 // unsigned long Get_Flush_Frequency(void) {return FlushFrequency;} bool Get_Allow_Deltas(void) {return AllowDeltas;} bool Get_Allow_Combos(void) {return AllowCombos;} void Disable_Optimizations(void); enum ErrorStateEnum { STATE_OK, STATE_WS_BUFFERS_FULL, }; ErrorStateEnum Get_Error_State(void); private: /* ** Delta compression. */ static int Build_Delta_Packet_Patch(unsigned char *base_packet, unsigned char *add_packet, unsigned char *delta_packet, int base_packet_size, int add_packet_size); static int Reconstruct_From_Delta(unsigned char *base_packet, unsigned char *reconstructed_packet, unsigned char *delta_packet, int base_packet_size, int &delta_size); bool Break_Packet(unsigned char *packet, int packet_len, unsigned char *ip_address, unsigned short port); /* ** Bit packing. */ static inline int Add_Bit(bool bit, unsigned char * &bitstream, int &position); static inline unsigned char Get_Bit(unsigned char * &bitstream, int &position); /* ** Buffer allocation. */ int Get_Next_Free_Buffer_Index(void); /* ** Error handling. */ void Clear_Socket_Error(SOCKET socket); /* ** Stats management. */ struct BandwidthStatsStruct { unsigned long IPAddress; unsigned short Port; unsigned long UncompressedBytesIn; unsigned long UncompressedBytesOut; unsigned long CompressedBytesIn; unsigned long CompressedBytesOut; unsigned long UncompressedBandwidthIn; unsigned long UncompressedBandwidthOut; unsigned long CompressedBandwidthIn; unsigned long CompressedBandwidthOut; bool operator == (BandwidthStatsStruct const &stats); bool operator != (BandwidthStatsStruct const &stats); }; int Get_Stats_Index(unsigned long ip_address, unsigned short port, bool can_create = true); void Register_Packet_In(unsigned char *ip_address, unsigned short port, unsigned long compressed_size, unsigned long uncompressed_size); void Register_Packet_Out(unsigned char *ip_address, unsigned short port, unsigned long compressed_size, unsigned long uncompressed_size); /* ** Send buffers. */ typedef struct tPacketBufferType { unsigned char Buffer [600]; } PacketBufferType; class SendBufferClass { public: PacketBufferType *PacketBuffer; unsigned char IPAddress[4]; unsigned short Port; int PacketLength; bool PacketReady; int PacketSendLength; SOCKET PacketSendSocket; SendBufferClass(void) { PacketBuffer = new PacketBufferType; IPAddress[0] = 0; IPAddress[1] = 0; IPAddress[2] = 0; IPAddress[3] = 0; Port = 0; PacketLength = 0; PacketReady = false; PacketSendLength = 0; PacketSendSocket = INVALID_SOCKET; }; ~SendBufferClass(void) { delete PacketBuffer; PacketBuffer = NULL; }; }; int NumSendBuffers; SendBufferClass *SendBuffers; //unsigned char *PacketBuffers; //[PACKET_MANAGER_BUFFERS][600]; //unsigned char *IPAddresses; //[PACKET_MANAGER_BUFFERS][4]; //unsigned short *Ports; //[PACKET_MANAGER_BUFFERS]; //int *PacketLengths //[PACKET_MANAGER_BUFFERS]; //bool *PacketReady; //[PACKET_MANAGER_BUFFERS]; //int *PacketSendLength; //[PACKET_MANAGER_BUFFERS]; //SOCKET *PacketSendSockets; //[PACKET_MANAGER_BUFFERS]; int NextPacket; int NumPackets; unsigned char BuildPacket[PACKET_MANAGER_MTU]; unsigned char DeltaPacket[PACKET_MANAGER_MTU + 128]; /* ** Receive buffers. Don't need so many since we only process one packet at a time. */ class ReceiveBufferClass { public: unsigned char ReceiveHoldingBuffer[600]; unsigned long ReceivePacketLength; }; int NumReceiveBuffers; ReceiveBufferClass *ReceiveBuffers; //unsigned char ReceiveHoldingBuffers[PACKET_MANAGER_RECEIVE_BUFFERS][600]; //unsigned long ReceivePacketLengths[PACKET_MANAGER_RECEIVE_BUFFERS]; unsigned char ReceiveIPAddress[4]; unsigned short ReceivePort; int NumReceivePackets; int CurrentPacket; SOCKET ReceiveSocket; /* ** Send timing. */ unsigned long LastSendTime; unsigned long FlushFrequency; /* ** Bandwidth measurement. */ DynamicVectorClass BandwidthList; unsigned long TotalCompressedBandwidthIn; unsigned long TotalCompressedBandwidthOut; unsigned long TotalUncompressedBandwidthIn; unsigned long TotalUncompressedBandwidthOut; unsigned long StatsFrequency; unsigned long LastStatsUpdate; bool ResetStatsIn; bool ResetStatsOut; /* ** Debug */ bool AllowDeltas; bool AllowCombos; /* ** Winsock error handling. */ ErrorStateEnum ErrorState; /* ** Thread safety */ CriticalSectionClass CriticalSection; }; /* ** Single instance of the packet manager. */ extern PacketManagerClass PacketManager; #endif //_PACKETMGR_H