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