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 | |
12 | class CHuffman; |
13 | class CNetBan; |
14 | class CPacker; |
15 | |
16 | /* |
17 | |
18 | CURRENT: |
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 | |
38 | enum |
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 | |
54 | enum |
55 | { |
56 | NET_VERSION = 2, |
57 | |
58 | NET_MAX_PACKETSIZE = 1400, |
59 | NET_MAX_PAYLOAD = NET_MAX_PACKETSIZE - 6, |
60 | = 3, |
61 | = 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 | |
98 | typedef int SECURITY_TOKEN; |
99 | |
100 | SECURITY_TOKEN ToSecurityToken(const unsigned char *pData); |
101 | void WriteSecurityToken(unsigned char *pData, SECURITY_TOKEN Token); |
102 | |
103 | extern const unsigned char SECURITY_TOKEN_MAGIC[4]; |
104 | |
105 | enum |
106 | { |
107 | NET_SECURITY_TOKEN_UNKNOWN = -1, |
108 | NET_SECURITY_TOKEN_UNSUPPORTED = 0, |
109 | }; |
110 | |
111 | typedef int (*NETFUNC_DELCLIENT)(int ClientId, const char *pReason, void *pUser); |
112 | typedef int (*NETFUNC_NEWCLIENT_CON)(int ClientId, void *pUser); |
113 | typedef int (*NETFUNC_NEWCLIENT)(int ClientId, void *pUser, bool Sixup); |
114 | typedef int (*NETFUNC_NEWCLIENT_NOAUTH)(int ClientId, void *pUser); |
115 | typedef int (*NETFUNC_CLIENTREJOIN)(int ClientId, void *pUser); |
116 | |
117 | struct 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 [4]; |
128 | }; |
129 | |
130 | class |
131 | { |
132 | public: |
133 | int ; |
134 | int ; |
135 | int ; |
136 | |
137 | unsigned char *(unsigned char *pData, int Split = 4) const; |
138 | unsigned char *(unsigned char *pData, int Split = 4); |
139 | }; |
140 | |
141 | class CNetChunkResend |
142 | { |
143 | public: |
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 | |
153 | class CNetPacketConstruct |
154 | { |
155 | public: |
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 [4]; |
162 | }; |
163 | |
164 | enum class CONNECTIVITY |
165 | { |
166 | UNKNOWN, |
167 | CHECKING, |
168 | UNREACHABLE, |
169 | REACHABLE, |
170 | ADDRESS_KNOWN, |
171 | }; |
172 | |
173 | class 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 | |
198 | public: |
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 | |
207 | class 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 | |
214 | private: |
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 *, int ); |
249 | void ResendChunk(CNetChunkResend *pResend); |
250 | void Resend(); |
251 | |
252 | public: |
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 | |
300 | class CConsoleNetConnection |
301 | { |
302 | private: |
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 | |
316 | public: |
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 | |
330 | class CNetRecvUnpacker |
331 | { |
332 | public: |
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 |
349 | class 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 ; |
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 *, int , 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 | |
402 | public: |
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 | |
445 | class 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 | |
462 | public: |
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 |
484 | class CNetClient |
485 | { |
486 | CNetConnection m_Connection; |
487 | CNetRecvUnpacker m_RecvUnpacker; |
488 | |
489 | CStun *m_pStun = nullptr; |
490 | |
491 | public: |
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 |
526 | class CNetBase |
527 | { |
528 | static IOHANDLE ms_DataLogSent; |
529 | static IOHANDLE ms_DataLogRecv; |
530 | static CHuffman ms_Huffman; |
531 | |
532 | public: |
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 *, int , SECURITY_TOKEN SecurityToken, bool Sixup = false); |
540 | static void SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize, bool Extended, unsigned char [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 | |