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