Files
LazyByteDev b40d5e9d01 src stuff
2026-03-02 03:31:00 -05:00

130 lines
3.5 KiB
C++

#pragma once
#include "P2PConnectionManager.h"
// STUN message types (RFC 5389)
#define STUN_BINDING_REQUEST 0x0001
#define STUN_BINDING_RESPONSE 0x0101
#define STUN_BINDING_ERROR_RESPONSE 0x0111
// STUN attribute types
#define STUN_ATTR_MAPPED_ADDRESS 0x0001
#define STUN_ATTR_XOR_MAPPED_ADDRESS 0x0020
#define STUN_ATTR_SOFTWARE 0x8022
// STUN magic cookie (RFC 5389)
#define STUN_MAGIC_COOKIE 0x2112A442
// STUN header size
#define STUN_HEADER_SIZE 20
// Max STUN response size
#define STUN_MAX_RESPONSE_SIZE 512
// NAT traversal timeouts
#define NAT_STUN_TIMEOUT_MS 3000
#define NAT_PUNCH_INTERVAL_MS 500
#define NAT_PUNCH_MAX_ATTEMPTS 10
#define NAT_PUNCH_TIMEOUT_MS 5000
// P2P keepalive interval
#define P2P_KEEPALIVE_INTERVAL_MS 2000
// P2P connection timeout (no data received)
#define P2P_CONNECTION_TIMEOUT_MS 10000
// STUN server entry
struct STUNServer
{
const char* hostname;
unsigned short port;
};
// Well-known public STUN servers
static const STUNServer g_STUNServers[] =
{
{ "stun.l.google.com", 19302 },
{ "stun1.l.google.com", 19302 },
{ "stun.stunprotocol.org", 3478 },
};
static const int g_numSTUNServers = sizeof(g_STUNServers) / sizeof(g_STUNServers[0]);
// STUN transaction ID (96 bits)
struct STUNTransactionID
{
unsigned char id[12];
};
// STUN message header
#pragma pack(push, 1)
struct STUNHeader
{
unsigned short type;
unsigned short length;
unsigned int magicCookie;
STUNTransactionID transactionID;
};
#pragma pack(pop)
// NAT type classification
enum ENATType
{
NAT_TYPE_UNKNOWN = 0,
NAT_TYPE_OPEN, // No NAT / directly reachable
NAT_TYPE_FULL_CONE, // Easy to traverse
NAT_TYPE_RESTRICTED_CONE, // Moderate - needs hole punch
NAT_TYPE_PORT_RESTRICTED, // Harder - needs coordinated punch
NAT_TYPE_SYMMETRIC // Hardest - may need relay
};
// Abstract STUN client interface
class ISTUNClient
{
public:
virtual ~ISTUNClient() {}
virtual bool DiscoverEndpoint(PeerEndpoint& outEndpoint) = 0;
// Classify NAT type (optional, for diagnostics)
virtual ENATType ClassifyNAT() = 0;
// Get last error description
virtual const char* GetLastError() = 0;
};
// NAT hole punch helper
class NATHolePuncher
{
public:
// Generate a STUN binding request
static int BuildBindingRequest(unsigned char* buffer, int bufferSize, STUNTransactionID& outTxnID);
// Parse a STUN binding response to extract mapped address
static bool ParseBindingResponse(const unsigned char* data, int dataSize,
const STUNTransactionID& expectedTxnID, PeerEndpoint& outEndpoint);
// Generate a hole punch probe packet
static int BuildPunchProbe(unsigned char* buffer, int bufferSize, PlayerUID senderUID);
// Check if received data is a punch probe and extract sender UID
static bool IsPunchProbe(const unsigned char* data, int dataSize, PlayerUID& outSenderUID);
// Generate a punch acknowledgment
static int BuildPunchAck(unsigned char* buffer, int bufferSize, PlayerUID senderUID);
// Check if received data is a punch acknowledgment
static bool IsPunchAck(const unsigned char* data, int dataSize, PlayerUID& outSenderUID);
// Generate a keepalive packet
static int BuildKeepalive(unsigned char* buffer, int bufferSize);
// Check if received data is a keepalive
static bool IsKeepalive(const unsigned char* data, int dataSize);
private:
// P2P protocol magic bytes to distinguish from game data
static const unsigned int P2P_MAGIC = 0x4D435032; // "MCP2"
static const unsigned char P2P_MSG_PROBE = 0x01;
static const unsigned char P2P_MSG_ACK = 0x02;
static const unsigned char P2P_MSG_KEEPALIVE = 0x03;
};