This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwnet/packetmgr.cpp

1814 lines
No EOL
83 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.cpp $*
* *
* $Author:: Steve_t $*
* *
* $Modtime:: 8/08/02 3:26p $*
* *
* $Revision:: 36 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "packetmgr.h"
#include <always.h>
#include <memory.h>
//#include <winsock.h>
#include "systimer.h"
#include <malloc.h>
#include "netutil.h"
#include "wwmemlog.h"
#include "crc.h"
#include "wwprofile.h"
#include "connect.h"
/*
** Single instance of PacketManagerClass.
*/
PacketManagerClass PacketManager;
/***********************************************************************************************
* PacketManagerClass::Add_Bit -- Add a bit to a delta compressed packet stream *
* *
* *
* *
* INPUT: Bit to add as a bool - true or false *
* Ptr to bitstream *
* Bit position at pointer *
* *
* OUTPUT: New bit position *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/24/2001 1:34PM ST : Created *
*=============================================================================================*/
inline int PacketManagerClass::Add_Bit(bool bit, unsigned char * &bitstream, int &position)
{
pm_assert(position < 8);
unsigned char whole = bit ? 1 : 0;
whole <<= position;
*bitstream |= whole;
position++;
if (position == 8) {
bitstream++;
*bitstream = 0;
position = 0;
}
return(position);
}
/***********************************************************************************************
* PacketManagerClass::Get_Bit -- Get a bit from a delta compressed bitstream *
* *
* *
* *
* INPUT: Ptr to bitstream *
* Bit position *
* *
* OUTPUT: 0 or 1 *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/24/2001 1:35PM ST : Created *
*=============================================================================================*/
inline unsigned char PacketManagerClass::Get_Bit(unsigned char * &bitstream, int &position)
{
pm_assert(position < 8);
unsigned char whole = *bitstream;
whole >>= position;
whole &= 1;
position++;
if (position == 8) {
bitstream++;
position = 0;
}
return(whole);
}
/***********************************************************************************************
* PacketManagerClass::PacketManagerClass -- Class constructor. *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/24/2001 1:36PM ST : Created *
*=============================================================================================*/
PacketManagerClass::PacketManagerClass(void)
{
BandwidthList.Set_Growth_Step(128);
//memset(PacketLengths, 0, sizeof(PacketLengths));
NextPacket = 0;
NumPackets = 0;
NumReceivePackets = 0;
CurrentPacket = 0;
LastSendTime = 0;
FlushFrequency = 1000 / 10; // Default = 10 times per second.
AllowDeltas = true;
AllowCombos = true;
StatsFrequency = 10 * 1000;
LastStatsUpdate = TIMEGETTIME();
ErrorState = STATE_OK;
ResetStatsIn = true;
ResetStatsOut = true;
NumSendBuffers = PACKET_MANAGER_BUFFERS;
SendBuffers = new SendBufferClass[NumSendBuffers];
NumReceiveBuffers = PACKET_MANAGER_RECEIVE_BUFFERS;
ReceiveBuffers = new ReceiveBufferClass[NumReceiveBuffers];
}
/***********************************************************************************************
* PacketManagerClass::~PacketManagerClass -- Class destructor *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/15/2001 11:24AM ST : Created *
*=============================================================================================*/
PacketManagerClass::~PacketManagerClass(void)
{
if (SendBuffers) {
delete [] SendBuffers;
SendBuffers = NULL;
}
if (ReceiveBuffers) {
delete [] ReceiveBuffers;
ReceiveBuffers = NULL;
}
}
/***********************************************************************************************
* PacketManagerClass::Set_Is_Server -- Set whether to operate in server mode or not. *
* *
* *
* *
* INPUT: is_server - true if we are to be a server *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/15/2001 11:29AM ST : Created *
*=============================================================================================*/
void PacketManagerClass::Set_Is_Server(bool is_server)
{
CriticalSectionClass::LockClass lock(CriticalSection);
WWMEMLOG(MEM_NETWORK);
bool reset = false;
if (is_server && NumSendBuffers != PACKET_MANAGER_BUFFERS_WHEN_SERVER) {
NumSendBuffers = PACKET_MANAGER_BUFFERS_WHEN_SERVER;
NumReceiveBuffers = PACKET_MANAGER_RECEIVE_BUFFERS_AS_SERVER;
reset = true;
} else {
if (!is_server && NumSendBuffers != PACKET_MANAGER_BUFFERS) {
NumSendBuffers = PACKET_MANAGER_BUFFERS;
NumReceiveBuffers = PACKET_MANAGER_RECEIVE_BUFFERS;
reset = true;
}
}
if (reset) {
NextPacket = 0;
NumPackets = 0;
NumReceivePackets = 0;
CurrentPacket = 0;
if (SendBuffers) {
delete [] SendBuffers;
}
SendBuffers = new SendBufferClass[NumSendBuffers];
if (ReceiveBuffers) {
delete [] ReceiveBuffers;
}
ReceiveBuffers = new ReceiveBufferClass[NumReceiveBuffers];
Reset_Stats();
}
}
/***********************************************************************************************
* PacketManagerClass::Build_Delta_Packet_Patch -- Calc a delta between two packets *
* *
* *
* *
* INPUT: Ptr to base packet *
* Ptr to packet to compare with base packet *
* Ptr to delta patch that describes differences between base and add packets *
* Size of base packet (packet sizes must match) *
* Size of add packet (must match base packets size) *
* *
* OUTPUT: Size of delta patch *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/24/2001 1:36PM ST : Created *
*=============================================================================================*/
int PacketManagerClass::Build_Delta_Packet_Patch(unsigned char *base_packet, unsigned char *add_packet, unsigned char *delta_packet, int base_packet_size, int add_packet_size)
{
/*
** Here's how this works.
**
** The source and delta packets are compared 8 bytes at a time and am equality bit is set in the output stream
** for each block of 8. Then, for each non-matching block, a per byte bit is set in the output stream to indicate
** whether a byte can be used from the base packet or if a patch byte is needed. Finally, patch bytes are added to
** the stream at the end starting at a byte boundry.
**
*/
/*
** Locals.
*/
int write_bit_pos = 0;
int read_bit_pos = 0;
int num_diff_bytes = 0;
unsigned char diff_bytes[1024];
/*
** Parameter asserts.
*/
pm_assert(base_packet != NULL);
pm_assert(add_packet != NULL);
pm_assert(delta_packet != NULL);
pm_assert(base_packet_size == add_packet_size);
pm_assert(base_packet_size < sizeof(diff_bytes));
/*
** dereference pointers to the packet header and the packet build pointer.
*/
PacketDeltaHeaderStruct *header = (PacketDeltaHeaderStruct*) delta_packet;
unsigned char *build_delta_ptr = delta_packet + sizeof(PacketDeltaHeaderStruct);
unsigned char *chunk_ptr = build_delta_ptr;
pm_assert(sizeof(PacketDeltaHeaderStruct) == 1);
*build_delta_ptr = 0;
header->BytePack = 0;
if (base_packet_size == add_packet_size) {
/*
** Break it up into 8 byte chunks and see whether any of the chunks are the same.
*/
bool chunks = false;
bool this_match = false;
for (int i=0 ; i<base_packet_size - 7 ; i+=8) {
this_match = false;
if (*((long*)&base_packet[i]) == *((long*)&add_packet[i])) {
if (*((long*)&base_packet[i+4]) == *((long*)&add_packet[i+4])) {
chunks = true;
this_match = true;
}
}
write_bit_pos = Add_Bit(this_match, build_delta_ptr, write_bit_pos);
}
/*
** Mark the tail end of the buffer as different.
*/
if ((base_packet_size & 7) != 0) {
if (chunks) {
write_bit_pos = Add_Bit(false, build_delta_ptr, write_bit_pos);
}
}
/*
** If none of the chunks were the same then this is a pointless endevour. Mark in the header that we don't have
** chunk info and move on to trying byte for byte.
*/
header->ChunkPack = chunks ? 1 : 0;
/*
** Lost the useless chunk info if none of the chunks matched anyway.
*/
if (!chunks) {
build_delta_ptr = chunk_ptr;
*build_delta_ptr = 0;
write_bit_pos = 0;
}
/*
** Try a byte for byte check in the chunks that don't match. For any bytes that are different, save the changed value
** so we can add it to the end of the delta packet later.
*/
read_bit_pos = 0;
num_diff_bytes = 0;
for (i=0 ; i<base_packet_size ; i+= 8) {
/*
** If we have chunk info, then use it to skip matching chunks.
*/
if (chunks) {
if (Get_Bit(chunk_ptr, read_bit_pos)) {
continue;
}
}
/*
** If this chunk didn't match then go through byte by byte and note differences.
*/
for (int j=i ; j<i+8 && j<base_packet_size ; j++) {
header->BytePack = 1;
this_match = (base_packet[j] == add_packet[j]) ? true : false;
write_bit_pos = Add_Bit(this_match, build_delta_ptr, write_bit_pos);
if (!this_match) {
diff_bytes[num_diff_bytes++] = add_packet[j];
}
}
}
/*
** OK, now we have bitfields that mark the differences. A 1 in the bitfield means that the corresponding chunk or byte
** in the add packet is the same as in the base packet.
** Throw the non-matching bytes onto the end of the bitfield and we have a complete delta patch.
*/
unsigned char *delta_bytes_ptr = build_delta_ptr;
if (write_bit_pos != 0) {
delta_bytes_ptr++;
}
memcpy(delta_bytes_ptr, diff_bytes, num_diff_bytes);
/*
** Calculate the size of the whole delta patch.
*/
int patch_size = (delta_bytes_ptr - delta_packet) + num_diff_bytes;
return(patch_size);
}
return(-1);
}
/***********************************************************************************************
* PacketManagerClass::Reconstruct_From_Delta -- Rebuild a packet from a delta stream *
* *
* *
* *
* INPUT: Base packet to copy same bytes from *
* Buffer to store reconstructed packet into *
* Ptr to delta packet stream. *
* Size of base packet *
* (out) bytes extracted from delta stream *
* *
* OUTPUT: Size of restored packet (should match size of base packet) *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/26/2001 2:14PM ST : Created *
*=============================================================================================*/
int PacketManagerClass::Reconstruct_From_Delta(unsigned char *base_packet, unsigned char *reconstructed_packet, unsigned char *delta_packet, int base_packet_size, int &delta_size)
{
if (base_packet == NULL) {
WWDEBUG_SAY(("*** WARNING: MALFORMED PACKET - PacketManagerClass::Reconstruct_From_Delta -- Bad base packet\n"));
return(0);
}
if (reconstructed_packet == NULL) {
WWDEBUG_SAY(("*** WARNING: MALFORMED PACKET - PacketManagerClass::Reconstruct_From_Delta -- Bad reconstructed packet\n"));
return(0);
}
if (delta_packet == NULL) {
WWDEBUG_SAY(("*** WARNING: MALFORMED PACKET - PacketManagerClass::Reconstruct_From_Delta -- Bad delta packet\n"));
return(0);
}
if (base_packet_size > 500) {
WWDEBUG_SAY(("*** WARNING: MALFORMED PACKET - PacketManagerClass::Reconstruct_From_Delta -- Bad base packet size\n"));
return(0);
}
pm_assert(base_packet != NULL);
pm_assert(reconstructed_packet != NULL);
pm_assert(delta_packet != NULL);
int patch_list[1024];
int num_patches = 0;
int read_bit_pos = 0;
int read_chunk_pos = 0;
int restored_bytes = 0;
PacketDeltaHeaderStruct *header = (PacketDeltaHeaderStruct*) delta_packet;
unsigned char *read_delta_ptr = delta_packet + sizeof(PacketDeltaHeaderStruct);
pm_assert(sizeof(PacketDeltaHeaderStruct) == 1);
unsigned char *chunk_ptr = read_delta_ptr;
/*
** If there is chunk info then extract that first. Use it to copy the approprate parts of the base packet into the add packet.
*/
if (header->ChunkPack) {
for (int i=0 ; i<base_packet_size - 7 ; i+=8) {
if (Get_Bit(read_delta_ptr, read_bit_pos)) {
memcpy(&reconstructed_packet[i], &base_packet[i], 8);
restored_bytes += 8;
}
}
/*
** If the packet isn't an even number of chunks long then pull out an extra bit and throw it away. It should always be 0.
*/
if ((base_packet_size & 7) != 0) {
//#ifdef WWDEBUG
unsigned char bitty =
//#endif //WWDEBUG
Get_Bit(read_delta_ptr, read_bit_pos);
if (bitty != 0) {
WWDEBUG_SAY(("*** WARNING: MALFORMED PACKET - PacketManagerClass::Reconstruct_From_Delta -- Bad bitty\n"));
return(0);
}
pm_assert(bitty == 0);
}
}
/*
** Now use the per byte bitmask to restore the rest of the data.
*/
for (int i=0 ; i<base_packet_size ; i+= 8) {
/*
** If we have chunk info, then use it to skip matching chunks.
*/
if (header->ChunkPack) {
if (Get_Bit(chunk_ptr, read_chunk_pos)) {
continue;
}
}
/*
** If this chunk didn't match then go through byte by byte and note differences.
*/
for (int j=i ; j<i+8 && j<base_packet_size ; j++) {
if (Get_Bit(read_delta_ptr, read_bit_pos)) {
reconstructed_packet[j] = base_packet[j];
restored_bytes++;
} else {
patch_list[num_patches++] = j;
}
}
}
/*
** Well, the patch bytes must be here somewhere.
*/
unsigned char *patch_bytes = read_delta_ptr;
if (read_bit_pos != 0) {
patch_bytes++;
}
/*
** Work out how many delta bytes we processed - it's needed for meta packet decoding.
*/
delta_size = (patch_bytes - delta_packet) + num_patches;
/*
** Copy the patch bytes into the correct positions.
*/
for (int p=0 ; p<num_patches ; p++) {
reconstructed_packet[patch_list[p]] = *patch_bytes++;
}
restored_bytes += num_patches;
//pm_assert(restored_bytes == base_packet_size);
return(restored_bytes);
}
/***********************************************************************************************
* PacketManagerClass::Get_Next_Free_Buffer_Index -- Get next buffer to use for taking packets *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Buffer index (-1 if none free) *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/26/2001 2:17PM ST : Created *
*=============================================================================================*/
int PacketManagerClass::Get_Next_Free_Buffer_Index(void)
{
int return_index = -1;
for (int i=0 ; i<NumSendBuffers ; i++) {
NextPacket++;
if (NextPacket >= NumSendBuffers) {
NextPacket = 0;
}
if (SendBuffers[NextPacket].PacketLength == 0) {
return_index = NextPacket;
break;
}
}
return(return_index);
}
/***********************************************************************************************
* PacketManagerClass::Take_Packet -- Intercept a packet before it's sent *
* *
* *
* *
* INPUT: Ptr to packet *
* Length of packet *
* IP of packet recipient *
* Port of packet recipient *
* *
* OUTPUT: True if packet was accepted *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/18/2001 4:24PM ST : Created *
*=============================================================================================*/
bool PacketManagerClass::Take_Packet(unsigned char *packet, int packet_len, unsigned char *dest_ip, unsigned short dest_port, SOCKET source_socket)
{
CriticalSectionClass::LockClass lock(CriticalSection);
if (NumPackets < NumSendBuffers) {
if (packet_len > 0 && packet_len < (PACKET_MANAGER_MTU - sizeof(PacketPackHeaderStruct))) {
int index = Get_Next_Free_Buffer_Index();
if (index != -1) {
memcpy(SendBuffers[index].PacketBuffer, packet, packet_len);
SendBuffers[index].PacketLength = packet_len;
SendBuffers[index].Port = dest_port;
memcpy(&SendBuffers[index].IPAddress[0], dest_ip, 4);
SendBuffers[index].PacketSendSocket = source_socket;
NumPackets++;
//WWDEBUG_SAY(("NumPackets = %d (added packet at index %d)\n", NumPackets, index));
if (NumPackets > NumSendBuffers - 4) {
WWDEBUG_SAY(("***WARNING*** Outgoing packet buffer full - NumPackets = %d\n", NumPackets, index));
Flush(true);
WWDEBUG_SAY(("NumPackets = %d after flush\n", NumPackets, index));
}
Register_Packet_Out(dest_ip, dest_port, 0, packet_len + UDP_HEADER_SIZE);
return(true);
}
}
}
return(false);
}
/***********************************************************************************************
* PacketManagerClass::Flush -- Coalesce and send any pending packets *
* *
* *
* *
* INPUT: Forced - set to true if packets should be sent even if it's not time *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/26/2001 2:19PM ST : Created *
*=============================================================================================*/
void PacketManagerClass::Flush(bool forced)
{
{
WWPROFILE("PMgr Flush");
CriticalSectionClass::LockClass lock(CriticalSection);
int base_index = -1;
int length = 0;
unsigned char *base_packet = NULL;
int new_length = 0;
PacketPackHeaderStruct *header = (PacketPackHeaderStruct*) BuildPacket;
unsigned char *next_packet_pos = NULL;
int index = 0;
int i;
SOCKET socket = INVALID_SOCKET;
/*
** If it's not time to send packets yet then just return.
*/
unsigned long time = TIMEGETTIME();
if (!forced && FlushFrequency != 0) {
if (time - LastSendTime < FlushFrequency) {
return;
}
}
LastSendTime = time;
//WWDEBUG_SAY(("NumPackets = %d\n", NumPackets));
/*
** Clear the array that indicates whether a packet is ready to be sent.
*/
for (i=0 ; i<NumSendBuffers ; i++) {
SendBuffers[i].PacketReady = false;
}
/*
** Loop until we process all packets.
*/
while (NumPackets) {
/*
** Get a packet to start with. Find the oldest packet first in each case.
*/
index = NextPacket + 1;
if (index >= NumSendBuffers) {
index = 0;
}
base_index = -1;
for (i=0 ; i<NumSendBuffers ; i++) {
if (SendBuffers[index].PacketLength != 0) {
base_index = index;
length = SendBuffers[index].PacketLength;
base_packet = (unsigned char *) SendBuffers[index].PacketBuffer;
//WWDEBUG_SAY(("Found base packet %d\n", base_index));
socket = SendBuffers[index].PacketSendSocket;
header->NumPackets = 1;
header->PacketSize = length;
header->MorePackets = 0;
pm_assert(header->NumPackets > 0 && header->NumPackets <= PACKET_MANAGER_MAX_PACKETS);
next_packet_pos = BuildPacket + sizeof(*header);
memcpy(next_packet_pos, base_packet, length);
next_packet_pos += length;
new_length = length + sizeof(*header);
//WWDEBUG_SAY(("Added base packet %d to metapacket - %d (+2) bytes\n", index, length));
index++;
if (index >= NumSendBuffers) {
index = 0;
}
break;
}
index++;
if (index >= NumSendBuffers) {
index = 0;
}
}
/*
** If we found a packet, see if there are more packets of the same size that we can package up with it.
*/
if (base_index != -1 && NumPackets > 1) {
if ((new_length + length + sizeof(PacketDeltaHeaderStruct)) < PACKET_MANAGER_MTU) {
for (int j=i ; j<NumSendBuffers ; j++) {
/*
** If we can't fit any more packets in this packet then break out of the loop and send it as is.
*/
if (header->NumPackets == PACKET_MANAGER_MAX_PACKETS) {
break;
}
/*
** Is this packet the same length? If so, it might be suitable for coagulation.
*/
if (SendBuffers[index].PacketLength == length && SendBuffers[index].PacketSendSocket == socket) {
pm_assert(index != base_index);
/*
** Is this packet for the same recipient?
*/
if (SendBuffers[base_index].Port == SendBuffers[index].Port && (*(unsigned long*)(&SendBuffers[index].IPAddress[0])) == (*(unsigned long*)(&SendBuffers[base_index].IPAddress[0]))) {
//WWDEBUG_SAY(("Found secondary packet %d\n", index));
/*
** See if using a delta of the two packets would be smaller than including the whole packet.
*/
int bytes = Build_Delta_Packet_Patch(base_packet, SendBuffers[index].PacketBuffer->Buffer, DeltaPacket, length, length);
if (bytes < length && AllowDeltas) {
/*
** Yes, the delta is smaller so use that.
*/
memcpy(next_packet_pos, DeltaPacket, bytes);
next_packet_pos += bytes;
new_length += bytes;
//WWDEBUG_SAY(("Added delta packet %d to metapacket - %d bytes\n", index, bytes));
header->NumPackets++;
pm_assert(header->NumPackets > 0 && header->NumPackets <= PACKET_MANAGER_MAX_PACKETS);
} else {
/*
** The delta was no better than the original. Stick a 0 byte in to say it's not a delta and then
** Copy the whole thing.
*/
PacketDeltaHeaderStruct *delta_header = (PacketDeltaHeaderStruct*) next_packet_pos;
delta_header->ChunkPack = 0;
delta_header->BytePack = 0;
next_packet_pos += sizeof(PacketDeltaHeaderStruct);
new_length += sizeof(PacketDeltaHeaderStruct);
memcpy(next_packet_pos, SendBuffers[index].PacketBuffer, length);
next_packet_pos += length;
new_length += length;
//WWDEBUG_SAY(("Added secondary packet %d to metapacket - %d (+1) bytes\n", index, length));
header->NumPackets++;
pm_assert(header->NumPackets > 0 && header->NumPackets <= PACKET_MANAGER_MAX_PACKETS);
}
/*
** Discard the packet buffer now that we have added this packet to the current staging buffer area.
*/
SendBuffers[index].PacketLength = 0;
NumPackets--;
//WWDEBUG_SAY(("NumPackets = %d (discarding secondary packet index %d)\n", NumPackets, index));
pm_assert(header->NumPackets > 0 && header->NumPackets <= PACKET_MANAGER_MAX_PACKETS);
/*
** If there's no room for any more of these packets then bail out.
*/
if ((new_length + length + sizeof(PacketDeltaHeaderStruct)) >= PACKET_MANAGER_MTU) {
break;
}
}
}
index++;
if (index >= NumSendBuffers) {
index = 0;
}
}
}
}
pm_assert(header->NumPackets > 0 && header->NumPackets <= PACKET_MANAGER_MAX_PACKETS);
/*
** Allright, it's time to send this sucker.
*/
if (base_index != -1) {
/*
** Just copy it back into the base index for now and mark it as ready to go.
*/
memcpy(SendBuffers[base_index].PacketBuffer, BuildPacket, new_length);
SendBuffers[base_index].PacketReady = true;
SendBuffers[base_index].PacketSendLength = new_length;
SendBuffers[base_index].PacketLength = 0;
NumPackets--;
//WWDEBUG_SAY(("NumPackets = %d (discarding base packet %d)\n", NumPackets, base_index));
pm_assert(NumPackets >= 0);
}
pm_assert(header->NumPackets > 0 && header->NumPackets <= PACKET_MANAGER_MAX_PACKETS);
}
/*
** Merge ready buffers where possible. This is the step that adds runs of different sizeed packets into the same packet.
*/
if (AllowCombos) {
for (i=0 ; i<NumSendBuffers ; i++) {
if (SendBuffers[i].PacketReady) {
PacketPackHeaderStruct *current_header = (PacketPackHeaderStruct*) SendBuffers[i].PacketBuffer;
int current_len = SendBuffers[i].PacketSendLength;
socket = SendBuffers[i].PacketSendSocket;
/*
** See if we can find another packet for the same destination that will fit into the same buffer.
*/
#ifdef WWDEBUG
int num_sub_packets = 1;
#endif //WWDEBUG
for (int j=i+1 ; j<NumSendBuffers ; j++) {
if (SendBuffers[j].PacketReady && SendBuffers[j].PacketSendSocket == socket) {
if (SendBuffers[i].PacketSendLength + SendBuffers[j].PacketSendLength < PACKET_MANAGER_MTU) {
if (SendBuffers[i].Port == SendBuffers[j].Port && (*(unsigned long*)(&SendBuffers[i].IPAddress[0])) == (*(unsigned long*)(&SendBuffers[j].IPAddress[0]))) {
unsigned char *dest_ptr = &SendBuffers[i].PacketBuffer->Buffer[current_len];
memcpy(dest_ptr, SendBuffers[j].PacketBuffer, SendBuffers[j].PacketSendLength);
current_header->MorePackets = 1;
current_header = (PacketPackHeaderStruct*) dest_ptr;
current_len += SendBuffers[j].PacketSendLength;
SendBuffers[i].PacketSendLength = current_len;
SendBuffers[j].PacketReady = false;
#ifdef WWDEBUG
num_sub_packets++;
#endif //WWDEBUG
//WWDEBUG_SAY(("Added packet %d with %d sub packets to packet %d\n", j, ((PacketPackHeaderStruct*)&PacketBuffers[j][0])->NumPackets, i));
//WWDEBUG_SAY(("Packet %d has %d packets total\n", i, num_sub_packets));
}
}
}
}
}
}
}
/*
** Send any packets marked as ready.
*/
for (i=0 ; i<NumSendBuffers ; i++) {
if (SendBuffers[i].PacketReady) {
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = SendBuffers[i].Port;
memcpy (&addr.sin_addr.s_addr, &SendBuffers[i].IPAddress[0], 4);
socket = SendBuffers[i].PacketSendSocket;
#ifdef WWDEBUG
int debug_num_packets = (int)(((PacketPackHeaderStruct*)SendBuffers[i].PacketBuffer)->NumPackets);
int debug_packet_size = (int)(((PacketPackHeaderStruct*)SendBuffers[i].PacketBuffer)->PacketSize);
pm_assert(debug_num_packets > 0);
pm_assert(debug_packet_size < PACKET_MANAGER_MTU);
pm_assert(SendBuffers[i].PacketSendLength < PACKET_MANAGER_MTU);
//WWDEBUG_SAY(("Sending packet %d (%d bytes) to %s. Packet has %d packets of %d bytes each\n", i, PacketSendLength[i], Addr_As_String(&addr), debug_num_packets, debug_packet_size));
#endif //WWDEBUG
#ifdef WRAPPER_CRC
unsigned long crc = CRC::Memory((unsigned char*)SendBuffers[i].PacketBuffer, SendBuffers[i].PacketSendLength);
#if (1)
/*
** Reverse byte order to prevent the demo from having the same CRC as the game.
*/
_asm {
push eax;
mov eax,crc;
bswap eax;
mov crc,eax;
pop eax;
};
#endif //(0)
char *crc_and_buffer = (char*)_alloca(SendBuffers[i].PacketSendLength + sizeof(crc));
*((unsigned long*) crc_and_buffer) = crc;
memcpy(crc_and_buffer + sizeof(crc), (const char*)SendBuffers[i].PacketBuffer, SendBuffers[i].PacketSendLength);
Register_Packet_Out(&SendBuffers[i].IPAddress[0], SendBuffers[i].Port, SendBuffers[i].PacketSendLength + UDP_HEADER_SIZE + sizeof(crc), 0);
int result = sendto(socket, crc_and_buffer, SendBuffers[i].PacketSendLength + sizeof(crc), 0, (LPSOCKADDR) &addr, sizeof(SOCKADDR_IN));
#else //WRAPPER_CRC
Register_Packet_Out(&SendBuffers[i].IPAddress[0], SendBuffers[i].Port, SendBuffers[i].PacketSendLength + UDP_HEADER_SIZE, 0);
int result = sendto(socket, (const char*)SendBuffers[i].PacketBuffer, SendBuffers[i].PacketSendLength, 0, (LPSOCKADDR) &addr, sizeof(SOCKADDR_IN));
#endif //WRAPPER_CRC
if (result == SOCKET_ERROR){
if (WSAGetLastError() != WSAEWOULDBLOCK) {
int error_code = 0;
error_code = WSAGetLastError();// avoid release build compiler warning
WWDEBUG_SAY(("PacketManagerClass - sendto returned error code %d - %s\n", error_code, cNetUtil::Winsock_Error_Text(error_code)));
Clear_Socket_Error(socket);
} else {
/*
** No more room for outgoing packets. Unfortunately, this means we lose the lot.
*/
WWDEBUG_SAY(("PacketManagerClass - sendto returned WSAEWOULDBLOCK\n"));
Sleep(0);
ErrorState = STATE_WS_BUFFERS_FULL;
}
}
/*
** Send some random garbage to see if we crash.
*/
//char garbage[640];
//for (int i=0 ; i<540 ; i++) {
// garbage[i] = rand();
//}
//sendto(socket, (const char*)garbage, 540, 0, (LPSOCKADDR) &addr, sizeof(SOCKADDR_IN));
}
}
Update_Stats();
}
}
/***********************************************************************************************
* PacketManagerClass::Disable_Optimizations -- Disable all low level optimizations *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/26/2001 2:24PM TSS : Created *
*=============================================================================================*/
void PacketManagerClass::Disable_Optimizations(void)
{
FlushFrequency = 0;
AllowDeltas = false;
AllowCombos = false;
}
/***********************************************************************************************
* PacketManagerClass::Break_Packet -- Break up in incoming packet into it's original packets *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/26/2001 2:25PM ST : Created *
*=============================================================================================*/
bool PacketManagerClass::Break_Packet(unsigned char *packet, int original_packet_size, unsigned char *ip_address, unsigned short port)
{
/*
** Dereference a pointer to the packet header.
*/
PacketPackHeaderStruct *header = (PacketPackHeaderStruct*) packet;
/*
** Pull out the number of packets and the size of each.
*/
int num_packets = header->NumPackets;
int packet_size = header->PacketSize;
bool more_packets = header->MorePackets;
if (num_packets < 1 || packet_size > PACKET_MANAGER_MTU) {
WWDEBUG_SAY(("PacketManager - Packet decode error. num_packets = %d\n, packet_size = %d\n", num_packets, packet_size));
return(false);
}
pm_assert(num_packets >= 1);
pm_assert(packet_size <= PACKET_MANAGER_MTU);
/*
** Get the first packet. This is needed as a reference for other delta packets.
*/
unsigned char *packet_ptr = packet + sizeof(*header);
memcpy(&ReceiveBuffers[NumReceivePackets].ReceiveHoldingBuffer[0], packet_ptr, packet_size);
ReceiveBuffers[NumReceivePackets].ReceivePacketLength = packet_size;
Register_Packet_In(ip_address, port, 0, packet_size + UDP_HEADER_SIZE);
int delta_base_index = NumReceivePackets;
memcpy(ReceiveIPAddress, ip_address, 4);
ReceivePort = port;
NumReceivePackets++;
//WWDEBUG_SAY(("Extracted base packet from metapacket - %d bytes\n", packet_size));
packet_ptr += packet_size;
/*
** Get the rest of the packets.
*/
for (int i=0 ; i<num_packets-1 ; i++) {
PacketDeltaHeaderStruct * delta_header = (PacketDeltaHeaderStruct*) packet_ptr;
/*
** If this is a delta packet then we need to reconstruct it before copying it into the buffer.
*/
if (delta_header->ChunkPack || delta_header->BytePack) {
int delta_size = 0;
//#ifdef WWDEBUG
int bytes =
//#endif //WWDEBUG
Reconstruct_From_Delta(&ReceiveBuffers[delta_base_index].ReceiveHoldingBuffer[0], &ReceiveBuffers[NumReceivePackets].ReceiveHoldingBuffer[0], (unsigned char *)delta_header, packet_size, delta_size);
if (bytes != packet_size) {
WWDEBUG_SAY(("*** WARNING: MALFORMED PACKET - PacketManagerClass::Break_Packet -- bytes != packet_size\n"));
return(false);
}
if (delta_size <= 0) {
WWDEBUG_SAY(("*** WARNING: MALFORMED PACKET - PacketManagerClass::Break_Packet -- delta_size <= 0\n"));
return(false);
}
pm_assert(bytes == packet_size);
pm_assert(delta_size > 0);
ReceiveBuffers[NumReceivePackets].ReceivePacketLength = packet_size;
NumReceivePackets++;
packet_ptr += delta_size;
Register_Packet_In(ip_address, port, 0, packet_size + UDP_HEADER_SIZE);
//WWDEBUG_SAY(("Extracted delta packet from metapacket - %d bytes (delta size = %d)\n", bytes, delta_size));
} else {
/*
** Not a delta, just copy the whole thing.
*/
packet_ptr += sizeof(*delta_header);
memcpy(&ReceiveBuffers[NumReceivePackets].ReceiveHoldingBuffer[0], packet_ptr, packet_size);
ReceiveBuffers[NumReceivePackets].ReceivePacketLength = packet_size;
packet_ptr += packet_size;
NumReceivePackets++;
Register_Packet_In(ip_address, port, 0, packet_size + UDP_HEADER_SIZE);
//WWDEBUG_SAY(("Extracted secondary packet from metapacket - %d (+1) bytes\n", PacketLength));
}
if (NumReceivePackets >= PACKET_MANAGER_RECEIVE_BUFFERS) {
break;
}
}
int bytes_pulled_from_packet = packet_ptr - packet;
/*
** More packets in this buffer?
*/
if (more_packets && NumReceivePackets < PACKET_MANAGER_RECEIVE_BUFFERS) {
if (!Break_Packet(packet_ptr, original_packet_size - bytes_pulled_from_packet, ip_address, port)) {
return(false);
}
}
//if (NumReceivePackets > 20) {
// WWDEBUG_SAY(("Sub packet broken into %d packets\n", NumReceivePackets));
//}
return(true);
}
/***********************************************************************************************
* PacketManagerClass::Clear_Socket_Error -- Clear an error condition on a socket *
* *
* *
* *
* INPUT: Socket *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/17/2001 12:19PM ST : Created *
*=============================================================================================*/
void PacketManagerClass::Clear_Socket_Error(SOCKET socket)
{
unsigned long error_code;
int length = 4;
assert(socket != INVALID_SOCKET);
if (socket != INVALID_SOCKET) {
getsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, &length);
WWDEBUG_SAY(("Per socket error is %d - %s\n", error_code, cNetUtil::Winsock_Error_Text(error_code)));
}
}
/***********************************************************************************************
* PacketManagerClass::Get_Packet -- Return the next incoming packet to the app *
* *
* *
* *
* INPUT: Socket to use *
* Ptr to packet buffer *
* Size of packet buffer *
* (out) Ptr to ip_address *
* (out) Port number *
* *
* OUTPUT: Size of packet (0 = no packet, -1 = fatal socket error) *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 9/26/2001 2:28PM ST : Created *
*=============================================================================================*/
int PacketManagerClass::Get_Packet(SOCKET socket, unsigned char *packet_buffer, int packet_buffer_size, unsigned char *ip_address, unsigned short &port)
{
{
WWPROFILE("Pmgr Get");
CriticalSectionClass::LockClass lock(CriticalSection);
if (NumReceivePackets == 0) {
int address_size = sizeof(sockaddr_in);
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
pm_assert(packet_buffer_size >= PACKET_MANAGER_MTU);
int bytes;
int result = ioctlsocket(socket, FIONREAD, (unsigned long *)&bytes);
if (result == 0 && bytes != 0) {
bytes = recvfrom(socket, (char*)packet_buffer, packet_buffer_size, 0, (LPSOCKADDR) &addr, &address_size);
if (bytes > 0) {
#ifndef WRAPPER_CRC
Register_Packet_In((unsigned char*) &addr.sin_addr.s_addr, addr.sin_port, bytes + UDP_HEADER_SIZE, 0);
#endif //WRAPPER_CRC
#ifdef WRAPPER_CRC
unsigned long crc = CRC::Memory((unsigned char*)packet_buffer + 4, bytes - sizeof(crc));
#if (1)
/*
** Reverse byte order to prevent the demo from having the same CRC as the game.
*/
_asm {
push eax;
mov eax,crc;
bswap eax;
mov crc,eax;
pop eax;
};
#endif //(0)
if (crc != *((unsigned long*)packet_buffer)) {
WWDEBUG_SAY(("PMC::Get_Packet: Socket %d, received packet %d bytes long from %s\n", socket, bytes, Addr_As_String(&addr)));
WWDEBUG_SAY(("PMC::Get_Packet: *** PACKET WRAPPER CRC ERROR ***"));
NumReceivePackets = 0;
} else {
Register_Packet_In((unsigned char*) &addr.sin_addr.s_addr, addr.sin_port, bytes + UDP_HEADER_SIZE, 0);
bytes -= sizeof(crc);
memmove(packet_buffer, packet_buffer + sizeof(crc), bytes);
#endif //WRAPPER_CRC
//WWDEBUG_SAY(("PMC::Get_Packet: Socket %d, received packet %d bytes long from %s\n", socket, bytes, Addr_As_String(&addr)));
ReceiveSocket = socket;
//WWDEBUG_SAY(("Breaking packet %d bytes long from %s\n", bytes, Addr_As_String(&addr)));
bool broken = Break_Packet(packet_buffer, bytes, (unsigned char*) &addr.sin_addr.s_addr, addr.sin_port);
if (!broken) {
WWDEBUG_SAY(("Failed to break packet %d bytes long from %s\n", bytes, Addr_As_String(&addr)));
WWDEBUG_SAY(("Discarding %d suspect packets due to decode failure\n", NumReceivePackets));
NumReceivePackets = 0;
} else {
//WWDEBUG_SAY(("PMC::Get_Packet: Packet broken into %d packets\n", NumReceivePackets));
}
CurrentPacket = 0;
#ifdef WRAPPER_CRC
}
#endif //WRAPPER_CRC
} else {
if (bytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) {
int error_code = 0;
error_code = WSAGetLastError();// avoid release build compiler warning
WWDEBUG_SAY(("PacketManagerClass - recvfrom failed with error %d - %s\n", error_code, cNetUtil::Winsock_Error_Text(error_code)));
Clear_Socket_Error(socket);
if (error_code == WSAECONNRESET) {
WWDEBUG_SAY(("PacketManagerClass - WSAECONNRESET from address %s\n", Addr_As_String(&addr)));
memcpy(ip_address, &addr.sin_addr.s_addr, 4);
port = addr.sin_port;
return(-1);
}
} else {
WWDEBUG_SAY(("PacketManagerClass - recvfrom failed with error WSAEWOULDBLOCK\n", WSAGetLastError()));
}
}
}
}
if (CurrentPacket < NumReceivePackets && socket == ReceiveSocket) {
/*
** Copy the current packet into the return buffer. We have to zero out the rest of the buffer or the CRC won't come out
** right. Lordy. FIxed in CRC code now ST - 9/24/2001 3:36PM
*/
int size = (int)ReceiveBuffers[CurrentPacket].ReceivePacketLength;
memcpy(packet_buffer, &ReceiveBuffers[CurrentPacket].ReceiveHoldingBuffer[0], min(size, packet_buffer_size));
//if (size < packet_buffer_size) {
// memset(packet_buffer + size, 0, packet_buffer_size - size);
//}
memcpy(ip_address, ReceiveIPAddress, 4);
port = ReceivePort;
CurrentPacket++;
if (CurrentPacket >= NumReceivePackets) {
CurrentPacket = 0;
NumReceivePackets = 0;
}
return(size);
}
return(0);
}
}
/***********************************************************************************************
* PacketManager::Reset_Stats -- Reset bandwidth stats *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:54AM ST : Created *
*=============================================================================================*/
void PacketManagerClass::Reset_Stats(void)
{
CriticalSectionClass::LockClass lock(CriticalSection);
WWDEBUG_SAY(("PacketManagerClass Resetting stats\n"));
BandwidthList.Delete_All();
LastStatsUpdate = TIMEGETTIME();
ResetStatsIn = true;
ResetStatsOut = true;
}
/***********************************************************************************************
* PacketManager::Get_Stats_Index -- Get stats struct index for ip/port pair *
* *
* *
* *
* INPUT: IP *
* Port *
* Can create - true if allowed to create an entry if one doesn't exist *
* *
* OUTPUT: Index of stats struct for this ip/port, -1 for not found *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:54AM ST : Created *
*=============================================================================================*/
int PacketManagerClass::Get_Stats_Index(unsigned long ip_address, unsigned short port, bool can_create)
{
/*
** Find the stats struct entry for this ip/port.
*/
for (int i=0 ; i<BandwidthList.Count() ; i++) {
if (ip_address == BandwidthList[i].IPAddress && port == BandwidthList[i].Port) {
return(i);
}
}
if (can_create) {
/*
** No entry found - create a new one.
*/
BandwidthStatsStruct stats;
stats.IPAddress = ip_address;
stats.Port = port;
stats.UncompressedBytesIn = 0;
stats.UncompressedBytesOut = 0;
stats.CompressedBytesIn = 0;
stats.CompressedBytesOut = 0;
stats.UncompressedBandwidthIn = 0;
stats.UncompressedBandwidthOut = 0;
stats.CompressedBandwidthIn = 0;
stats.CompressedBandwidthOut = 0;
BandwidthList.Add(stats);
return(BandwidthList.Count()-1);
}
return(-1);
}
/***********************************************************************************************
* PacketManager::Register_Packet_In -- Register an incoming packet for bandwidth stats *
* *
* *
* *
* INPUT: IP address packet came from *
* Port packet came from *
* Compressed size of packet (can be 0) *
* Uncompressed size of packet (can be 0) *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:56AM ST : Created *
*=============================================================================================*/
void PacketManagerClass::Register_Packet_In(unsigned char *ip_address, unsigned short port, unsigned long compressed_size, unsigned long uncompressed_size)
{
static unsigned long _last_ip = 0;
static unsigned short _last_port = 0;
static int _last_stats = -1;
unsigned long long_ip = *((unsigned long*)ip_address);
if (ResetStatsIn) {
_last_ip = 0;
_last_port = 0;
_last_stats = -1;
ResetStatsIn = false;
}
if (_last_stats != -1 && _last_ip == long_ip && _last_port == port && BandwidthList.Count()) {
BandwidthList[_last_stats].UncompressedBytesIn += uncompressed_size;
BandwidthList[_last_stats].CompressedBytesIn += compressed_size;
} else {
int stats_index = Get_Stats_Index(long_ip, port);
assert(stats_index != -1);
if (stats_index != -1) {
BandwidthList[stats_index].UncompressedBytesIn += uncompressed_size;
BandwidthList[stats_index].CompressedBytesIn += compressed_size;
_last_stats = stats_index;
_last_ip = long_ip;
_last_port = port;
}
}
}
/***********************************************************************************************
* PacketManager::Register_Packet_Out -- Register an outgoing packet for bandwidth stats *
* *
* *
* *
* INPUT: IP address packet is going to *
* Port the packet is going to *
* Compressed size of packet (can be 0) *
* Uncompressed size of packet (can be 0) *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:56AM ST : Created *
*=============================================================================================*/
void PacketManagerClass::Register_Packet_Out(unsigned char *ip_address, unsigned short port, unsigned long compressed_size, unsigned long uncompressed_size)
{
static unsigned long _last_ip = 0;
static unsigned short _last_port = 0;
static int _last_stats = -1;
unsigned long long_ip = *((unsigned long*)ip_address);
if (ResetStatsOut) {
_last_ip = 0;
_last_port = 0;
_last_stats = -1;
ResetStatsOut = false;
}
if (_last_stats != -1 && _last_ip == long_ip && _last_port == port && BandwidthList.Count()) {
BandwidthList[_last_stats].UncompressedBytesOut += uncompressed_size;
BandwidthList[_last_stats].CompressedBytesOut += compressed_size;
} else {
int stats_index = Get_Stats_Index(long_ip, port);
assert(stats_index != -1);
if (stats_index != -1) {
BandwidthList[stats_index].UncompressedBytesOut += uncompressed_size;
BandwidthList[stats_index].CompressedBytesOut += compressed_size;
_last_stats = stats_index;
_last_ip = long_ip;
_last_port = port;
}
}
}
/***********************************************************************************************
* PacketManagerClass::Update_Stats -- Periodically update the bandwidth stats *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:57AM ST : Created *
*=============================================================================================*/
void PacketManagerClass::Update_Stats(bool forced)
{
CriticalSectionClass::LockClass lock(CriticalSection);
unsigned long time = TIMEGETTIME();
/*
** Handle timer resetting.
*/
if (time < LastStatsUpdate) {
LastStatsUpdate = 0;
}
/*
** Only update every 'n' seconds.
*/
if (time - LastStatsUpdate > StatsFrequency || forced) {
LastStatsUpdate = time;
/*
** Reset the bandwidth totals.
*/
TotalCompressedBandwidthIn = 0;
TotalCompressedBandwidthOut = 0;
TotalUncompressedBandwidthIn = 0;
TotalUncompressedBandwidthOut = 0;
/*
** Go through the entry for each ip/port and work out the averages.
*/
for (int i=0 ; i<BandwidthList.Count() ; i++) {
BandwidthStatsStruct *stats = &BandwidthList[i];
if (stats->CompressedBytesOut) {
//stats->CompressedBandwidthOut = (stats->CompressedBytesOut * 8) / StatsFrequency;
stats->CompressedBandwidthOut = (int)((1000 * stats->CompressedBytesOut * 8) / (float) StatsFrequency);
stats->CompressedBytesOut = 0;
TotalCompressedBandwidthOut += stats->CompressedBandwidthOut;
}
if (stats->CompressedBytesIn) {
//stats->CompressedBandwidthIn = (stats->CompressedBytesIn * 8) / StatsFrequency;
stats->CompressedBandwidthIn = (int)((1000 * stats->CompressedBytesIn * 8) / (float) StatsFrequency);
stats->CompressedBytesIn = 0;
TotalCompressedBandwidthIn += stats->CompressedBandwidthIn;
}
if (stats->UncompressedBytesOut) {
//stats->UncompressedBandwidthOut = (stats->UncompressedBytesOut * 8) / StatsFrequency;
stats->UncompressedBandwidthOut = (int)((1000 * stats->UncompressedBytesOut * 8) / (float) StatsFrequency);
stats->UncompressedBytesOut = 0;
TotalUncompressedBandwidthOut += stats->UncompressedBandwidthOut;
}
if (stats->UncompressedBytesIn) {
//stats->UncompressedBandwidthIn = (stats->UncompressedBytesIn * 8) / StatsFrequency;
stats->UncompressedBandwidthIn = (int)((1000 * stats->UncompressedBytesIn * 8) / (float) StatsFrequency);
stats->UncompressedBytesIn = 0;
TotalUncompressedBandwidthIn += stats->UncompressedBandwidthIn;
}
}
/*
** Just debug output.
*/
//WWDEBUG_SAY(("TotalUncompressedBandwidthOut = %d bits per second\n", TotalUncompressedBandwidthOut));
//WWDEBUG_SAY(("TotalCompressedBandwidthOut = %d bits per second\n", TotalCompressedBandwidthOut));
//WWDEBUG_SAY(("TotalUncompressedBandwidthIn = %d bits per second\n", TotalUncompressedBandwidthIn));
//WWDEBUG_SAY(("TotalCompressedBandwidthIn = %d bits per second\n", TotalCompressedBandwidthIn));
//unsigned long comp_out = 100 - ((100 * TotalCompressedBandwidthOut) / TotalUncompressedBandwidthOut);
//unsigned long comp_in = 100 - ((100 * TotalCompressedBandwidthIn) / TotalUncompressedBandwidthIn);
//WWDEBUG_SAY(("Compression out = %d percent\n", comp_out));
//WWDEBUG_SAY(("Compression in = %d percent\n", comp_in));
}
}
/***********************************************************************************************
* PacketManager::Get_Total_Raw_Bandwidth_In -- Get total uncompressed bandwidth in *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Total bandwidth before compression, in bits per second *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:59AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Total_Raw_Bandwidth_In(void)
{
return(TotalUncompressedBandwidthIn);
}
/***********************************************************************************************
* PacketManager::Get_Total_Raw_Bandwidth_Out -- Get total uncompressed bandwidth out *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Total bandwidth before compression, in bits per second *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:59AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Total_Raw_Bandwidth_Out(void)
{
return(TotalUncompressedBandwidthOut);
}
/***********************************************************************************************
* PacketManager::Get_Total_Compressed_Bandwidth_In -- Get total compressed bandwidth in *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Total bandwidth after compression, in bits per second *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:59AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Total_Compressed_Bandwidth_In(void)
{
return(TotalCompressedBandwidthIn);
}
/***********************************************************************************************
* PacketManager::Get_Total_Compressed_Bandwidth_Out -- Get total compressed bandwidth out *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Total bandwidth after compression, in bits per second *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 8:59AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Total_Compressed_Bandwidth_Out(void)
{
return(TotalCompressedBandwidthOut);
}
/***********************************************************************************************
* PacketManager::Get_Raw_Bandwidth_In -- Get uncompressed bandwidth in from given address *
* *
* *
* *
* INPUT: Address *
* *
* OUTPUT: Uncompressed bandwidth from address, in bits per second *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 9:01AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Raw_Bandwidth_In(SOCKADDR_IN *address)
{
CriticalSectionClass::LockClass lock(CriticalSection);
unsigned long ip = *((unsigned long*)&address->sin_addr.s_addr);
unsigned short port = address->sin_port;
int stats = Get_Stats_Index(ip, port, false);
unsigned long bw = 0;
if (stats != -1) {
bw = BandwidthList[stats].UncompressedBandwidthIn;
}
return(bw);
}
/***********************************************************************************************
* PacketManager::Get_Raw_Bandwidth_Out -- Get uncompressed bandwidth to given address *
* *
* *
* *
* INPUT: Address *
* *
* OUTPUT: Uncompressed bandwidth to address, in bits per second *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 9:01AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Raw_Bandwidth_Out(SOCKADDR_IN *address)
{
CriticalSectionClass::LockClass lock(CriticalSection);
unsigned long ip = *((unsigned long*)&address->sin_addr.s_addr);
unsigned short port = address->sin_port;
int stats = Get_Stats_Index(ip, port, false);
unsigned long bw = 0;
if (stats != -1) {
bw = BandwidthList[stats].UncompressedBandwidthOut;
}
return(bw);
}
/***********************************************************************************************
* PacketManager::Get_Raw_Bytes_Out -- Get uncompressed bytes to given address *
* *
* *
* *
* INPUT: Address *
* *
* OUTPUT: Uncompressed bytes sent to address. *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 9:01AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Raw_Bytes_Out(SOCKADDR_IN *address)
{
CriticalSectionClass::LockClass lock(CriticalSection);
unsigned long ip = *((unsigned long*)&address->sin_addr.s_addr);
unsigned short port = address->sin_port;
int stats = Get_Stats_Index(ip, port, false);
unsigned long bytes = 0;
if (stats != -1) {
bytes = BandwidthList[stats].UncompressedBytesOut;
}
return(bytes);
}
/***********************************************************************************************
* PacketManager::Get_Compressed_Bandwidth_In -- Get compressed bandwidth in from address *
* *
* *
* *
* INPUT: Address *
* *
* OUTPUT: Compressed bandwidth in from address, in bits per second *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 9:01AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Compressed_Bandwidth_In(SOCKADDR_IN *address)
{
CriticalSectionClass::LockClass lock(CriticalSection);
unsigned long ip = *((unsigned long*)&address->sin_addr.s_addr);
unsigned short port = address->sin_port;
int stats = Get_Stats_Index(ip, port, false);
unsigned long bw = 0;
if (stats != -1) {
bw = BandwidthList[stats].CompressedBandwidthIn;
}
return(bw);
}
/***********************************************************************************************
* PacketManager::Get_Compressed_Bandwidth_Out -- Get compressed bandwidth to address *
* *
* *
* *
* INPUT: Address *
* *
* OUTPUT: Compressed bandwidth to address, in bits per second *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 9:01AM ST : Created *
*=============================================================================================*/
unsigned long PacketManagerClass::Get_Compressed_Bandwidth_Out(SOCKADDR_IN *address)
{
CriticalSectionClass::LockClass lock(CriticalSection);
unsigned long ip = *((unsigned long*)&address->sin_addr.s_addr);
unsigned short port = address->sin_port;
int stats = Get_Stats_Index(ip, port, false);
unsigned long bw = 0;
if (stats != -1) {
bw = BandwidthList[stats].CompressedBandwidthOut;
}
return(bw);
}
/***********************************************************************************************
* PacketManagerClass::Set_Stats_Sampling_Frequency -- Set sample freq for stats *
* *
* *
* *
* INPUT: New frequency (delay in ms) *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 9:58AM ST : Created *
*=============================================================================================*/
void PacketManagerClass::Set_Stats_Sampling_Frequency_Delay(unsigned long time_ms)
{
assert(time_ms > 0);
StatsFrequency = time_ms;
Reset_Stats();
}
/***********************************************************************************************
* PacketManagerClass::Get_Error_State -- Report and clear winsock error state *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Class error state *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/24/2001 1:53PM ST : Created *
*=============================================================================================*/
PacketManagerClass::ErrorStateEnum PacketManagerClass::Get_Error_State(void)
{
ErrorStateEnum state = ErrorState;
ErrorState = STATE_OK;
return(state);
}
/*
** Operators required to allow us to add BandwidthStateStruct to a dynamic vector.
*/
bool PacketManagerClass::BandwidthStatsStruct::operator == (BandwidthStatsStruct const &stats) {
return((memcmp(this, &stats, sizeof(*this)) == 0) ? true : false);
}
bool PacketManagerClass::BandwidthStatsStruct::operator != (BandwidthStatsStruct const &stats) {
return((memcmp(this, &stats, sizeof(*this)) == 0) ? false : true);
}