359 lines
No EOL
11 KiB
C++
359 lines
No EOL
11 KiB
C++
/*
|
|
** 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** 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 <winsock.h> // 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<BandwidthStatsStruct> 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
|