1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef ENGINE_SHARED_NETWORK_H
4#define ENGINE_SHARED_NETWORK_H
5
6#include "ringbuffer.h"
7#include "stun.h"
8
9#include <base/math.h>
10#include <base/system.h>
11
12class CHuffman;
13class CNetBan;
14class CPacker;
15
16/*
17
18CURRENT:
19 packet header: 3 bytes
20 unsigned char flags_ack; // 6bit flags, 2bit ack
21 0.6: ORNCaaAA
22 0.6.5: ORNCTUAA
23 0.7: --NORCAA
24
25 unsigned char ack; // 8 bit ack
26 unsigned char num_chunks; // 8 bit chunks
27
28 (unsigned char padding[3]) // 24 bit extra in case it's a connection less packet
29 // this is to make sure that it's compatible with the
30 // old protocol
31
32 chunk header: 2-3 bytes
33 unsigned char flags_size; // 2bit flags, 6 bit size
34 unsigned char size_seq; // 4bit size, 4bit seq
35 (unsigned char seq;) // 8bit seq, if vital flag is set
36*/
37
38enum
39{
40 NETFLAG_ALLOWSTATELESS = 1,
41 NETSENDFLAG_VITAL = 1,
42 NETSENDFLAG_CONNLESS = 2,
43 NETSENDFLAG_FLUSH = 4,
44 NETSENDFLAG_EXTENDED = 8,
45
46 NETSTATE_OFFLINE = 0,
47 NETSTATE_CONNECTING,
48 NETSTATE_ONLINE,
49
50 NETBANTYPE_SOFT = 1,
51 NETBANTYPE_DROP = 2
52};
53
54enum
55{
56 NET_VERSION = 2,
57
58 NET_MAX_PACKETSIZE = 1400,
59 NET_MAX_PAYLOAD = NET_MAX_PACKETSIZE - 6,
60 NET_MAX_CHUNKHEADERSIZE = 3,
61 NET_PACKETHEADERSIZE = 3,
62 NET_MAX_CLIENTS = 64,
63 NET_MAX_CONSOLE_CLIENTS = 4,
64 NET_MAX_SEQUENCE = 1 << 10,
65 NET_SEQUENCE_MASK = NET_MAX_SEQUENCE - 1,
66
67 NET_CONNSTATE_OFFLINE = 0,
68 NET_CONNSTATE_CONNECT = 1,
69 NET_CONNSTATE_PENDING = 2,
70 NET_CONNSTATE_ONLINE = 3,
71 NET_CONNSTATE_ERROR = 4,
72
73 NET_PACKETFLAG_UNUSED = 1 << 0,
74 NET_PACKETFLAG_TOKEN = 1 << 1,
75 NET_PACKETFLAG_CONTROL = 1 << 2,
76 NET_PACKETFLAG_CONNLESS = 1 << 3,
77 NET_PACKETFLAG_RESEND = 1 << 4,
78 NET_PACKETFLAG_COMPRESSION = 1 << 5,
79 // NOT SENT VIA THE NETWORK DIRECTLY:
80 NET_PACKETFLAG_EXTENDED = 1 << 6,
81
82 NET_CHUNKFLAG_VITAL = 1,
83 NET_CHUNKFLAG_RESEND = 2,
84
85 NET_CTRLMSG_KEEPALIVE = 0,
86 NET_CTRLMSG_CONNECT = 1,
87 NET_CTRLMSG_CONNECTACCEPT = 2,
88 NET_CTRLMSG_ACCEPT = 3,
89 NET_CTRLMSG_CLOSE = 4,
90
91 NET_CONN_BUFFERSIZE = 1024 * 32,
92
93 NET_CONNLIMIT_IPS = 16,
94
95 NET_ENUM_TERMINATOR
96};
97
98typedef int SECURITY_TOKEN;
99
100SECURITY_TOKEN ToSecurityToken(const unsigned char *pData);
101void WriteSecurityToken(unsigned char *pData, SECURITY_TOKEN Token);
102
103extern const unsigned char SECURITY_TOKEN_MAGIC[4];
104
105enum
106{
107 NET_SECURITY_TOKEN_UNKNOWN = -1,
108 NET_SECURITY_TOKEN_UNSUPPORTED = 0,
109};
110
111typedef int (*NETFUNC_DELCLIENT)(int ClientId, const char *pReason, void *pUser);
112typedef int (*NETFUNC_NEWCLIENT_CON)(int ClientId, void *pUser);
113typedef int (*NETFUNC_NEWCLIENT)(int ClientId, void *pUser, bool Sixup);
114typedef int (*NETFUNC_NEWCLIENT_NOAUTH)(int ClientId, void *pUser);
115typedef int (*NETFUNC_CLIENTREJOIN)(int ClientId, void *pUser);
116
117struct CNetChunk
118{
119 // -1 means that it's a stateless packet
120 // 0 on the client means the server
121 int m_ClientId;
122 NETADDR m_Address; // only used when client_id == -1
123 int m_Flags;
124 int m_DataSize;
125 const void *m_pData;
126 // only used if the flags contain NETSENDFLAG_EXTENDED and NETSENDFLAG_CONNLESS
127 unsigned char m_aExtraData[4];
128};
129
130class CNetChunkHeader
131{
132public:
133 int m_Flags;
134 int m_Size;
135 int m_Sequence;
136
137 unsigned char *Pack(unsigned char *pData, int Split = 4) const;
138 unsigned char *Unpack(unsigned char *pData, int Split = 4);
139};
140
141class CNetChunkResend
142{
143public:
144 int m_Flags;
145 int m_DataSize;
146 unsigned char *m_pData;
147
148 int m_Sequence;
149 int64_t m_LastSendTime;
150 int64_t m_FirstSendTime;
151};
152
153class CNetPacketConstruct
154{
155public:
156 int m_Flags;
157 int m_Ack;
158 int m_NumChunks;
159 int m_DataSize;
160 unsigned char m_aChunkData[NET_MAX_PAYLOAD];
161 unsigned char m_aExtraData[4];
162};
163
164enum class CONNECTIVITY
165{
166 UNKNOWN,
167 CHECKING,
168 UNREACHABLE,
169 REACHABLE,
170 ADDRESS_KNOWN,
171};
172
173class CStun
174{
175 class CProtocol
176 {
177 int m_Index;
178 NETSOCKET m_Socket;
179 CStunData m_Stun;
180 bool m_HaveStunServer = false;
181 NETADDR m_StunServer;
182 bool m_HaveAddr = false;
183 NETADDR m_Addr;
184 int64_t m_LastResponse = -1;
185 int64_t m_NextTry = -1;
186 int m_NumUnsuccessfulTries = -1;
187
188 public:
189 CProtocol(int Index, NETSOCKET Socket);
190 void FeedStunServer(NETADDR StunServer);
191 void Refresh();
192 void Update();
193 bool OnPacket(NETADDR Addr, unsigned char *pData, int DataSize);
194 CONNECTIVITY GetConnectivity(NETADDR *pGlobalAddr);
195 };
196 CProtocol m_aProtocols[2];
197
198public:
199 CStun(NETSOCKET Socket);
200 void FeedStunServer(NETADDR StunServer);
201 void Refresh();
202 void Update();
203 bool OnPacket(NETADDR Addr, unsigned char *pData, int DataSize);
204 CONNECTIVITY GetConnectivity(int NetType, NETADDR *pGlobalAddr);
205};
206
207class CNetConnection
208{
209 // TODO: is this needed because this needs to be aware of
210 // the ack sequencing number and is also responible for updating
211 // that. this should be fixed.
212 friend class CNetRecvUnpacker;
213
214private:
215 unsigned short m_Sequence;
216 unsigned short m_Ack;
217 unsigned short m_PeerAck;
218 unsigned m_State;
219
220 SECURITY_TOKEN m_SecurityToken;
221 int m_RemoteClosed;
222 bool m_BlockCloseMsg;
223 bool m_UnknownSeq;
224
225 CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> m_Buffer;
226
227 int64_t m_LastUpdateTime;
228 int64_t m_LastRecvTime;
229 int64_t m_LastSendTime;
230
231 char m_aErrorString[256];
232
233 CNetPacketConstruct m_Construct;
234
235 NETADDR m_aConnectAddrs[16];
236 int m_NumConnectAddrs;
237 NETADDR m_PeerAddr;
238 NETSOCKET m_Socket;
239 NETSTATS m_Stats;
240
241 //
242 void ResetStats();
243 void SetError(const char *pString);
244 void AckChunks(int Ack);
245
246 int QueueChunkEx(int Flags, int DataSize, const void *pData, int Sequence);
247 void SendConnect();
248 void SendControl(int ControlMsg, const void *pExtra, int ExtraSize);
249 void ResendChunk(CNetChunkResend *pResend);
250 void Resend();
251
252public:
253 bool m_TimeoutProtected;
254 bool m_TimeoutSituation;
255
256 void Reset(bool Rejoin = false);
257 void Init(NETSOCKET Socket, bool BlockCloseMsg);
258 int Connect(const NETADDR *pAddr, int NumAddrs);
259 void Disconnect(const char *pReason);
260
261 int Update();
262 int Flush();
263
264 int Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr, SECURITY_TOKEN SecurityToken = NET_SECURITY_TOKEN_UNSUPPORTED);
265 int QueueChunk(int Flags, int DataSize, const void *pData);
266
267 const char *ErrorString();
268 void SignalResend();
269 int State() const { return m_State; }
270 const NETADDR *PeerAddress() const { return &m_PeerAddr; }
271 void ConnectAddresses(const NETADDR **ppAddrs, int *pNumAddrs) const
272 {
273 *ppAddrs = m_aConnectAddrs;
274 *pNumAddrs = m_NumConnectAddrs;
275 }
276
277 void ResetErrorString() { m_aErrorString[0] = 0; }
278 const char *ErrorString() const { return m_aErrorString; }
279
280 // Needed for GotProblems in NetClient
281 int64_t LastRecvTime() const { return m_LastRecvTime; }
282 int64_t ConnectTime() const { return m_LastUpdateTime; }
283
284 int AckSequence() const { return m_Ack; }
285 int SeqSequence() const { return m_Sequence; }
286 int SecurityToken() const { return m_SecurityToken; }
287 CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> *ResendBuffer() { return &m_Buffer; }
288
289 void SetTimedOut(const NETADDR *pAddr, int Sequence, int Ack, SECURITY_TOKEN SecurityToken, CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> *pResendBuffer, bool Sixup);
290
291 // anti spoof
292 void DirectInit(const NETADDR &Addr, SECURITY_TOKEN SecurityToken, SECURITY_TOKEN Token, bool Sixup);
293 void SetUnknownSeq() { m_UnknownSeq = true; }
294 void SetSequence(int Sequence) { m_Sequence = Sequence; }
295
296 bool m_Sixup;
297 SECURITY_TOKEN m_Token;
298};
299
300class CConsoleNetConnection
301{
302private:
303 int m_State;
304
305 NETADDR m_PeerAddr;
306 NETSOCKET m_Socket;
307
308 char m_aBuffer[NET_MAX_PACKETSIZE];
309 int m_BufferOffset;
310
311 char m_aErrorString[256];
312
313 bool m_LineEndingDetected;
314 char m_aLineEnding[3];
315
316public:
317 void Init(NETSOCKET Socket, const NETADDR *pAddr);
318 void Disconnect(const char *pReason);
319
320 int State() const { return m_State; }
321 const NETADDR *PeerAddress() const { return &m_PeerAddr; }
322 const char *ErrorString() const { return m_aErrorString; }
323
324 void Reset();
325 int Update();
326 int Send(const char *pLine);
327 int Recv(char *pLine, int MaxLength);
328};
329
330class CNetRecvUnpacker
331{
332public:
333 bool m_Valid;
334
335 NETADDR m_Addr;
336 CNetConnection *m_pConnection;
337 int m_CurrentChunk;
338 int m_ClientId;
339 CNetPacketConstruct m_Data;
340 unsigned char m_aBuffer[NET_MAX_PACKETSIZE];
341
342 CNetRecvUnpacker() { Clear(); }
343 void Clear();
344 void Start(const NETADDR *pAddr, CNetConnection *pConnection, int ClientId);
345 int FetchChunk(CNetChunk *pChunk);
346};
347
348// server side
349class CNetServer
350{
351 struct CSlot
352 {
353 public:
354 CNetConnection m_Connection;
355 };
356
357 struct CSpamConn
358 {
359 NETADDR m_Addr;
360 int64_t m_Time;
361 int m_Conns;
362 };
363
364 NETADDR m_Address;
365 NETSOCKET m_Socket;
366 CNetBan *m_pNetBan;
367 CSlot m_aSlots[NET_MAX_CLIENTS];
368 int m_MaxClients;
369 int m_MaxClientsPerIp;
370
371 NETFUNC_NEWCLIENT m_pfnNewClient;
372 NETFUNC_NEWCLIENT_NOAUTH m_pfnNewClientNoAuth;
373 NETFUNC_DELCLIENT m_pfnDelClient;
374 NETFUNC_CLIENTREJOIN m_pfnClientRejoin;
375 void *m_pUser;
376
377 int m_NumConAttempts; // log flooding attacks
378 int64_t m_TimeNumConAttempts;
379 unsigned char m_aSecurityTokenSeed[16];
380
381 // vanilla connect flood detection
382 int64_t m_VConnFirst;
383 int m_VConnNum;
384
385 CSpamConn m_aSpamConns[NET_CONNLIMIT_IPS];
386
387 CNetRecvUnpacker m_RecvUnpacker;
388
389 void OnTokenCtrlMsg(NETADDR &Addr, int ControlMsg, const CNetPacketConstruct &Packet);
390 int OnSixupCtrlMsg(NETADDR &Addr, CNetChunk *pChunk, int ControlMsg, const CNetPacketConstruct &Packet, SECURITY_TOKEN &ResponseToken, SECURITY_TOKEN Token);
391 void OnPreConnMsg(NETADDR &Addr, CNetPacketConstruct &Packet);
392 void OnConnCtrlMsg(NETADDR &Addr, int ClientId, int ControlMsg, const CNetPacketConstruct &Packet);
393 bool ClientExists(const NETADDR &Addr) { return GetClientSlot(Addr) != -1; }
394 int GetClientSlot(const NETADDR &Addr);
395 void SendControl(NETADDR &Addr, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken);
396
397 int TryAcceptClient(NETADDR &Addr, SECURITY_TOKEN SecurityToken, bool VanillaAuth = false, bool Sixup = false, SECURITY_TOKEN Token = 0);
398 int NumClientsWithAddr(NETADDR Addr);
399 bool Connlimit(NETADDR Addr);
400 void SendMsgs(NETADDR &Addr, const CPacker **ppMsgs, int Num);
401
402public:
403 int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
404 int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_NEWCLIENT_NOAUTH pfnNewClientNoAuth, NETFUNC_CLIENTREJOIN pfnClientRejoin, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
405
406 //
407 bool Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int MaxClientsPerIp);
408 int Close();
409
410 //
411 int Recv(CNetChunk *pChunk, SECURITY_TOKEN *pResponseToken);
412 int Send(CNetChunk *pChunk);
413 int Update();
414
415 //
416 int Drop(int ClientId, const char *pReason);
417
418 // status requests
419 const NETADDR *ClientAddr(int ClientId) const { return m_aSlots[ClientId].m_Connection.PeerAddress(); }
420 bool HasSecurityToken(int ClientId) const { return m_aSlots[ClientId].m_Connection.SecurityToken() != NET_SECURITY_TOKEN_UNSUPPORTED; }
421 NETADDR Address() const { return m_Address; }
422 NETSOCKET Socket() const { return m_Socket; }
423 CNetBan *NetBan() const { return m_pNetBan; }
424 int NetType() const { return net_socket_type(sock: m_Socket); }
425 int MaxClients() const { return m_MaxClients; }
426
427 void SendTokenSixup(NETADDR &Addr, SECURITY_TOKEN Token);
428 int SendConnlessSixup(CNetChunk *pChunk, SECURITY_TOKEN ResponseToken);
429
430 //
431 void SetMaxClientsPerIp(int Max);
432 bool SetTimedOut(int ClientId, int OrigId);
433 void SetTimeoutProtected(int ClientId);
434
435 int ResetErrorString(int ClientId);
436 const char *ErrorString(int ClientId);
437
438 // anti spoof
439 SECURITY_TOKEN GetGlobalToken();
440 SECURITY_TOKEN GetToken(const NETADDR &Addr);
441 // vanilla token/gametick shouldn't be negative
442 SECURITY_TOKEN GetVanillaToken(const NETADDR &Addr) { return absolute(a: GetToken(Addr)); }
443};
444
445class CNetConsole
446{
447 struct CSlot
448 {
449 CConsoleNetConnection m_Connection;
450 };
451
452 NETSOCKET m_Socket;
453 CNetBan *m_pNetBan;
454 CSlot m_aSlots[NET_MAX_CONSOLE_CLIENTS];
455
456 NETFUNC_NEWCLIENT_CON m_pfnNewClient;
457 NETFUNC_DELCLIENT m_pfnDelClient;
458 void *m_pUser;
459
460 CNetRecvUnpacker m_RecvUnpacker;
461
462public:
463 void SetCallbacks(NETFUNC_NEWCLIENT_CON pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
464
465 //
466 bool Open(NETADDR BindAddr, CNetBan *pNetBan);
467 int Close();
468
469 //
470 int Recv(char *pLine, int MaxLength, int *pClientId = nullptr);
471 int Send(int ClientId, const char *pLine);
472 int Update();
473
474 //
475 int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr);
476 int Drop(int ClientId, const char *pReason);
477
478 // status requests
479 const NETADDR *ClientAddr(int ClientId) const { return m_aSlots[ClientId].m_Connection.PeerAddress(); }
480 CNetBan *NetBan() const { return m_pNetBan; }
481};
482
483// client side
484class CNetClient
485{
486 CNetConnection m_Connection;
487 CNetRecvUnpacker m_RecvUnpacker;
488
489 CStun *m_pStun = nullptr;
490
491public:
492 NETSOCKET m_Socket;
493 // openness
494 bool Open(NETADDR BindAddr);
495 int Close();
496
497 // connection state
498 int Disconnect(const char *pReason);
499 int Connect(const NETADDR *pAddr, int NumAddrs);
500
501 // communication
502 int Recv(CNetChunk *pChunk);
503 int Send(CNetChunk *pChunk);
504
505 // pumping
506 int Update();
507 int Flush();
508
509 int ResetErrorString();
510
511 // error and state
512 int NetType() const { return net_socket_type(sock: m_Socket); }
513 int State();
514 const NETADDR *ServerAddress() const { return m_Connection.PeerAddress(); }
515 void ConnectAddresses(const NETADDR **ppAddrs, int *pNumAddrs) const { m_Connection.ConnectAddresses(ppAddrs, pNumAddrs); }
516 int GotProblems(int64_t MaxLatency) const;
517 const char *ErrorString() const;
518
519 // stun
520 void FeedStunServer(NETADDR StunServer);
521 void RefreshStun();
522 CONNECTIVITY GetConnectivity(int NetType, NETADDR *pGlobalAddr);
523};
524
525// TODO: both, fix these. This feels like a junk class for stuff that doesn't fit anywhere
526class CNetBase
527{
528 static IOHANDLE ms_DataLogSent;
529 static IOHANDLE ms_DataLogRecv;
530 static CHuffman ms_Huffman;
531
532public:
533 static void OpenLog(IOHANDLE DataLogSent, IOHANDLE DataLogRecv);
534 static void CloseLog();
535 static void Init();
536 static int Compress(const void *pData, int DataSize, void *pOutput, int OutputSize);
537 static int Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize);
538
539 static void SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken, bool Sixup = false);
540 static void SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize, bool Extended, unsigned char aExtra[4]);
541 static void SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket, SECURITY_TOKEN SecurityToken, bool Sixup = false, bool NoCompress = false);
542
543 static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket, bool &Sixup, SECURITY_TOKEN *pSecurityToken = nullptr, SECURITY_TOKEN *pResponseToken = nullptr);
544
545 // The backroom is ack-NET_MAX_SEQUENCE/2. Used for knowing if we acked a packet or not
546 static bool IsSeqInBackroom(int Seq, int Ack);
547};
548
549#endif
550