/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* $Archive:: /Commando/Code/Commando/natter.h $*
* *
* $Author:: Steve_t $*
* *
* $Modtime:: 3/01/02 2:27p $*
* *
* $Revision:: 18 $*
* *
* *
*---------------------------------------------------------------------------------------------*
* *
* *
*---------------------------------------------------------------------------------------------*
* *
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#pragma once
#ifndef NATTER_H
#define NATTER_H
#include "always.h"
//#include "nat.h"
#include "nataddr.h"
/*
** Project specific includes.
*/
#include
#include
#include
#include
#include
/*
** Commonly available components.
*/
#include
#ifdef WWASSERT
#ifndef fw_assert
#define fw_assert WWASSERT
#endif //fw_assert
#else //WWASSERT
#define fw_assert assert
#endif //WWASSERT
/*
** Size of temporary game options storage buffers.
*/
#define OPTIONS_STAGING_BUFFER_SIZE 512
#define PORT_BASE_MIN 1024
#define PORT_BASE_MAX 4095
#define PORT_POOL_MIN 4096
#define PORT_POOL_MAX 65535
/*
** Forward declarations.
*/
class SocketHandlerClass;
class RegistryClass;
/*
** This class performs the inevitable task of interfacing with whatever piece of code happens to be talking to WOLAPI.
**
** Will have to be completely replaced per project.
**
*/
class WOLNATInterfaceClass : public Observer,
public Observer,
public Observer,
public Observer
{
public:
/*
** Constructor, destructor.
*/
WOLNATInterfaceClass(void);
~WOLNATInterfaceClass(void);
/*
** Startup, shutdown.
*/
void Init(void);
void Shutdown(void);
/*
** Service.
*/
void Service(void);
void Set_Service_Socket_Handler(SocketHandlerClass *socket);
void Service_Receive_Queue(SocketHandlerClass *socket);
/*
** User event notification.
*/
void HandleNotification(WWOnline::UserEvent&);
/*
** Game options notificaton.
*/
void HandleNotification(WWOnline::GameOptionsMessage&);
/*
** Server connection notification.
*/
void HandleNotification(WWOnline::ConnectionStatus&);
/*
** User IP event.
*/
void HandleNotification(WWOnline::UserIPEvent&);
/*
** Server query.
*/
void Get_Current_Server_ConnData(char *buffer, int size);
/*
** Private game options.
*/
void Send_Private_Game_Options(WOL::User *user, char *options);
bool Get_Private_Game_Options(WOL::User *user, char *options, int option_buffer_len);
/*
** Conversion.
*/
char *Get_Silly_String(WideStringClass *silly_string, char *buffer, int buffer_size);
/*
** Game packet handling.
*/
bool Get_Packet(char *packet_buffer, int buffer_size, IPAddressClass &address);
void Intercept_Game_Packet(cPacket &packet);
bool Send_Game_Format_Packet_To(IPAddressClass *address, char *payload, int payload_size, SocketHandlerClass *socket_handler = NULL);
/*
** General game helper functions.
*/
bool Get_My_Name(char *namebuf);
bool Am_I_Server(void) {return(IsServer);};
void Set_Server(bool is_server);
void Set_Server_Negotiated_Address(IPAddressClass *server_address);
DynamicVectorClass Get_Mangler_Server_List(void);
unsigned short Get_Mangler_Port_By_Index(int index);
bool Get_Mangler_Name_By_Index(int index, char *mangler_name);
int Get_Num_Mangler_Servers(void);
unsigned long Get_Local_Address(void) {
return(0);//return(FirewallHelper.Get_Local_Address());
};
void Tell_Server_That_Client_Is_In_Channel(void);
bool Is_NAT_Thread_Busy(void);
/*
** Game port management.
*/
unsigned short Get_Next_Client_Port(void);
unsigned short Get_Port_As_Server(void);
unsigned short Get_Port_As_Server_Client(void);
unsigned short Get_Force_Port(void) {return(ForcePort);};
/*
** Config.
*/
void Get_Config(RegistryClass *reg, int &port_number, bool &send_delay);
void Set_Config(RegistryClass *reg, int port_number, bool send_delay);
void Save_Firewall_Info_To_Registry(void);
unsigned long Get_Reg_External_IP(void) {return(RegExternalIP);}
unsigned long Get_Reg_External_Port(void) {return(RegExternalPort);}
void Get_Compact_Log(StringClass &log_string);
unsigned long Get_Chat_External_IP(void) {return(ChatExternalIP);}
/*
** Game options string types.
*/
enum {
OPTION_ERROR = 'a',
OPTION_INVITE_PORT_NEGOTIATION,
OPTION_ACCEPT_PORT_NEGOTIATION_INVITATION,
OPTION_PORT_NOTIFICATION,
OPTION_CONNECTION_RESULT,
OPTION_QUEUE_STATE,
OPTION_ABORT_NEGOTIATION,
OPTION_CLIENT_IN_CHANNEL
};
/*
** Game options format for the firewall code only. All firewall options packets are prefixed with "NAT:"
*/
typedef struct tPrivateGameOptions {
/*
** Option previx (Always "NAT:" for us.
*/
char NATOptionsPrefix[4];
/*
** Option type. See list above.
*/
char Option;
/*
** Option payload union. Each type of option has a different payload.
*/
union tOptionData {
/*
** Data for OPTION_INVITE_PORT_NEGOTIATION.
*/
struct InvitationStruct {
char LocalIP[9]; // 00000000,
char LocalPort[5]; // 0000,
char ExternalIP[9]; // 00000000,
char FirewallType[9]; // 00000000,
char Queued[5]; // 0000(null)
} Invitation;
/*
** Data for OPTION_ACCEPT_PORT_NEGOTIATION_INVITATION.
*/
struct AcceptStruct {
char LocalIP[9]; // 00000000,
char LocalPort[5]; // 0000,
char ExternalIP[9]; // 00000000,
char FirewallType[9]; // 00000000(null)
} Accept;
/*
** Data for OPTION_PORT_NOTIFICATION.
*/
struct PortStruct {
char MangledPort[5]; // 0000,
char Name[64]; // "Players name......"(null)
} Port;
/*
** Data for OPTION_CONNECTION_RESULT.
*/
struct ConnectionResultStruct {
char Result[2]; // n,
char Port[5]; // 0000,
char Name[64]; // "Players name......"(null)
} ConnectionResult;
/*
** Data for OPTION_QUEUE_STATE
*/
struct QueueStateStruct {
char Position[3]; // 00(null)
} QueueState;
/*
** Data for OPTION_ABORT_NEGOTIATION
*/
struct QuitTalkingStruct {
char Nothing; // 00
} QuitTalking;
/*
** Data for OPTION_CLIENT_IN_CHANNEL
*/
struct ClientInChannelStruct {
char Name[64]; // "Players name......"(null)
} ClientInChannel;
} OptionData;
} PrivateGameOptionsStruct;
private:
/*
** PortBase is the start of the current port number range we are using. The range is added to the port base every time
** we start a new game so we are always using a fresh port. The server uses 2 ports per game and the client uses 1 port.
*/
unsigned short PortBase;
/*
** Set this to non-zero to force it to be used as the local port.
*/
unsigned short ForcePort;
/*
** External IP and port from the registry.
*/
unsigned long RegExternalIP;
unsigned short RegExternalPort;
/*
** Our IP according to westwood chat.
*/
unsigned long ChatExternalIP;
/*
** Bloat pointer to the Session class.
*/
RefPtr SessionPtr;
/*
** Address we used to send to the server.
*/
IPAddressClass ServerNegotiatedAddress;
/*
** Holding area for incoming game packets.
*/
struct GamePacketStruct {
IPAddressClass FromAddress;
unsigned char Payload[512];
};
DynamicVectorClass IncomingPackets;
/*
** This is the socket handler to use when sending or receiving game packets. It's only used on the client side since
** the server side has to use the games mechanisms to send and receive (the game already has a socket bound to the port
** we want to use in the server case).
*/
SocketHandlerClass *ServiceSocketHandler;
/*
** Am I a game server?
*/
bool IsServer;
/*
** Game options staging areas.
*/
typedef struct tGameOptionsStagingStruct {
WOL::User User;
char Options[OPTIONS_STAGING_BUFFER_SIZE];
} GameOptionsStagingStruct;
DynamicVectorClass IncomingOptions;
DynamicVectorClass OutgoingOptions;
/*
** Mutex to serialise access to game options.
*/
HANDLE GameOptionsMutex;
/*
** Thread safety for game options.
*/
class ThreadLockClass
{
public:
/*
** Constructor. Grabs the mutex.
*/
inline ThreadLockClass(WOLNATInterfaceClass *wnptr) {
WNPtr = wnptr;
int deadlock = WaitForSingleObject(wnptr->GameOptionsMutex, 10 * 1000);
if (deadlock == WAIT_TIMEOUT) {
WWDEBUG_SAY(("FirewallHelper - Timeout waiting for firewall helper data mutex\n"));
fw_assert(deadlock != WAIT_TIMEOUT);
}
};
WOLNATInterfaceClass *WNPtr;
/*
** Destructor, releases the mutex.
*/
inline ~ThreadLockClass(void) {
ReleaseMutex(WNPtr->GameOptionsMutex);
};
};
friend ThreadLockClass;
};
/*
** Extern for single instance of the WOLNATInterface.
*/
extern WOLNATInterfaceClass WOLNATInterface;
#endif //NATTER_H