Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
parent
2e338c00cb
commit
3d0ee53a05
6072 changed files with 2283311 additions and 0 deletions
319
Generals/Code/Tools/matchbot/wnet/field.cpp
Normal file
319
Generals/Code/Tools/matchbot/wnet/field.cpp
Normal file
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood Auto Registration App *
|
||||
* *
|
||||
* File Name : FIELD.CPP *
|
||||
* *
|
||||
* Programmer : Philip W. Gorrow *
|
||||
* *
|
||||
* Start Date : 04/22/96 *
|
||||
* *
|
||||
* Last Update : April 22, 1996 [PWG] *
|
||||
* *
|
||||
* Actual member function for the field class. *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef _WINDOWS
|
||||
#include <netinet/in.h>
|
||||
#else
|
||||
#define Win32_Winsock
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "field.h"
|
||||
|
||||
|
||||
// private member func
|
||||
void FieldClass::Clear(void)
|
||||
{
|
||||
delete[](Data);
|
||||
|
||||
strcpy(ID,"");
|
||||
DataType=0;
|
||||
Size=0;
|
||||
Data=NULL;
|
||||
Next=NULL;
|
||||
}
|
||||
|
||||
|
||||
FieldClass::FieldClass(char *id, char data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, unsigned char data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, short data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, unsigned short data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, long data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, unsigned long data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, char *data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, void *data, int length)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data,length);
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, char data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_CHAR;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, unsigned char data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_UNSIGNED_CHAR;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, short data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_SHORT;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, unsigned short data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_UNSIGNED_SHORT;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, long data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_LONG;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, unsigned long data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_UNSIGNED_LONG;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, char *data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_STRING;
|
||||
Size = (unsigned short)(strlen(data)+1);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
|
||||
void FieldClass::Set(char *id, void *data, int length)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_CHUNK;
|
||||
Size = (unsigned short)length;
|
||||
Data = new char[Size];
|
||||
memcpy(Data, data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
|
||||
FieldClass::~FieldClass()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
// Fetch the datatype
|
||||
int FieldClass::Get_Type(void)
|
||||
{
|
||||
return(DataType);
|
||||
}
|
||||
|
||||
void *FieldClass::Get_Data(void)
|
||||
{
|
||||
return(Data);
|
||||
}
|
||||
|
||||
char *FieldClass::Get_ID(void)
|
||||
{
|
||||
return(ID);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::HOST_TO_NET_FIELD -- Converts host field to net format *
|
||||
* *
|
||||
* INPUT: FIELD * to the data field we need to convert *
|
||||
* *
|
||||
* OUTPUT: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/22/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
void FieldClass::Host_To_Net(void)
|
||||
{
|
||||
//
|
||||
// Before we convert the data type, we should convert the actual data
|
||||
// sent.
|
||||
//
|
||||
switch (DataType) {
|
||||
case TYPE_CHAR:
|
||||
case TYPE_UNSIGNED_CHAR:
|
||||
case TYPE_STRING:
|
||||
break;
|
||||
|
||||
case TYPE_SHORT:
|
||||
case TYPE_UNSIGNED_SHORT:
|
||||
*((unsigned short *)Data) = htons(*((unsigned short *)Data));
|
||||
break;
|
||||
|
||||
case TYPE_LONG:
|
||||
case TYPE_UNSIGNED_LONG:
|
||||
*((unsigned long *)Data) = htonl(*((unsigned long *)Data));
|
||||
break;
|
||||
|
||||
//
|
||||
// Might be good to insert some type of error message here for unknown
|
||||
// datatypes -- but will leave that for later.
|
||||
//
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Finally convert over the data type and the size of the packet.
|
||||
//
|
||||
DataType = htons(DataType);
|
||||
Size = htons(Size);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::NET_TO_HOST_FIELD -- Converts net field to host format *
|
||||
* *
|
||||
* INPUT: FIELD * to the data field we need to convert *
|
||||
* *
|
||||
* OUTPUT: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/22/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
void FieldClass::Net_To_Host(void)
|
||||
{
|
||||
//
|
||||
// Finally convert over the data type and the size of the packet.
|
||||
//
|
||||
DataType = ntohs(DataType);
|
||||
Size = ntohs(Size);
|
||||
|
||||
//
|
||||
// Before we convert the data type, we should convert the actual data
|
||||
// sent.
|
||||
//
|
||||
switch (DataType) {
|
||||
case TYPE_CHAR:
|
||||
case TYPE_UNSIGNED_CHAR:
|
||||
case TYPE_STRING:
|
||||
break;
|
||||
|
||||
case TYPE_SHORT:
|
||||
case TYPE_UNSIGNED_SHORT:
|
||||
*((unsigned short *)Data) = ntohs(*((unsigned short *)Data));
|
||||
break;
|
||||
|
||||
case TYPE_LONG:
|
||||
case TYPE_UNSIGNED_LONG:
|
||||
*((unsigned long *)Data) = ntohl(*((unsigned long *)Data));
|
||||
break;
|
||||
|
||||
//
|
||||
// Might be good to insert some type of error message here for unknown
|
||||
// datatypes -- but will leave that for later.
|
||||
//
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
101
Generals/Code/Tools/matchbot/wnet/field.h
Normal file
101
Generals/Code/Tools/matchbot/wnet/field.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood Auto Registration App *
|
||||
* *
|
||||
* File Name : FIELD.H *
|
||||
* *
|
||||
* Programmer : Philip W. Gorrow *
|
||||
* *
|
||||
* Start Date : 04/22/96 *
|
||||
* *
|
||||
* Last Update : April 22, 1996 [PWG] *
|
||||
* *
|
||||
* This module takes care of maintaining the field list used to process *
|
||||
* packets. *
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#define FIELD_HEADER_SIZE (sizeof(FieldClass) - (sizeof(void *) * 2))
|
||||
|
||||
#define TYPE_CHAR 1
|
||||
#define TYPE_UNSIGNED_CHAR 2
|
||||
#define TYPE_SHORT 3
|
||||
#define TYPE_UNSIGNED_SHORT 4
|
||||
#define TYPE_LONG 5
|
||||
#define TYPE_UNSIGNED_LONG 6
|
||||
#define TYPE_STRING 7
|
||||
#define TYPE_CHUNK 20
|
||||
|
||||
class PacketClass;
|
||||
|
||||
class FieldClass
|
||||
{
|
||||
public:
|
||||
friend PacketClass;
|
||||
//
|
||||
// Define constructors to be able to create all the different kinds
|
||||
// of fields.
|
||||
//
|
||||
FieldClass(void) {};
|
||||
FieldClass(char *id, char data);
|
||||
FieldClass(char *id, unsigned char data);
|
||||
FieldClass(char *id, short data);
|
||||
FieldClass(char *id, unsigned short data);
|
||||
FieldClass(char *id, long data);
|
||||
FieldClass(char *id, unsigned long data);
|
||||
FieldClass(char *id, char *data);
|
||||
FieldClass(char *id, void *data, int length);
|
||||
|
||||
~FieldClass();
|
||||
|
||||
// Change the field contents
|
||||
void Set(char *id, char data);
|
||||
void Set(char *id, unsigned char data);
|
||||
void Set(char *id, short data);
|
||||
void Set(char *id, unsigned short data);
|
||||
void Set(char *id, long data);
|
||||
void Set(char *id, unsigned long data);
|
||||
void Set(char *id, char *data);
|
||||
void Set(char *id, void *data, int length);
|
||||
|
||||
int Get_Type(void); // get the datatype of this field
|
||||
unsigned short Get_Size(void) { return Size; }
|
||||
void * Get_Data(void); // get the datatype of this field
|
||||
char * Get_ID(void); // get the datatype of this field
|
||||
|
||||
void Host_To_Net(void);
|
||||
void Net_To_Host(void);
|
||||
|
||||
private:
|
||||
|
||||
void Clear(void); // dealloc mem & zero safely
|
||||
|
||||
char ID[4]; // id value of this field
|
||||
unsigned short DataType; // id of the data type we are using
|
||||
unsigned short Size; // size of the data portion of this field
|
||||
char *Data; // pointer to the data portion of this field
|
||||
FieldClass *Next; // pointer to the next field in the field list
|
||||
};
|
||||
|
||||
|
||||
|
522
Generals/Code/Tools/matchbot/wnet/packet.cpp
Normal file
522
Generals/Code/Tools/matchbot/wnet/packet.cpp
Normal file
|
@ -0,0 +1,522 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood Auto Registration App *
|
||||
* *
|
||||
* File Name : PACKET.CPP *
|
||||
* *
|
||||
* Programmer : Philip W. Gorrow *
|
||||
* *
|
||||
* Start Date : 04/22/96 *
|
||||
* *
|
||||
* Last Update : April 24, 1996 [PWG] *
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* *PacketClass::Find_Field -- Finds a field if it exists in the packets *
|
||||
* Get_Field -- Find specified name and returns data *
|
||||
* PacketClass::~PacketClass -- destroys a packet class be freeing list *
|
||||
* PacketClass::Add_Field -- Adds a FieldClass entry to head of packet li*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef _WINDOWS
|
||||
#include <netinet/in.h>
|
||||
#else
|
||||
#define Win32_Winsock
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::~PACKETCLASS -- destroys a packet class be freeing list *
|
||||
* *
|
||||
* INPUT: none *
|
||||
* *
|
||||
* OUTPUT: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/24/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
PacketClass::~PacketClass()
|
||||
{
|
||||
FieldClass *current;
|
||||
FieldClass *next;
|
||||
|
||||
//
|
||||
// Loop through the entire field list and delete each entry.
|
||||
//
|
||||
for (current = Head; current; current = next) {
|
||||
next = current->Next;
|
||||
delete(current);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::ADD_FIELD -- Adds a FieldClass entry to head of packet li *
|
||||
* *
|
||||
* INPUT: FieldClass * - a properly constructed field class entry. *
|
||||
* *
|
||||
* OUTPUT: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/24/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
void PacketClass::Add_Field(FieldClass *field)
|
||||
{
|
||||
field->Next = Head;
|
||||
Head = field;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::PACKETCLASS -- Creates a Packet object from a COMMS packe *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/22/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
PacketClass::PacketClass(char *curbuf)
|
||||
{
|
||||
int remaining_size;
|
||||
//
|
||||
// Pull the size and packet ID out of the linear packet stream.
|
||||
//
|
||||
Size = *((unsigned short *)curbuf);
|
||||
curbuf += sizeof(unsigned short);
|
||||
Size = ntohs(Size);
|
||||
ID = *((short *)curbuf);
|
||||
curbuf += sizeof(unsigned short);
|
||||
ID = ntohs(ID);
|
||||
Head = NULL;
|
||||
|
||||
//
|
||||
// Calculate the remaining size so that we can loop through the
|
||||
// packets and extract them.
|
||||
//
|
||||
remaining_size = Size - 4;
|
||||
|
||||
//
|
||||
// Loop through the linear packet until we run out of room and
|
||||
// create a field for each.
|
||||
//
|
||||
while (remaining_size > 0)
|
||||
{
|
||||
FieldClass *field = new FieldClass;
|
||||
|
||||
//
|
||||
// Copy the adjusted header into the buffer and then advance the buffer
|
||||
//
|
||||
memcpy(field, curbuf, FIELD_HEADER_SIZE);
|
||||
curbuf += FIELD_HEADER_SIZE;
|
||||
remaining_size -= FIELD_HEADER_SIZE;
|
||||
|
||||
//
|
||||
// Copy the data into the buffer
|
||||
//
|
||||
int size = ntohs(field->Size);
|
||||
field->Data = new char[size];
|
||||
memcpy(field->Data, curbuf, size);
|
||||
curbuf += size;
|
||||
remaining_size -= size;
|
||||
|
||||
//
|
||||
// Make sure we allow for the pad bytes.
|
||||
//
|
||||
int pad = (4 - (ntohs(field->Size) & 3)) & 3;
|
||||
curbuf += pad;
|
||||
remaining_size -= pad;
|
||||
|
||||
//
|
||||
// Convert the field back to the host format
|
||||
//
|
||||
field->Net_To_Host();
|
||||
|
||||
//
|
||||
// Finally add the field to the field list in the packet
|
||||
// structure.
|
||||
//
|
||||
Add_Field(field);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* CREATE_COMMS_PACKET -- Walks field list creating a packet *
|
||||
* *
|
||||
* INPUT: short - the id of the packet so the server can identify it *
|
||||
* unsigned short & - the size of the packet returned here *
|
||||
* *
|
||||
* OUTPUT: void * pointer to the linear packet data *
|
||||
* *
|
||||
* WARNINGS: This routine allocates memory that the user is responsible *
|
||||
* for freeing. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/22/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
char *PacketClass::Create_Comms_Packet(int &size)
|
||||
{
|
||||
FieldClass *current;
|
||||
|
||||
//
|
||||
// Size starts at four because that is the size of the packet header.
|
||||
//
|
||||
size = 4;
|
||||
|
||||
//
|
||||
// Take a quick spin through and calculate the size of the packet we
|
||||
// are building.
|
||||
//
|
||||
for (current = Head; current; current=current->Next)
|
||||
{
|
||||
size += (unsigned short)FIELD_HEADER_SIZE; // add in packet header size
|
||||
size += current->Size; // add in data size
|
||||
size += (4 - (size & 3)) & 3; // add in pad value to dword align next packet
|
||||
}
|
||||
|
||||
//
|
||||
// Now that we know the size allocate a buffer big enough to hold the
|
||||
// packet.
|
||||
//
|
||||
char *retval = new char[size];
|
||||
char *curbuf = retval;
|
||||
|
||||
//
|
||||
// write the size into the packet header
|
||||
//
|
||||
*((unsigned short *)curbuf) = (unsigned short)htons(size);
|
||||
curbuf += sizeof(unsigned short);
|
||||
*((short *)curbuf) = htons(ID);
|
||||
curbuf += sizeof(unsigned short);
|
||||
|
||||
//
|
||||
// Ok now that the actual header information has been written we need to write out
|
||||
// field information.
|
||||
//
|
||||
for (current = Head; current; current = current->Next)
|
||||
{
|
||||
//
|
||||
// Temporarily convert the packet to net format (this saves alot of
|
||||
// effort, and seems safe...)
|
||||
//
|
||||
current->Host_To_Net();
|
||||
|
||||
//
|
||||
// Copy the adjusted header into the buffer and then advance the buffer
|
||||
//
|
||||
memcpy(curbuf, current, FIELD_HEADER_SIZE);
|
||||
curbuf += FIELD_HEADER_SIZE;
|
||||
|
||||
//
|
||||
// Copy the data into the buffer and then advance the buffer
|
||||
//
|
||||
memcpy(curbuf, current->Data, ntohs(current->Size));
|
||||
curbuf += ntohs(current->Size);
|
||||
|
||||
//
|
||||
// Finally take care of any pad bytes by setting them to 0
|
||||
//
|
||||
int pad = (4 - (ntohs(current->Size) & 3)) & 3;
|
||||
curbuf += pad;
|
||||
|
||||
current->Net_To_Host();
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::FIND_FIELD -- Finds a field if it exists in the packets *
|
||||
* *
|
||||
* INPUT: char * - the id of the field we are looking for. *
|
||||
* *
|
||||
* OUTPUT: FieldClass * pointer to the field class *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
FieldClass *PacketClass::Find_Field(char *id)
|
||||
{
|
||||
for (FieldClass *current = Head; current; current = current->Next)
|
||||
{
|
||||
if ( strncmp(id, current->ID, 4) == 0)
|
||||
return current;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// gks 9/25/2000
|
||||
FieldClass *PacketClass::Get_Field_At(int position)
|
||||
{
|
||||
int i = 0;
|
||||
FieldClass *current = Head;
|
||||
for (; (current && (i < position)); current = current->Next, i++) {
|
||||
}
|
||||
|
||||
if (current) return current;
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
// gks 9/25/2000
|
||||
int PacketClass::Get_Num_Fields()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (FieldClass *current = Head; current; current = current->Next, i++) {}
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* char & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, char &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((char *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* unsigned char & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, unsigned char &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((unsigned char *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* short & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, short &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((short *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* unsigned short & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, unsigned short &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((unsigned short *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* long & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, long &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((long *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bit8 PacketClass::Get_Field(char *id, int &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((int *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data as a string *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* char * - the string to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The string is not changed if the field is not found. It *
|
||||
* is assumed that the string variabled specified by the *
|
||||
* pointer is large enough to hold the data. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, char *data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
strcpy(data, (char *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* unsigned long & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, unsigned long &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((unsigned long *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
bit8 PacketClass::Get_Field(char *id, unsigned &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((unsigned *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* void * - the reference to store the data into *
|
||||
* int - the length of the buffer passed in *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/4/96 4:46PM ST : Created *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, void *data, int &length)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
memcpy (data, field->Data, MIN(field->Size, length));
|
||||
length = (int) field->Size;
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
unsigned short PacketClass::Get_Field_Size(char* id)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field)
|
||||
return field->Get_Size();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
108
Generals/Code/Tools/matchbot/wnet/packet.h
Normal file
108
Generals/Code/Tools/matchbot/wnet/packet.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood Auto Registration App *
|
||||
* *
|
||||
* File Name : PACKET.H *
|
||||
* *
|
||||
* Programmer : Philip W. Gorrow *
|
||||
* *
|
||||
* Start Date : 04/19/96 *
|
||||
* *
|
||||
* Last Update : April 19, 1996 [PWG] *
|
||||
* *
|
||||
* This header defines the functions for the PacketClass. The packet *
|
||||
* class is used to create a linked list of field entries which can be *
|
||||
* converted to a linear packet in a COMMS API compatible format. *
|
||||
* *
|
||||
* Packets can be created empty and then have fields added to them or can *
|
||||
* be created from an existing linear packet. *
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "field.h"
|
||||
#include <wlib/wstypes.h>
|
||||
|
||||
|
||||
class PacketClass
|
||||
{
|
||||
public:
|
||||
|
||||
PacketClass(short id = 0)
|
||||
{
|
||||
Size = 0;
|
||||
ID = id;
|
||||
Head = 0;
|
||||
}
|
||||
PacketClass(char *cur_buf);
|
||||
~PacketClass();
|
||||
|
||||
//
|
||||
// This function allows us to add a field to the start of the list. As the field is just
|
||||
// a big linked list it makes no difference which end we add a member to.
|
||||
//
|
||||
void Add_Field(FieldClass *field);
|
||||
|
||||
//
|
||||
// These conveniance functions allow us to add a field directly to the list without
|
||||
// having to worry about newing one first.
|
||||
//
|
||||
void Add_Field(char *field, char data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, unsigned char data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, short data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, unsigned short data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, long data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, unsigned long data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, char *data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, void *data, int length) {Add_Field(new FieldClass(field, data, length));};
|
||||
|
||||
//
|
||||
// These functions search for a field of a given name in the list and
|
||||
// return the data via a reference value.
|
||||
//
|
||||
FieldClass *Find_Field(char *id);
|
||||
|
||||
bit8 Get_Field(char *id, int &data);
|
||||
bit8 Get_Field(char *id, char &data);
|
||||
bit8 Get_Field(char *id, unsigned char &data);
|
||||
bit8 Get_Field(char *id, short &data);
|
||||
bit8 Get_Field(char *id, unsigned short &data);
|
||||
bit8 Get_Field(char *id, long &data);
|
||||
bit8 Get_Field(char *id, unsigned long &data);
|
||||
bit8 Get_Field(char *id, unsigned &data);
|
||||
bit8 Get_Field(char *id, char *data);
|
||||
bit8 Get_Field(char *id, void *data, int &length);
|
||||
unsigned short Get_Field_Size(char* id);
|
||||
|
||||
// gks 9/25/2000
|
||||
FieldClass *Get_Field_At(int position);
|
||||
int Get_Num_Fields();
|
||||
|
||||
char *Create_Comms_Packet(int &size);
|
||||
|
||||
private:
|
||||
unsigned short Size;
|
||||
short ID;
|
||||
FieldClass *Head;
|
||||
FieldClass *Current;
|
||||
};
|
||||
|
1242
Generals/Code/Tools/matchbot/wnet/tcp.cpp
Normal file
1242
Generals/Code/Tools/matchbot/wnet/tcp.cpp
Normal file
File diff suppressed because it is too large
Load diff
199
Generals/Code/Tools/matchbot/wnet/tcp.h
Normal file
199
Generals/Code/Tools/matchbot/wnet/tcp.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
TCP Neal Kettler neal@westwood.com
|
||||
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef TCP_HEADER
|
||||
#define TCP_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#define close _close
|
||||
#define read _read
|
||||
#define write _write
|
||||
|
||||
#else //UNIX
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
typedef signed int SOCKET;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AIX
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PROTOCOL 0
|
||||
|
||||
#include "wlib/wstypes.h"
|
||||
#include "wlib/wdebug.h"
|
||||
#include "wlib/wtime.h"
|
||||
|
||||
class TCP
|
||||
{
|
||||
|
||||
// DATA ---------------
|
||||
|
||||
private:
|
||||
int mode; // client or server
|
||||
sint32 fd; // the primary FD
|
||||
|
||||
uint32 myIP; // after bind myIP & myPort will be
|
||||
uint16 myPort; // whatever we bound to
|
||||
|
||||
struct sockaddr_in addr;
|
||||
int maxFD; // value of the biggest FD
|
||||
int clientCount; // how many clients open
|
||||
|
||||
|
||||
sint32 inputDelay; // default delay for semi-blocking reads
|
||||
sint32 outputDelay; // default delay for semi-blocking writes
|
||||
|
||||
enum ConnectionState
|
||||
{
|
||||
CLOSED,
|
||||
CONNECTING,
|
||||
CONNECTED
|
||||
} connectionState; // What state is client FD in
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
CLIENT = 1,
|
||||
SERVER = 2
|
||||
};
|
||||
|
||||
// These defines specify a system independent way to
|
||||
// get error codes for socket services.
|
||||
enum
|
||||
{
|
||||
OK, // Everything's cool
|
||||
UNKNOWN, // There was an error of unknown type
|
||||
ISCONN, // The socket is already connected
|
||||
INPROGRESS, // The socket is non-blocking and the operation
|
||||
// isn't done yet
|
||||
ALREADY, // The socket is already attempting a connection
|
||||
// but isn't done yet
|
||||
AGAIN, // Try again.
|
||||
ADDRINUSE, // Address already in use
|
||||
ADDRNOTAVAIL, // That address is not available on the remote host
|
||||
BADF, // Not a valid FD
|
||||
CONNREFUSED, // Connection was refused
|
||||
INTR, // Operation was interrupted
|
||||
NOTSOCK, // FD wasn't a socket
|
||||
PIPE, // That operation just made a SIGPIPE
|
||||
WOULDBLOCK, // That operation would block
|
||||
INVAL, // Invalid
|
||||
TIMEDOUT // Timeout
|
||||
};
|
||||
|
||||
// for client list (if this is a server)
|
||||
fd_set clientList;
|
||||
|
||||
|
||||
// CODE ----------------
|
||||
|
||||
public:
|
||||
TCP(int newMode);
|
||||
TCP(int newMode,sint16 socket);
|
||||
~TCP();
|
||||
bit8 Bind(uint32 IP,uint16 port,bit8 reuseAddr=FALSE);
|
||||
bit8 Bind(char *Host,uint16 port,bit8 reuseAddr=FALSE);
|
||||
|
||||
sint32 GetMaxFD(void);
|
||||
|
||||
bit8 Connect(uint32 IP,uint16 port);
|
||||
bit8 Connect(char *Host,uint16 port);
|
||||
bit8 ConnectAsync(uint32 IP,uint16 port);
|
||||
bit8 ConnectAsync(char *Host,uint16 port);
|
||||
|
||||
bit8 IsConnected(sint32 whichFD=0);
|
||||
|
||||
sint32 GetFD(void);
|
||||
sint32 GetClientCount(void) { return(clientCount); }
|
||||
|
||||
// Get IP or Port of a connected endpoint
|
||||
uint32 GetRemoteIP(sint32 whichFD=0);
|
||||
uint16 GetRemotePort(sint32 whichFD=0);
|
||||
|
||||
sint32 GetConnection(void);
|
||||
sint32 GetConnection(struct sockaddr *clientAddr);
|
||||
void WaitWrite(sint32 whichFD=0);
|
||||
bit8 CanWrite(sint32 whichFD=0);
|
||||
sint32 Write(const uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 WriteNB(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 EncapsulatedWrite(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 WriteString(char *msg,sint32 whichFD=0);
|
||||
sint32 Printf(sint32 whichFD,const char *format,...);
|
||||
sint32 Read(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 TimedRead(uint8 *msg,uint32 len,int seconds,sint32 whichFD=0);
|
||||
sint32 Peek(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 EncapsulatedRead(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
|
||||
char *Gets(char *string,int n,int whichFD=0);
|
||||
|
||||
// Wait on all sockets (or a specified one)
|
||||
// return when ready for reading (or timeout occurs)
|
||||
int Wait(sint32 sec,sint32 usec,fd_set &returnSet,sint32 whichFD=0);
|
||||
int Wait(sint32 sec,sint32 usec,fd_set &inputSet,fd_set &returnSet);
|
||||
|
||||
int GetStatus(void);
|
||||
void ClearStatus(void);
|
||||
|
||||
//sint32 GetSockStatus(sint32 whichFD=0);
|
||||
|
||||
// give up ownership of the socket without closing it
|
||||
void DisownSocket(void);
|
||||
|
||||
sint32 Close(sint32 whichFD=0);
|
||||
sint32 CloseAll(void); // close all sockets (same as close for client)
|
||||
|
||||
sint32 SetBlocking(bit8 block,sint32 whichFD=0);
|
||||
|
||||
// Set default delays for semi-blocking reads & writes
|
||||
// default input = 5, output = 5
|
||||
// this is new and not used everywhere
|
||||
//
|
||||
bit8 SetInputDelay(sint32 delay) { inputDelay=delay; return(TRUE); };
|
||||
bit8 SetOutputDelay(sint32 delay) { outputDelay=delay; return(TRUE); };
|
||||
|
||||
};
|
||||
|
||||
#endif
|
372
Generals/Code/Tools/matchbot/wnet/udp.cpp
Normal file
372
Generals/Code/Tools/matchbot/wnet/udp.cpp
Normal file
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
#include "udp.h"
|
||||
#include "wlib/wdebug.h"
|
||||
|
||||
UDP::UDP()
|
||||
{
|
||||
fd=0;
|
||||
}
|
||||
|
||||
UDP::~UDP()
|
||||
{
|
||||
}
|
||||
|
||||
sint32 UDP::Bind(char *Host,uint16 port)
|
||||
{
|
||||
char hostName[100];
|
||||
struct hostent *hostStruct;
|
||||
struct in_addr *hostNode;
|
||||
|
||||
if (isdigit(Host[0]))
|
||||
return ( Bind( ntohl(inet_addr(Host)), port) );
|
||||
|
||||
strcpy(hostName, Host);
|
||||
|
||||
hostStruct = gethostbyname(Host);
|
||||
if (hostStruct == NULL)
|
||||
return (0);
|
||||
hostNode = (struct in_addr *) hostStruct->h_addr;
|
||||
return ( Bind(ntohl(hostNode->s_addr),port) );
|
||||
}
|
||||
|
||||
// You must call bind, implicit binding is for sissies
|
||||
// Well... you can get implicit binding if you pass 0 for either arg
|
||||
sint32 UDP::Bind(uint32 IP,uint16 Port)
|
||||
{
|
||||
int retval;
|
||||
int status;
|
||||
|
||||
IP=htonl(IP);
|
||||
Port=htons(Port);
|
||||
|
||||
addr.sin_family=AF_INET;
|
||||
addr.sin_port=Port;
|
||||
addr.sin_addr.s_addr=IP;
|
||||
fd=socket(AF_INET,SOCK_DGRAM,DEFAULT_PROTOCOL);
|
||||
#ifdef _WINDOWS
|
||||
if (fd==SOCKET_ERROR)
|
||||
fd=-1;
|
||||
#endif
|
||||
if (fd==-1)
|
||||
return(UNKNOWN);
|
||||
|
||||
retval=bind(fd,(struct sockaddr *)&addr,sizeof(addr));
|
||||
|
||||
#ifdef _WINDOWS
|
||||
if (retval==SOCKET_ERROR)
|
||||
retval=-1;
|
||||
#endif
|
||||
if (retval==-1)
|
||||
{
|
||||
status=GetStatus();
|
||||
//CERR("Bind failure (" << status << ") IP " << IP << " PORT " << Port )
|
||||
return(status);
|
||||
}
|
||||
|
||||
int namelen=sizeof(addr);
|
||||
getsockname(fd, (struct sockaddr *)&addr, &namelen);
|
||||
|
||||
myIP=ntohl(addr.sin_addr.s_addr);
|
||||
myPort=ntohs(addr.sin_port);
|
||||
|
||||
retval=SetBlocking(FALSE);
|
||||
if (retval==-1)
|
||||
fprintf(stderr,"Couldn't set nonblocking mode!\n");
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
bit8 UDP::getLocalAddr(uint32 &ip, uint16 &port)
|
||||
{
|
||||
ip=myIP;
|
||||
port=myPort;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
// private function
|
||||
sint32 UDP::SetBlocking(bit8 block)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
unsigned long flag=1;
|
||||
if (block)
|
||||
flag=0;
|
||||
int retval;
|
||||
retval=ioctlsocket(fd,FIONBIO,&flag);
|
||||
if (retval==SOCKET_ERROR)
|
||||
return(UNKNOWN);
|
||||
else
|
||||
return(OK);
|
||||
#else // UNIX
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (block==FALSE) // set nonblocking
|
||||
flags |= O_NONBLOCK;
|
||||
else // set blocking
|
||||
flags &= ~(O_NONBLOCK);
|
||||
|
||||
if (fcntl(fd, F_SETFL, flags) < 0)
|
||||
{
|
||||
return(UNKNOWN);
|
||||
}
|
||||
return(OK);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
sint32 UDP::Write(uint8 *msg,uint32 len,uint32 IP,uint16 port)
|
||||
{
|
||||
sint32 retval;
|
||||
struct sockaddr_in to;
|
||||
|
||||
// This happens frequently
|
||||
if ((IP==0)||(port==0)) return(ADDRNOTAVAIL);
|
||||
|
||||
errno=0;
|
||||
to.sin_port=htons(port);
|
||||
to.sin_addr.s_addr=htonl(IP);
|
||||
to.sin_family=AF_INET;
|
||||
|
||||
ClearStatus();
|
||||
retval=sendto(fd,(char *)msg,len,0,(struct sockaddr *)&to,sizeof(to));
|
||||
#ifdef _WINDOWS
|
||||
if (retval==SOCKET_ERROR)
|
||||
retval=-1;
|
||||
#endif
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
sint32 UDP::Read(uint8 *msg,uint32 len,sockaddr_in *from)
|
||||
{
|
||||
sint32 retval;
|
||||
int alen=sizeof(sockaddr_in);
|
||||
|
||||
if (from!=NULL)
|
||||
{
|
||||
retval=recvfrom(fd,(char *)msg,len,0,(struct sockaddr *)from,&alen);
|
||||
#ifdef _WINDOWS
|
||||
if (retval==SOCKET_ERROR)
|
||||
retval=-1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
retval=recvfrom(fd,(char *)msg,len,0,NULL,NULL);
|
||||
#ifdef _WINDOWS
|
||||
if (retval==SOCKET_ERROR)
|
||||
retval=-1;
|
||||
#endif
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
void UDP::ClearStatus(void)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
errno=0;
|
||||
#endif
|
||||
}
|
||||
|
||||
UDP::sockStat UDP::GetStatus(void)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
int status=WSAGetLastError();
|
||||
if (status==0) return(OK);
|
||||
else if (status==WSAEINTR) return(INTR);
|
||||
else if (status==WSAEINPROGRESS) return(INPROGRESS);
|
||||
else if (status==WSAECONNREFUSED) return(CONNREFUSED);
|
||||
else if (status==WSAEINVAL) return(INVAL);
|
||||
else if (status==WSAEISCONN) return(ISCONN);
|
||||
else if (status==WSAENOTSOCK) return(NOTSOCK);
|
||||
else if (status==WSAETIMEDOUT) return(TIMEDOUT);
|
||||
else if (status==WSAEALREADY) return(ALREADY);
|
||||
else if (status==WSAEWOULDBLOCK) return(WOULDBLOCK);
|
||||
else if (status==WSAEBADF) return(BADF);
|
||||
else return(UNKNOWN);
|
||||
#else
|
||||
int status=errno;
|
||||
if (status==0) return(OK);
|
||||
else if (status==EINTR) return(INTR);
|
||||
else if (status==EINPROGRESS) return(INPROGRESS);
|
||||
else if (status==ECONNREFUSED) return(CONNREFUSED);
|
||||
else if (status==EINVAL) return(INVAL);
|
||||
else if (status==EISCONN) return(ISCONN);
|
||||
else if (status==ENOTSOCK) return(NOTSOCK);
|
||||
else if (status==ETIMEDOUT) return(TIMEDOUT);
|
||||
else if (status==EALREADY) return(ALREADY);
|
||||
else if (status==EAGAIN) return(AGAIN);
|
||||
else if (status==EWOULDBLOCK) return(WOULDBLOCK);
|
||||
else if (status==EBADF) return(BADF);
|
||||
else return(UNKNOWN);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Wait for net activity on this socket
|
||||
//
|
||||
int UDP::Wait(sint32 sec,sint32 usec,fd_set &returnSet)
|
||||
{
|
||||
fd_set inputSet;
|
||||
|
||||
FD_ZERO(&inputSet);
|
||||
FD_SET(fd,&inputSet);
|
||||
|
||||
return(Wait(sec,usec,inputSet,returnSet));
|
||||
}
|
||||
|
||||
//
|
||||
// Wait for net activity on a list of sockets
|
||||
//
|
||||
int UDP::Wait(sint32 sec,sint32 usec,fd_set &givenSet,fd_set &returnSet)
|
||||
{
|
||||
Wtime timeout,timenow,timethen;
|
||||
fd_set backupSet;
|
||||
int retval=0,done,givenMax;
|
||||
bit8 noTimeout=FALSE;
|
||||
timeval tv;
|
||||
|
||||
returnSet=givenSet;
|
||||
backupSet=returnSet;
|
||||
|
||||
if ((sec==-1)&&(usec==-1))
|
||||
noTimeout=TRUE;
|
||||
|
||||
timeout.SetSec(sec);
|
||||
timeout.SetUsec(usec);
|
||||
timethen+=timeout;
|
||||
|
||||
givenMax=fd;
|
||||
for (uint32 i=0; i<(sizeof(fd_set)*8); i++) // i=maxFD+1
|
||||
{
|
||||
if (FD_ISSET(i,&givenSet))
|
||||
givenMax=i;
|
||||
}
|
||||
///DBGMSG("WAIT fd="<<fd<<" givenMax="<<givenMax);
|
||||
|
||||
done=0;
|
||||
while( ! done)
|
||||
{
|
||||
if (noTimeout)
|
||||
retval=select(givenMax+1,&returnSet,0,0,NULL);
|
||||
else
|
||||
{
|
||||
timeout.GetTimevalMT(tv);
|
||||
retval=select(givenMax+1,&returnSet,0,0,&tv);
|
||||
}
|
||||
|
||||
if (retval>=0)
|
||||
done=1;
|
||||
|
||||
else if ((retval==-1)&&(errno==EINTR)) // in case of signal
|
||||
{
|
||||
if (noTimeout==FALSE)
|
||||
{
|
||||
timenow.Update();
|
||||
timeout=timethen-timenow;
|
||||
}
|
||||
if ((noTimeout==FALSE)&&(timenow.GetSec()==0)&&(timenow.GetUsec()==0))
|
||||
done=1;
|
||||
else
|
||||
returnSet=backupSet;
|
||||
}
|
||||
else // maybe out of memory?
|
||||
{
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
///DBGMSG("Wait retval: "<<retval);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Set the kernel buffer sizes for incoming, and outgoing packets
|
||||
//
|
||||
// Linux seems to have a buffer max of 32767 bytes for this,
|
||||
// (which is the default). If you try and set the size to
|
||||
// greater than the default it just sets it to 32767.
|
||||
|
||||
bit8 UDP::SetInputBuffer(uint32 bytes)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
int retval,arg=bytes;
|
||||
|
||||
retval=setsockopt(fd,SOL_SOCKET,SO_RCVBUF,
|
||||
(char *)&arg,sizeof(int));
|
||||
if (retval==0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
#else
|
||||
return(FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Same note goes for the output buffer
|
||||
|
||||
bit8 UDP::SetOutputBuffer(uint32 bytes)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
int retval,arg=bytes;
|
||||
|
||||
retval=setsockopt(fd,SOL_SOCKET,SO_SNDBUF,
|
||||
(char *)&arg,sizeof(int));
|
||||
if (retval==0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
#else
|
||||
return(FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the system buffer sizes
|
||||
|
||||
int UDP::GetInputBuffer(void)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
int retval,arg=0,len=sizeof(int);
|
||||
|
||||
retval=getsockopt(fd,SOL_SOCKET,SO_RCVBUF,
|
||||
(char *)&arg,&len);
|
||||
return(arg);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int UDP::GetOutputBuffer(void)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
int retval,arg=0,len=sizeof(int);
|
||||
|
||||
retval=getsockopt(fd,SOL_SOCKET,SO_SNDBUF,
|
||||
(char *)&arg,&len);
|
||||
return(arg);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
114
Generals/Code/Tools/matchbot/wnet/udp.h
Normal file
114
Generals/Code/Tools/matchbot/wnet/udp.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
#ifndef UDP_HEADER
|
||||
#define UDP_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#define close _close
|
||||
#define read _read
|
||||
#define write _write
|
||||
|
||||
#else //UNIX
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifdef AIX
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PROTOCOL 0
|
||||
|
||||
#include <wlib/wstypes.h>
|
||||
#include <wlib/wtime.h>
|
||||
|
||||
class UDP
|
||||
{
|
||||
// DATA
|
||||
private:
|
||||
sint32 fd;
|
||||
uint32 myIP;
|
||||
uint16 myPort;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
// These defines specify a system independent way to
|
||||
// get error codes for socket services.
|
||||
enum sockStat
|
||||
{
|
||||
OK = 0, // Everything's cool
|
||||
UNKNOWN = -1, // There was an error of unknown type
|
||||
ISCONN = -2, // The socket is already connected
|
||||
INPROGRESS = -3, // The socket is non-blocking and the operation
|
||||
// isn't done yet
|
||||
ALREADY = -4, // The socket is already attempting a connection
|
||||
// but isn't done yet
|
||||
AGAIN = -5, // Try again.
|
||||
ADDRINUSE = -6, // Address already in use
|
||||
ADDRNOTAVAIL = -7, // That address is not available on the remote host
|
||||
BADF = -8, // Not a valid FD
|
||||
CONNREFUSED = -9, // Connection was refused
|
||||
INTR =-10, // Operation was interrupted
|
||||
NOTSOCK =-11, // FD wasn't a socket
|
||||
PIPE =-12, // That operation just made a SIGPIPE
|
||||
WOULDBLOCK =-13, // That operation would block
|
||||
INVAL =-14, // Invalid
|
||||
TIMEDOUT =-15 // Timeout
|
||||
};
|
||||
|
||||
// CODE
|
||||
private:
|
||||
sint32 SetBlocking(bit8 block);
|
||||
|
||||
public:
|
||||
UDP();
|
||||
~UDP();
|
||||
sint32 Bind(uint32 IP,uint16 port);
|
||||
sint32 Bind(char *Host,uint16 port);
|
||||
sint32 Write(uint8 *msg,uint32 len,uint32 IP,uint16 port);
|
||||
sint32 Read(uint8 *msg,uint32 len,sockaddr_in *from);
|
||||
sockStat GetStatus(void);
|
||||
void ClearStatus(void);
|
||||
int Wait(sint32 sec,sint32 usec,fd_set &returnSet);
|
||||
int Wait(sint32 sec,sint32 usec,fd_set &givenSet,fd_set &returnSet);
|
||||
|
||||
bit8 getLocalAddr(uint32 &ip, uint16 &port);
|
||||
sint32 getFD(void) { return(fd); }
|
||||
|
||||
bit8 SetInputBuffer(uint32 bytes);
|
||||
bit8 SetOutputBuffer(uint32 bytes);
|
||||
int GetInputBuffer(void);
|
||||
int GetOutputBuffer(void);
|
||||
};
|
||||
|
||||
#endif
|
Reference in a new issue