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/net.h>
10#include <base/types.h>
11
12#include <array>
13#include <optional>
14
15class CHuffman;
16class CNetBan;
17class CPacker;
18
19/*
20
21CURRENT:
22 packet header: 3 bytes
23 unsigned char flags_ack; // 6bit flags, 2bit ack
24 0.6: ORNCaaAA
25 0.6.5: ORNCT-AA
26 0.7: --NORCAA
27
28 O = flag compression
29 R = flag resend
30 N = flag connless
31 C = flag control
32 T = flag token (0.6.5 only not supported by ddnet)
33 - = unused, should be zero
34 a = should be zero otherwise it messes up the ack number
35 A = bit of ack number
36
37
38 unsigned char ack; // 8 bit ack
39 unsigned char num_chunks; // 8 bit chunks
40
41 (unsigned char padding[3]) // 24 bit extra in case it's a connection less packet
42 // this is to make sure that it's compatible with the
43 // old protocol
44
45 chunk header: 2-3 bytes
46 unsigned char flags_size; // 2bit flags, 6 bit size
47 unsigned char size_seq; // 4bit size, 4bit seq
48 (unsigned char seq;) // 8bit seq, if vital flag is set
49*/
50
51enum
52{
53 NETSENDFLAG_VITAL = 1 << 0,
54 NETSENDFLAG_CONNLESS = 1 << 1,
55 NETSENDFLAG_FLUSH = 1 << 2,
56 NETSENDFLAG_EXTENDED = 1 << 3,
57};
58
59enum
60{
61 NETSTATE_OFFLINE = 0,
62 NETSTATE_CONNECTING,
63 NETSTATE_ONLINE,
64};
65
66enum
67{
68 NET_MAX_PACKETSIZE = 1400,
69 NET_MAX_PAYLOAD = NET_MAX_PACKETSIZE - 6,
70 /**
71 * The maximum size of a chunk within a connection-oriented packet.
72 *
73 * This is 1023 because the size is packed into 10 bits in the chunk header.
74 */
75 NET_MAX_CHUNK_SIZE = 1023,
76 NET_MAX_CHUNKHEADERSIZE = 3,
77 NET_PACKETHEADERSIZE = 3,
78 NET_CONNLESS_EXTRA_SIZE = 4,
79 NET_MAX_CLIENTS = 64,
80 NET_MAX_CONSOLE_CLIENTS = 4,
81 NET_MAX_SEQUENCE = 1 << 10,
82 NET_MAX_PACKET_CHUNKS = 0xFF,
83
84 NET_PACKETFLAG_UNUSED = 1 << 0,
85 NET_PACKETFLAG_TOKEN = 1 << 1,
86 NET_PACKETFLAG_CONTROL = 1 << 2,
87 NET_PACKETFLAG_CONNLESS = 1 << 3,
88 NET_PACKETFLAG_RESEND = 1 << 4,
89 NET_PACKETFLAG_COMPRESSION = 1 << 5,
90 // NOT SENT VIA THE NETWORK DIRECTLY:
91 NET_PACKETFLAG_EXTENDED = 1 << 6,
92
93 NET_CHUNKFLAG_VITAL = 1,
94 NET_CHUNKFLAG_RESEND = 2,
95
96 NET_CTRLMSG_KEEPALIVE = 0,
97 NET_CTRLMSG_CONNECT = 1,
98 NET_CTRLMSG_CONNECTACCEPT = 2,
99 NET_CTRLMSG_ACCEPT = 3,
100 NET_CTRLMSG_CLOSE = 4,
101
102 NET_CONN_BUFFERSIZE = 1024 * 32,
103
104 NET_CONNLIMIT_IPS = 16,
105
106 NET_TOKENCACHE_ADDRESSEXPIRY = 64,
107 NET_TOKENCACHE_PACKETEXPIRY = 5,
108};
109enum
110{
111 NET_TOKEN_MAX = 0xffffffff,
112 NET_TOKEN_NONE = NET_TOKEN_MAX,
113 NET_TOKEN_MASK = NET_TOKEN_MAX,
114
115 NET_TOKENREQUEST_DATASIZE = 512,
116};
117
118typedef int SECURITY_TOKEN;
119typedef unsigned int TOKEN;
120
121SECURITY_TOKEN ToSecurityToken(const unsigned char *pData);
122void WriteSecurityToken(unsigned char *pData, SECURITY_TOKEN Token);
123
124extern const unsigned char SECURITY_TOKEN_MAGIC[4];
125
126enum
127{
128 NET_SECURITY_TOKEN_UNKNOWN = -1,
129 NET_SECURITY_TOKEN_UNSUPPORTED = 0,
130};
131
132typedef int (*NETFUNC_DELCLIENT)(int ClientId, const char *pReason, void *pUser);
133typedef int (*NETFUNC_NEWCLIENT_CON)(int ClientId, void *pUser);
134typedef int (*NETFUNC_NEWCLIENT)(int ClientId, void *pUser, bool Sixup);
135typedef int (*NETFUNC_NEWCLIENT_NOAUTH)(int ClientId, void *pUser);
136typedef int (*NETFUNC_CLIENTREJOIN)(int ClientId, void *pUser);
137
138struct CNetChunk
139{
140 // -1 means that it's a stateless packet
141 // 0 on the client means the server
142 int m_ClientId;
143 NETADDR m_Address; // only used when client_id == -1
144 int m_Flags;
145 int m_DataSize;
146 const void *m_pData;
147 // only used if the flags contain NETSENDFLAG_EXTENDED and NETSENDFLAG_CONNLESS
148 unsigned char m_aExtraData[NET_CONNLESS_EXTRA_SIZE];
149};
150
151class CNetChunkHeader
152{
153public:
154 int m_Flags;
155 int m_Size;
156 int m_Sequence;
157
158 unsigned char *Pack(unsigned char *pData, int Split = 4) const;
159 unsigned char *Unpack(unsigned char *pData, int Split = 4);
160};
161
162class CNetChunkResend
163{
164public:
165 int m_Flags;
166 int m_DataSize;
167 unsigned char *m_pData;
168
169 int m_Sequence;
170 int64_t m_LastSendTime;
171 int64_t m_FirstSendTime;
172};
173
174class CNetPacketConstruct
175{
176public:
177 int m_Flags;
178 int m_Ack;
179 int m_NumChunks;
180 int m_DataSize;
181 unsigned char m_aChunkData[NET_MAX_PAYLOAD];
182 unsigned char m_aExtraData[NET_CONNLESS_EXTRA_SIZE];
183};
184
185enum class CONNECTIVITY
186{
187 UNKNOWN,
188 CHECKING,
189 UNREACHABLE,
190 REACHABLE,
191 ADDRESS_KNOWN,
192};
193
194class CStun
195{
196 class CProtocol
197 {
198 int m_Index;
199 NETSOCKET m_Socket;
200 CStunData m_Stun;
201 bool m_HaveStunServer = false;
202 NETADDR m_StunServer;
203 bool m_HaveAddr = false;
204 NETADDR m_Addr;
205 int64_t m_LastResponse = -1;
206 int64_t m_NextTry = -1;
207 int m_NumUnsuccessfulTries = -1;
208
209 public:
210 CProtocol(int Index, NETSOCKET Socket);
211 void FeedStunServer(NETADDR StunServer);
212 void Refresh();
213 void Update();
214 bool OnPacket(NETADDR Addr, unsigned char *pData, int DataSize);
215 CONNECTIVITY GetConnectivity(NETADDR *pGlobalAddr);
216 };
217 CProtocol m_aProtocols[2];
218
219public:
220 CStun(NETSOCKET Socket);
221 void FeedStunServer(NETADDR StunServer);
222 void Refresh();
223 void Update();
224 bool OnPacket(NETADDR Addr, unsigned char *pData, int DataSize);
225 CONNECTIVITY GetConnectivity(int NetType, NETADDR *pGlobalAddr);
226};
227
228class CNetConnection
229{
230 // TODO: is this needed because this needs to be aware of
231 // the ack sequencing number and is also responsible for updating
232 // that. this should be fixed.
233 friend class CPacketChunkUnpacker;
234
235public:
236 enum class EState
237 {
238 OFFLINE,
239 WANT_TOKEN,
240 CONNECT,
241 PENDING,
242 ONLINE,
243 ERROR,
244 };
245
246 SECURITY_TOKEN m_SecurityToken;
247
248private:
249 unsigned short m_Sequence;
250 unsigned short m_Ack;
251 unsigned short m_PeerAck;
252 EState m_State = EState::OFFLINE;
253 int m_RemoteClosed;
254 bool m_BlockCloseMsg;
255 bool m_UnknownSeq;
256
257 CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> m_Buffer;
258
259 int64_t m_LastUpdateTime;
260 int64_t m_LastRecvTime;
261 int64_t m_LastSendTime;
262
263 char m_aErrorString[256];
264
265 CNetPacketConstruct m_Construct;
266
267 NETADDR m_aConnectAddrs[16];
268 int m_NumConnectAddrs;
269 NETADDR m_PeerAddr;
270 NETSOCKET m_Socket;
271 NETSTATS m_Stats;
272
273 std::array<char, NETADDR_MAXSTRSIZE> m_aPeerAddrStr;
274 std::array<char, NETADDR_MAXSTRSIZE> m_aPeerAddrStrNoPort;
275 // client 0.7
276 static TOKEN GenerateToken7(const NETADDR *pPeerAddr);
277 class CNetBase *m_pNetBase;
278 bool IsSixup() const { return m_Sixup; }
279
280 //
281 void SetPeerAddr(const NETADDR *pAddr);
282 void ClearPeerAddr();
283 void ResetStats();
284 void SetError(const char *pString);
285 void AckChunks(int Ack);
286
287 int QueueChunkEx(int Flags, int DataSize, const void *pData, int Sequence);
288 void SendConnect();
289 void SendControl(int ControlMsg, const void *pExtra, int ExtraSize);
290 void SendControlWithToken7(int ControlMsg, SECURITY_TOKEN ResponseToken);
291 void ResendChunk(CNetChunkResend *pResend);
292 void Resend();
293
294public:
295 bool m_TimeoutProtected;
296 bool m_TimeoutSituation;
297
298 void SetToken7(TOKEN Token);
299
300 void Reset(bool Rejoin = false);
301 void Init(NETSOCKET Socket, bool BlockCloseMsg);
302 int Connect(const NETADDR *pAddr, int NumAddrs);
303 int Connect7(const NETADDR *pAddr, int NumAddrs);
304 void Disconnect(const char *pReason);
305
306 int Update();
307 int Flush();
308
309 int Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr, SECURITY_TOKEN SecurityToken = NET_SECURITY_TOKEN_UNSUPPORTED, SECURITY_TOKEN ResponseToken = NET_SECURITY_TOKEN_UNSUPPORTED);
310 int QueueChunk(int Flags, int DataSize, const void *pData);
311
312 const char *ErrorString();
313 void SignalResend();
314 EState State() const { return m_State; }
315 const NETADDR *PeerAddress() const { return &m_PeerAddr; }
316 const std::array<char, NETADDR_MAXSTRSIZE> &PeerAddressString(bool IncludePort) const
317 {
318 return IncludePort ? m_aPeerAddrStr : m_aPeerAddrStrNoPort;
319 }
320 void ConnectAddresses(const NETADDR **ppAddrs, int *pNumAddrs) const
321 {
322 *ppAddrs = m_aConnectAddrs;
323 *pNumAddrs = m_NumConnectAddrs;
324 }
325
326 void ResetErrorString() { m_aErrorString[0] = 0; }
327 const char *ErrorString() const { return m_aErrorString; }
328
329 // Needed for GotProblems in NetClient
330 int64_t LastRecvTime() const { return m_LastRecvTime; }
331 int64_t ConnectTime() const { return m_LastUpdateTime; }
332
333 int AckSequence() const { return m_Ack; }
334 int SeqSequence() const { return m_Sequence; }
335 int SecurityToken() const { return m_SecurityToken; }
336 CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> *ResendBuffer() { return &m_Buffer; }
337
338 void ResumeConnection(const NETADDR *pAddr, int Sequence, int Ack, SECURITY_TOKEN SecurityToken, CStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> *pResendBuffer, bool Sixup);
339
340 // anti spoof
341 void DirectInit(const NETADDR &Addr, SECURITY_TOKEN SecurityToken, SECURITY_TOKEN Token, bool Sixup);
342 void SetUnknownSeq() { m_UnknownSeq = true; }
343 void SetSequence(int Sequence) { m_Sequence = Sequence; }
344
345 bool m_Sixup;
346 SECURITY_TOKEN m_Token;
347};
348
349class CConsoleNetConnection
350{
351public:
352 enum class EState
353 {
354 OFFLINE,
355 ONLINE,
356 ERROR,
357 };
358
359private:
360 EState m_State;
361
362 NETADDR m_PeerAddr;
363 std::array<char, NETADDR_MAXSTRSIZE> m_aPeerAddrStr;
364 NETSOCKET m_Socket;
365
366 char m_aBuffer[NET_MAX_PACKETSIZE];
367 int m_BufferOffset;
368
369 char m_aErrorString[256];
370
371 bool m_LineEndingDetected;
372 char m_aLineEnding[3];
373
374 void SetPeerAddr(const NETADDR *pAddr);
375 void ClearPeerAddr();
376
377public:
378 int Init(NETSOCKET Socket, const NETADDR *pAddr);
379 void Disconnect(const char *pReason);
380
381 EState State() const { return m_State; }
382 const NETADDR *PeerAddress() const { return &m_PeerAddr; }
383 const std::array<char, NETADDR_MAXSTRSIZE> &PeerAddressString() const { return m_aPeerAddrStr; }
384 const char *ErrorString() const { return m_aErrorString; }
385
386 void Reset();
387 int Update();
388 int Send(const char *pLine);
389 int Recv(char *pLine, int MaxLength);
390};
391
392/**
393 * Accepts a non-control packet containing one or more chunks and unpacks each chunk individually.
394 * After a packet has been fed into the unpacker by calling @link FeedPacket @endlink, all chunks have
395 * to be unpacked by calling @link UnpackNextChunk @endlink until the function returns `false`, before
396 * the unpacker can be fed another packet.
397 */
398class CPacketChunkUnpacker
399{
400public:
401 void FeedPacket(const NETADDR &Addr, const CNetPacketConstruct &Packet, CNetConnection *pConnection, int ClientId);
402 bool UnpackNextChunk(CNetChunk *pChunk);
403
404private:
405 bool m_Valid = false;
406 NETADDR m_Addr;
407 CNetConnection *m_pConnection;
408 int m_CurrentChunk;
409 int m_ClientId;
410 CNetPacketConstruct m_Data;
411};
412
413// server side
414class CNetServer
415{
416 struct CSlot
417 {
418 public:
419 CNetConnection m_Connection;
420 };
421
422 struct CSpamConn
423 {
424 NETADDR m_Addr;
425 int64_t m_Time;
426 int m_Conns;
427 };
428
429 NETADDR m_Address;
430 NETSOCKET m_Socket;
431 CNetBan *m_pNetBan;
432 CSlot m_aSlots[NET_MAX_CLIENTS];
433 int m_MaxClients = NET_MAX_CLIENTS;
434 int m_MaxClientsPerIp;
435
436 NETFUNC_NEWCLIENT m_pfnNewClient;
437 NETFUNC_NEWCLIENT_NOAUTH m_pfnNewClientNoAuth;
438 NETFUNC_DELCLIENT m_pfnDelClient;
439 NETFUNC_CLIENTREJOIN m_pfnClientRejoin;
440 void *m_pUser;
441
442 unsigned char m_aSecurityTokenSeed[16];
443
444 // vanilla connect flood detection
445 int64_t m_VConnFirst;
446 int m_VConnNum;
447
448 CSpamConn m_aSpamConns[NET_CONNLIMIT_IPS];
449
450 CPacketChunkUnpacker m_PacketChunkUnpacker;
451 CNetPacketConstruct m_RecvBuffer;
452
453 void OnTokenCtrlMsg(NETADDR &Addr, int ControlMsg, const CNetPacketConstruct &Packet);
454 int OnSixupCtrlMsg(NETADDR &Addr, CNetChunk *pChunk, int ControlMsg, const CNetPacketConstruct &Packet, SECURITY_TOKEN &ResponseToken, SECURITY_TOKEN Token);
455 void OnPreConnMsg(NETADDR &Addr, CNetPacketConstruct &Packet);
456 void OnConnCtrlMsg(NETADDR &Addr, int ClientId, int ControlMsg, const CNetPacketConstruct &Packet);
457 bool ClientExists(const NETADDR &Addr) { return GetClientSlot(Addr) != -1; }
458 int GetClientSlot(const NETADDR &Addr);
459 void SendControl(NETADDR &Addr, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken);
460
461 int TryAcceptClient(NETADDR &Addr, SECURITY_TOKEN SecurityToken, bool VanillaAuth = false, bool Sixup = false, SECURITY_TOKEN Token = 0);
462 int NumClientsWithAddr(NETADDR Addr);
463 bool Connlimit(NETADDR Addr);
464 void SendMsgs(NETADDR &Addr, const CPacker **ppMsgs, int Num);
465
466public:
467 int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
468 int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_NEWCLIENT_NOAUTH pfnNewClientNoAuth, NETFUNC_CLIENTREJOIN pfnClientRejoin, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
469
470 //
471 bool Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int MaxClientsPerIp);
472 void Close();
473
474 //
475 int Recv(CNetChunk *pChunk, SECURITY_TOKEN *pResponseToken);
476 int Send(CNetChunk *pChunk);
477 void Update();
478
479 //
480 void Drop(int ClientId, const char *pReason);
481
482 // status requests
483 const NETADDR *ClientAddr(int ClientId) const { return m_aSlots[ClientId].m_Connection.PeerAddress(); }
484 const std::array<char, NETADDR_MAXSTRSIZE> &ClientAddrString(int ClientId, bool IncludePort) const { return m_aSlots[ClientId].m_Connection.PeerAddressString(IncludePort); }
485 bool HasSecurityToken(int ClientId) const { return m_aSlots[ClientId].m_Connection.SecurityToken() != NET_SECURITY_TOKEN_UNSUPPORTED; }
486 NETADDR Address() const { return m_Address; }
487 NETSOCKET Socket() const { return m_Socket; }
488 CNetBan *NetBan() const { return m_pNetBan; }
489 int NetType() const { return net_socket_type(sock: m_Socket); }
490 int MaxClients() const { return m_MaxClients; }
491
492 void SendTokenSixup(NETADDR &Addr, SECURITY_TOKEN Token);
493
494 //
495 void SetMaxClientsPerIp(int Max);
496 bool HasErrored(int ClientId);
497 void ResumeOldConnection(int ClientId, int OrigId);
498 void IgnoreTimeouts(int ClientId);
499
500 void ResetErrorString(int ClientId);
501 const char *ErrorString(int ClientId);
502
503 // anti spoof
504 SECURITY_TOKEN GetGlobalToken();
505 SECURITY_TOKEN GetToken(const NETADDR &Addr);
506 SECURITY_TOKEN GetVanillaToken(const NETADDR &Addr);
507};
508
509class CNetConsole
510{
511 struct CSlot
512 {
513 CConsoleNetConnection m_Connection;
514 };
515
516 NETSOCKET m_Socket;
517 CNetBan *m_pNetBan;
518 CSlot m_aSlots[NET_MAX_CONSOLE_CLIENTS];
519
520 NETFUNC_NEWCLIENT_CON m_pfnNewClient;
521 NETFUNC_DELCLIENT m_pfnDelClient;
522 void *m_pUser;
523
524public:
525 void SetCallbacks(NETFUNC_NEWCLIENT_CON pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
526
527 //
528 bool Open(NETADDR BindAddr, CNetBan *pNetBan);
529 void Close();
530
531 //
532 int Recv(char *pLine, int MaxLength, int *pClientId = nullptr);
533 int Send(int ClientId, const char *pLine);
534 void Update();
535
536 //
537 int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr);
538 void Drop(int ClientId, const char *pReason);
539
540 // status requests
541 const NETADDR *ClientAddr(int ClientId) const { return m_aSlots[ClientId].m_Connection.PeerAddress(); }
542 const std::array<char, NETADDR_MAXSTRSIZE> &ClientAddrString(int ClientId) const { return m_aSlots[ClientId].m_Connection.PeerAddressString(); }
543 CNetBan *NetBan() const { return m_pNetBan; }
544};
545
546class CNetTokenCache
547{
548public:
549 void Init(NETSOCKET Socket);
550 void SendPacketConnless(CNetChunk *pChunk);
551 void FetchToken(NETADDR *pAddr);
552 void AddToken(const NETADDR *pAddr, TOKEN Token);
553 TOKEN GetToken(const NETADDR *pAddr);
554 TOKEN GenerateToken();
555 void Update();
556
557private:
558 class CConnlessPacketInfo
559 {
560 public:
561 NETADDR m_Addr;
562 int m_DataSize;
563 unsigned char m_aData[NET_MAX_PAYLOAD];
564 int64_t m_Expiry;
565 };
566
567 class CAddressInfo
568 {
569 public:
570 NETADDR m_Addr;
571 TOKEN m_Token;
572 int64_t m_Expiry;
573 };
574
575 NETSOCKET m_Socket;
576 std::vector<CAddressInfo> m_TokenCache;
577 std::vector<CConnlessPacketInfo> m_ConnlessPackets;
578};
579
580// client side
581class CNetClient
582{
583 CNetConnection m_Connection;
584 CPacketChunkUnpacker m_PacketChunkUnpacker;
585 CNetPacketConstruct m_RecvBuffer;
586 CNetTokenCache m_TokenCache;
587
588 CStun *m_pStun = nullptr;
589
590public:
591 NETSOCKET m_Socket = nullptr;
592 // openness
593 bool Open(NETADDR BindAddr);
594 void Close();
595
596 // connection state
597 void Disconnect(const char *pReason);
598 void Connect(const NETADDR *pAddr, int NumAddrs);
599 void Connect7(const NETADDR *pAddr, int NumAddrs);
600
601 // communication
602 int Recv(CNetChunk *pChunk, SECURITY_TOKEN *pResponseToken, bool Sixup);
603 int Send(CNetChunk *pChunk);
604
605 // pumping
606 void Update();
607 int Flush();
608
609 void ResetErrorString();
610
611 // error and state
612 int NetType() const { return net_socket_type(sock: m_Socket); }
613 int State();
614 const NETADDR *ServerAddress() const { return m_Connection.PeerAddress(); }
615 void ConnectAddresses(const NETADDR **ppAddrs, int *pNumAddrs) const { m_Connection.ConnectAddresses(ppAddrs, pNumAddrs); }
616 bool GotProblems(int64_t MaxLatency) const;
617 const char *ErrorString() const;
618
619 // stun
620 void FeedStunServer(NETADDR StunServer);
621 void RefreshStun();
622 CONNECTIVITY GetConnectivity(int NetType, NETADDR *pGlobalAddr);
623};
624
625// TODO: both, fix these. This feels like a junk class for stuff that doesn't fit anywhere
626class CNetBase
627{
628 static IOHANDLE ms_DataLogSent;
629 static IOHANDLE ms_DataLogRecv;
630 static CHuffman ms_Huffman;
631
632public:
633 static void OpenLog(IOHANDLE DataLogSent, IOHANDLE DataLogRecv);
634 static void CloseLog();
635 static void Init();
636 static int Compress(const void *pData, int DataSize, void *pOutput, int OutputSize);
637 static int Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize);
638
639 static bool IsValidConnectionOrientedPacket(const CNetPacketConstruct *pPacket);
640
641 static void SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken, bool Sixup = false);
642 static void SendControlMsgWithToken7(NETSOCKET Socket, NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken, bool Extended);
643 static void SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize, bool Extended, unsigned char aExtra[NET_CONNLESS_EXTRA_SIZE]);
644 static void SendPacketConnlessWithToken7(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize, SECURITY_TOKEN Token, SECURITY_TOKEN ResponseToken);
645 static void SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket, SECURITY_TOKEN SecurityToken, bool Sixup = false);
646
647 static std::optional<int> UnpackPacketFlags(unsigned char *pBuffer, int Size);
648 static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket, bool &Sixup, SECURITY_TOKEN *pSecurityToken = nullptr, SECURITY_TOKEN *pResponseToken = nullptr);
649
650 // The backroom is ack-NET_MAX_SEQUENCE/2. Used for knowing if we acked a packet or not
651 static bool IsSeqInBackroom(int Seq, int Ack);
652};
653
654#endif
655