/*
** 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