Skip to content

Commit

Permalink
Endian fixes for the Red Alert lobby networking code.
Browse files Browse the repository at this point in the history
  • Loading branch information
isojalka authored and hifi committed Mar 16, 2024
1 parent 4e8cd33 commit f52d4d2
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 79 deletions.
2 changes: 2 additions & 0 deletions common/connect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ int ConnectionClass::Send_Packet(void* buf, int buflen, int ack_req)
((CommHeaderType*)PacketBuf)->PacketID = NumSendNoAck;
}

SwapCommHeaderType((CommHeaderType*)PacketBuf);

/*------------------------------------------------------------------------
Now build the packet
------------------------------------------------------------------------*/
Expand Down
7 changes: 7 additions & 0 deletions common/connect.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
********************************* Includes **********************************
*/
#include "combuf.h"
#include "endianness.h"

/*
********************************** Defines **********************************
Expand All @@ -122,6 +123,12 @@ typedef struct
unsigned int PacketID;
} CommHeaderType;

inline void SwapCommHeaderType(CommHeaderType* cht)
{
cht->MagicNumber = le16toh(cht->MagicNumber);
cht->PacketID = le32toh(cht->PacketID);
}

/*
***************************** Class Declaration *****************************
*/
Expand Down
8 changes: 6 additions & 2 deletions redalert/ipxgconn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ int IPXGlobalConnClass::Send_Packet(void* buf, int buflen, IPXAddressClass* addr
------------------------------------------------------------------------*/
((GlobalHeaderType*)PacketBuf)->ProductID = ProductID;

SwapGlobalHeaderType((GlobalHeaderType*)PacketBuf);

/*------------------------------------------------------------------------
Set this packet's destination address. If no address is specified, use
a Broadcast address (which IPXAddressClass's default constructor creates).
Expand Down Expand Up @@ -253,6 +255,7 @@ int IPXGlobalConnClass::Receive_Packet(void* buf, int buflen, IPXAddressClass* a
ackpacket.Header.Code = PACKET_ACK;
ackpacket.Header.PacketID = packet->Header.PacketID;
ackpacket.ProductID = ProductID;
SwapGlobalHeaderType(&ackpacket);
Send((char*)&ackpacket, sizeof(GlobalHeaderType), address, sizeof(IPXAddressClass));
}

Expand Down Expand Up @@ -288,7 +291,8 @@ int IPXGlobalConnClass::Receive_Packet(void* buf, int buflen, IPXAddressClass* a
/*...............................................................
If ACK is for this entry, mark it
...............................................................*/
if (packet->Header.PacketID == entry_data->Header.PacketID && entry_data->Header.Code == PACKET_DATA_ACK) {
if (packet->Header.PacketID == le32toh(entry_data->Header.PacketID)
&& entry_data->Header.Code == PACKET_DATA_ACK) {
send_entry->IsACK = 1;
break;
}
Expand Down Expand Up @@ -361,7 +365,7 @@ int IPXGlobalConnClass::Get_Packet(void* buf, int* buflen, IPXAddressClass* addr
memcpy(buf, rec_entry->Buffer + sizeof(GlobalHeaderType), packetlen);
}
(*buflen) = packetlen;
(*product_id) = packet->ProductID;
(*product_id) = le16toh(packet->ProductID);
(*address) = (*((IPXAddressClass*)(rec_entry->ExtraBuffer)));

return (1);
Expand Down
7 changes: 7 additions & 0 deletions redalert/ipxgconn.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
#ifndef IPXGLOBALCONN_H
#define IPXGLOBALCONN_H

#include "common/endianness.h"
#include "ipxconn.h"

/*
Expand All @@ -94,6 +95,12 @@ typedef struct
unsigned short ProductID;
} GlobalHeaderType;

inline void SwapGlobalHeaderType(GlobalHeaderType* ght)
{
SwapCommHeaderType(&ght->Header);
ght->ProductID = le16toh(ght->ProductID);
}

/*
***************************** Class Declaration *****************************
*/
Expand Down
31 changes: 31 additions & 0 deletions redalert/ipxmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,19 @@ int IPXManagerClass::Send_Global_Message(void* buf, int buflen, int ack_req, IPX

} /* end of Send_Global_Message */

int IPXManagerClass::Send_Global_Message(GlobalPacketType* buf, int buflen, int ack_req, IPXAddressClass* address)
{
int rc;

SwapGlobalPacketType(buf, true);

rc = Send_Global_Message((void*)buf, buflen, ack_req, address);

SwapGlobalPacketType(buf, false);

return rc;
} /* end of Send_Global_Message */

/***************************************************************************
* IPXManagerClass::Get_Global_Message -- polls the Global Message queue *
* *
Expand Down Expand Up @@ -769,6 +782,20 @@ int IPXManagerClass::Get_Global_Message(void* buf, int* buflen, IPXAddressClass*

} /* end of Get_Global_Message */

int IPXManagerClass::Get_Global_Message(GlobalPacketType* buf,
int* buflen,
IPXAddressClass* address,
unsigned short* product_id)
{
int rc;

rc = Get_Global_Message((void*)buf, buflen, address, product_id);

SwapGlobalPacketType(buf, false);

return rc;
} /* end of Get_Global_Message */

/***************************************************************************
* IPXManagerClass::Send_Private_Message -- Sends a Private Message *
* *
Expand Down Expand Up @@ -962,6 +989,9 @@ int IPXManagerClass::Service(void)
address = *((IPXAddressClass*)temp_address);

packet = (CommHeaderType*)CurDataBuf;

SwapCommHeaderType(packet);

if (packet->MagicNumber == GlobalChannel->Magic_Num()) {

/*
Expand Down Expand Up @@ -1067,6 +1097,7 @@ int IPXManagerClass::Service(void)
packet goes into the Global Queue, or into one of the Private Queues
.....................................................................*/
packet = (CommHeaderType*)CurDataBuf;
SwapCommHeaderType(packet);
if (packet->MagicNumber == GlobalChannel->Magic_Num()) {
/*..................................................................
Put the packet in the Global Queue
Expand Down
4 changes: 4 additions & 0 deletions redalert/ipxmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@
#include "common/ipxaddr.h"
#include "connmgr.h"

struct GlobalPacketType;

/*
********************************** Defines **********************************
*/
Expand Down Expand Up @@ -186,7 +188,9 @@ class IPXManagerClass : public ConnManClass
This is how the application sends & receives messages.
.....................................................................*/
int Send_Global_Message(void* buf, int buflen, int ack_req = 0, IPXAddressClass* address = NULL);
int Send_Global_Message(GlobalPacketType* buf, int buflen, int ack_req = 0, IPXAddressClass* address = NULL);
int Get_Global_Message(void* buf, int* buflen, IPXAddressClass* address, unsigned short* product_id);
int Get_Global_Message(GlobalPacketType* buf, int* buflen, IPXAddressClass* address, unsigned short* product_id);

virtual int Send_Private_Message(void* buf, int buflen, int ack_req = 1, int conn_id = CONNECTION_NONE);
virtual int Get_Private_Message(void* buf, int* buflen, int* conn_id);
Expand Down
136 changes: 118 additions & 18 deletions redalert/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

#include "common/ipxaddr.h"
#include "common/bitfields.h"
#include "common/endianness.h"
#include "msglist.h"
#include "connect.h"
#include "version.h"
Expand Down Expand Up @@ -321,7 +322,7 @@ typedef struct
#ifdef WOLAPI_INTEGRATION
char ShortFileName[13]; // Name of scenario file to expect from host
#else
char ShortFileName[12]; // Name of scenario file to expect from host
char ShortFileName[12]; // Name of scenario file to expect from host
#endif
unsigned char FileDigest[32]; // Digest of scenario file to expect from host
// ajw - This is not necessarily null-terminated.
Expand Down Expand Up @@ -361,7 +362,18 @@ typedef struct GlobalPacketType
{
struct BITFIELD_STRUCT
{
unsigned int IsOpen : 1; // 1 = game is open for joining
union
{
unsigned int Bitfield;

struct
{
#ifdef __BIG_ENDIAN__
unsigned int Unused : 31;
#endif
unsigned int IsOpen : 1; // 1 = game is open for joining
};
};
} GameInfo;
struct
{
Expand All @@ -374,25 +386,42 @@ typedef struct GlobalPacketType
} PlayerInfo;
struct BITFIELD_STRUCT
{
char Scenario[DESCRIP_MAX]; // Scenario Name
unsigned int Credits; // player's credits
unsigned int IsBases : 1; // 1 = bases are allowed
unsigned int IsTiberium : 1; // 1 = tiberium is allowed
unsigned int IsGoodies : 1; // 1 = goodies are allowed
unsigned int IsGhosties : 1; // 1 = ghosts are allowed
unsigned int OfficialScenario : 1; // Is this scenario an official Westwood one?
unsigned char BuildLevel; // buildable level
unsigned char UnitCount; // max # units
unsigned char AIPlayers; // # of AI players allowed
int Seed; // random number seed
SpecialClass Special; // command-line options
unsigned int GameSpeed; // Game Speed
unsigned int Version; // version # common to all players
unsigned int FileLength; // Length of scenario file to expect from host.
char Scenario[DESCRIP_MAX]; // Scenario Name
unsigned int Credits; // player's credits
union
{
unsigned int Bitfield;

struct
{
#ifdef __BIG_ENDIAN__
unsigned int Unused : 27;
unsigned int OfficialScenario : 1; // Is this scenario an official Westwood one?
unsigned int IsGhosties : 1; // 1 = ghosts are allowed
unsigned int IsGoodies : 1; // 1 = goodies are allowed
unsigned int IsTiberium : 1; // 1 = tiberium is allowed
unsigned int IsBases : 1; // 1 = bases are allowed
#else
unsigned int IsBases : 1; // 1 = bases are allowed
unsigned int IsTiberium : 1; // 1 = tiberium is allowed
unsigned int IsGoodies : 1; // 1 = goodies are allowed
unsigned int IsGhosties : 1; // 1 = ghosts are allowed
unsigned int OfficialScenario : 1; // Is this scenario an official Westwood one?
#endif
};
};
unsigned char BuildLevel; // buildable level
unsigned char UnitCount; // max # units
unsigned char AIPlayers; // # of AI players allowed
int Seed; // random number seed
SpecialClass Special; // command-line options
unsigned int GameSpeed; // Game Speed
unsigned int Version; // version # common to all players
unsigned int FileLength; // Length of scenario file to expect from host.
#ifdef WOLAPI_INTEGRATION
char ShortFileName[13]; // Name of scenario file to expect from host
#else
char ShortFileName[12]; // Name of scenario file to expect from host
char ShortFileName[12]; // Name of scenario file to expect from host
#endif
unsigned char FileDigest[32]; // Digest of scenario file to expect from host
// ajw - This is not necessarily null-terminated.
Expand All @@ -419,6 +448,77 @@ typedef struct GlobalPacketType
};
} GlobalPacketType;
#pragma pack(pop)

inline void SwapGlobalPacketType(GlobalPacketType* gpt, bool sending)
{
enum NetCommandType command;

if (sending) {
command = gpt->Command;
} else {
command = (enum NetCommandType)le32toh(gpt->Command);
}

gpt->Command = (enum NetCommandType)le32toh(gpt->Command);

switch (command) {
case NET_QUERY_GAME:
break;

case NET_ANSWER_GAME:
gpt->GameInfo.Bitfield = le32toh(gpt->GameInfo.Bitfield);
break;

case NET_QUERY_PLAYER:
break;

case NET_ANSWER_PLAYER:
case NET_QUERY_JOIN:
case NET_CONFIRM_JOIN:
gpt->PlayerInfo.NameCRC = le32toh(gpt->PlayerInfo.NameCRC);
gpt->PlayerInfo.MinVersion = le32toh(gpt->PlayerInfo.MinVersion);
gpt->PlayerInfo.MaxVersion = le32toh(gpt->PlayerInfo.MaxVersion);
gpt->PlayerInfo.CheatCheck = le32toh(gpt->PlayerInfo.CheatCheck);
break;

case NET_CHAT_ANNOUNCE:
gpt->Chat.ID = le32toh(gpt->Chat.ID);
break;

case NET_CHAT_REQUEST:
break;

case NET_REJECT_JOIN:
gpt->Reject.Why = le32toh(gpt->Reject.Why);
break;

case NET_GAME_OPTIONS:
gpt->ScenarioInfo.Credits = le32toh(gpt->ScenarioInfo.Credits);
gpt->ScenarioInfo.Bitfield = le32toh(gpt->ScenarioInfo.Bitfield);
gpt->ScenarioInfo.Seed = le32toh(gpt->ScenarioInfo.Seed);
gpt->ScenarioInfo.Special.Bitfield = le32toh(gpt->ScenarioInfo.Special.Bitfield);
gpt->ScenarioInfo.GameSpeed = le32toh(gpt->ScenarioInfo.GameSpeed);
gpt->ScenarioInfo.Version = le32toh(gpt->ScenarioInfo.Version);
gpt->ScenarioInfo.FileLength = le32toh(gpt->ScenarioInfo.FileLength);
break;

case NET_SIGN_OFF:
break;

case NET_GO:
case NET_LOADGAME:
gpt->ResponseTime.OneWay = le32toh(gpt->ResponseTime.OneWay);
break;

case NET_MESSAGE:
gpt->Message.NameCRC = le32toh(gpt->Message.NameCRC);
break;

case NET_PING:
break;
}
}

//...........................................................................
// For finding sync bugs; filled in by the engine when certain conditions
// are met; the pointers allow examination of objects in the debugger.
Expand Down
Loading

0 comments on commit f52d4d2

Please sign in to comment.