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 "editor/C4Console.h"
20 #include "gui/C4GameLobby.h" // fullscreen network lobby
21 #include "network/C4Network2.h"
23 #include "player/C4PlayerList.h"
24 
25 // *** C4Network2Client
26 
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 
39 {
40  ClearGraphs();
41  if (pMsgConn) { pMsgConn->Close(); pMsgConn->DelRef(); } pMsgConn = nullptr;
42  if (pDataConn) { pDataConn->Close(); pDataConn->DelRef(); } pDataConn = nullptr;
44 }
45 
47 {
48  return pMsgConn == pConn || pDataConn == pConn;
49 }
50 
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 
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 
76 {
77  if (pConn == pMsgConn)
78  { pMsgConn->DelRef(); pMsgConn = nullptr; }
79  if (pConn == pDataConn)
80  { pDataConn->DelRef(); pDataConn = nullptr; }
83 }
84 
85 
86 void C4Network2Client::CloseConns(const char *szMsg)
87 {
88  C4PacketConnRe Pkt(false, false, szMsg);
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 
104 {
105  return getMsgConn() && getMsgConn()->Send(rPkt);
106 }
107 
109 {
110  return getDataConn() && getDataConn()->Send(rPkt);
111 }
112 
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 
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 
165 {
166  iAddrCnt = 0;
167 }
168 
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)
182  return false;
183  // done
184  return true;
185 }
186 
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 
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);
219  if (pConn)
220  pConn->Send(Pkt);
221  else
223  }
224 
225 }
226 
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
237  pstatPing->SetColorDw(dwClientClr);
238  pstatPing->SetTitle(getName());
239  // register into stat module
240  if (Game.pNetworkStatistics) Game.pNetworkStatistics->statPings.AddGraph(pstatPing);
241 }
242 
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 
257  : pIO(pIO), pFirst(nullptr), pLocal(nullptr)
258 {
259 
260 }
261 
263 {
264  Clear();
265 }
266 
268 {
269  for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
270  if (pClient->getID() == iID)
271  return pClient;
272  return nullptr;
273 }
274 
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 
287 {
288  for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
289  if (SEqual(pClient->getName(), szName))
290  return pClient;
291  return nullptr;
292 }
293 
295 {
296  for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
297  if (pClient->hasConn(pConn))
298  return pClient;
299  return nullptr;
300 }
301 
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 
311 {
312  unsigned int ret(0);
313  for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext) ret++;
314  return ret;
315 }
316 
318 {
320 }
321 
323 {
324  return pClient ? pClient->pNext : pFirst;
325 }
326 
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 
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 
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 
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  {
398  }
399  pLocal = nullptr;
400 }
401 
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 
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 
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 
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);
472 }
473 
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 
514 {
515  // send all client addresses known
516  for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
517  pClient->SendAddresses(pConn);
518 }
519 
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 
531 {
532  for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
533  if (pClient->isWaitedFor())
534  pClient->SetStatus(NCS_NotReady);
535 }
536 
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 
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 
556 {
558  pComp->Value(mkNamingAdapt(addr, "Addr"));
559 }
560 
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)
void CompileFunc(StdCompiler *pComp) override
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:364
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
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:92
int32_t getID() const
Definition: C4Client.h:105
C4Network2IOProtocol getProtocol() const
Definition: C4Network2IO.h:263
int32_t FrameCounter
Definition: C4Game.h:128
void ClearNetwork()
Definition: C4Client.cpp:262
class C4TableGraph * pstatPing
int GetScopeId() const
Definition: C4NetIO.cpp:296
bool LogSilentF(const char *strMessage,...)
Definition: C4Log.cpp:260
void AddClient(int32_t iClient)
Definition: C4Packet2.cpp:459
static std::vector< HostAddress > GetLocalAddresses()
Definition: C4NetIO.cpp:626
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:526
C4PlayerList Players
void SetListType(bool fnNegativeList)
Definition: C4Packet2.cpp:454
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:289
C4Network2IOConnection * pDataConn
const int32_t C4NetClientConnectAttempts
void Value(const T &rStruct)
Definition: StdCompiler.h:161
#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:759
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:449
bool BroadcastMsgToConnClients(const C4NetIOPacket &rPkt)
C4Network2IOConnection * pMsgConn
std::unique_ptr< C4Network2Stats > pNetworkStatistics
Definition: C4Game.h:95
uint32_t DWORD
C4Network2Client * GetHost()
void InitNetwork(class C4Network2ClientList *pNetClients)
Definition: C4Client.cpp:251
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)