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