Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View 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;
}
}

View 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
};

View 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;
}

View 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;
};

File diff suppressed because it is too large Load diff

View 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

View 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
}

View 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