1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2010-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 #include "C4Include.h"
17 #include "network/C4Network2Client.h"
18 
19 #include "editor/C4Console.h"
20 #include "gui/C4GameLobby.h" // fullscreen network lobby
21 #include "network/C4Network2.h"
22 #include "network/C4Network2Stats.h"
23 #include "player/C4PlayerList.h"
24 
25 // *** C4Network2Client
26 
C4Network2Client(C4Client * pClient)27 C4Network2Client::C4Network2Client(C4Client *pClient)
28 		: pClient(pClient),
29 		iAddrCnt(0),
30 		eStatus(NCS_Ready),
31 		iLastActivity(0),
32 		pMsgConn(nullptr), pDataConn(nullptr),
33 		iNextConnAttempt(0),
34 		pNext(nullptr), pParent(nullptr), pstatPing(nullptr)
35 {
36 }
37 
~C4Network2Client()38 C4Network2Client::~C4Network2Client()
39 {
40 	ClearGraphs();
41 	if (pMsgConn) { pMsgConn->Close(); pMsgConn->DelRef(); } pMsgConn = nullptr;
42 	if (pDataConn) { pDataConn->Close(); pDataConn->DelRef(); } pDataConn = nullptr;
43 	if (pClient) pClient->UnlinkNetClient();
44 }
45 
hasConn(C4Network2IOConnection * pConn)46 bool C4Network2Client::hasConn(C4Network2IOConnection *pConn)
47 {
48 	return pMsgConn == pConn || pDataConn == pConn;
49 }
50 
SetMsgConn(C4Network2IOConnection * pConn)51 void C4Network2Client::SetMsgConn(C4Network2IOConnection *pConn)
52 {
53 	// security
54 	if (pConn != pMsgConn)
55 	{
56 		if (pMsgConn) pMsgConn->DelRef();
57 		pMsgConn = pConn;
58 		pMsgConn->AddRef();
59 	}
60 	if (!pDataConn) SetDataConn(pConn);
61 }
62 
SetDataConn(C4Network2IOConnection * pConn)63 void C4Network2Client::SetDataConn(C4Network2IOConnection *pConn)
64 {
65 	// security
66 	if (pConn != pDataConn)
67 	{
68 		if (pDataConn) pDataConn->DelRef();
69 		pDataConn = pConn;
70 		pDataConn->AddRef();
71 	}
72 	if (!pMsgConn) SetMsgConn(pConn);
73 }
74 
RemoveConn(C4Network2IOConnection * pConn)75 void C4Network2Client::RemoveConn(C4Network2IOConnection *pConn)
76 {
77 	if (pConn == pMsgConn)
78 		{ pMsgConn->DelRef(); pMsgConn = nullptr; }
79 	if (pConn == pDataConn)
80 		{ pDataConn->DelRef(); pDataConn = nullptr; }
81 	if (pMsgConn && !pDataConn) SetDataConn(pMsgConn);
82 	if (!pMsgConn && pDataConn) SetMsgConn(pDataConn);
83 }
84 
85 
CloseConns(const char * szMsg)86 void C4Network2Client::CloseConns(const char *szMsg)
87 {
88 	C4PacketConnRe Pkt(false, false, szMsg);
89 	C4Network2IOConnection *pConn;
90 	while ((pConn = pMsgConn))
91 	{
92 		// send packet, close
93 		if (pConn->isOpen())
94 		{
95 			pConn->Send(MkC4NetIOPacket(PID_ConnRe, Pkt));
96 			pConn->Close();
97 		}
98 		// remove
99 		RemoveConn(pConn);
100 	}
101 }
102 
SendMsg(C4NetIOPacket rPkt) const103 bool C4Network2Client::SendMsg(C4NetIOPacket rPkt) const
104 {
105 	return getMsgConn() && getMsgConn()->Send(rPkt);
106 }
107 
SendData(C4NetIOPacket rPkt) const108 bool C4Network2Client::SendData(C4NetIOPacket rPkt) const
109 {
110 	return getDataConn() && getDataConn()->Send(rPkt);
111 }
112 
DoConnectAttempt(C4Network2IO * pIO)113 bool C4Network2Client::DoConnectAttempt(C4Network2IO *pIO)
114 {
115 	// local?
116 	if (isLocal()) { iNextConnAttempt = 0; return true; }
117 	// msg and data connected? Nothing to do
118 	if (getMsgConn() != getDataConn()) { iNextConnAttempt = time(nullptr) + 10; return true; }
119 	// too early?
120 	if (iNextConnAttempt && iNextConnAttempt > time(nullptr)) return true;
121 	// find address to try
122 	int32_t iBestAddress = -1;
123 	for (int32_t i = 0; i < iAddrCnt; i++)
124 		// no connection for this protocol?
125 		if ((!pDataConn || Addr[i].getProtocol() != pDataConn->getProtocol()) &&
126 		    (!pMsgConn  || Addr[i].getProtocol() != pMsgConn->getProtocol()))
127 			// protocol available?
128 			if (pIO->getNetIO(Addr[i].getProtocol()))
129 				// new best address?
130 				if (iBestAddress < 0 || AddrAttempts[i] < AddrAttempts[iBestAddress])
131 					iBestAddress = i;
132 	// too many attempts or nothing found?
133 	if (iBestAddress < 0 || AddrAttempts[iBestAddress] > C4NetClientConnectAttempts)
134 		{ iNextConnAttempt = time(nullptr) + 10; return true; }
135 	// save attempt
136 	AddrAttempts[iBestAddress]++; iNextConnAttempt = time(nullptr) + C4NetClientConnectInterval;
137 	auto addr = Addr[iBestAddress].getAddr();
138 	std::set<int> interfaceIDs;
139 	if (addr.IsLocal())
140 	    interfaceIDs = Network.Clients.GetLocal()->getInterfaceIDs();
141 	else
142 	    interfaceIDs = {0};
143 	for (auto id : interfaceIDs)
144 	{
145 	    addr.SetScopeId(id);
146 	    // log
147 	    LogSilentF("Network: connecting client %s on %s...", getName(), addr.ToString().getData());
148 	    // connect
149 	    if (pIO->Connect(addr, Addr[iBestAddress].getProtocol(), pClient->getCore()))
150 		return true;
151 	}
152 	return false;
153 }
154 
hasAddr(const C4Network2Address & addr) const155 bool C4Network2Client::hasAddr(const C4Network2Address &addr) const
156 {
157 	// Note that the host only knows its own address as 0.0.0.0, so if the real address is being added, that can't be sorted out.
158 	for (int32_t i = 0; i < iAddrCnt; i++)
159 		if (Addr[i] == addr)
160 			return true;
161 	return false;
162 }
163 
ClearAddr()164 void C4Network2Client::ClearAddr()
165 {
166 	iAddrCnt = 0;
167 }
168 
AddAddr(const C4Network2Address & addr,bool fAnnounce)169 bool C4Network2Client::AddAddr(const C4Network2Address &addr, bool fAnnounce)
170 {
171 	// checks
172 	if (iAddrCnt + 1 >= C4ClientMaxAddr) return false;
173 	if (hasAddr(addr)) return true;
174 	// add
175 	Addr[iAddrCnt] = addr; AddrAttempts[iAddrCnt] = 0;
176 	iAddrCnt++;
177 	// attempt to use this one
178 	if (!iNextConnAttempt) iNextConnAttempt = time(nullptr);
179 	// announce
180 	if (fAnnounce)
181 		if (!pParent->BroadcastMsgToConnClients(MkC4NetIOPacket(PID_Addr, C4PacketAddr(getID(), addr))))
182 			return false;
183 	// done
184 	return true;
185 }
186 
AddLocalAddrs(int16_t iPortTCP,int16_t iPortUDP)187 void C4Network2Client::AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP)
188 {
189 	C4NetIO::addr_t addr;
190 
191 	for (auto& ha : C4NetIO::GetLocalAddresses())
192 	{
193 		addr.SetAddress(ha);
194 		if (iPortTCP)
195 		{
196 			addr.SetPort(iPortTCP);
197 			AddAddr(C4Network2Address(addr, P_TCP), false);
198 		}
199 		if (iPortUDP)
200 		{
201 			addr.SetPort(iPortUDP);
202 			AddAddr(C4Network2Address(addr, P_UDP), false);
203 		}
204 		if (addr.GetScopeId())
205 			InterfaceIDs.insert(addr.GetScopeId());
206 	}
207 }
208 
SendAddresses(C4Network2IOConnection * pConn)209 void C4Network2Client::SendAddresses(C4Network2IOConnection *pConn)
210 {
211 	// send all addresses
212 	for (int32_t i = 0; i < iAddrCnt; i++)
213 	{
214 		if (Addr[i].getAddr().GetScopeId() && (!pConn || pConn->getPeerAddr().GetScopeId() != Addr[i].getAddr().GetScopeId()))
215 			continue;
216 		C4Network2Address addr(Addr[i]);
217 		addr.getAddr().SetScopeId(0);
218 		C4NetIOPacket Pkt = MkC4NetIOPacket(PID_Addr, C4PacketAddr(getID(), addr));
219 		if (pConn)
220 			pConn->Send(Pkt);
221 		else
222 			pParent->BroadcastMsgToConnClients(Pkt);
223 	}
224 
225 }
226 
CreateGraphs()227 void C4Network2Client::CreateGraphs()
228 {
229 	// del prev
230 	ClearGraphs();
231 	// get client color
232 	static const DWORD ClientDefColors[] = {0xff0000, 0x00ff00, 0xffff00, 0x7f7fff, 0xffffff, 0x00ffff, 0xff00ff, 0x7f7f7f, 0xff7f7f, 0x7fff7f, 0x0000ff};
233 	int32_t iClientColorNum = sizeof(ClientDefColors)/sizeof(DWORD);
234 	DWORD dwClientClr = ClientDefColors[std::max<int32_t>(getID(), 0) % iClientColorNum];
235 	// create graphs
236 	pstatPing = new C4TableGraph(C4TableGraph::DefaultBlockLength, Game.pNetworkStatistics ? Game.pNetworkStatistics->SecondCounter : 0);
237 	pstatPing->SetColorDw(dwClientClr);
238 	pstatPing->SetTitle(getName());
239 	// register into stat module
240 	if (Game.pNetworkStatistics) Game.pNetworkStatistics->statPings.AddGraph(pstatPing);
241 }
242 
ClearGraphs()243 void C4Network2Client::ClearGraphs()
244 {
245 	// del all assigned graphs
246 	if (pstatPing)
247 	{
248 		if (Game.pNetworkStatistics) Game.pNetworkStatistics->statPings.RemoveGraph(pstatPing);
249 		delete pstatPing;
250 		pstatPing = nullptr;
251 	}
252 }
253 
254 // *** C4Network2ClientList
255 
C4Network2ClientList(C4Network2IO * pIO)256 C4Network2ClientList::C4Network2ClientList(C4Network2IO *pIO)
257 		: pIO(pIO), pFirst(nullptr), pLocal(nullptr)
258 {
259 
260 }
261 
~C4Network2ClientList()262 C4Network2ClientList::~C4Network2ClientList()
263 {
264 	Clear();
265 }
266 
GetClientByID(int32_t iID) const267 C4Network2Client *C4Network2ClientList::GetClientByID(int32_t iID) const
268 {
269 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
270 		if (pClient->getID() == iID)
271 			return pClient;
272 	return nullptr;
273 }
274 
GetNextClientAfterID(int32_t iSmallerClientID) const275 C4Network2Client *C4Network2ClientList::GetNextClientAfterID(int32_t iSmallerClientID) const
276 {
277 	// return client with smallest ID > iSmallerClientID
278 	C4Network2Client *pBest = nullptr;
279 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
280 		if (pClient->getID() > iSmallerClientID)
281 			if (!pBest || pBest->getID() > pClient->getID())
282 				pBest = pClient;
283 	return pBest;
284 }
285 
GetClient(const char * szName) const286 C4Network2Client *C4Network2ClientList::GetClient(const char *szName) const
287 {
288 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
289 		if (SEqual(pClient->getName(), szName))
290 			return pClient;
291 	return nullptr;
292 }
293 
GetClient(C4Network2IOConnection * pConn) const294 C4Network2Client *C4Network2ClientList::GetClient(C4Network2IOConnection *pConn) const
295 {
296 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
297 		if (pClient->hasConn(pConn))
298 			return pClient;
299 	return nullptr;
300 }
301 
GetClient(const C4ClientCore & CCore,int32_t iMaxDiffLevel)302 C4Network2Client *C4Network2ClientList::GetClient(const C4ClientCore &CCore, int32_t iMaxDiffLevel)
303 {
304 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
305 		if (pClient->getCore().getDiffLevel(CCore) <= iMaxDiffLevel)
306 			return pClient;
307 	return nullptr;
308 }
309 
Count()310 unsigned int C4Network2ClientList::Count()
311 {
312 	unsigned int ret(0);
313 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext) ret++;
314 	return ret;
315 }
316 
GetHost()317 C4Network2Client *C4Network2ClientList::GetHost()
318 {
319 	return GetClientByID(C4ClientIDHost);
320 }
321 
GetNextClient(C4Network2Client * pClient)322 C4Network2Client *C4Network2ClientList::GetNextClient(C4Network2Client *pClient)
323 {
324 	return pClient ? pClient->pNext : pFirst;
325 }
326 
Init(C4ClientList * pnClientList,bool fnHost)327 void C4Network2ClientList::Init(C4ClientList *pnClientList, bool fnHost)
328 {
329 	// save flag
330 	fHost = fnHost;
331 	// initialize
332 	pClientList = pnClientList;
333 	pClientList->InitNetwork(this);
334 }
335 
RegClient(C4Client * pClient)336 C4Network2Client *C4Network2ClientList::RegClient(C4Client *pClient)
337 {
338 	// security
339 	if (pClient->getNetClient())
340 		return pClient->getNetClient();
341 	// find insert position
342 	C4Network2Client *pPos = pFirst, *pLast = nullptr;
343 	for (; pPos; pLast = pPos, pPos = pPos->getNext())
344 		if (pPos->getID() > pClient->getID())
345 			break;
346 	assert(!pLast || pLast->getID() != pClient->getID());
347 	// create new client
348 	C4Network2Client *pNetClient = new C4Network2Client(pClient);
349 	// add to list
350 	pNetClient->pNext = pPos;
351 	(pLast ? pLast->pNext : pFirst) = pNetClient;
352 	pNetClient->pParent = this;
353 	// local?
354 	if (pClient->isLocal())
355 		pLocal = pNetClient;
356 	else
357 		// set auto-accept
358 		pIO->AddAutoAccept(pClient->getCore());
359 	// add
360 	return pNetClient;
361 }
362 
DeleteClient(C4Network2Client * pClient)363 void C4Network2ClientList::DeleteClient(C4Network2Client *pClient)
364 {
365 	// close connections
366 	pClient->CloseConns("removing client");
367 	// remove from list
368 	if (pClient == pFirst)
369 		pFirst = pClient->getNext();
370 	else
371 	{
372 		C4Network2Client *pPrev;
373 		for (pPrev = pFirst; pPrev && pPrev->getNext(); pPrev = pPrev->getNext())
374 			if (pPrev->getNext() == pClient)
375 				break;
376 		if (pPrev && pPrev->getNext() == pClient)
377 			pPrev->pNext = pClient->getNext();
378 	}
379 	// remove auto-accept
380 	pIO->RemoveAutoAccept(pClient->getCore());
381 	// delete
382 	delete pClient;
383 }
384 
Clear()385 void C4Network2ClientList::Clear()
386 {
387 	// remove link to main client list
388 	if (pClientList)
389 	{
390 		C4ClientList *poClientList = pClientList;
391 		pClientList = nullptr;
392 		poClientList->ClearNetwork();
393 	}
394 	// delete clients
395 	while (pFirst)
396 	{
397 		DeleteClient(pFirst);
398 	}
399 	pLocal = nullptr;
400 }
401 
BroadcastMsgToConnClients(const C4NetIOPacket & rPkt)402 bool C4Network2ClientList::BroadcastMsgToConnClients(const C4NetIOPacket &rPkt)
403 {
404 	// Send a msg to all clients that are currently directly reachable.
405 
406 	// lock
407 	pIO->BeginBroadcast(false);
408 	// select connections for broadcast
409 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
410 		if (pClient->isConnected())
411 			pClient->getMsgConn()->SetBroadcastTarget(true);
412 	// broadcast
413 	bool fSuccess = pIO->Broadcast(rPkt);
414 	// unlock
415 	pIO->EndBroadcast();
416 	// finished
417 	return fSuccess;
418 }
419 
BroadcastMsgToClients(const C4NetIOPacket & rPkt)420 bool C4Network2ClientList::BroadcastMsgToClients(const C4NetIOPacket &rPkt)
421 {
422 	// Send a msg to all clients, including clients that are not connected to
423 	// this computer (will get forwarded by host).
424 
425 	C4PacketFwd Fwd; Fwd.SetListType(true);
426 	// lock
427 	pIO->BeginBroadcast(false);
428 	// select connections for broadcast
429 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
430 		if (!pClient->isHost())
431 			if (pClient->isConnected())
432 			{
433 				pClient->getMsgConn()->SetBroadcastTarget(true);
434 				Fwd.AddClient(pClient->getID());
435 			}
436 	// broadcast
437 	bool fSuccess = pIO->Broadcast(rPkt);
438 	// unlock
439 	pIO->EndBroadcast();
440 	// clients: send forward request to host
441 	if (!fHost)
442 	{
443 		Fwd.SetData(rPkt);
444 		fSuccess &= SendMsgToHost(MkC4NetIOPacket(PID_FwdReq, Fwd));
445 	}
446 	return fSuccess;
447 }
448 
SendMsgToHost(C4NetIOPacket rPkt)449 bool C4Network2ClientList::SendMsgToHost(C4NetIOPacket rPkt)
450 {
451 	// find host
452 	C4Network2Client *pHost = GetHost();
453 	if (!pHost) return false;
454 	// send message
455 	if (!pHost->getMsgConn()) return false;
456 	return pHost->SendMsg(rPkt);
457 }
458 
SendMsgToClient(int32_t iClient,C4NetIOPacket && rPkt)459 bool C4Network2ClientList::SendMsgToClient(int32_t iClient, C4NetIOPacket &&rPkt)
460 {
461 	// find client
462 	C4Network2Client *pClient = GetClientByID(iClient);
463 	if (!pClient) return false;
464 	// connected? send directly
465 	if (pClient->isConnected())
466 		return pClient->SendMsg(rPkt);
467 	// forward
468 	C4PacketFwd Fwd; Fwd.SetListType(false);
469 	Fwd.AddClient(iClient);
470 	Fwd.SetData(rPkt);
471 	return SendMsgToHost(MkC4NetIOPacket(PID_FwdReq, Fwd));
472 }
473 
HandlePacket(char cStatus,const C4PacketBase * pBasePkt,C4Network2IOConnection * pConn)474 void C4Network2ClientList::HandlePacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn)
475 {
476 	// find associated client
477 	C4Network2Client *pClient = GetClient(pConn);
478 	if (!pClient) return;
479 
480 #define GETPKT(type, name) \
481     assert(pBasePkt); const type &name = \
482      static_cast<const type &>(*pBasePkt);
483 
484 	switch (cStatus)
485 	{
486 
487 	case PID_Addr: // address propagation
488 	{
489 		GETPKT(C4PacketAddr, rPkt)
490 		// find client
491 		pClient = GetClientByID(rPkt.getClientID());
492 		if (pClient)
493 		{
494 			C4Network2Address addr = rPkt.getAddr();
495 			// IP zero? Set to IP from where the packet came
496 			if (addr.isIPNull())
497 			{
498 				addr.SetIP(pConn->getPeerAddr());
499 			}
500 			// add (no announce)
501 			if (pClient->AddAddr(addr, true))
502 				// new address? Try to connect
503 				pClient->DoConnectAttempt(pIO);
504 		}
505 	}
506 	break;
507 
508 	}
509 
510 #undef GETPKT
511 }
512 
SendAddresses(C4Network2IOConnection * pConn)513 void C4Network2ClientList::SendAddresses(C4Network2IOConnection *pConn)
514 {
515 	// send all client addresses known
516 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
517 		pClient->SendAddresses(pConn);
518 }
519 
DoConnectAttempts()520 void C4Network2ClientList::DoConnectAttempts()
521 {
522 	// check interval
523 	time_t t; time(&t);
524 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
525 		if (!pClient->isLocal() && !pClient->isRemoved() && pClient->getNextConnAttempt() && pClient->getNextConnAttempt() <= t)
526 			// attempt connect
527 			pClient->DoConnectAttempt(pIO);
528 }
529 
ResetReady()530 void C4Network2ClientList::ResetReady()
531 {
532 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
533 		if (pClient->isWaitedFor())
534 			pClient->SetStatus(NCS_NotReady);
535 }
536 
AllClientsReady() const537 bool C4Network2ClientList::AllClientsReady() const
538 {
539 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
540 		if (!pClient->isLocal() && pClient->isWaitedFor() && !pClient->isReady())
541 			return false;
542 	return true;
543 }
544 
UpdateClientActivity()545 void C4Network2ClientList::UpdateClientActivity()
546 {
547 	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
548 		if (pClient->isActivated())
549 			if (::Players.GetAtClient(pClient->getID()))
550 				pClient->SetLastActivity(Game.FrameCounter);
551 }
552 
553 // *** C4PacketAddr
554 
CompileFunc(StdCompiler * pComp)555 void C4PacketAddr::CompileFunc(StdCompiler *pComp)
556 {
557 	pComp->Value(mkNamingAdapt(mkIntPackAdapt(iClientID), "ClientID", C4ClientIDUnknown));
558 	pComp->Value(mkNamingAdapt(addr, "Addr"));
559 }
560 
561