ddnet/src/engine/shared/network.h

489 lines
13 KiB
C
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2010-05-29 07:25:38 +00:00
#ifndef ENGINE_SHARED_NETWORK_H
#define ENGINE_SHARED_NETWORK_H
2007-07-13 13:40:04 +00:00
2010-05-29 07:25:38 +00:00
#include "huffman.h"
#include "ringbuffer.h"
2015-08-13 08:58:47 +00:00
#include <base/math.h>
#include <engine/message.h>
2009-10-27 14:38:53 +00:00
/*
2009-10-27 14:38:53 +00:00
CURRENT:
packet header: 3 bytes
2020-04-13 09:27:30 +00:00
unsigned char flags_ack; // 6bit flags, 2bit ack
0.6: ORNCaaAA
0.6.5: ORNCTUAA
0.7: --NORCAA
2009-10-27 14:38:53 +00:00
unsigned char ack; // 8 bit ack
unsigned char num_chunks; // 8 bit chunks
2018-07-10 09:29:02 +00:00
(unsigned char padding[3]) // 24 bit extra in case it's a connection less packet
2009-10-27 14:38:53 +00:00
// this is to make sure that it's compatible with the
// old protocol
2007-07-13 13:40:04 +00:00
2009-10-27 14:38:53 +00:00
chunk header: 2-3 bytes
unsigned char flags_size; // 2bit flags, 6 bit size
unsigned char size_seq; // 4bit size, 4bit seq
(unsigned char seq;) // 8bit seq, if vital flag is set
*/
2007-07-13 13:40:04 +00:00
enum
{
NETFLAG_ALLOWSTATELESS = 1,
NETSENDFLAG_VITAL = 1,
NETSENDFLAG_CONNLESS = 2,
NETSENDFLAG_FLUSH = 4,
NETSENDFLAG_EXTENDED = 8,
NETSTATE_OFFLINE = 0,
2007-07-13 13:40:04 +00:00
NETSTATE_CONNECTING,
NETSTATE_ONLINE,
NETBANTYPE_SOFT = 1,
NETBANTYPE_DROP = 2
2007-07-13 13:40:04 +00:00
};
2009-10-27 14:38:53 +00:00
enum
{
NET_VERSION = 2,
NET_MAX_PACKETSIZE = 1400,
NET_MAX_PAYLOAD = NET_MAX_PACKETSIZE - 6,
2009-10-27 14:38:53 +00:00
NET_MAX_CHUNKHEADERSIZE = 5,
NET_PACKETHEADERSIZE = 3,
2013-12-31 05:13:57 +00:00
NET_MAX_CLIENTS = 64,
2011-07-30 11:40:01 +00:00
NET_MAX_CONSOLE_CLIENTS = 4,
NET_MAX_SEQUENCE = 1 << 10,
NET_SEQUENCE_MASK = NET_MAX_SEQUENCE - 1,
NET_CONNSTATE_OFFLINE = 0,
NET_CONNSTATE_CONNECT = 1,
NET_CONNSTATE_PENDING = 2,
NET_CONNSTATE_ONLINE = 3,
NET_CONNSTATE_ERROR = 4,
NET_PACKETFLAG_UNUSED = 1 << 0,
NET_PACKETFLAG_TOKEN = 1 << 1,
NET_PACKETFLAG_CONTROL = 1 << 2,
NET_PACKETFLAG_CONNLESS = 1 << 3,
NET_PACKETFLAG_RESEND = 1 << 4,
NET_PACKETFLAG_COMPRESSION = 1 << 5,
// NOT SENT VIA THE NETWORK DIRECTLY:
NET_PACKETFLAG_EXTENDED = 1 << 6,
2009-10-27 14:38:53 +00:00
NET_CHUNKFLAG_VITAL = 1,
NET_CHUNKFLAG_RESEND = 2,
NET_CTRLMSG_KEEPALIVE = 0,
NET_CTRLMSG_CONNECT = 1,
NET_CTRLMSG_CONNECTACCEPT = 2,
NET_CTRLMSG_ACCEPT = 3,
NET_CTRLMSG_CLOSE = 4,
NET_CONN_BUFFERSIZE = 1024 * 32,
NET_CONNLIMIT_IPS = 16,
2016-04-27 20:09:18 +00:00
2009-10-27 14:38:53 +00:00
NET_ENUM_TERMINATOR
};
typedef int SECURITY_TOKEN;
2017-03-21 10:24:44 +00:00
SECURITY_TOKEN ToSecurityToken(unsigned char *pData);
static const unsigned char SECURITY_TOKEN_MAGIC[] = {'T', 'K', 'E', 'N'};
enum
{
NET_SECURITY_TOKEN_UNKNOWN = -1,
NET_SECURITY_TOKEN_UNSUPPORTED = 0,
};
2009-10-27 14:38:53 +00:00
2017-03-21 10:24:44 +00:00
typedef int (*NETFUNC_DELCLIENT)(int ClientID, const char *pReason, void *pUser);
2020-03-29 02:36:38 +00:00
typedef int (*NETFUNC_NEWCLIENT_CON)(int ClientID, void *pUser);
typedef int (*NETFUNC_NEWCLIENT)(int ClientID, void *pUser, bool Sixup);
typedef int (*NETFUNC_NEWCLIENT_NOAUTH)(int ClientID, void *pUser);
2015-08-23 15:51:28 +00:00
typedef int (*NETFUNC_CLIENTREJOIN)(int ClientID, void *pUser);
2009-10-27 14:38:53 +00:00
struct CNetChunk
{
2010-05-29 07:25:38 +00:00
// -1 means that it's a stateless packet
// 0 on the client means the server
2009-10-27 14:38:53 +00:00
int m_ClientID;
2010-05-29 07:25:38 +00:00
NETADDR m_Address; // only used when client_id == -1
2009-10-27 14:38:53 +00:00
int m_Flags;
int m_DataSize;
const void *m_pData;
// only used if the flags contain NETSENDFLAG_EXTENDED and NETSENDFLAG_CONNLESS
unsigned char m_aExtraData[4];
2009-10-27 14:38:53 +00:00
};
2009-10-27 14:38:53 +00:00
class CNetChunkHeader
{
public:
int m_Flags;
int m_Size;
int m_Sequence;
2020-10-27 17:57:14 +00:00
unsigned char *Pack(unsigned char *pData, int Split = 4);
unsigned char *Unpack(unsigned char *pData, int Split = 4);
2009-10-27 14:38:53 +00:00
};
2007-07-13 13:40:04 +00:00
2009-10-27 14:38:53 +00:00
class CNetChunkResend
{
public:
int m_Flags;
int m_DataSize;
unsigned char *m_pData;
int m_Sequence;
int64 m_LastSendTime;
int64 m_FirstSendTime;
};
class CNetPacketConstruct
2007-07-13 13:40:04 +00:00
{
public:
2009-10-27 14:38:53 +00:00
int m_Flags;
int m_Ack;
int m_NumChunks;
int m_DataSize;
unsigned char m_aChunkData[NET_MAX_PAYLOAD];
unsigned char m_aExtraData[4];
2009-10-27 14:38:53 +00:00
};
class CNetConnection
{
// TODO: is this needed because this needs to be aware of
// the ack sequencing number and is also responible for updating
// that. this should be fixed.
friend class CNetRecvUnpacker;
2009-10-27 14:38:53 +00:00
private:
unsigned short m_Sequence;
unsigned short m_Ack;
unsigned short m_PeerAck;
2009-10-27 14:38:53 +00:00
unsigned m_State;
SECURITY_TOKEN m_SecurityToken;
2009-10-27 14:38:53 +00:00
int m_RemoteClosed;
bool m_BlockCloseMsg;
bool m_UnknownSeq;
2020-10-27 17:57:14 +00:00
CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> m_Buffer;
2009-10-27 14:38:53 +00:00
int64 m_LastUpdateTime;
int64 m_LastRecvTime;
int64 m_LastSendTime;
2020-10-27 17:57:14 +00:00
char m_aErrorString[256];
2009-10-27 14:38:53 +00:00
CNetPacketConstruct m_Construct;
2009-10-27 14:38:53 +00:00
NETADDR m_PeerAddr;
NETSOCKET m_Socket;
NETSTATS m_Stats;
2009-10-27 14:38:53 +00:00
//
void ResetStats();
void SetError(const char *pString);
void AckChunks(int Ack);
2010-05-29 07:25:38 +00:00
int QueueChunkEx(int Flags, int DataSize, const void *pData, int Sequence);
2009-10-27 14:38:53 +00:00
void SendControl(int ControlMsg, const void *pExtra, int ExtraSize);
void ResendChunk(CNetChunkResend *pResend);
void Resend();
2009-10-27 14:38:53 +00:00
public:
bool m_TimeoutProtected;
bool m_TimeoutSituation;
void Reset(bool Rejoin = false);
void Init(NETSOCKET Socket, bool BlockCloseMsg);
2009-10-27 14:38:53 +00:00
int Connect(NETADDR *pAddr);
void Disconnect(const char *pReason);
int Update();
int Flush();
2009-10-27 14:38:53 +00:00
int Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr, SECURITY_TOKEN SecurityToken = NET_SECURITY_TOKEN_UNSUPPORTED);
2010-05-29 07:25:38 +00:00
int QueueChunk(int Flags, int DataSize, const void *pData);
2009-10-27 14:38:53 +00:00
const char *ErrorString();
void SignalResend();
int State() const { return m_State; }
2011-12-29 22:36:53 +00:00
const NETADDR *PeerAddress() const { return &m_PeerAddr; }
2020-10-27 17:57:14 +00:00
void ResetErrorString() { m_aErrorString[0] = 0; }
const char *ErrorString() const { return m_aErrorString; }
2009-10-27 14:38:53 +00:00
// Needed for GotProblems in NetClient
int64 LastRecvTime() const { return m_LastRecvTime; }
2013-02-24 18:13:45 +00:00
int64 ConnectTime() const { return m_LastUpdateTime; }
2009-10-27 14:38:53 +00:00
int AckSequence() const { return m_Ack; }
2014-08-09 15:53:24 +00:00
int SeqSequence() const { return m_Sequence; }
int SecurityToken() const { return m_SecurityToken; }
2020-10-27 17:57:14 +00:00
CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> *ResendBuffer() { return &m_Buffer; };
2020-10-27 17:57:14 +00:00
void SetTimedOut(const NETADDR *pAddr, int Sequence, int Ack, SECURITY_TOKEN SecurityToken, CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> *pResendBuffer, bool Sixup);
2015-08-12 20:43:37 +00:00
// anti spoof
2020-03-29 02:36:38 +00:00
void DirectInit(NETADDR &Addr, SECURITY_TOKEN SecurityToken, SECURITY_TOKEN Token, bool Sixup);
void SetUnknownSeq() { m_UnknownSeq = true; }
void SetSequence(int Sequence) { m_Sequence = Sequence; }
2020-03-29 02:36:38 +00:00
bool m_Sixup;
SECURITY_TOKEN m_Token;
2009-10-27 14:38:53 +00:00
};
2011-07-02 06:36:14 +00:00
class CConsoleNetConnection
{
private:
2011-07-30 11:40:01 +00:00
int m_State;
2011-07-02 06:36:14 +00:00
NETADDR m_PeerAddr;
NETSOCKET m_Socket;
char m_aBuffer[NET_MAX_PACKETSIZE];
2011-07-30 11:40:01 +00:00
int m_BufferOffset;
2011-07-02 06:36:14 +00:00
char m_aErrorString[256];
2011-07-30 11:40:01 +00:00
bool m_LineEndingDetected;
char m_aLineEnding[3];
2011-07-02 06:36:14 +00:00
public:
void Init(NETSOCKET Socket, const NETADDR *pAddr);
void Disconnect(const char *pReason);
int State() const { return m_State; }
2011-12-29 22:36:53 +00:00
const NETADDR *PeerAddress() const { return &m_PeerAddr; }
2011-07-02 06:36:14 +00:00
const char *ErrorString() const { return m_aErrorString; }
void Reset();
int Update();
int Send(const char *pLine);
int Recv(char *pLine, int MaxLength);
};
class CNetRecvUnpacker
2009-10-27 14:38:53 +00:00
{
public:
bool m_Valid;
2009-10-27 14:38:53 +00:00
NETADDR m_Addr;
CNetConnection *m_pConnection;
int m_CurrentChunk;
int m_ClientID;
CNetPacketConstruct m_Data;
unsigned char m_aBuffer[NET_MAX_PACKETSIZE];
CNetRecvUnpacker() { Clear(); }
void Clear();
void Start(const NETADDR *pAddr, CNetConnection *pConnection, int ClientID);
int FetchChunk(CNetChunk *pChunk);
2009-10-27 14:38:53 +00:00
};
2010-05-29 07:25:38 +00:00
// server side
2009-10-27 14:38:53 +00:00
class CNetServer
{
struct CSlot
2009-10-27 14:38:53 +00:00
{
public:
CNetConnection m_Connection;
};
2016-04-27 20:09:18 +00:00
struct CSpamConn
{
NETADDR m_Addr;
int64 m_Time;
int m_Conns;
};
NETADDR m_Address;
2009-10-27 14:38:53 +00:00
NETSOCKET m_Socket;
MMSGS m_MMSGS;
2011-12-29 22:36:53 +00:00
class CNetBan *m_pNetBan;
2009-10-27 14:38:53 +00:00
CSlot m_aSlots[NET_MAX_CLIENTS];
int m_MaxClients;
int m_MaxClientsPerIP;
2009-10-27 14:38:53 +00:00
NETFUNC_NEWCLIENT m_pfnNewClient;
2015-08-13 08:58:47 +00:00
NETFUNC_NEWCLIENT_NOAUTH m_pfnNewClientNoAuth;
2009-10-27 14:38:53 +00:00
NETFUNC_DELCLIENT m_pfnDelClient;
2015-08-23 15:51:28 +00:00
NETFUNC_CLIENTREJOIN m_pfnClientRejoin;
2020-10-27 17:57:14 +00:00
void *m_pUser;
int m_NumConAttempts; // log flooding attacks
int64 m_TimeNumConAttempts;
2020-10-27 17:57:14 +00:00
unsigned char m_aSecurityTokenSeed[16];
2016-04-23 15:23:01 +00:00
// vanilla connect flood detection
int64 m_VConnFirst;
int m_VConnNum;
2016-04-27 20:09:18 +00:00
CSpamConn m_aSpamConns[NET_CONNLIMIT_IPS];
2009-10-27 14:38:53 +00:00
CNetRecvUnpacker m_RecvUnpacker;
2015-08-12 20:43:37 +00:00
void OnTokenCtrlMsg(NETADDR &Addr, int ControlMsg, const CNetPacketConstruct &Packet);
int OnSixupCtrlMsg(NETADDR &Addr, CNetChunk *pChunk, int ControlMsg, const CNetPacketConstruct &Packet, SECURITY_TOKEN &ResponseToken, SECURITY_TOKEN Token);
2015-08-13 08:58:47 +00:00
void OnPreConnMsg(NETADDR &Addr, CNetPacketConstruct &Packet);
2015-08-23 15:01:01 +00:00
void OnConnCtrlMsg(NETADDR &Addr, int ClientID, int ControlMsg, const CNetPacketConstruct &Packet);
2015-08-23 10:29:41 +00:00
bool ClientExists(const NETADDR &Addr) { return GetClientSlot(Addr) != -1; };
int GetClientSlot(const NETADDR &Addr);
2015-08-12 20:43:37 +00:00
void SendControl(NETADDR &Addr, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken);
int TryAcceptClient(NETADDR &Addr, SECURITY_TOKEN SecurityToken, bool VanillaAuth = false, bool Sixup = false, SECURITY_TOKEN Token = 0);
2015-08-12 20:43:37 +00:00
int NumClientsWithAddr(NETADDR Addr);
2016-04-27 20:09:18 +00:00
bool Connlimit(NETADDR Addr);
2020-10-27 17:57:14 +00:00
void SendMsgs(NETADDR &Addr, const CMsgPacker *apMsgs[], int Num);
2015-08-12 20:43:37 +00:00
2009-10-27 14:38:53 +00:00
public:
int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
2015-08-23 15:51:28 +00:00
int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_NEWCLIENT_NOAUTH pfnNewClientNoAuth, NETFUNC_CLIENTREJOIN pfnClientRejoin, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
2009-10-27 14:38:53 +00:00
//
2011-12-29 22:36:53 +00:00
bool Open(NETADDR BindAddr, class CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP, int Flags);
2009-10-27 14:38:53 +00:00
int Close();
2009-10-27 14:38:53 +00:00
//
2020-10-27 17:57:14 +00:00
int Recv(CNetChunk *pChunk, SECURITY_TOKEN *pResponseToken);
2009-10-27 14:38:53 +00:00
int Send(CNetChunk *pChunk);
int Update();
2009-10-27 14:38:53 +00:00
//
int Drop(int ClientID, const char *pReason);
2009-10-27 14:38:53 +00:00
// status requests
2011-12-29 22:36:53 +00:00
const NETADDR *ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
2015-08-14 14:46:01 +00:00
bool HasSecurityToken(int ClientID) const { return m_aSlots[ClientID].m_Connection.SecurityToken() != NET_SECURITY_TOKEN_UNSUPPORTED; }
NETADDR Address() const { return m_Address; }
2009-10-27 14:38:53 +00:00
NETSOCKET Socket() const { return m_Socket; }
2011-12-29 22:36:53 +00:00
class CNetBan *NetBan() const { return m_pNetBan; }
2011-12-04 15:51:33 +00:00
int NetType() const { return m_Socket.type; }
2009-10-27 14:38:53 +00:00
int MaxClients() const { return m_MaxClients; }
void SendTokenSixup(NETADDR &Addr, SECURITY_TOKEN Token);
int SendConnlessSixup(CNetChunk *pChunk, SECURITY_TOKEN ResponseToken);
//
void SetMaxClientsPerIP(int Max);
2014-08-09 15:25:29 +00:00
bool SetTimedOut(int ClientID, int OrigID);
void SetTimeoutProtected(int ClientID);
2014-08-17 03:04:37 +00:00
int ResetErrorString(int ClientID);
const char *ErrorString(int ClientID);
2015-08-12 20:43:37 +00:00
// anti spoof
SECURITY_TOKEN GetToken(const NETADDR &Addr);
2015-08-13 08:58:47 +00:00
// vanilla token/gametick shouldn't be negative
SECURITY_TOKEN GetVanillaToken(const NETADDR &Addr) { return absolute(GetToken(Addr)); }
2007-07-13 13:40:04 +00:00
};
2011-07-02 06:36:14 +00:00
class CNetConsole
{
struct CSlot
{
CConsoleNetConnection m_Connection;
};
NETSOCKET m_Socket;
2011-12-29 22:36:53 +00:00
class CNetBan *m_pNetBan;
2011-07-30 11:40:01 +00:00
CSlot m_aSlots[NET_MAX_CONSOLE_CLIENTS];
2011-07-02 06:36:14 +00:00
2020-03-29 02:36:38 +00:00
NETFUNC_NEWCLIENT_CON m_pfnNewClient;
2011-07-02 06:36:14 +00:00
NETFUNC_DELCLIENT m_pfnDelClient;
2020-10-27 17:57:14 +00:00
void *m_pUser;
2011-07-02 06:36:14 +00:00
CNetRecvUnpacker m_RecvUnpacker;
public:
2020-03-29 02:36:38 +00:00
void SetCallbacks(NETFUNC_NEWCLIENT_CON pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
2011-07-02 06:36:14 +00:00
//
2011-12-29 22:36:53 +00:00
bool Open(NETADDR BindAddr, class CNetBan *pNetBan, int Flags);
2011-07-02 06:36:14 +00:00
int Close();
//
int Recv(char *pLine, int MaxLength, int *pClientID = 0);
int Send(int ClientID, const char *pLine);
int Update();
//
int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr);
int Drop(int ClientID, const char *pReason);
// status requests
2011-12-29 22:36:53 +00:00
const NETADDR *ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
class CNetBan *NetBan() const { return m_pNetBan; }
2011-07-02 06:36:14 +00:00
};
2010-05-29 07:25:38 +00:00
// client side
2009-10-27 14:38:53 +00:00
class CNetClient
2007-07-13 13:40:04 +00:00
{
2009-10-27 14:38:53 +00:00
CNetConnection m_Connection;
CNetRecvUnpacker m_RecvUnpacker;
2007-07-13 13:40:04 +00:00
public:
2014-01-14 23:02:19 +00:00
NETSOCKET m_Socket;
MMSGS m_MMSGS;
2009-10-27 14:38:53 +00:00
// openness
bool Open(NETADDR BindAddr, int Flags);
int Close();
2009-10-27 14:38:53 +00:00
// connection state
2020-10-27 17:57:14 +00:00
int Disconnect(const char *pReason);
int Connect(NETADDR *pAddr);
2009-10-27 14:38:53 +00:00
// communication
2020-10-27 17:57:14 +00:00
int Recv(CNetChunk *pChunk);
int Send(CNetChunk *pChunk);
2009-10-27 14:38:53 +00:00
// pumping
int Update();
int Flush();
int ResetErrorString();
2009-10-27 14:38:53 +00:00
// error and state
int NetType() const { return m_Socket.type; }
2009-10-27 14:38:53 +00:00
int State();
int GotProblems();
const char *ErrorString();
bool SecurityTokenUnknown() { return m_Connection.SecurityToken() == NET_SECURITY_TOKEN_UNKNOWN; }
2009-10-27 14:38:53 +00:00
};
// TODO: both, fix these. This feels like a junk class for stuff that doesn't fit anywere
class CNetBase
{
static IOHANDLE ms_DataLogSent;
static IOHANDLE ms_DataLogRecv;
2010-05-29 07:25:38 +00:00
static CHuffman ms_Huffman;
2009-10-27 14:38:53 +00:00
public:
static void OpenLog(IOHANDLE DataLogSent, IOHANDLE DataLogRecv);
static void CloseLog();
2009-10-27 14:38:53 +00:00
static void Init();
static int Compress(const void *pData, int DataSize, void *pOutput, int OutputSize);
static int Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize);
2020-03-29 02:36:38 +00:00
static void SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken, bool Sixup = false);
static void SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize, bool Extended, unsigned char aExtra[4]);
static void SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket, SECURITY_TOKEN SecurityToken, bool Sixup = false, bool NoCompress = false);
2015-08-12 20:43:37 +00:00
2020-10-27 17:57:14 +00:00
static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket, bool &Sixup, SECURITY_TOKEN *pSecurityToken = 0, SECURITY_TOKEN *pResponseToken = 0);
2009-10-27 14:38:53 +00:00
2010-05-29 07:25:38 +00:00
// The backroom is ack-NET_MAX_SEQUENCE/2. Used for knowing if we acked a packet or not
static int IsSeqInBackroom(int Seq, int Ack);
2007-07-13 13:40:04 +00:00
};
#endif