1 /* 2 * OpenClonk, http://www.openclonk.org 3 * 4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/ 5 * Copyright (c) 2009-2016, The OpenClonk Team and contributors 6 * 7 * Distributed under the terms of the ISC license; see accompanying file 8 * "COPYING" for details. 9 * 10 * "Clonk" is a registered trademark of Matthes Bender, used with permission. 11 * See accompanying file "TRADEMARK" for details. 12 * 13 * To redistribute this file separately, substitute the full license texts 14 * for the above references. 15 */ 16 #ifndef INC_C4Network2IO 17 #define INC_C4Network2IO 18 19 #include "netpuncher/C4PuncherPacket.h" 20 #include "network/C4Client.h" 21 #include "network/C4InteractiveThread.h" 22 #include "network/C4NetIO.h" 23 24 #include <atomic> 25 26 class C4Network2IOConnection; 27 28 // enums & constants 29 enum C4Network2IOProtocol 30 { 31 P_UDP, P_TCP, P_NONE = -1 32 }; 33 34 const int C4NetTimer = 500, // ms 35 C4NetPingFreq = 1000, // ms 36 C4NetStatisticsFreq = 1000, // ms 37 C4NetAcceptTimeout = 10, // s 38 C4NetPingTimeout = 30000;// ms 39 40 // client count 41 const int C4NetMaxClients = 256; 42 43 class C4Network2IO 44 : protected C4InteractiveThread::Callback, 45 protected C4NetIO::CBClass, 46 protected StdSchedulerProc 47 { 48 public: 49 C4Network2IO(); 50 ~C4Network2IO() override; 51 52 protected: 53 54 // main traffic net i/o classes 55 C4NetIO *pNetIO_TCP{nullptr}, *pNetIO_UDP{nullptr}; 56 57 // discovery net i/o 58 class C4Network2IODiscover *pNetIODiscover{nullptr}; 59 60 // reference server 61 class C4Network2RefServer *pRefServer{nullptr}; 62 63 // UPnP port mapping manager 64 class C4Network2UPnP *UPnPMgr{nullptr}; 65 66 // local client core 67 C4ClientCore LCCore; 68 CStdCSec LCCoreCSec; 69 70 // connection list 71 C4Network2IOConnection *pConnList{nullptr}; 72 CStdCSec ConnListCSec, BroadcastCSec; 73 74 // next connection ID to use 75 uint32_t iNextConnID{0}; 76 77 // allow incoming connections? 78 bool fAllowConnect{false}; 79 80 // connection acceptance 81 struct AutoAccept 82 { 83 C4ClientCore CCore; 84 AutoAccept *Next; 85 } 86 *pAutoAcceptList{nullptr}; 87 CStdCSec AutoAcceptCSec; 88 89 // make sure only one connection is established? 90 bool fExclusiveConn{false}; 91 92 // timer & ping 93 C4TimeMilliseconds tLastExecute; 94 C4TimeMilliseconds tLastPing; 95 96 // statistics 97 C4TimeMilliseconds tLastStatistic; 98 int iTCPIRate{0}, iTCPORate{0}, iTCPBCRate{0}, 99 iUDPIRate{0}, iUDPORate{0}, iUDPBCRate{0}; 100 101 // punching 102 C4NetIO::addr_t PuncherAddrIPv4, PuncherAddrIPv6; 103 bool IsPuncherAddr(const C4NetIO::addr_t& addr) const; 104 105 public: 106 hasTCP()107 bool hasTCP() const { return !! pNetIO_TCP; } hasUDP()108 bool hasUDP() const { return !! pNetIO_UDP; } 109 110 // initialization 111 bool Init(int16_t iPortTCP, int16_t iPortUDP, int16_t iPortDiscovery = -1, int16_t iPortRefServer = -1, bool fBroadcast = false, bool enable_upnp = true); // by main thread 112 void Clear(); // by main thread 113 void SetLocalCCore(const C4ClientCore &CCore); // by main thread 114 115 // i/o types 116 C4NetIO *MsgIO(); // by both 117 C4NetIO *DataIO(); // by both 118 119 // connections 120 bool Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol eProt, const C4ClientCore &nCCore, const char *szPassword = nullptr); // by main thread 121 void SetAcceptMode(bool fAcceptAll); // by main thread 122 void SetExclusiveConnMode(bool fExclusiveConn); // by main thread 123 int getConnectionCount(); // by main thread 124 125 void ClearAutoAccept(); // by main thread 126 void AddAutoAccept(const C4ClientCore &CCore); // by main thread 127 void RemoveAutoAccept(const C4ClientCore &CCore); // by main thread 128 129 C4Network2IOConnection *GetMsgConnection(int iClientID); // by both (returns referenced connection!) 130 C4Network2IOConnection *GetDataConnection(int iClientID); // by both (returns referenced connection!) 131 132 // broadcasting 133 void BeginBroadcast(bool fSelectAll = false); // by both 134 void EndBroadcast(); // by both 135 bool Broadcast(const C4NetIOPacket &rPkt); // by both 136 137 // sending helpers 138 bool SendMsgToClient(C4NetIOPacket &rPkt, int iClient); // by both 139 bool BroadcastMsg(const C4NetIOPacket &rPkt); // by both 140 141 // punch 142 bool InitPuncher(C4NetIO::addr_t PuncherAddr); // by main thread 143 void SendPuncherPacket(const C4NetpuncherPacket&, C4NetIO::HostAddress::AddressFamily family); 144 void Punch(const C4NetIO::addr_t&); // sends a ping packet 145 146 // stuff 147 C4NetIO *getNetIO(C4Network2IOProtocol eProt); // by both 148 const char *getNetIOName(C4NetIO *pNetIO); 149 C4Network2IOProtocol getNetIOProt(C4NetIO *pNetIO); 150 151 // statistics getProtIRate(C4Network2IOProtocol eProt)152 int getProtIRate(C4Network2IOProtocol eProt) const { return eProt == P_TCP ? iTCPIRate : iUDPIRate; } getProtORate(C4Network2IOProtocol eProt)153 int getProtORate(C4Network2IOProtocol eProt) const { return eProt == P_TCP ? iTCPORate : iUDPORate; } getProtBCRate(C4Network2IOProtocol eProt)154 int getProtBCRate(C4Network2IOProtocol eProt) const { return eProt == P_TCP ? iTCPBCRate : iUDPBCRate; } 155 156 // reference 157 void SetReference(class C4Network2Reference *pReference); 158 bool IsReferenceNeeded(); 159 160 protected: 161 // *** callbacks 162 // C4NetIO-Callbacks 163 bool OnConn(const C4NetIO::addr_t &addr, const C4NetIO::addr_t &AddrConnect, const C4NetIO::addr_t *pOwnAddr, C4NetIO *pNetIO) override; 164 void OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const char *szReason) override; 165 void OnPacket(const C4NetIOPacket &rPacket, C4NetIO *pNetIO) override; 166 // C4NetIOMan 167 virtual void OnError(const char *strError, C4NetIO *pNetIO); 168 // StdSchedulerProc 169 bool Execute(int iTimeout, pollfd *) override; 170 C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow) override; 171 // Event callback by C4InteractiveThread 172 void OnThreadEvent(C4InteractiveEventType eEvent, void *pEventData) override; // by main thread 173 174 // connections list 175 void AddConnection(C4Network2IOConnection *pConn); // by both 176 void RemoveConnection(C4Network2IOConnection *pConn); // by both 177 C4Network2IOConnection *GetConnection(const C4NetIO::addr_t &addr, C4NetIO *pNetIO); // by both 178 C4Network2IOConnection *GetConnectionByConnAddr(const C4NetIO::addr_t &addr, C4NetIO *pNetIO); // by both 179 C4Network2IOConnection *GetConnectionByID(uint32_t iConnID); // by thread 180 181 // network events (signals to main thread) 182 struct NetEvPacketData; 183 184 // connection acceptance 185 bool doAutoAccept(const C4ClientCore &CCore, const C4Network2IOConnection &Conn); 186 187 // general packet handling (= forward in most cases) 188 bool HandlePacket(const C4NetIOPacket &rPacket, C4Network2IOConnection *pConn, bool fThread); // by both 189 void CallHandlers(int iHandlers, const class C4IDPacket *pPacket, C4Network2IOConnection *pConn, bool fThread); // by both 190 191 // packet handling (some are really handled here) 192 void HandlePacket(char cStatus, const C4PacketBase *pPacket, C4Network2IOConnection *pConn); 193 void HandleFwdReq(const class C4PacketFwd &rFwd, C4Network2IOConnection *pBy); 194 void HandlePuncherPacket(const C4NetIOPacket &rPacket); 195 196 // misc 197 bool Ping(); 198 void CheckTimeout(); 199 void GenerateStatistics(int iInterval); 200 void SendConnPackets(); 201 }; 202 203 enum C4Network2IOConnStatus 204 { 205 CS_Connect, // waiting for connection 206 CS_Connected, // waiting for Conn 207 CS_HalfAccepted, // got Conn (peer identified, client class created if neccessary) 208 CS_Accepted, // got ConnRe (peer did accept) 209 CS_Closed, 210 CS_ConnectFail // got closed before HalfAccepted was reached 211 }; 212 213 class C4Network2IOConnection // shared 214 { 215 friend class C4Network2IO; 216 public: 217 C4Network2IOConnection(); 218 ~C4Network2IOConnection(); 219 220 protected: 221 222 // connection data 223 class C4NetIO *pNetClass{nullptr}; 224 C4Network2IOProtocol eProt; 225 C4NetIO::addr_t PeerAddr, ConnectAddr; 226 227 // status data 228 C4Network2IOConnStatus Status; 229 uint32_t iID, iRemoteID; // connection ID for this and the remote client 230 bool fAutoAccept{false}; // auto accepted by thread? 231 bool fBroadcastTarget{false}; // broadcast target? 232 time_t iTimestamp{0}; // timestamp of last status change 233 int iPingTime{-1}; // ping 234 C4TimeMilliseconds tLastPing; // if > iLastPong, it's the first ping that hasn't been answered yet, nullptr if no ping received yet 235 C4TimeMilliseconds tLastPong; // last pong received, nullptr if no pong received yet 236 C4ClientCore CCore; // client core (>= CS_HalfAccepted) 237 CStdCSec CCoreCSec; 238 int iIRate, iORate; // input/output rates (by C4NetIO, in b/s) 239 int iPacketLoss; // lost packets (in the last seconds) 240 StdCopyStrBuf Password; // password to use for connect 241 bool fConnSent{false}; // initial connection packet send 242 bool fPostMortemSent{false}; // post mortem send 243 244 // packet backlog 245 uint32_t iOutPacketCounter{0}, iInPacketCounter{0}; 246 struct PacketLogEntry 247 { 248 uint32_t Number; 249 C4NetIOPacket Pkt; 250 PacketLogEntry *Next; 251 }; 252 PacketLogEntry *pPacketLog{nullptr}; 253 CStdCSec PacketLogCSec; 254 255 // list (C4Network2IO) 256 C4Network2IOConnection *pNext{nullptr}; 257 258 // reference counter 259 std::atomic_long iRefCnt; 260 261 public: getNetClass()262 C4NetIO *getNetClass() const { return pNetClass; } getProtocol()263 C4Network2IOProtocol getProtocol() const { return eProt; } getPeerAddr()264 const C4NetIO::addr_t &getPeerAddr() const { return PeerAddr.GetPort() ? PeerAddr : ConnectAddr; } getConnectAddr()265 const C4NetIO::addr_t &getConnectAddr() const { return ConnectAddr; } getID()266 uint32_t getID() const { return iID; } getRemoteID()267 uint32_t getRemoteID() const { return iRemoteID; } getTimestamp()268 time_t getTimestamp() const { return iTimestamp; } getCCore()269 const C4ClientCore &getCCore() const { return CCore; } getCCoreCSec()270 CStdCSec &getCCoreCSec() { return CCoreCSec; } getClientID()271 int getClientID() const { return CCore.getID(); } isHost()272 bool isHost() const { return CCore.isHost(); } getPingTime()273 int getPingTime() const { return iPingTime; } 274 int getLag() const; getIRate()275 int getIRate() const { return iIRate; } getORate()276 int getORate() const { return iORate; } getPacketLoss()277 int getPacketLoss() const { return iPacketLoss; } getPassword()278 const char *getPassword() const { return Password.getData(); } isConnSent()279 bool isConnSent() const { return fConnSent; } 280 getInPacketCounter()281 uint32_t getInPacketCounter() const { return iInPacketCounter; } getOutPacketCounter()282 uint32_t getOutPacketCounter() const { return iOutPacketCounter; } 283 isConnecting()284 bool isConnecting() const { return Status == CS_Connect; } isOpen()285 bool isOpen() const { return Status != CS_Connect && Status != CS_Closed && Status != CS_ConnectFail; } isHalfAccepted()286 bool isHalfAccepted()const { return Status == CS_HalfAccepted || Status == CS_Accepted; } isAccepted()287 bool isAccepted() const { return Status == CS_Accepted; } isClosed()288 bool isClosed() const { return Status == CS_Closed || Status == CS_ConnectFail; } isAutoAccepted()289 bool isAutoAccepted()const { return fAutoAccept; } isBroadcastTarget()290 bool isBroadcastTarget() const { return fBroadcastTarget; } isFailed()291 bool isFailed() const { return Status == CS_ConnectFail; } 292 293 protected: 294 // called by C4Network2IO only 295 void Set(C4NetIO *pnNetClass, C4Network2IOProtocol eProt, const C4NetIO::addr_t &nPeerAddr, const C4NetIO::addr_t &nConnectAddr, C4Network2IOConnStatus nStatus, const char *szPassword, uint32_t iID); 296 void SetRemoteID(uint32_t iRemoteID); 297 void SetPeerAddr(const C4NetIO::addr_t &nPeerAddr); 298 void OnPing(); 299 void SetPingTime(int iPingTime); 300 void SetStatus(C4Network2IOConnStatus nStatus); 301 void SetAutoAccepted(); 302 void OnPacketReceived(uint8_t iPacketType); 303 void ClearPacketLog(uint32_t iStartNumber = ~0); 304 305 public: 306 // status changing SetHalfAccepted()307 void SetHalfAccepted() { SetStatus(CS_HalfAccepted); } SetAccepted()308 void SetAccepted() { SetStatus(CS_Accepted); } 309 void SetCCore(const C4ClientCore &nCCore); ResetAutoAccepted()310 void ResetAutoAccepted() { fAutoAccept = false; } SetConnSent()311 void SetConnSent() { fConnSent = true; } 312 313 // connection operations 314 bool Connect(); 315 void Close(); 316 bool Send(const C4NetIOPacket &rPkt); 317 void SetBroadcastTarget(bool fSet); // (only call after C4Network2IO::BeginBroadcast!) 318 319 // statistics 320 void DoStatistics(int iInterval, int *pIRateSum, int *pORateSum); 321 322 // reference counting 323 void AddRef(); void DelRef(); 324 325 // post mortem 326 bool CreatePostMortem(class C4PacketPostMortem *pPkt); 327 328 }; 329 330 // * Packets * 331 332 class C4PacketPing : public C4PacketBase 333 { 334 public: 335 C4PacketPing(uint32_t iPacketCounter = 0, uint32_t iRemotePacketCounter = 0); 336 337 protected: 338 C4TimeMilliseconds tTime; 339 uint32_t iPacketCounter; 340 341 public: 342 uint32_t getTravelTime() const; getPacketCounter()343 uint32_t getPacketCounter() const { return iPacketCounter; } 344 345 void CompileFunc(StdCompiler *pComp) override; 346 }; 347 348 class C4PacketConn : public C4PacketBase 349 { 350 public: 351 C4PacketConn(); 352 C4PacketConn(const class C4ClientCore &nCCore, uint32_t iConnID, const char *szPassword = nullptr); 353 354 protected: 355 int32_t iVer; 356 uint32_t iConnID; 357 C4ClientCore CCore; 358 StdCopyStrBuf Password; 359 360 public: getVer()361 int32_t getVer() const { return iVer; } getConnID()362 uint32_t getConnID() const { return iConnID; } getCCore()363 const C4ClientCore &getCCore() const { return CCore; } getPassword()364 const char *getPassword() const { return Password.getData(); } 365 366 void CompileFunc(StdCompiler *pComp) override; 367 }; 368 369 class C4PacketConnRe : public C4PacketBase 370 { 371 public: 372 C4PacketConnRe(); 373 C4PacketConnRe(bool fOK, bool fWrongPassword, const char *szMsg = nullptr); 374 375 protected: 376 bool fOK, fWrongPassword; 377 StdStrBuf szMsg; 378 379 public: isOK()380 bool isOK() const { return fOK; } isPasswordWrong()381 bool isPasswordWrong() const { return fWrongPassword; } getMsg()382 const char *getMsg() const { return szMsg.getData(); } 383 384 void CompileFunc(StdCompiler *pComp) override; 385 }; 386 387 class C4PacketFwd : public C4PacketBase 388 { 389 public: 390 C4PacketFwd(); 391 C4PacketFwd(const StdBuf &Pkt); 392 393 protected: 394 bool fNegativeList{false}; 395 int32_t iClients[C4NetMaxClients]; 396 int32_t iClientCnt{0}; 397 StdCopyBuf Data; 398 399 public: getData()400 const StdCopyBuf &getData() const { return Data; } isNegativeList()401 bool isNegativeList() const { return fNegativeList; } getClient(int32_t i)402 int32_t getClient(int32_t i) const { return iClients[i]; } getClientCnt()403 int32_t getClientCnt() const { return iClientCnt; } 404 405 bool DoFwdTo(int32_t iClient) const; 406 407 void SetData(const StdBuf &Pkt); 408 void SetListType(bool fnNegativeList); 409 void AddClient(int32_t iClient); 410 411 void CompileFunc(StdCompiler *pComp) override; 412 }; 413 414 class C4PacketPostMortem : public C4PacketBase 415 { 416 public: 417 C4PacketPostMortem(); 418 ~C4PacketPostMortem() override; 419 420 private: 421 uint32_t iConnID; 422 uint32_t iPacketCounter; // last packet counter of dead connection 423 uint32_t iPacketCount{0}; 424 struct PacketLink 425 { 426 C4NetIOPacket Pkt; 427 PacketLink *Next; 428 }; 429 PacketLink *pPackets{nullptr}; 430 431 public: getConnID()432 uint32_t getConnID() const { return iConnID; } getPacketCount()433 uint32_t getPacketCount() const { return iPacketCount; } SetConnID(uint32_t inConnID)434 void SetConnID(uint32_t inConnID) { iConnID = inConnID; } 435 436 const C4NetIOPacket *getPacket(uint32_t iNumber) const; 437 void SetPacketCounter(uint32_t iPacketCounter); 438 void Add(const C4NetIOPacket &rPkt); 439 440 void CompileFunc(StdCompiler *pComp) override; 441 }; 442 443 #endif 444