OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4NetIO.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) 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 #include "C4Include.h"
17 #include "network/C4NetIO.h"
18 
19 #include "config/C4Constants.h"
20 #include "lib/C4Random.h"
21 
22 #include <sys/stat.h>
23 
24 // platform specifics
25 #ifdef _WIN32
26 
27 #include <process.h>
28 #include <share.h>
29 #include <winsock2.h>
30 #include <iphlpapi.h>
31 
32 typedef int socklen_t;
33 int pipe(int *phandles) { return _pipe(phandles, 10, O_BINARY); }
34 
35 #else
36 
37 #include <sys/ioctl.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42 #include <ifaddrs.h>
43 #include <net/if.h>
44 
45 #define ioctlsocket ioctl
46 #define closesocket close
47 #define SOCKET_ERROR (-1)
48 
49 #endif
50 
51 #ifdef _MSC_VER
52 #pragma warning (disable : 4355)
53 #endif
54 
55 // These are named differently on mac.
56 #if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP)
57 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
58 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
59 #endif
60 
61 #ifdef __linux__
62 #include <linux/in6.h>
63 #include <linux/if_addr.h>
64 
65 // Linux definitions needed for parsing /proc/if_inet6
66 #define IPV6_ADDR_LOOPBACK 0x0010U
67 #define IPV6_ADDR_LINKLOCAL 0x0020U
68 #define IPV6_ADDR_SITELOCAL 0x0040U
69 #endif
70 
71 // constants definition
72 const int C4NetIO::TO_INF = -1;
73 
74 // simulate packet loss (loss probability in percent)
75 // #define C4NETIO_SIMULATE_PACKETLOSS 10
76 
77 // *** helpers
78 
79 #ifdef HAVE_WINSOCK
80 
81 const char *GetSocketErrorMsg(int iError)
82 {
83  switch (iError)
84  {
85  case WSAEACCES: return "Permission denied.";
86  case WSAEADDRINUSE: return "Address already in use.";
87  case WSAEADDRNOTAVAIL: return "Cannot assign requested address.";
88  case WSAEAFNOSUPPORT: return "Address family not supported by protocol family.";
89  case WSAEALREADY: return "Operation already in progress.";
90  case WSAECONNABORTED: return "Software caused connection abort.";
91  case WSAECONNREFUSED: return "Connection refused.";
92  case WSAECONNRESET: return "Connection reset by peer.";
93  case WSAEDESTADDRREQ: return "Destination address required.";
94  case WSAEFAULT: return "Bad address.";
95  case WSAEHOSTDOWN: return "Host is down.";
96  case WSAEHOSTUNREACH: return "No route to host.";
97  case WSAEINPROGRESS: return "Operation now in progress.";
98  case WSAEINTR: return "Interrupted function call.";
99  case WSAEINVAL: return "Invalid argument.";
100  case WSAEISCONN: return "Socket is already connected.";
101  case WSAEMFILE: return "Too many open files.";
102  case WSAEMSGSIZE: return "Message too long.";
103  case WSAENETDOWN: return "Network is down.";
104  case WSAENETRESET: return "Network dropped connection on reset.";
105  case WSAENETUNREACH: return "Network is unreachable.";
106  case WSAENOBUFS: return "No buffer space available.";
107  case WSAENOPROTOOPT: return "Bad protocol option.";
108  case WSAENOTCONN: return "Socket is not connected.";
109  case WSAENOTSOCK: return "Socket operation on non-socket.";
110  case WSAEOPNOTSUPP: return "Operation not supported.";
111  case WSAEPFNOSUPPORT: return "Protocol family not supported.";
112  case WSAEPROCLIM: return "Too many processes.";
113  case WSAEPROTONOSUPPORT: return "Protocol not supported.";
114  case WSAEPROTOTYPE: return "Protocol wrong type for socket.";
115  case WSAESHUTDOWN: return "Cannot send after socket shutdown.";
116  case WSAESOCKTNOSUPPORT: return "Socket type not supported.";
117  case WSAETIMEDOUT: return "Connection timed out.";
118  case WSATYPE_NOT_FOUND: return "Class type not found.";
119  case WSAEWOULDBLOCK: return "Resource temporarily unavailable.";
120  case WSAHOST_NOT_FOUND: return "Host not found.";
121  case WSA_INVALID_HANDLE: return "Specified event object handle is invalid.";
122  case WSA_INVALID_PARAMETER: return "One or more parameters are invalid.";
123  case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state.";
124  case WSA_IO_PENDING: return "Overlapped operations will complete later.";
125  case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available.";
126  case WSANOTINITIALISED: return "Successful WSAStartup not yet performed.";
127  case WSANO_DATA: return "Valid name, no data record of requested type.";
128  case WSANO_RECOVERY: return "This is a non-recoverable error.";
129  case WSASYSCALLFAILURE: return "System call failure.";
130  case WSASYSNOTREADY: return "Network subsystem is unavailable.";
131  case WSATRY_AGAIN: return "Non-authoritative host not found.";
132  case WSAVERNOTSUPPORTED: return "WINSOCK.DLL version out of range.";
133  case WSAEDISCON: return "Graceful shutdown in progress.";
134  case WSA_OPERATION_ABORTED: return "Overlapped operation aborted.";
135  case 0: return "no error";
136  default: return "Stupid Error.";
137  }
138 }
139 const char *GetSocketErrorMsg()
140 {
141  return GetSocketErrorMsg(WSAGetLastError());
142 }
143 bool HaveSocketError()
144 {
145  return !! WSAGetLastError();
146 }
147 bool HaveWouldBlockError()
148 {
149  return WSAGetLastError() == WSAEWOULDBLOCK;
150 }
151 bool HaveConnResetError()
152 {
153  return WSAGetLastError() == WSAECONNRESET;
154 }
155 void ResetSocketError()
156 {
157  WSASetLastError(0);
158 }
159 
160 static int iWSockUseCounter = 0;
161 
162 bool AcquireWinSock()
163 {
164  if (!iWSockUseCounter)
165  {
166  // initialize winsock
167  WSADATA data;
168  int res = WSAStartup(WINSOCK_VERSION, &data);
169  // success? count
170  if (!res)
171  iWSockUseCounter++;
172  // return result
173  return !res;
174  }
175  // winsock already initialized
176  iWSockUseCounter++;
177  return true;
178 }
179 
180 void ReleaseWinSock()
181 {
182  iWSockUseCounter--;
183  // last use?
184  if (!iWSockUseCounter)
185  WSACleanup();
186 }
187 
188 #else
189 
190 const char *GetSocketErrorMsg(int iError)
191 {
192  return strerror(iError);
193 }
194 const char *GetSocketErrorMsg()
195 {
196  return GetSocketErrorMsg(errno);
197 }
198 
200 {
201  return !! errno;
202 }
204 {
205  return errno == EINPROGRESS || errno == EWOULDBLOCK;
206 }
208 {
209  return errno == ECONNRESET;
210 }
212 {
213  errno = 0;
214 }
215 
216 #endif // HAVE_WINSOCK
217 
218 // *** C4NetIO::HostAddress
220 {
221  v6.sin6_family = AF_INET6;
222  v6.sin6_flowinfo = 0;
223  v6.sin6_scope_id = 0;
224  memset(&v6.sin6_addr, 0, sizeof(v6.sin6_addr));
225 }
226 
227 // *** C4NetIO::EndpointAddress
230 
232 {
234  SetPort(IPPORT_NONE);
235 }
236 
238 {
239  SetHost(&other.gen);
240 }
241 
243 {
244  if (gen.sa_family == AF_INET6)
245  return IN6_IS_ADDR_MULTICAST(&v6.sin6_addr) != 0;
246  if (gen.sa_family == AF_INET)
247  return (ntohl(v4.sin_addr.s_addr) >> 24) == 239;
248  return false;
249 }
250 
252 {
253  if (gen.sa_family == AF_INET6)
254  return IN6_IS_ADDR_LOOPBACK(&v6.sin6_addr) != 0;
255  if (gen.sa_family == AF_INET)
256  return (ntohl(v4.sin_addr.s_addr) >> 24) == 127;
257  return false;
258 }
259 
261 {
262  if (gen.sa_family == AF_INET6)
263  return IN6_IS_ADDR_LINKLOCAL(&v6.sin6_addr) != 0;
264  // We don't really care about local 169.256.0.0/16 addresses here as users will either have a
265  // router doing DHCP (which will prevent usage of these addresses) or have a network that
266  // doesn't care about IP and IPv6 link-local addresses will work.
267  return false;
268 }
269 
271 {
272  // IPv6 unique local address
273  if (gen.sa_family == AF_INET6)
274  return (v6.sin6_addr.s6_addr[0] & 0xfe) == 0xfc;
275  if (gen.sa_family == AF_INET)
276  {
277  uint32_t addr = ntohl(v4.sin_addr.s_addr);
278  uint32_t s = (addr >> 16) & 0xff;
279  switch (addr >> 24)
280  {
281  case 10: return true;
282  case 172: return s >= 16 && s <= 31;
283  case 192: return s == 168;
284  }
285  }
286  return false;
287 }
288 
290 {
291  if (gen.sa_family != AF_INET6) return;
292  if (IN6_IS_ADDR_LINKLOCAL(&v6.sin6_addr) != 0)
293  v6.sin6_scope_id = scopeId;
294 }
295 
297 {
298  if (gen.sa_family == AF_INET6)
299  return v6.sin6_scope_id;
300  return 0;
301 }
302 
304 {
305  static const uint8_t v6_mapped_v4_prefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
306 
307  HostAddress nrv(*this);
308  switch (gen.sa_family)
309  {
310  case AF_INET6:
311  // That was easy
312  break;
313  case AF_INET:
314  memmove(((char*)&nrv.v6.sin6_addr) + sizeof(v6_mapped_v4_prefix), &v4.sin_addr, sizeof(v4.sin_addr));
315  nrv.v6.sin6_family = AF_INET6;
316  memcpy(&nrv.v6.sin6_addr, v6_mapped_v4_prefix, sizeof(v6_mapped_v4_prefix));
317  nrv.v6.sin6_flowinfo = 0;
318  nrv.v6.sin6_scope_id = 0;
319  break;
320  default: assert(!"Shouldn't reach this"); break;
321  }
322  return nrv;
323 }
324 
326 {
327  HostAddress nrv(*this);
328  if (gen.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&v6.sin6_addr))
329  {
330  nrv.v4.sin_family = AF_INET;
331  memcpy((char*) &nrv.v4.sin_addr, (char*) &v6.sin6_addr.s6_addr[12], sizeof(v4.sin_addr));
332  }
333  return nrv;
334 }
335 
337 {
338  return EndpointAddress(HostAddress::AsIPv6(), GetPort());
339 }
340 
342 {
343  return EndpointAddress(HostAddress::AsIPv4(), GetPort());
344 }
345 
346 void C4NetIO::HostAddress::SetHost(const sockaddr *addr)
347 {
348  // Copy all but port number
349  if (addr->sa_family == AF_INET6)
350  {
351  v6.sin6_family = ((const sockaddr_in6*)addr)->sin6_family;
352  v6.sin6_flowinfo = ((const sockaddr_in6*)addr)->sin6_flowinfo;
353  memcpy(&v6.sin6_addr, &((const sockaddr_in6*)addr)->sin6_addr, sizeof(v6.sin6_addr));
354  v6.sin6_scope_id = ((const sockaddr_in6*)addr)->sin6_scope_id;
355  }
356  else if (addr->sa_family == AF_INET)
357  {
358  v4.sin_family = ((const sockaddr_in*)addr)->sin_family;
359  v4.sin_addr.s_addr = ((const sockaddr_in*)addr)->sin_addr.s_addr;
360  memset(&v4.sin_zero, 0, sizeof(v4.sin_zero));
361  }
362 }
363 
364 void C4NetIO::EndpointAddress::SetAddress(const sockaddr *addr)
365 {
366  switch (addr->sa_family)
367  {
368  case AF_INET: memcpy(&v4, addr, sizeof(v4)); break;
369  case AF_INET6: memcpy(&v6, addr, sizeof(v6)); break;
370  default:
371  assert(!"Unexpected address family");
372  memcpy(&gen, addr, sizeof(gen)); break;
373  }
374 }
375 
377 {
378  switch (addr)
379  {
380  case Any:
381  v6.sin6_family = AF_INET6;
382  memset(&v6.sin6_addr, 0, sizeof(v6.sin6_addr));
383  v6.sin6_flowinfo = 0;
384  v6.sin6_scope_id = 0;
385  break;
386  case AnyIPv4:
387  v4.sin_family = AF_INET;
388  v4.sin_addr.s_addr = 0;
389  memset(&v4.sin_zero, 0, sizeof(v4.sin_zero));
390  break;
391  case Loopback:
392  v6.sin6_family = AF_INET6;
393  memset(&v6.sin6_addr, 0, sizeof(v6.sin6_addr)); v6.sin6_addr.s6_addr[15] = 1;
394  v6.sin6_flowinfo = 0;
395  v6.sin6_scope_id = 0;
396  break;
397  }
398 }
399 
400 void C4NetIO::HostAddress::SetHost(uint32_t v4addr)
401 {
402  v4.sin_family = AF_INET;
403  v4.sin_addr.s_addr = v4addr;
404  memset(&v4.sin_zero, 0, sizeof(v4.sin_zero));
405 }
406 
408 {
409  addrinfo hints = addrinfo();
410  hints.ai_family = family;
411  addrinfo *addresses = nullptr;
412  if (getaddrinfo(addr.getData(), nullptr, &hints, &addresses) != 0)
413  // GAI failed
414  return;
415  SetHost(addresses->ai_addr);
416  freeaddrinfo(addresses);
417 }
418 
420 {
421  Clear();
422 
423  if (addr.isNull()) return;
424 
425  const char *begin = addr.getData();
426  const char *end = begin + addr.getLength();
427 
428  const char *ab = begin;
429  const char *ae = end;
430 
431  const char *pb = end;
432  const char *pe = end;
433 
434  bool isIPv6 = false;
435 
436  // If addr begins with [, it's an IPv6 address
437  if (ab[0] == '[')
438  {
439  ++ab; // skip bracket
440  const char *cbracket = std::find(ab, ae, ']');
441  if (cbracket == ae)
442  // No closing bracket found: invalid
443  return;
444  ae = cbracket++;
445  if (cbracket != end && cbracket[0] == ':')
446  {
447  // port number given
448  pb = ++cbracket;
449  if (pb == end)
450  // Trailing colon: invalid
451  return;
452  }
453  isIPv6 = true;
454  }
455  // If there's more than 1 colon in the address, it's IPv6
456  else if (std::count(ab, ae, ':') > 1)
457  {
458  isIPv6 = true;
459  }
460  // It's probably not IPv6, but look for a port specification
461  else
462  {
463  const char *colon = std::find(ab, ae, ':');
464  if (colon != ae)
465  {
466  ae = colon;
467  pb = colon + 1;
468  if (pb == end)
469  // Trailing colon: invalid
470  return;
471  }
472  }
473 
474  addrinfo hints = addrinfo();
475  hints.ai_family = family;
476  //hints.ai_flags = AI_NUMERICHOST;
477  addrinfo *addresses = nullptr;
478  if (getaddrinfo(std::string(ab, ae).c_str(), pb != end ? std::string(pb, pe).c_str() : nullptr, &hints, &addresses) != 0)
479  // GAI failed
480  return;
481  SetAddress(addresses->ai_addr);
482  freeaddrinfo(addresses);
483 }
484 
486 {
487  SetHost(addr);
488  SetPort(addr.GetPort());
489 }
490 
492 {
493  SetHost(host);
494  SetPort(port);
495 }
496 
497 void C4NetIO::EndpointAddress::SetAddress(const HostAddress &host, uint16_t port)
498 {
499  SetHost(host);
500  SetPort(port);
501 }
502 
504 {
505  return IsNullHost() && GetPort() == IPPORT_NONE;
506 }
507 
509 {
510  switch (gen.sa_family)
511  {
512  case AF_INET: return v4.sin_addr.s_addr == 0;
513  case AF_INET6:
514  return !!IN6_IS_ADDR_UNSPECIFIED(&v6.sin6_addr);
515  }
516  assert(!"Shouldn't reach this");
517  return false;
518 }
519 
521 {
522  return gen.sa_family == AF_INET ? IPv4 :
523  gen.sa_family == AF_INET6 ? IPv6 : UnknownFamily;
524 }
525 
527 {
528  return GetFamily() == IPv4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
529 }
530 
532 {
533  switch (gen.sa_family)
534  {
535  case AF_INET: v4.sin_port = htons(port); break;
536  case AF_INET6: v6.sin6_port = htons(port); break;
537  default: assert(!"Shouldn't reach this"); break;
538  }
539 }
540 
542 {
543  if (GetPort() == IPPORT_NONE)
544  SetPort(port);
545 }
546 
548 {
549  switch (gen.sa_family)
550  {
551  case AF_INET: return ntohs(v4.sin_port);
552  case AF_INET6: return ntohs(v6.sin6_port);
553  }
554  assert(!"Shouldn't reach this");
555  return IPPORT_NONE;
556 }
557 
559 {
560  // Check for IPv4-mapped IPv6 addresses.
561  if (gen.sa_family != rhs.gen.sa_family)
562  return AsIPv6() == rhs.AsIPv6();
563  if (gen.sa_family == AF_INET)
564  return v4.sin_addr.s_addr == rhs.v4.sin_addr.s_addr;
565  if (gen.sa_family == AF_INET6)
566  return memcmp(&v6.sin6_addr, &rhs.v6.sin6_addr, sizeof(v6.sin6_addr)) == 0 &&
567  v6.sin6_scope_id == rhs.v6.sin6_scope_id;
568  assert(!"Shouldn't reach this");
569  return false;
570 }
571 
573 {
574  if (!HostAddress::operator==(rhs)) return false;
575  if (gen.sa_family == AF_INET)
576  {
577  return v4.sin_port == rhs.v4.sin_port;
578  }
579  else if (gen.sa_family == AF_INET6)
580  {
581  return v6.sin6_port == rhs.v6.sin6_port &&
582  v6.sin6_scope_id == rhs.v6.sin6_scope_id;
583  }
584  assert(!"Shouldn't reach this");
585  return false;
586 }
587 
589 {
590  if (gen.sa_family == AF_INET6 && v6.sin6_scope_id != 0 && (flags & TSF_SkipZoneId))
591  {
592  HostAddress addr = *this;
593  addr.v6.sin6_scope_id = 0;
594  return addr.ToString(flags);
595  }
596 
597  char buf[INET6_ADDRSTRLEN];
598  if (getnameinfo(&gen, GetAddrLen(), buf, sizeof(buf), nullptr, 0, NI_NUMERICHOST) != 0)
599  return StdStrBuf();
600 
601  return StdStrBuf(buf, true);
602 }
603 
605 {
606  if (flags & TSF_SkipPort)
607  return HostAddress::ToString(flags);
608 
609  switch (GetFamily())
610  {
611  case IPv4: return FormatString("%s:%d", HostAddress::ToString(flags).getData(), GetPort());
612  case IPv6: return FormatString("[%s]:%d", HostAddress::ToString(flags).getData(), GetPort());
613  default: assert(!"Shouldn't reach this");
614  }
615  return StdStrBuf();
616 }
617 
619 {
620  if (!comp->isDeserializer())
621  {
622  StdStrBuf val(ToString(TSF_SkipZoneId));
623  comp->Value(val);
624  } else {
625  StdStrBuf val;
626  comp->Value(val);
627  SetAddress(val);
628  }
629 }
630 
631 std::vector<C4NetIO::HostAddress> C4NetIO::GetLocalAddresses()
632 {
633  std::vector<HostAddress> result;
634 
635 #ifdef HAVE_WINSOCK
636  HostAddress addr;
637  const size_t BUFFER_SIZE = 16000;
638  PIP_ADAPTER_ADDRESSES addresses = nullptr;
639  for (int i = 0; i < 3; ++i)
640  {
641  addresses = (PIP_ADAPTER_ADDRESSES) realloc(addresses, BUFFER_SIZE * (i+1));
642  if (!addresses)
643  // allocation failed
644  return result;
645  ULONG bufsz = BUFFER_SIZE * (i+1);
646  DWORD rv = GetAdaptersAddresses(AF_UNSPEC,
647  GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_FRIENDLY_NAME,
648  nullptr, addresses, &bufsz);
649  if (rv == ERROR_BUFFER_OVERFLOW)
650  // too little space, try again
651  continue;
652  if (rv != NO_ERROR)
653  {
654  // Something else happened
655  free(addresses);
656  return result;
657  }
658  // All okay, add addresses
659  for (PIP_ADAPTER_ADDRESSES address = addresses; address; address = address->Next)
660  {
661  for (PIP_ADAPTER_UNICAST_ADDRESS unicast = address->FirstUnicastAddress; unicast; unicast = unicast->Next)
662  {
663  addr.SetHost(unicast->Address.lpSockaddr);
664  if (addr.IsLoopback())
665  continue;
666  result.push_back(addr);
667  }
668  }
669  }
670  free(addresses);
671 #else
672  bool have_ipv6 = false;
673 
674 #ifdef __linux__
675  // Get IPv6 addresses on Linux from procfs which allows filtering deprecated privacy addresses.
676  FILE *f = fopen("/proc/net/if_inet6", "r");
677  if (f)
678  {
679  sockaddr_in6 sa6 = sockaddr_in6();
680  sa6.sin6_family = AF_INET6;
681  auto a6 = sa6.sin6_addr.s6_addr;
682  uint8_t if_idx, plen, scope, flags;
683  char devname[20];
684  while (fscanf(f, "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx %02hhx %02hhx %02hhx %02hhx %20s\n",
685  &a6[0], &a6[1], &a6[2], &a6[3], &a6[4], &a6[5], &a6[6], &a6[7],
686  &a6[8], &a6[9], &a6[10], &a6[11], &a6[12], &a6[13], &a6[14], &a6[15],
687  &if_idx, &plen, &scope, &flags, devname) != EOF)
688  {
689  // Skip loopback and deprecated addresses.
690  if (scope == IPV6_ADDR_LOOPBACK || flags & IFA_F_DEPRECATED)
691  continue;
692  sa6.sin6_scope_id = scope == IPV6_ADDR_LINKLOCAL ? if_idx : 0;
693  result.emplace_back((sockaddr*) &sa6);
694  }
695  have_ipv6 = result.size() > 0;
696  fclose(f);
697  }
698 #endif
699 
700  struct ifaddrs* addrs;
701  if (getifaddrs(&addrs) < 0)
702  return result;
703  for (struct ifaddrs* ifaddr = addrs; ifaddr != nullptr; ifaddr = ifaddr->ifa_next)
704  {
705  struct sockaddr* ad = ifaddr->ifa_addr;
706  if (ad == nullptr) continue;
707 
708  if ((ad->sa_family == AF_INET || (!have_ipv6 && ad->sa_family == AF_INET6)) && (~ifaddr->ifa_flags & IFF_LOOPBACK)) // Choose only non-loopback IPv4/6 devices
709  {
710  result.emplace_back(ad);
711  }
712  }
713  freeifaddrs(addrs);
714 #endif
715 
716  return result;
717 }
718 
719 // *** C4NetIO
720 
721 // construction / destruction
722 
724 {
725  ResetError();
726 }
727 
728 C4NetIO::~C4NetIO() = default;
729 
731 {
732  int opt = 0;
733  if (setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&opt), sizeof(opt)) == SOCKET_ERROR)
734  {
735  SetError("could not enable dual-stack socket", true);
736  return false;
737  }
738 
739 #ifdef IPV6_ADDR_PREFERENCES
740  // Prefer stable addresses. This should prevent issues with address
741  // deprecation while a match is running. No error handling - if the call
742  // fails, we just take any address.
743  opt = IPV6_PREFER_SRC_PUBLIC;
744  setsockopt(socket, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, reinterpret_cast<char*>(&opt), sizeof(opt));
745 #endif
746 
747  return true;
748 }
749 
750 void C4NetIO::SetError(const char *strnError, bool fSockErr)
751 {
752  fSockErr &= HaveSocketError();
753  if (fSockErr)
754  Error.Format("%s (%s)", strnError, GetSocketErrorMsg());
755  else
756  Error.Copy(strnError);
757 }
758 
759 // *** C4NetIOPacket
760 
761 // construction / destruction
762 
763 C4NetIOPacket::C4NetIOPacket() = default;
764 
765 C4NetIOPacket::C4NetIOPacket(const void *pnData, size_t inSize, bool fCopy, const C4NetIO::addr_t &naddr)
766  : StdCopyBuf(pnData, inSize, fCopy), addr(naddr)
767 {
768 }
769 
771  : StdCopyBuf(Buf), addr(naddr)
772 {
773 }
774 
775 C4NetIOPacket::C4NetIOPacket(uint8_t cStatusByte, const char *pnData, size_t inSize, const C4NetIO::addr_t &naddr)
776 {
777  // Create buffer
778  New(sizeof(cStatusByte) + inSize);
779  // Write data
780  *getMBufPtr<uint8_t>(*this) = cStatusByte;
781  Write(pnData, inSize, sizeof(cStatusByte));
782 }
783 
785 {
786  Clear();
787 }
788 
790 {
791  addr = C4NetIO::addr_t();
792  StdBuf::Clear();
793 }
794 
795 // *** C4NetIOTCP
796 
797 // construction / destruction
798 
800  PeerListCSec(this),
801  iListenPort(~0), lsock(INVALID_SOCKET)
802 {
803 
804 }
805 
807 {
808  Close();
809 }
810 
811 bool C4NetIOTCP::Init(uint16_t iPort)
812 {
813  // already init? close first
814  if (fInit) Close();
815 
816 #ifdef HAVE_WINSOCK
817  // init winsock
818  if (!AcquireWinSock())
819  {
820  SetError("could not start winsock");
821  return false;
822  }
823 #endif
824 
825 #ifdef STDSCHEDULER_USE_EVENTS
826  // create event
827  if ((Event = WSACreateEvent()) == WSA_INVALID_EVENT)
828  {
829  SetError("could not create socket event", true); // to do: more error information
830  return false;
831  }
832 #else
833  // create pipe
834  if (pipe(Pipe) != 0)
835  {
836  SetError("could not create pipe", true);
837  return false;
838  }
839 #endif
840 
841  // create listen socket (if necessary)
842  if (iPort != addr_t::IPPORT_NONE)
843  if (!Listen(iPort))
844  return false;
845 
846  // ok
847  fInit = true;
848  return true;
849 }
850 
851 bool C4NetIOTCP::InitBroadcast(addr_t *pBroadcastAddr)
852 {
853  // ignore
854  return true;
855 }
856 
858 {
859  ResetError();
860 
861  // not init?
862  if (!fInit) return false;
863 
864  // terminate connections
865  CStdShareLock PeerListLock(&PeerListCSec);
866  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
867  if (pPeer->Open())
868  {
869  pPeer->Close();
870  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, "owner class closed");
871  }
872 
874 
875  // close listen socket
876  if (lsock != INVALID_SOCKET)
877  {
880  }
881 
882 #ifdef STDSCHEDULER_USE_EVENTS
883  // close event
884  if (Event != nullptr)
885  {
886  WSACloseEvent(Event);
887  Event = nullptr;
888  }
889 #else
890  // close pipe
891  close(Pipe[0]);
892  close(Pipe[1]);
893 #endif
894 
895 #ifdef HAVE_WINSOCK
896  // release winsock
897  ReleaseWinSock();
898 #endif
899 
900  // ok
901  fInit = false;
902  return true;
903 }
904 
906 {
907  return true;
908 }
909 
910 #ifdef __APPLE__
911 static int fix_poll_timeout(int timeout) {
912  if (timeout < 0 || timeout > 1000)
913  return 1000;
914  else
915  return timeout;
916 }
917 #endif
918 
919 bool C4NetIOTCP::Execute(int iMaxTime, pollfd *fds) // (mt-safe)
920 {
921  // security
922  if (!fInit) return false;
923 
924 #ifdef STDSCHEDULER_USE_EVENTS
925  // wait for something to happen
926  if (WaitForSingleObject(Event, iMaxTime == C4NetIO::TO_INF ? INFINITE : iMaxTime) == WAIT_TIMEOUT)
927  // timeout -> nothing happened
928  return true;
929  WSAResetEvent(Event);
930 
931  WSANETWORKEVENTS wsaEvents;
932 #else
933 
934 #ifdef __APPLE__
935  iMaxTime = fix_poll_timeout(iMaxTime);
936 #endif
937 
938  std::vector<pollfd> fdvec;
939  std::map<SOCKET, const pollfd*> fdmap;
940  if (!fds)
941  {
942  // build socket sets
943  GetFDs(fdvec);
944  fds = &fdvec[0];
945  // wait for something to happen
946  int ret = poll(fds, fdvec.size(), iMaxTime);
947  // error
948  if (ret < 0)
949  {
950  SetError("poll failed");
951  return false;
952  }
953  // nothing happened
954  if (ret == 0)
955  return true;
956  }
957  else
958  {
959  // We need to know the size of fdvec, so construct the vector
960  GetFDs(fdvec);
961  // Now overwrite with the poll result
962  std::copy(fds, fds + fdvec.size(), fdvec.begin());
963  }
964 
965  // flush pipe
966  assert(fdvec[0].fd == Pipe[0]);
967  if (fdvec[0].events & fdvec[0].revents)
968  {
969  char c;
970  if (::read(Pipe[0], &c, 1) == -1)
971  SetError("read failed");
972  }
973 
974  for (std::vector<pollfd>::const_iterator i = fdvec.begin(); i != fdvec.end(); ++i)
975  fdmap[i->fd] = &*i;
976  std::map<SOCKET, const pollfd*>::const_iterator cur_fd;
977 #endif
978 
979  // check sockets for events
980 
981  // first: the listen socket
982  if (lsock != INVALID_SOCKET)
983  {
984 
985 #ifdef STDSCHEDULER_USE_EVENTS
986  // get event list
987  if (::WSAEnumNetworkEvents(lsock, nullptr, &wsaEvents) == SOCKET_ERROR)
988  return false;
989 
990  // a connection waiting for accept?
991  if (wsaEvents.lNetworkEvents & FD_ACCEPT)
992 #else
993  cur_fd = fdmap.find(lsock);
994  // a connection waiting for accept?
995  if (cur_fd != fdmap.end() && (cur_fd->second->events & cur_fd->second->revents))
996 #endif
997  if (!Accept())
998  return false;
999  // (note: what happens if there are more connections waiting?)
1000 
1001 #ifdef STDSCHEDULER_USE_EVENTS
1002  // closed?
1003  if (wsaEvents.lNetworkEvents & FD_CLOSE)
1004  // try to recreate the listen socket
1006 #endif
1007  }
1008 
1009  // second: waited-for connection
1010  CStdShareLock PeerListLock(&PeerListCSec);
1011  for (ConnectWait *pWait = pConnectWaits, *pNext; pWait; pWait = pNext)
1012  {
1013  pNext = pWait->Next;
1014 
1015  // not closed?
1016  if (pWait->sock)
1017  {
1018 #ifdef STDSCHEDULER_USE_EVENTS
1019  // get event list
1020  if (::WSAEnumNetworkEvents(pWait->sock, nullptr, &wsaEvents) == SOCKET_ERROR)
1021  return false;
1022 
1023  if (wsaEvents.lNetworkEvents & FD_CONNECT)
1024 #else
1025  // got connection?
1026  cur_fd = fdmap.find(pWait->sock);
1027  if (cur_fd != fdmap.end() && (cur_fd->second->events & cur_fd->second->revents))
1028 #endif
1029  {
1030  // remove from list
1031  SOCKET sock = pWait->sock; pWait->sock = 0;
1032 
1033 #ifdef STDSCHEDULER_USE_EVENTS
1034  // error?
1035  if (wsaEvents.iErrorCode[FD_CONNECT_BIT])
1036  {
1037  // disconnect-callback
1038  if (pCB) pCB->OnDisconn(pWait->addr, this, GetSocketErrorMsg(wsaEvents.iErrorCode[FD_CONNECT_BIT]));
1039  }
1040  else
1041 #else
1042  // get error code
1043  int iErrCode; socklen_t iErrCodeLen = sizeof(iErrCode);
1044  if (getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&iErrCode), &iErrCodeLen) != 0)
1045  {
1046  close(sock);
1047  if (pCB) pCB->OnDisconn(pWait->addr, this, GetSocketErrorMsg());
1048  }
1049  // error?
1050  else if (iErrCode)
1051  {
1052  close(sock);
1053  if (pCB) pCB->OnDisconn(pWait->addr, this, GetSocketErrorMsg(iErrCode));
1054  }
1055  else
1056 #endif
1057  // accept connection, do callback
1058  if (!Accept(sock, pWait->addr))
1059  return false;
1060  }
1061  }
1062 
1063  }
1064 
1065  // last: all connected sockets
1066  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1067  if (pPeer->Open())
1068  {
1069  SOCKET sock = pPeer->GetSocket();
1070 
1071 #ifdef STDSCHEDULER_USE_EVENTS
1072  // get event list
1073  if (::WSAEnumNetworkEvents(sock, nullptr, &wsaEvents) == SOCKET_ERROR)
1074  return false;
1075 
1076  // something to read from socket?
1077  if (wsaEvents.lNetworkEvents & FD_READ)
1078 #else
1079  // something to read from socket?
1080  cur_fd = fdmap.find(sock);
1081  if (cur_fd != fdmap.end() && (POLLIN & cur_fd->second->revents))
1082 #endif
1083  for (;;)
1084  {
1085  // how much?
1086 #ifdef _WIN32
1087  DWORD iBytesToRead;
1088 #else
1089  int iBytesToRead;
1090 #endif
1091  if (::ioctlsocket(pPeer->GetSocket(), FIONREAD, &iBytesToRead) == SOCKET_ERROR)
1092  {
1093  pPeer->Close();
1094  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, GetSocketErrorMsg());
1095  break;
1096  }
1097  // The following two lines of code will make sure that if the variable
1098  // "iBytesToRead" is zero, it will be increased by one.
1099  // In this case, it will hold the value 1 after the operation.
1100  // Note it doesn't do anything for negative values.
1101  // (This comment has been sponsored by Sven2)
1102  if (!iBytesToRead)
1103  ++iBytesToRead;
1104  // get buffer
1105  void *pBuf = pPeer->GetRecvBuf(iBytesToRead);
1106  // read a buffer full of data from socket
1107  int iBytesRead;
1108  if ((iBytesRead = ::recv(sock, reinterpret_cast<char *>(pBuf), iBytesToRead, 0)) == SOCKET_ERROR)
1109  {
1110  // Would block? Ok, let's try this again later
1111  if (HaveWouldBlockError()) { ResetSocketError(); break; }
1112  // So he's serious after all...
1113  pPeer->Close ();
1114  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, GetSocketErrorMsg());
1115  break;
1116  }
1117  // nothing? this means the conection was closed, if you trust in linux manpages.
1118  if (!iBytesRead)
1119  {
1120  pPeer->Close();
1121  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, "connection closed");
1122  break;
1123  }
1124  // pass to Peer::OnRecv
1125  pPeer->OnRecv(iBytesRead);
1126  }
1127 
1128  // socket has become writeable?
1129 #ifdef STDSCHEDULER_USE_EVENTS
1130  if (wsaEvents.lNetworkEvents & FD_WRITE)
1131 #else
1132  if (cur_fd != fdmap.end() && (POLLOUT & cur_fd->second->revents))
1133 #endif
1134  // send remaining data
1135  pPeer->Send();
1136 
1137 #ifdef STDSCHEDULER_USE_EVENTS
1138  // socket was closed?
1139  if (wsaEvents.lNetworkEvents & FD_CLOSE)
1140  {
1141  const char *szReason = wsaEvents.iErrorCode[FD_CLOSE_BIT] ? GetSocketErrorMsg(wsaEvents.iErrorCode[FD_CLOSE_BIT]) : "closed by peer";
1142  // close socket
1143  pPeer->Close();
1144  // do callback
1145  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, szReason);
1146  }
1147 #endif
1148  }
1149 
1150  // done
1151  return true;
1152 }
1153 
1154 bool C4NetIOTCP::Connect(const C4NetIO::addr_t &addr) // (mt-safe)
1155 {
1156  // create new socket
1157  SOCKET nsock = ::socket(addr.GetFamily() == HostAddress::IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
1158  if (nsock == INVALID_SOCKET)
1159  {
1160  SetError("socket creation failed", true);
1161  return false;
1162  }
1163 
1164  if (addr.GetFamily() == HostAddress::IPv6)
1165  if (!InitIPv6Socket(nsock))
1166  return false;
1167 
1168 #ifdef STDSCHEDULER_USE_EVENTS
1169  // set event
1170  if (::WSAEventSelect(nsock, Event, FD_CONNECT) == SOCKET_ERROR)
1171  {
1172  // set error
1173  SetError("connect failed: could not set event", true);
1174  closesocket(nsock);
1175  return false;
1176  }
1177 
1178  // add to list
1179  AddConnectWait(nsock, addr);
1180 
1181 #elif defined(HAVE_WINSOCK)
1182  // disable blocking
1183  unsigned long iBlock = 1;
1184  if (::ioctlsocket(nsock, FIONBIO, &iBlock) == SOCKET_ERROR)
1185  {
1186  // set error
1187  SetError("connect failed: could not disable blocking", true);
1188  close(nsock);
1189  return false;
1190  }
1191 #else
1192  // disable blocking
1193  if (::fcntl(nsock, F_SETFL, fcntl(nsock, F_GETFL) | O_NONBLOCK) == SOCKET_ERROR)
1194  {
1195  // set error
1196  SetError("connect failed: could not disable blocking", true);
1197  close(nsock);
1198  return false;
1199  }
1200 #endif
1201 
1202  // connect (async)
1203  if (::connect(nsock, &addr, addr.GetAddrLen()) == SOCKET_ERROR)
1204  {
1205  if (!HaveWouldBlockError()) // expected
1206  {
1207  SetError("socket connection failed", true);
1208  closesocket(nsock);
1209  return false;
1210  }
1211  }
1212 
1213 #ifndef STDSCHEDULER_USE_EVENTS
1214  // add to list
1215  AddConnectWait(nsock, addr);
1216 #endif
1217 
1218  // ok
1219  return true;
1220 }
1221 
1222 bool C4NetIOTCP::Close(const addr_t &addr) // (mt-safe)
1223 {
1224  CStdShareLock PeerListLock(&PeerListCSec);
1225  // find connect wait
1226  ConnectWait *pWait = GetConnectWait(addr);
1227  if (pWait)
1228  {
1229  // close socket, do callback
1230  closesocket(pWait->sock); pWait->sock = 0;
1231  if (pCB) pCB->OnDisconn(pWait->addr, this, "closed");
1232  }
1233  else
1234  {
1235  // find peer
1236  Peer *pPeer = GetPeer(addr);
1237  if (pPeer)
1238  {
1239  C4NetIO::addr_t addr = pPeer->GetAddr();
1240  // close peer
1241  pPeer->Close();
1242  // do callback
1243  if (pCB) pCB->OnDisconn(addr, this, "closed");
1244  }
1245  // not found
1246  else
1247  return false;
1248  }
1249  // ok
1250  return true;
1251 }
1252 
1253 bool C4NetIOTCP::Send(const C4NetIOPacket &rPacket) // (mt-safe)
1254 {
1255  CStdShareLock PeerListLock(&PeerListCSec);
1256  // find peer
1257  Peer *pPeer = GetPeer(rPacket.getAddr());
1258  // not found?
1259  if (!pPeer) return false;
1260  // send
1261  return pPeer->Send(rPacket);
1262 }
1263 
1264 bool C4NetIOTCP::SetBroadcast(const addr_t &addr, bool fSet) // (mt-safe)
1265 {
1266  CStdShareLock PeerListLock(&PeerListCSec);
1267  // find peer
1268  Peer *pPeer = GetPeer(addr);
1269  if (!pPeer) return false;
1270  // set flag
1271  pPeer->SetBroadcast(fSet);
1272  return true;
1273 }
1274 
1275 bool C4NetIOTCP::Broadcast(const C4NetIOPacket &rPacket) // (mt-safe)
1276 {
1277  CStdShareLock PeerListLock(&PeerListCSec);
1278  // just send to all clients
1279  bool fSuccess = true;
1280  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1281  if (pPeer->Open() && pPeer->doBroadcast())
1282  fSuccess &= Send(C4NetIOPacket(rPacket.getRef(), pPeer->GetAddr()));
1283  return fSuccess;
1284 }
1285 
1286 void C4NetIOTCP::UnBlock() // (mt-safe)
1287 {
1288 #ifdef STDSCHEDULER_USE_EVENTS
1289  // unblock WaitForSingleObject in C4NetIOTCP::Execute manually
1290  // by setting the Event
1291  WSASetEvent(Event);
1292 #else
1293  // write one character to the pipe, this will unblock everything that
1294  // waits for the FD set returned by GetFDs.
1295  char c = 1;
1296  if (write(Pipe[1], &c, 1) == -1)
1297  SetError("write failed");
1298 #endif
1299 }
1300 
1301 #ifdef STDSCHEDULER_USE_EVENTS
1302 HANDLE C4NetIOTCP::GetEvent() // (mt-safe)
1303 {
1304  return Event;
1305 }
1306 #else
1307 void C4NetIOTCP::GetFDs(std::vector<struct pollfd> & fds)
1308 {
1309  pollfd pfd; pfd.revents = 0;
1310  // add pipe
1311  pfd.fd = Pipe[0]; pfd.events = POLLIN;
1312  fds.push_back(pfd);
1313  // add listener
1314  if (lsock != INVALID_SOCKET)
1315  {
1316  pfd.fd = lsock; pfd.events = POLLIN;
1317  fds.push_back(pfd);
1318  }
1319  // add connect waits (wait for them to become writeable)
1320  CStdShareLock PeerListLock(&PeerListCSec);
1321  for (ConnectWait *pWait = pConnectWaits; pWait; pWait = pWait->Next)
1322  {
1323  pfd.fd = pWait->sock; pfd.events = POLLOUT;
1324  fds.push_back(pfd);
1325  }
1326  // add sockets
1327  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1328  if (pPeer->GetSocket())
1329  {
1330  // Wait for socket to become readable
1331  pfd.fd = pPeer->GetSocket(); pfd.events = POLLIN;
1332  // Wait for socket to become writeable, if there is data waiting
1333  if (pPeer->hasWaitingData())
1334  {
1335  pfd.events |= POLLOUT;
1336  }
1337  fds.push_back(pfd);
1338  }
1339 }
1340 #endif
1341 
1342 bool C4NetIOTCP::GetStatistic(int *pBroadcastRate) // (mt-safe)
1343 {
1344  // no broadcast
1345  if (pBroadcastRate) *pBroadcastRate = 0;
1346  return true;
1347 }
1348 
1349 bool C4NetIOTCP::GetConnStatistic(const addr_t &addr, int *pIRate, int *pORate, int *pLoss) // (mt-safe)
1350 {
1351  CStdShareLock PeerListLock(&PeerListCSec);
1352  // find peer
1353  Peer *pPeer = GetPeer(addr);
1354  if (!pPeer || !pPeer->Open()) return false;
1355  // return statistics
1356  if (pIRate) *pIRate = pPeer->GetIRate();
1357  if (pORate) *pORate = pPeer->GetORate();
1358  if (pLoss) *pLoss = 0;
1359  return true;
1360 }
1361 
1363 {
1364  CStdShareLock PeerListLock(&PeerListCSec);
1365  // clear all peer statistics
1366  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1367  pPeer->ClearStatistics();
1368 }
1369 
1370 C4NetIOTCP::Peer *C4NetIOTCP::Accept(SOCKET nsock, const addr_t &ConnectAddr) // (mt-safe)
1371 {
1372 
1373  addr_t caddr = ConnectAddr;
1374 
1375  // accept incoming connection?
1376  C4NetIO::addr_t addr; socklen_t iAddrSize = addr.GetAddrLen();
1377  if (nsock == INVALID_SOCKET)
1378  {
1379  // accept from listener
1380 #ifdef __linux__
1381  if ((nsock = ::accept4(lsock, &addr, &iAddrSize, SOCK_CLOEXEC)) == INVALID_SOCKET)
1382 #else
1383  if ((nsock = ::accept(lsock, &addr, &iAddrSize)) == INVALID_SOCKET)
1384 #endif
1385  {
1386  // set error
1387  SetError("socket accept failed", true);
1388  return nullptr;
1389  }
1390  // connect address unknown, so zero it
1391  caddr.Clear();
1392  }
1393  else
1394  {
1395  // get peer address
1396  if (::getpeername(nsock, &addr, &iAddrSize) == SOCKET_ERROR)
1397  {
1398 #ifndef HAVE_WINSOCK
1399  // getpeername behaves strangely on exotic platforms. Just ignore it.
1400  if (errno != ENOTCONN)
1401  {
1402 #endif
1403  // set error
1404  SetError("could not get peer address for connected socket", true);
1405  return nullptr;
1406 #ifndef HAVE_WINSOCK
1407  }
1408 #endif
1409  }
1410  }
1411 
1412  // check address
1413  if (addr.GetFamily() == addr_t::UnknownFamily)
1414  {
1415  // set error
1416  SetError("socket accept failed: invalid address returned");
1417  closesocket(nsock);
1418  return nullptr;
1419  }
1420 
1421  // disable nagle (yep, we know what we are doing here - I think)
1422  int iNoDelay = 1;
1423  ::setsockopt(nsock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&iNoDelay), sizeof(iNoDelay));
1424 
1425 #ifdef STDSCHEDULER_USE_EVENTS
1426  // set event
1427  if (::WSAEventSelect(nsock, Event, FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1428  {
1429  // set error
1430  SetError("connection accept failed: could not set event", true);
1431  closesocket(nsock);
1432  return nullptr;
1433  }
1434 #elif defined(HAVE_WINSOCK)
1435  // disable blocking
1436  unsigned long iBlock = 1;
1437  if (::ioctlsocket(nsock, FIONBIO, &iBlock) == SOCKET_ERROR)
1438  {
1439  // set error
1440  SetError("connect failed: could not disable blocking", true);
1441  close(nsock);
1442  return false;
1443  }
1444 #else
1445  // disable blocking
1446  if (::fcntl(nsock, F_SETFL, fcntl(nsock, F_GETFL) | O_NONBLOCK) == SOCKET_ERROR)
1447  {
1448  // set error
1449  SetError("connection accept failed: could not disable blocking", true);
1450  close(nsock);
1451  return nullptr;
1452  }
1453 #endif
1454 
1455 
1456  // create new peer
1457  Peer *pnPeer = new Peer(addr, nsock, this);
1458 
1459  // get required locks to add item to list
1460  CStdShareLock PeerListLock(&PeerListCSec);
1461  CStdLock PeerListAddLock(&PeerListAddCSec);
1462 
1463  // add to list
1464  pnPeer->Next = pPeerList;
1465  pPeerList = pnPeer;
1466 
1467  // clear add-lock
1468  PeerListAddLock.Clear();
1469 
1470  Changed();
1471 
1472  // ask callback if connection should be permitted
1473  if (pCB && !pCB->OnConn(addr, caddr, nullptr, this))
1474  // close socket immediately (will be deleted later)
1475  pnPeer->Close();
1476 
1477  // ok
1478  return pnPeer;
1479 }
1480 
1481 bool C4NetIOTCP::Listen(uint16_t inListenPort)
1482 {
1483  // already listening?
1484  if (lsock != INVALID_SOCKET)
1485  // close existing socket
1486  closesocket(lsock);
1488 
1489  // create socket
1490  if ((lsock = ::socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP)) == INVALID_SOCKET)
1491  {
1492  SetError("socket creation failed", true);
1493  return false;
1494  }
1495  if (!InitIPv6Socket(lsock))
1496  return false;
1497  // To be able to reuse the port after close
1498 #if !defined(_DEBUG) && !defined(_WIN32)
1499  int reuseaddr = 1;
1500  setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&reuseaddr), sizeof(reuseaddr));
1501 #endif
1502  // bind listen socket
1503  addr_t addr = addr_t::Any;
1504  addr.SetPort(inListenPort);
1505  if (::bind(lsock, &addr, addr.GetAddrLen()) == SOCKET_ERROR)
1506  {
1507  SetError("socket bind failed", true);
1509  return false;
1510  }
1511 
1512 #ifdef STDSCHEDULER_USE_EVENTS
1513  // set event callback
1514  if (::WSAEventSelect(lsock, Event, FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
1515  {
1516  SetError("could not set event for listen socket", true);
1518  return false;
1519  }
1520 #endif
1521 
1522  // start listening
1523  if (::listen(lsock, SOMAXCONN) == SOCKET_ERROR)
1524  {
1525  SetError("socket listen failed", true);
1527  return false;
1528  }
1529 
1530  // ok
1531  iListenPort = inListenPort;
1532  Changed();
1533  return true;
1534 }
1535 
1536 C4NetIOTCP::Peer *C4NetIOTCP::GetPeer(const addr_t &addr) // (mt-safe)
1537 {
1538  CStdShareLock PeerListLock(&PeerListCSec);
1539  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1540  if (pPeer->Open())
1541  if (pPeer->GetAddr() == addr)
1542  return pPeer;
1543  return nullptr;
1544 }
1545 
1547 {
1548  if (pCSec == &PeerListCSec)
1549  {
1550  // clear up
1551  Peer *pPeer = pPeerList, *pLast = nullptr;
1552  while (pPeer)
1553  {
1554  // delete?
1555  if (!pPeer->Open())
1556  {
1557  // unlink
1558  Peer *pDelete = pPeer;
1559  pPeer = pPeer->Next;
1560  (pLast ? pLast->Next : pPeerList) = pPeer;
1561  // delete
1562  delete pDelete;
1563  }
1564  else
1565  {
1566  // next peer
1567  pLast = pPeer;
1568  pPeer = pPeer->Next;
1569  }
1570  }
1571  ConnectWait *pWait = pConnectWaits, *pWLast = nullptr;
1572  while (pWait)
1573  {
1574  // delete?
1575  if (!pWait->sock)
1576  {
1577  // unlink
1578  ConnectWait *pDelete = pWait;
1579  pWait = pWait->Next;
1580  (pWLast ? pWLast->Next : pConnectWaits) = pWait;
1581  // delete
1582  delete pDelete;
1583  }
1584  else
1585  {
1586  // next peer
1587  pWLast = pWait;
1588  pWait = pWait->Next;
1589  }
1590  }
1591  }
1592 }
1593 
1594 void C4NetIOTCP::AddConnectWait(SOCKET sock, const addr_t &addr) // (mt-safe)
1595 {
1596  CStdShareLock PeerListLock(&PeerListCSec);
1597  CStdLock PeerListAddLock(&PeerListAddCSec);
1598  // create new entry, add to list
1599  ConnectWait *pnWait = new ConnectWait;
1600  pnWait->sock = sock; pnWait->addr = addr;
1601  pnWait->Next = pConnectWaits;
1602  pConnectWaits = pnWait;
1603 #ifndef STDSCHEDULER_USE_EVENTS
1604  // unblock, so new FD can be realized
1605  UnBlock();
1606 #endif
1607  Changed();
1608 }
1609 
1611 {
1612  CStdShareLock PeerListLock(&PeerListCSec);
1613  // search
1614  for (ConnectWait *pWait = pConnectWaits; pWait; pWait = pWait->Next)
1615  if (pWait->addr == addr)
1616  return pWait;
1617  return nullptr;
1618 }
1619 
1621 {
1622  CStdShareLock PeerListLock(&PeerListCSec);
1623  for (ConnectWait *pWait = pConnectWaits; pWait; pWait = pWait->Next)
1624  if (pWait->sock)
1625  {
1626  closesocket(pWait->sock);
1627  pWait->sock = 0;
1628  }
1629 }
1630 
1631 void C4NetIOTCP::PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf)
1632 {
1633  // packet data
1634  uint8_t cFirstByte = 0xff;
1635  uint32_t iSize = rPacket.getSize();
1636  uint32_t iOASize = sizeof(cFirstByte) + sizeof(iSize) + iSize;
1637 
1638  // enlarge buffer
1639  int iPos = rOutBuf.getSize();
1640  rOutBuf.Grow(iOASize);
1641 
1642  // write packet at end of outgoing buffer
1643  *getMBufPtr<uint8_t>(rOutBuf, iPos) = cFirstByte; iPos += sizeof(uint8_t);
1644  *getMBufPtr<uint32_t>(rOutBuf, iPos) = iSize; iPos += sizeof(uint32_t);
1645  rOutBuf.Write(rPacket, iPos);
1646 }
1647 
1648 size_t C4NetIOTCP::UnpackPacket(const StdBuf &IBuf, const C4NetIO::addr_t &addr)
1649 {
1650  size_t iPos = 0;
1651  // check first byte (should be 0xff)
1652  if (*getBufPtr<uint8_t>(IBuf, iPos) != (uint8_t) 0xff)
1653  // clear buffer
1654  return IBuf.getSize();
1655  iPos += sizeof(char);
1656  // read packet size
1657  uint32_t iPacketSize;
1658  if (iPos + sizeof(uint32_t) > IBuf.getSize())
1659  return 0;
1660  iPacketSize = *getBufPtr<uint32_t>(IBuf, iPos);
1661  iPos += sizeof(uint32_t);
1662  // packet incomplete?
1663  if (iPos + iPacketSize > IBuf.getSize())
1664  return 0;
1665  // ok, call back
1666  if (pCB) pCB->OnPacket(C4NetIOPacket(IBuf.getPart(iPos, iPacketSize), addr), this);
1667  // absorbed
1668  return iPos + iPacketSize;
1669 }
1670 
1671 // * C4NetIOTCP::Peer
1672 
1673 const unsigned int C4NetIOTCP::Peer::iTCPHeaderSize = 28 + 24; // (bytes)
1674 const unsigned int C4NetIOTCP::Peer::iMinIBufSize = 8192; // (bytes)
1675 
1676 // construction / destruction
1677 
1679  : pParent(pnParent),
1680  addr(naddr), sock(nsock),
1681  iIBufUsage(0), iIRate(0), iORate(0),
1682  fOpen(true), fDoBroadcast(false), Next(nullptr)
1683 {
1684 }
1685 
1687 {
1688  // close socket
1689  Close();
1690 }
1691 
1692 // implementation
1693 
1694 bool C4NetIOTCP::Peer::Send(const C4NetIOPacket &rPacket) // (mt-safe)
1695 {
1696  CStdLock OLock(&OCSec);
1697 
1698  // already data pending to be sent? try to sent them first (empty buffer)
1699  if (!OBuf.isNull()) Send();
1700  bool fSend = OBuf.isNull();
1701 
1702  // pack packet
1703  pParent->PackPacket(rPacket, OBuf);
1704 
1705  // (try to) send
1706  return fSend ? Send() : true;
1707 }
1708 
1709 bool C4NetIOTCP::Peer::Send() // (mt-safe)
1710 {
1711  CStdLock OLock(&OCSec);
1712  if (OBuf.isNull()) return true;
1713 
1714  // send as much as possibile
1715  int iBytesSent;
1716  if ((iBytesSent = ::send(sock, getBufPtr<char>(OBuf), OBuf.getSize(), 0)) == SOCKET_ERROR)
1717  if (!HaveWouldBlockError())
1718  {
1719  pParent->SetError("send failed", true);
1720  return false;
1721  }
1722 
1723  // nothin sent?
1724  if (iBytesSent == SOCKET_ERROR || !iBytesSent) return true;
1725 
1726  // increase output rate
1727  iORate += iBytesSent + iTCPHeaderSize;
1728 
1729  // data remaining?
1730  if (unsigned(iBytesSent) < OBuf.getSize())
1731  {
1732  // Shrink buffer
1733  OBuf.Move(iBytesSent, OBuf.getSize() - iBytesSent);
1734  OBuf.Shrink(iBytesSent);
1735 #ifndef STDSCHEDULER_USE_EVENTS
1736  // Unblock parent so the FD-list can be refreshed
1737  pParent->UnBlock();
1738 #endif
1739  }
1740  else
1741  // just delete buffer
1742  OBuf.Clear();
1743 
1744  // ok
1745  return true;
1746 }
1747 
1748 void *C4NetIOTCP::Peer::GetRecvBuf(int iSize) // (mt-safe)
1749 {
1750  CStdLock ILock(&ICSec);
1751  // Enlarge input buffer?
1752  size_t iIBufSize = std::max<size_t>(iMinIBufSize, IBuf.getSize());
1753  while ((size_t)(iIBufUsage + iSize) > iIBufSize)
1754  iIBufSize *= 2;
1755  if (iIBufSize != IBuf.getSize())
1756  IBuf.SetSize(iIBufSize);
1757  // Return the appropriate part of the input buffer
1758  return IBuf.getMPtr(iIBufUsage);
1759 }
1760 
1761 void C4NetIOTCP::Peer::OnRecv(int iSize) // (mt-safe)
1762 {
1763  CStdLock ILock(&ICSec);
1764  // increase input rate and input buffer usage
1765  iIRate += iTCPHeaderSize + iSize;
1766  iIBufUsage += iSize;
1767  // a prior call to GetRecvBuf should have ensured this
1768  assert(static_cast<size_t>(iIBufUsage) <= IBuf.getSize());
1769  // read packets
1770  size_t iPos = 0, iPacketPos;
1771  while ((iPacketPos = iPos) < (size_t)iIBufUsage)
1772  {
1773  // Try to unpack a packet
1774  StdBuf IBufPart = IBuf.getPart(iPos, iIBufUsage - iPos);
1775  int32_t iBytes = pParent->UnpackPacket(IBufPart, addr);
1776  // Could not unpack?
1777  if (!iBytes)
1778  break;
1779  // Advance
1780  iPos += iBytes;
1781  }
1782  // data left?
1783  if (iPacketPos < (size_t) iIBufUsage)
1784  {
1785  // no packet read?
1786  if (!iPacketPos) return;
1787  // move data
1788  IBuf.Move(iPacketPos, IBuf.getSize() - iPacketPos);
1789  iIBufUsage -= iPacketPos;
1790  // shrink buffer
1791  size_t iIBufSize = IBuf.getSize();
1792  while ((size_t) iIBufUsage <= iIBufSize / 2)
1793  iIBufSize /= 2;
1794  if (iIBufSize != IBuf.getSize())
1795  IBuf.Shrink(iPacketPos);
1796  }
1797  else
1798  {
1799  // the buffer is empty
1800  iIBufUsage = 0;
1801  // shrink buffer to minimum
1802  if (IBuf.getSize() > iMinIBufSize)
1803  IBuf.SetSize(iMinIBufSize);
1804  }
1805 }
1806 
1807 void C4NetIOTCP::Peer::Close() // (mt-safe)
1808 {
1809  CStdLock ILock(&ICSec); CStdLock OLock(&OCSec);
1810  if (!fOpen) return;
1811  // close socket
1812  closesocket(sock);
1813  // set flag
1814  fOpen = false;
1815  // clear buffers
1816  IBuf.Clear(); OBuf.Clear();
1817  iIBufUsage = 0;
1818  // reset statistics
1819  iIRate = iORate = 0;
1820 }
1821 
1823 {
1824  CStdLock ILock(&ICSec); CStdLock OLock(&OCSec);
1825  iIRate = iORate = 0;
1826 }
1827 
1828 // *** C4NetIOSimpleUDP
1829 
1831  : iPort(~0), sock(INVALID_SOCKET)
1832 {
1833 
1834 }
1835 
1837 {
1838  Close();
1839 }
1840 
1841 bool C4NetIOSimpleUDP::Init(uint16_t inPort)
1842 {
1843  // reset error
1844  ResetError();
1845 
1846  // already initialized? close first
1847  if (fInit) Close();
1848 
1849 #ifdef HAVE_WINSOCK
1850  // init winsock
1851  if (!AcquireWinSock())
1852  {
1853  SetError("could not start winsock");
1854  return false;
1855  }
1856 #endif
1857 
1858  // create sockets
1859  if ((sock = ::socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) == INVALID_SOCKET)
1860  {
1861  SetError("could not create socket", true);
1862  return false;
1863  }
1864 
1865  if (!InitIPv6Socket(sock))
1866  return false;
1867 
1868  // set reuse socket option
1869  if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&fAllowReUse), sizeof fAllowReUse) == SOCKET_ERROR)
1870  {
1871  SetError("could not set reuse options", true);
1872  return false;
1873  }
1874 
1875  // bind socket
1876  iPort = inPort;
1877  addr_t naddr = addr_t::Any;
1878  naddr.SetPort(iPort);
1879  if (::bind(sock, &naddr, sizeof(naddr)) == SOCKET_ERROR)
1880  {
1881  SetError("could not bind socket", true);
1882  return false;
1883  }
1884 
1885 #ifdef STDSCHEDULER_USE_EVENTS
1886 
1887  // create event
1888  if ((hEvent = WSACreateEvent()) == WSA_INVALID_EVENT)
1889  {
1890  SetError("could not create event", true);
1891  return false;
1892  }
1893 
1894  // set event for socket
1895  if (WSAEventSelect(sock, hEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1896  {
1897  SetError("could not select event", true);
1898  return false;
1899  }
1900 
1901 #else
1902 
1903  // disable blocking
1904  if (::fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) == SOCKET_ERROR)
1905  {
1906  // set error
1907  SetError("could not disable blocking", true);
1908  return false;
1909  }
1910 
1911  // create pipe
1912  if (pipe(Pipe) != 0)
1913  {
1914  SetError("could not create pipe", true);
1915  return false;
1916  }
1917 
1918 #endif
1919 
1920  // set flags
1921  fInit = true;
1922  fMultiCast = false;
1923 
1924  // ok, that's all for know.
1925  // call InitBroadcast for more initialization fun
1926  return true;
1927 }
1928 
1930 {
1931  // no error... yet
1932  ResetError();
1933 
1934  // security
1935  if (!pBroadcastAddr) return false;
1936 
1937  // Init() has to be called first
1938  if (!fInit) return false;
1939  // already activated?
1940  if (fMultiCast) CloseBroadcast();
1941 
1942  // broadcast addr valid?
1943  if (!pBroadcastAddr->IsMulticast() || pBroadcastAddr->GetFamily() != HostAddress::IPv6)
1944  {
1945  SetError("invalid broadcast address (only IPv6 multicast addresses are supported)");
1946  return false;
1947  }
1948  if (pBroadcastAddr->GetPort() != iPort)
1949  {
1950  SetError("invalid broadcast address (different port)");
1951  return false;
1952  }
1953 
1954  // set mc ttl to somewhat about "same net"
1955  int TTL = 16;
1956  if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, reinterpret_cast<char*>(&TTL), sizeof(TTL)) == SOCKET_ERROR)
1957  {
1958  SetError("could not set mc ttl", true);
1959  return false;
1960  }
1961 
1962  // set up multicast group information
1963  this->MCAddr = *pBroadcastAddr;
1964  MCGrpInfo.ipv6mr_multiaddr = static_cast<sockaddr_in6>(MCAddr).sin6_addr;
1965  // TODO: do multicast on all interfaces?
1966  MCGrpInfo.ipv6mr_interface = 0; // default interface
1967 
1968  // join multicast group
1969  if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
1970  reinterpret_cast<const char *>(&MCGrpInfo), sizeof(MCGrpInfo)) == SOCKET_ERROR)
1971  {
1972  SetError("could not join multicast group"); // to do: more error information
1973  return false;
1974  }
1975 
1976  // (try to) disable loopback (will set fLoopback accordingly)
1977  SetMCLoopback(false);
1978 
1979  // ok
1980  fMultiCast = true;
1981  return true;
1982 }
1983 
1985 {
1986  // should be initialized
1987  if (!fInit) return true;
1988 
1989  ResetError();
1990 
1991  // deactivate multicast
1992  if (fMultiCast)
1993  CloseBroadcast();
1994 
1995  // close sockets
1996  if (sock != INVALID_SOCKET)
1997  {
1998  closesocket(sock);
1999  sock = INVALID_SOCKET;
2000  }
2001 
2002 #ifdef STDSCHEDULER_USE_EVENTS
2003  // close event
2004  if (hEvent != nullptr)
2005  {
2006  WSACloseEvent(hEvent);
2007  hEvent = nullptr;
2008  }
2009 #else
2010  // close pipes
2011  close(Pipe[0]);
2012  close(Pipe[1]);
2013 #endif
2014 
2015 #ifdef HAVE_WINSOCK
2016  // release winsock
2017  ReleaseWinSock();
2018 #endif
2019 
2020  // ok
2021  fInit = false;
2022  return false;
2023 }
2024 
2026 {
2027  // multicast not active?
2028  if (!fMultiCast) return true;
2029 
2030  // leave multicast group
2031  if (setsockopt(sock, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
2032  reinterpret_cast<const char *>(&MCGrpInfo), sizeof(MCGrpInfo)) == SOCKET_ERROR)
2033  {
2034  SetError("could not leave multicast group"); // to do: more error information
2035  return false;
2036  }
2037 
2038  // ok
2039  fMultiCast = false;
2040  return true;
2041 }
2042 
2043 bool C4NetIOSimpleUDP::Execute(int iMaxTime, pollfd *)
2044 {
2045  if (!fInit) { SetError("not yet initialized"); return false; }
2046  ResetError();
2047 
2048 #ifdef __APPLE__
2049  iMaxTime = fix_poll_timeout(iMaxTime);
2050 #endif
2051 
2052  // wait for socket / timeout
2053  WaitResult eWR = WaitForSocket(iMaxTime);
2054  if (eWR == WR_Error) return false;
2055 
2056  // cancelled / timeout?
2057  if (eWR == WR_Cancelled || eWR == WR_Timeout) return true;
2058  assert(eWR == WR_Readable);
2059 
2060  // read packets from socket
2061  for (;;)
2062  {
2063  // how much can be read?
2064 #ifdef _WIN32
2065  u_long iMaxMsgSize;
2066 #else
2067  // The FIONREAD ioctl call takes an int on unix
2068  int iMaxMsgSize;
2069 #endif
2070  if (::ioctlsocket(sock, FIONREAD, &iMaxMsgSize) == SOCKET_ERROR)
2071  {
2072  SetError("Could not determine the amount of data that can be read from socket", true);
2073  return false;
2074  }
2075 
2076  // nothing?
2077  if (!iMaxMsgSize)
2078  break;
2079  // alloc buffer
2080  C4NetIOPacket Pkt; Pkt.New(iMaxMsgSize);
2081  // read data (note: it is _not_ garantueed that iMaxMsgSize bytes are available)
2082  addr_t SrcAddr; socklen_t iSrcAddrLen = sizeof(sockaddr_in6);
2083  int iMsgSize = ::recvfrom(sock, getMBufPtr<char>(Pkt), iMaxMsgSize, 0, &SrcAddr, &iSrcAddrLen);
2084  // error?
2085  if (iMsgSize == SOCKET_ERROR)
2086  {
2087  if (HaveConnResetError())
2088  {
2089  // this is actually some kind of notification: an ICMP msg (unreachable)
2090  // came back, so callback and continue reading
2091  if (pCB) pCB->OnDisconn(SrcAddr, this, GetSocketErrorMsg());
2092  continue;
2093  }
2094  else
2095  {
2096  // this is the real thing, though
2097  SetError("could not receive data from socket", true);
2098  return false;
2099  }
2100  }
2101  // invalid address?
2102  if ((iSrcAddrLen != sizeof(sockaddr_in) && iSrcAddrLen != sizeof(sockaddr_in6)) || SrcAddr.GetFamily() == addr_t::UnknownFamily)
2103  {
2104  SetError("recvfrom returned an invalid address");
2105  return false;
2106  }
2107  // again: nothing?
2108  if (!iMsgSize)
2109  // docs say that the connection has been closed (whatever that means for a connectionless socket...)
2110  // let's just pretend it didn't happen, but stop reading.
2111  break;
2112  // fill in packet information
2113  Pkt.SetSize(iMsgSize);
2114  Pkt.SetAddr(SrcAddr);
2115  // callback
2116  if (pCB) pCB->OnPacket(Pkt, this);
2117  }
2118 
2119  // ok
2120  return true;
2121 }
2122 
2124 {
2125  if (!fInit) { SetError("not yet initialized"); return false; }
2126 
2127  // send it
2128  C4NetIO::addr_t addr = rPacket.getAddr();
2129  if (::sendto(sock, getBufPtr<char>(rPacket), rPacket.getSize(), 0,
2130  &addr, addr.GetAddrLen())
2131  != int(rPacket.getSize()) &&
2133  {
2134  SetError("socket sendto failed", true);
2135  return false;
2136  }
2137 
2138  // ok
2139  ResetError();
2140  return true;
2141 }
2142 
2144 {
2145  // just set broadcast address and send
2146  return C4NetIOSimpleUDP::Send(C4NetIOPacket(rPacket.getRef(), MCAddr));
2147 }
2148 
2149 #ifdef STDSCHEDULER_USE_EVENTS
2150 
2151 void C4NetIOSimpleUDP::UnBlock() // (mt-safe)
2152 {
2153  // unblock WaitForSingleObject in C4NetIOTCP::Execute manually
2154  // by setting the Event
2155  WSASetEvent(hEvent);
2156 }
2157 
2158 HANDLE C4NetIOSimpleUDP::GetEvent() // (mt-safe)
2159 {
2160  return hEvent;
2161 }
2162 
2163 enum C4NetIOSimpleUDP::WaitResult C4NetIOSimpleUDP::WaitForSocket(int iTimeout)
2164 {
2165  // wait for anything to happen
2166  DWORD ret = WaitForSingleObject(hEvent, iTimeout == TO_INF ? INFINITE : iTimeout);
2167  if (ret == WAIT_TIMEOUT)
2168  return WR_Timeout;
2169  if (ret == WAIT_FAILED)
2170  { SetError("Wait for Event failed"); return WR_Error; }
2171  // get socket events (and reset the event)
2172  WSANETWORKEVENTS wsaEvents;
2173  if (WSAEnumNetworkEvents(sock, hEvent, &wsaEvents) == SOCKET_ERROR)
2174  { SetError("could not enumerate network events!"); return WR_Error; }
2175  // socket readable?
2176  if (wsaEvents.lNetworkEvents | FD_READ)
2177  return WR_Readable;
2178  // in case the event was set without the socket beeing readable,
2179  // the operation has been cancelled (see Unblock())
2180  WSAResetEvent(hEvent);
2181  return WR_Cancelled;
2182 }
2183 
2184 #else // STDSCHEDULER_USE_EVENTS
2185 
2186 void C4NetIOSimpleUDP::UnBlock() // (mt-safe)
2187 {
2188  // write one character to the pipe, this will unblock everything that
2189  // waits for the FD set returned by GetFDs.
2190  char c = 42;
2191  if (write(Pipe[1], &c, 1) == -1)
2192  SetError("write failed");
2193 }
2194 
2195 void C4NetIOSimpleUDP::GetFDs(std::vector<struct pollfd> & fds)
2196 {
2197  // add pipe
2198  pollfd pfd = { Pipe[0], POLLIN, 0 };
2199  fds.push_back(pfd);
2200  // add socket
2201  if (sock != INVALID_SOCKET)
2202  {
2203  pollfd pfd = { sock, POLLIN, 0 };
2204  fds.push_back(pfd);
2205  }
2206 }
2207 
2208 enum C4NetIOSimpleUDP::WaitResult C4NetIOSimpleUDP::WaitForSocket(int iTimeout)
2209 {
2210  // get file descriptors
2211  std::vector<pollfd> fds;
2212  GetFDs(fds);
2213  // wait for anything to happen
2214  int ret = poll(&fds[0], fds.size(), iTimeout);
2215  // catch simple cases
2216  if (ret < 0)
2217  { SetError("poll failed", true); return WR_Error; }
2218  if (!ret)
2219  return WR_Timeout;
2220  // flush pipe, if neccessary
2221  if (fds[0].revents & POLLIN)
2222  {
2223  char c;
2224  if (::read(Pipe[0], &c, 1) == -1)
2225  SetError("read failed");
2226  }
2227  // socket readable?
2228  return (sock != INVALID_SOCKET) && (fds[1].revents & POLLIN) ? WR_Readable : WR_Cancelled;
2229 }
2230 
2231 #endif // STDSCHEDULER_USE_EVENTS
2232 
2234 {
2235  // enable/disable MC loopback
2236  setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, reinterpret_cast<char *>(&fLoopback), sizeof fLoopback);
2237  // read result
2238  socklen_t iSize = sizeof(fLoopback);
2239  if (getsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, reinterpret_cast<char *>(&fLoopback), &iSize) == SOCKET_ERROR)
2240  return false;
2241  fMCLoopback = !! fLoopback;
2242  return true;
2243 }
2244 
2246 {
2247  fAllowReUse = fAllow;
2248 }
2249 
2250 // *** C4NetIOUDP
2251 
2252 // * build options / constants / structures
2253 
2254 // Check immediately when missing packets are detected?
2255 #define C4NETIOUDP_OPT_RECV_CHECK_IMMEDIATE
2256 
2257 // Protocol version
2258 const unsigned int C4NetIOUDP::iVersion = 2;
2259 
2260 // Standard timeout length
2261 const unsigned int C4NetIOUDP::iStdTimeout = 1000; // (ms)
2262 
2263 // Time interval for connection checks
2264 // Equals the maximum time that C4NetIOUDP::Execute might block
2265 const unsigned int C4NetIOUDP::iCheckInterval = 1000; // (ms)
2266 
2267 const unsigned int C4NetIOUDP::iMaxOPacketBacklog = 10000;
2268 
2269 const unsigned int C4NetIOUDP::iUDPHeaderSize = 8 + 24; // (bytes)
2270 
2271 #pragma pack (push, 1)
2272 
2273 // We need to adapt C4NetIO::addr_t to put it in our UDP packages.
2274 // Previously, the sockaddr_in struct was just put in directly. This is
2275 // horribly non-portable though, especially as the value of AF_INET6 differs
2276 // between platforms.
2278 {
2279  BinAddr() = default;
2281  {
2282  switch (addr.GetFamily())
2283  {
2285  {
2286  type = 1;
2287  auto addr4 = static_cast<const sockaddr_in*>(&addr);
2288  static_assert(sizeof(v4) == sizeof(addr4->sin_addr), "unexpected IPv4 address size");
2289  memcpy(&v4, &addr4->sin_addr, sizeof(v4));
2290  break;
2291  }
2293  {
2294  type = 2;
2295  auto addr6 = static_cast<const sockaddr_in6*>(&addr);
2296  static_assert(sizeof(v6) == sizeof(addr6->sin6_addr), "unexpected IPv6 address size");
2297  memcpy(&v6, &addr6->sin6_addr, sizeof(v6));
2298  break;
2299  }
2300  default:
2301  assert(!"Unexpected address family");
2302  }
2303  port = addr.GetPort();
2304  }
2305 
2306  operator C4NetIO::addr_t() const
2307  {
2308  C4NetIO::addr_t result;
2309  switch (type)
2310  {
2311  case 1:
2312  {
2313  sockaddr_in addr4 = sockaddr_in();
2314  addr4.sin_family = AF_INET;
2315  memcpy(&addr4.sin_addr, &v4, sizeof(v4));
2316  result.SetAddress(reinterpret_cast<sockaddr*>(&addr4));
2317  break;
2318  }
2319  case 2:
2320  {
2321  sockaddr_in6 addr6 = sockaddr_in6();
2322  addr6.sin6_family = AF_INET6;
2323  memcpy(&addr6.sin6_addr, &v6, sizeof(v6));
2324  result.SetAddress(reinterpret_cast<sockaddr*>(&addr6));
2325  break;
2326  }
2327  default:
2328  assert(!"Invalid address type");
2329  }
2330  result.SetPort(port);
2331  return result;
2332  }
2333 
2335  {
2336  return static_cast<C4NetIO::addr_t>(*this).ToString();
2337  }
2338 
2339  uint16_t port;
2340  uint8_t type{0};
2341  union
2342  {
2343  uint8_t v4[4];
2344  uint8_t v6[16];
2345  };
2346 };
2347 
2348 // packet structures
2350 {
2351  uint8_t StatusByte;
2352  uint32_t Nr; // packet nr
2353 };
2354 
2356 {
2357  uint32_t ProtocolVer;
2360 };
2361 
2363 {
2366 };
2367 
2369 {
2372 };
2373 
2375 {
2376  Packet::nr_t FNr; // start fragment of this series
2377  uint32_t Size; // packet size (all fragments)
2378 };
2379 
2381 {
2383  uint32_t AckNr, MCAckNr; // numbers of the last packets received
2384 };
2385 
2387 {
2389 };
2390 
2391 
2393 {
2394  unsigned int TestNr;
2395 };
2396 
2397 #pragma pack (pop)
2398 
2399 // construction / destruction
2400 
2402  : PeerListCSec(this),
2403  iPort(~0),
2404  tNextCheck(C4TimeMilliseconds::PositiveInfinity),
2405  OPackets(iMaxOPacketBacklog)
2406 {
2407 
2408 }
2409 
2411 {
2412  Close();
2413 }
2414 
2415 bool C4NetIOUDP::Init(uint16_t inPort)
2416 {
2417  // already initialized? close first
2418  if (fInit) Close();
2419 
2420 #ifdef C4NETIO_DEBUG
2421  // open log
2422  OpenDebugLog();
2423 #endif
2424 
2425  // Initialize UDP
2426  if (!C4NetIOSimpleUDP::Init(inPort))
2427  return false;
2428  iPort = inPort;
2429 
2430  // set callback
2432 
2433  // set flags
2434  fInit = true;
2435  fMultiCast = false;
2436 
2438 
2439  // ok, that's all for now.
2440  // call InitBroadcast for more initialization fun
2441  return true;
2442 }
2443 
2444 bool C4NetIOUDP::InitBroadcast(addr_t *pBroadcastAddr)
2445 {
2446  // no error... yet
2447  ResetError();
2448 
2449  // security
2450  if (!pBroadcastAddr) return false;
2451 
2452  // Init() has to be called first
2453  if (!fInit) return false;
2454  // already activated?
2455  if (fMultiCast) CloseBroadcast();
2456 
2457  // set up multicast group information
2458  C4NetIO::addr_t MCAddr = *pBroadcastAddr;
2459 
2460  // broadcast addr valid?
2461  if (!MCAddr.IsMulticast())
2462  {
2463  // port is needed in order to search a mc address automatically
2464  if (!iPort)
2465  {
2466  SetError("broadcast address is not valid");
2467  return false;
2468  }
2469  // Set up address as unicast-prefix-based IPv6 multicast address (RFC 3306).
2470  sockaddr_in6 saddrgen = sockaddr_in6();
2471  saddrgen.sin6_family = AF_INET6;
2472  uint8_t *addrgen = saddrgen.sin6_addr.s6_addr;
2473  // ff3e ("global multicast based on network prefix") : 64 (length of network prefix)
2474  static const uint8_t mcast_prefix[4] = { 0xff, 0x3e, 0, 64};
2475  memcpy(addrgen, mcast_prefix, sizeof(mcast_prefix));
2476  addrgen += sizeof(mcast_prefix);
2477  // 64 bit network prefix
2478  addr_t prefixAddr;
2479  for (auto& addr : GetLocalAddresses())
2480  if (addr.GetFamily() == HostAddress::IPv6 && !addr.IsLocal())
2481  {
2482  prefixAddr.SetAddress(addr);
2483  break;
2484  }
2485  if (prefixAddr.IsNull())
2486  {
2487  SetError("no IPv6 unicast address available");
2488  return false;
2489  }
2490  static const size_t network_prefix_size = 8;
2491  memcpy(addrgen, &static_cast<sockaddr_in6*>(&prefixAddr)->sin6_addr, network_prefix_size);
2492  addrgen += network_prefix_size;
2493  // 32 bit group id: search for a free one
2494  for (int iRetries = 1000; iRetries; iRetries--)
2495  {
2496  uint32_t rnd = UnsyncedRandom();
2497  memcpy(addrgen, &rnd, sizeof(rnd));
2498  // "high-order bit of the Group ID will be the same value as the T flag"
2499  addrgen[0] |= 0x80;
2500  // create new - random - address
2501  MCAddr.SetAddress((sockaddr*) &saddrgen);
2502  MCAddr.SetPort(iPort);
2503  // init broadcast
2504  if (!C4NetIOSimpleUDP::InitBroadcast(&MCAddr))
2505  return false;
2506  // do the loopback test
2507  if (!DoLoopbackTest())
2508  {
2510  if (!GetError()) SetError("multicast loopback test failed");
2511  return false;
2512  }
2513  // send a ping packet
2514  const PacketHdr PingPacket = { IPID_Ping | static_cast<uint8_t>(0x80u), 0 };
2515  if (!C4NetIOSimpleUDP::Broadcast(C4NetIOPacket(&PingPacket, sizeof(PingPacket))))
2516  {
2518  return false;
2519  }
2520  bool fSuccess = false;
2521  for (;;)
2522  {
2523  fSavePacket = true; LastPacket.Clear();
2524  // wait for something to happen
2526  {
2527  fSavePacket = false;
2529  return false;
2530  }
2531  fSavePacket = false;
2532  // Timeout? So expect this address to be unused
2533  if (LastPacket.isNull()) { fSuccess = true; break; }
2534  // looped back?
2536  // ignore this one
2537  continue;
2538  // otherwise: there must be someone else in this MC group
2540  break;
2541  }
2542  if (fSuccess) break;
2543  // no success? try again...
2544  }
2545 
2546  // return found address
2547  *pBroadcastAddr = MCAddr;
2548  }
2549  else
2550  {
2551  // check: must be same port
2552  if (MCAddr.GetPort() == iPort)
2553  {
2554  SetError("invalid multicast address: wrong port");
2555  return false;
2556  }
2557  // init
2558  if (!C4NetIOSimpleUDP::InitBroadcast(&MCAddr))
2559  return false;
2560  // do loopback test (if not delayed)
2561  if (!fDelayedLoopbackTest)
2562  if (!DoLoopbackTest())
2563  {
2565  if (!GetError()) SetError("multicast loopback test failed");
2566  return false;
2567  }
2568  }
2569 
2570  // (try to) disable multicast loopback
2572 
2573  // set flags
2574  fMultiCast = true;
2575  iOPacketCounter = 0;
2576  iBroadcastRate = 0;
2577 
2578  // ok
2579  return true;
2580 }
2581 
2583 {
2584  // should be initialized
2585  if (!fInit) return false;
2586 
2587  // close all peers
2588  CStdShareLock PeerListLock(&PeerListCSec);
2589  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
2590  pPeer->Close("owner class closed");
2591  PeerListLock.Clear();
2592 
2593  // deactivate multicast
2594  if (fMultiCast)
2595  CloseBroadcast();
2596 
2597  // close UDP
2598  bool fSuccess = C4NetIOSimpleUDP::Close();
2599 
2600 #ifdef C4NETIO_DEBUG
2601  // close log
2602  CloseDebugLog();
2603 #endif
2604 
2605  // ok
2606  fInit = false;
2607  return fSuccess;
2608 }
2609 
2611 {
2612  ResetError();
2613 
2614  // multicast not active?
2615  if (!fMultiCast) return true;
2616 
2617  // ok
2618  fMultiCast = false;
2620 }
2621 
2622 bool C4NetIOUDP::Execute(int iMaxTime, pollfd *) // (mt-safe)
2623 {
2624  if (!fInit) { SetError("not yet initialized"); return false; }
2625 
2626  CStdLock ExecuteLock(&ExecuteCSec);
2627  CStdShareLock PeerListLock(&PeerListCSec);
2628 
2629  ResetError();
2630 
2631  // adjust maximum block time
2633  uint32_t iMaxBlock = std::max(tNow, GetNextTick(tNow)) - tNow;
2634  if (iMaxTime == TO_INF || iMaxTime > (int) iMaxBlock) iMaxTime = iMaxBlock;
2635 
2636  // execute subclass
2637  if (!C4NetIOSimpleUDP::Execute(iMaxTime))
2638  return false;
2639 
2640  // connection check needed?
2642  DoCheck();
2643  // client timeout?
2644  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
2645  if (!pPeer->Closed())
2646  pPeer->CheckTimeout();
2647 
2648  // do a delayed loopback test once the incoming buffer is empty
2650  {
2651  if (fMultiCast)
2653  fDelayedLoopbackTest = false;
2654  }
2655 
2656  // ok
2657  return true;
2658 }
2659 
2660 bool C4NetIOUDP::Connect(const addr_t &addr) // (mt-safe)
2661 {
2662  // connect
2663  return !! ConnectPeer(addr, true);
2664 }
2665 
2666 bool C4NetIOUDP::Close(const addr_t &addr) // (mt-safe)
2667 {
2668  CStdShareLock PeerListLock(&PeerListCSec);
2669  // find peer
2670  Peer *pPeer = GetPeer(addr);
2671  if (!pPeer) return false;
2672  // close
2673  pPeer->Close("closed");
2674  return true;
2675 }
2676 
2677 bool C4NetIOUDP::Send(const C4NetIOPacket &rPacket) // (mt-safe)
2678 {
2679  // find Peer class for given address
2680  CStdShareLock PeerListLock(&PeerListCSec);
2681  Peer *pPeer = GetPeer(rPacket.getAddr());
2682  // not found?
2683  if (!pPeer) return false;
2684  // send the packet
2685  return pPeer->Send(rPacket);
2686 }
2687 
2688 bool C4NetIOUDP::Broadcast(const C4NetIOPacket &rPacket) // (mt-safe)
2689 {
2690  CStdShareLock PeerListLock(&PeerListCSec);
2691  // search: any client reachable via multicast?
2692  Peer *pPeer;
2693  for (pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
2694  if (pPeer->Open() && pPeer->MultiCast() && pPeer->doBroadcast())
2695  break;
2696  bool fSuccess = true;
2697  if (pPeer)
2698  {
2699  CStdLock OutLock(&OutCSec);
2700  // send it via multicast: encapsulate packet
2701  Packet *pPkt = new Packet(rPacket.Duplicate(), iOPacketCounter);
2702  iOPacketCounter += pPkt->FragmentCnt();
2703  // add to list
2704  OPackets.AddPacket(pPkt);
2705  // send it
2706  fSuccess &= BroadcastDirect(*pPkt);
2707  }
2708  // send to all clients connected via du, too
2709  for (pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
2710  if (pPeer->Open() && !pPeer->MultiCast() && pPeer->doBroadcast())
2711  pPeer->Send(rPacket);
2712  return true;
2713 }
2714 
2715 bool C4NetIOUDP::SetBroadcast(const addr_t &addr, bool fSet) // (mt-safe)
2716 {
2717  CStdShareLock PeerListLock(&PeerListCSec);
2718  // find peer
2719  Peer *pPeer = GetPeer(addr);
2720  if (!pPeer) return false;
2721  // set flag
2722  pPeer->SetBroadcast(fSet);
2723  return true;
2724 }
2725 
2727 {
2728  // maximum time: check interval
2729  C4TimeMilliseconds tTiming = tNextCheck.IsInfinite() ? tNow : std::max(tNow, tNextCheck);
2730 
2731  // client timeouts (e.g. connection timeout)
2732  CStdShareLock PeerListLock(&PeerListCSec);
2733  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
2734  if (!pPeer->Closed())
2735  if (!pPeer->GetTimeout().IsInfinite())
2736  tTiming = std::min(tTiming, pPeer->GetTimeout());
2737  // return timing value
2738  return tTiming;
2739 }
2740 
2741 bool C4NetIOUDP::GetStatistic(int *pBroadcastRate) // (mt-safe)
2742 {
2743  CStdLock StatLock(&StatCSec);
2744  if (pBroadcastRate) *pBroadcastRate = iBroadcastRate;
2745  return true;
2746 }
2747 
2748 bool C4NetIOUDP::GetConnStatistic(const addr_t &addr, int *pIRate, int *pORate, int *pLoss) // (mt-safe)
2749 {
2750  CStdShareLock PeerListLock(&PeerListCSec);
2751  // find peer
2752  Peer *pPeer = GetPeer(addr);
2753  if (!pPeer || !pPeer->Open()) return false;
2754  // return statistics
2755  if (pIRate) *pIRate = pPeer->GetIRate();
2756  if (pORate) *pORate = pPeer->GetORate();
2757  if (pLoss) *pLoss = 0;
2758  return true;
2759 }
2760 
2762 {
2763  CStdShareLock PeerListLock(&PeerListCSec);
2764  // clear all peer statistics
2765  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
2766  pPeer->ClearStatistics();
2767  // broadcast statistics
2768  CStdLock StatLock(&StatCSec);
2769  iBroadcastRate = 0;
2770 }
2771 
2772 void C4NetIOUDP::OnPacket(const C4NetIOPacket &Packet, C4NetIO *pNetIO)
2773 {
2774  assert(pNetIO == this);
2775 #ifdef C4NETIO_DEBUG
2776  // log it
2777  DebugLogPkt(false, Packet);
2778 #endif
2779  // save packet?
2780  if (fSavePacket)
2781  {
2782  LastPacket.Copy(Packet);
2783  return;
2784  }
2785  // looped back?
2787  if (Packet.getAddr() == MCLoopbackAddr)
2788  return;
2789  // loopback test packet? ignore
2790  if ((Packet.getStatus() & 0x7F) == IPID_Test) return;
2791  // address add? process directly
2792 
2793  // find out who's responsible
2794  Peer *pPeer = GetPeer(Packet.getAddr());
2795  // new connection?
2796  if (!pPeer)
2797  {
2798  // ping? answer without creating a connection
2799  if ((Packet.getStatus() & 0x7F) == IPID_Ping)
2800  {
2801  PacketHdr PingPacket = { uint8_t(IPID_Ping | (Packet.getStatus() & 0x80)), 0 };
2802  SendDirect(C4NetIOPacket(&PingPacket, sizeof(PingPacket), false, Packet.getAddr()));
2803  return;
2804  }
2805  // conn? create connection (du only!)
2806  else if (Packet.getStatus() == IPID_Conn)
2807  {
2808  pPeer = ConnectPeer(Packet.getAddr(), false);
2809  if (!pPeer) return;
2810  }
2811  // ignore all other packets
2812  }
2813  else
2814  {
2815  // address add?
2816  if (Packet.getStatus() == IPID_AddAddr)
2817  { OnAddAddress(Packet.getAddr(), *getBufPtr<AddAddrPacket>(Packet)); return; }
2818 
2819  // forward to Peer object
2820  pPeer->OnRecv(Packet);
2821  }
2822 }
2823 
2824 bool C4NetIOUDP::OnConn(const addr_t &AddrPeer, const addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO)
2825 {
2826  // ignore
2827  return true;
2828 }
2829 
2830 void C4NetIOUDP::OnDisconn(const addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason)
2831 {
2832  assert(pNetIO == this);
2833 
2834  // C4NetIOSimple thinks the given address is no-good and we shouldn't consider
2835  // any connection to this address valid.
2836 
2837  // So let's check wether we have some peer there
2838  Peer *pPeer = GetPeer(AddrPeer);
2839  if (!pPeer) return;
2840 
2841  // And close him (this will issue another callback)
2842  pPeer->Close(szReason);
2843 }
2844 
2845 void C4NetIOUDP::OnAddAddress(const addr_t &FromAddr, const AddAddrPacket &Packet)
2846 {
2847  // Security (this would be strange behavior indeed...)
2848  if (FromAddr != Packet.Addr && FromAddr != Packet.NewAddr) return;
2849  // Search peer(s)
2850  Peer *pPeer = GetPeer(Packet.Addr);
2851  Peer *pPeer2 = GetPeer(Packet.NewAddr);
2852  // Equal or not found? Nothing to do...
2853  if (!pPeer || pPeer == pPeer2) return;
2854  // Save alternate address
2855  pPeer->SetAltAddr(Packet.NewAddr);
2856  // Close superflous connection
2857  // (this will generate a close-packet, which will be ignored by the peer)
2858  pPeer2->Close("address equivalence detected");
2859 }
2860 
2861 // * C4NetIOUDP::Packet
2862 
2863 // construction / destruction
2864 
2866  : iNr(~0),
2867  Data()
2868 {
2869 
2870 }
2871 
2873  : iNr(inNr),
2874  Data(rnData),
2875  pFragmentGot(nullptr)
2876 {
2877 
2878 }
2879 
2881 {
2882  delete [] pFragmentGot; pFragmentGot = nullptr;
2883 }
2884 
2885 // implementation
2886 
2887 const size_t C4NetIOUDP::Packet::MaxSize = 512;
2888 const size_t C4NetIOUDP::Packet::MaxDataSize = MaxSize - sizeof(DataPacketHdr);
2889 
2891 {
2892  return Data.getSize() ? (Data.getSize() - 1) / MaxDataSize + 1 : 1;
2893 }
2894 
2895 C4NetIOPacket C4NetIOUDP::Packet::GetFragment(nr_t iFNr, bool fBroadcastFlag) const
2896 {
2897  assert(iFNr < FragmentCnt());
2898  // create buffer
2899  uint16_t iFragmentSize = FragmentSize(iFNr);
2900  StdBuf Packet; Packet.New(sizeof(DataPacketHdr) + iFragmentSize);
2901  // set up header
2902  DataPacketHdr *pnHdr = getMBufPtr<DataPacketHdr>(Packet);
2903  pnHdr->StatusByte = IPID_Data | (fBroadcastFlag ? 0x80 : 0x00);
2904  pnHdr->Nr = iNr + iFNr;
2905  pnHdr->FNr = iNr;
2906  pnHdr->Size = Data.getSize();
2907  // copy data
2908  Packet.Write(Data.getPart(iFNr * MaxDataSize, iFragmentSize),
2909  sizeof(DataPacketHdr));
2910  // return
2911  return C4NetIOPacket(Packet, Data.getAddr());
2912 }
2913 
2915 {
2916  if (Empty()) return false;
2917  for (unsigned int i = 0; i < FragmentCnt(); i++)
2918  if (!FragmentPresent(i))
2919  return false;
2920  return true;
2921 }
2922 
2923 bool C4NetIOUDP::Packet::FragmentPresent(uint32_t iFNr) const
2924 {
2925  return !Empty() && iFNr < FragmentCnt() && (!pFragmentGot || pFragmentGot[iFNr]);
2926 }
2927 
2929 {
2930  // ensure the packet is big enough
2931  if (Packet.getSize() < sizeof(DataPacketHdr)) return false;
2932  size_t iPacketDataSize = Packet.getSize() - sizeof(DataPacketHdr);
2933  // get header
2934  const DataPacketHdr *pHdr = getBufPtr<DataPacketHdr>(Packet);
2935  // first fragment got?
2936  bool fFirstFragment = Empty();
2937  if (fFirstFragment)
2938  {
2939  // init
2940  iNr = pHdr->FNr;
2941  Data.New(pHdr->Size); Data.SetAddr(addr);
2942  // fragmented? create fragment list
2943  if (FragmentCnt() > 1)
2944  memset(pFragmentGot = new bool [FragmentCnt()], false, FragmentCnt());
2945  // check header
2946  if (pHdr->Nr < iNr || pHdr->Nr >= iNr + FragmentCnt()) { Data.Clear(); return false; }
2947  }
2948  else
2949  {
2950  // check header
2951  if (pHdr->FNr != iNr) return false;
2952  if (pHdr->Size != Data.getSize()) return false;
2953  if (pHdr->Nr < iNr || pHdr->Nr >= iNr + FragmentCnt()) return false;
2954  }
2955  // check packet size
2956  nr_t iFNr = pHdr->Nr - iNr;
2957  if (iPacketDataSize != FragmentSize(iFNr)) return false;
2958  // already got this fragment? (needs check for first packet as FragmentPresent always assumes true if pFragmentGot is nullptr)
2959  StdBuf PacketData = Packet.getPart(sizeof(DataPacketHdr), iPacketDataSize);
2960  if (!fFirstFragment && FragmentPresent(iFNr))
2961  {
2962  // compare
2963  if (Data.Compare(PacketData, iFNr * MaxDataSize))
2964  return false;
2965  }
2966  else
2967  {
2968  // otherwise: copy data
2969  Data.Write(PacketData, iFNr * MaxDataSize);
2970  // set flag (if fragmented)
2971  if (pFragmentGot)
2972  pFragmentGot[iFNr] = true;
2973  // shouldn't happen
2974  else
2975  assert(Complete());
2976  }
2977  // ok
2978  return true;
2979 }
2980 
2982 {
2983  assert(iFNr < FragmentCnt());
2984  return std::min(MaxDataSize, Data.getSize() - iFNr * MaxDataSize);
2985 }
2986 
2987 // * C4NetIOUDP::PacketList
2988 
2989 // construction / destruction
2990 
2991 C4NetIOUDP::PacketList::PacketList(unsigned int inMaxPacketCnt)
2992  : iMaxPacketCnt(inMaxPacketCnt)
2993 {
2994 
2995 }
2996 
2998 {
2999  Clear();
3000 }
3001 
3003 {
3004  CStdShareLock ListLock(&ListCSec);
3005  for (Packet *pPkt = pBack; pPkt; pPkt = pPkt->Prev)
3006  if (pPkt->GetNr() == iNr)
3007  return pPkt;
3008  else if (pPkt->GetNr() < iNr)
3009  return nullptr;
3010  return nullptr;
3011 }
3012 
3014 {
3015  CStdShareLock ListLock(&ListCSec);
3016  for (Packet *pPkt = pBack; pPkt; pPkt = pPkt->Prev)
3017  if (pPkt->GetNr() <= iNr && pPkt->GetNr() + pPkt->FragmentCnt() > iNr)
3018  return pPkt;
3019  else if (pPkt->GetNr() < iNr)
3020  return nullptr;
3021  return nullptr;
3022 }
3023 
3025 {
3026  CStdShareLock ListLock(&ListCSec);
3027  return pFront && pFront->Complete() ? pFront : nullptr;
3028 }
3029 
3031 {
3032  CStdShareLock ListLock(&ListCSec);
3033  Packet *pPkt = GetPacketFrgm(iNr);
3034  return pPkt ? pPkt->FragmentPresent(iNr - pPkt->GetNr()) : false;
3035 }
3036 
3038 {
3039  CStdLock ListLock(&ListCSec);
3040  // find insert location
3041  Packet *pInsertAfter = pBack, *pInsertBefore = nullptr;
3042  for (; pInsertAfter; pInsertBefore = pInsertAfter, pInsertAfter = pInsertAfter->Prev)
3043  if (pInsertAfter->GetNr() + pInsertAfter->FragmentCnt() <= pPacket->GetNr())
3044  break;
3045  // check: enough space?
3046  if (pInsertBefore && pInsertBefore->GetNr() < pPacket->GetNr() + pPacket->FragmentCnt())
3047  return false;
3048  // insert
3049  (pInsertAfter ? pInsertAfter->Next : pFront) = pPacket;
3050  (pInsertBefore ? pInsertBefore->Prev : pBack) = pPacket;
3051  pPacket->Next = pInsertBefore;
3052  pPacket->Prev = pInsertAfter;
3053  // count packets, check limit
3054  ++iPacketCnt;
3055  while (iPacketCnt > iMaxPacketCnt)
3056  DeletePacket(pFront);
3057  // ok
3058  return true;
3059 }
3060 
3062 {
3063  CStdLock ListLock(&ListCSec);
3064 #ifdef _DEBUG
3065  // check: this list?
3066  Packet *pPos = pPacket;
3067  while (pPos && pPos != pFront) pPos = pPos->Prev;
3068  assert(pPos);
3069 #endif
3070  // unlink packet
3071  (pPacket->Prev ? pPacket->Prev->Next : pFront) = pPacket->Next;
3072  (pPacket->Next ? pPacket->Next->Prev : pBack) = pPacket->Prev;
3073  // delete packet
3074  delete pPacket;
3075  // decrease count
3076  --iPacketCnt;
3077  // ok
3078  return true;
3079 }
3080 
3081 void C4NetIOUDP::PacketList::ClearPackets(unsigned int iUntil)
3082 {
3083  CStdLock ListLock(&ListCSec);
3084  while (pFront && pFront->GetNr() < iUntil)
3085  DeletePacket(pFront);
3086 }
3087 
3089 {
3090  CStdLock ListLock(&ListCSec);
3091  while (iPacketCnt)
3092  DeletePacket(pFront);
3093 }
3094 
3095 // * C4NetIOUDP::Peer
3096 
3097 // constants
3098 
3099 const unsigned int C4NetIOUDP::Peer::iConnectRetries = 5;
3100 const unsigned int C4NetIOUDP::Peer::iReCheckInterval = 1000; // (ms)
3101 
3102 // construction / destruction
3103 
3104 C4NetIOUDP::Peer::Peer(const addr_t &naddr, C4NetIOUDP *pnParent)
3105  : pParent(pnParent), addr(naddr),
3106  eStatus(CS_None),
3107  fMultiCast(false), fDoBroadcast(false),
3109  iOPacketCounter(0),
3110  iIPacketCounter(0), iRIPacketCounter(0),
3111  iIMCPacketCounter(0), iRIMCPacketCounter(0),
3112  iMCAckPacketCounter(0),
3113  tNextReCheck(C4TimeMilliseconds::NegativeInfinity),
3114  iIRate(0), iORate(0), iLoss(0)
3115 {
3116 }
3117 
3119 {
3120  // send close-packet
3121  Close("deleted");
3122 }
3123 
3124 bool C4NetIOUDP::Peer::Connect(bool fFailCallback) // (mt-safe)
3125 {
3126  // initiate connection (DoConn will set status CS_Conn)
3127  fMultiCast = false; fConnFailCallback = fFailCallback;
3128  return DoConn(false);
3129 }
3130 
3131 bool C4NetIOUDP::Peer::Send(const C4NetIOPacket &rPacket) // (mt-safe)
3132 {
3133  CStdLock OutLock(&OutCSec);
3134  // encapsulate packet
3135  Packet *pnPacket = new Packet(rPacket.Duplicate(), iOPacketCounter);
3136  iOPacketCounter += pnPacket->FragmentCnt();
3137  pnPacket->GetData().SetAddr(addr);
3138  // add it to outgoing packet stack
3139  if (!OPackets.AddPacket(pnPacket))
3140  return false;
3141  // This should be ensured by calling function anyway.
3142  // It is not secure to send packets before the connection
3143  // is etablished completly.
3144  if (eStatus != CS_Works) return true;
3145  // send it
3146  if (!SendDirect(*pnPacket)) {
3147  Close("failed to send packet");
3148  return false;
3149  }
3150  return true;
3151 }
3152 
3153 bool C4NetIOUDP::Peer::Check(bool fForceCheck)
3154 {
3155  // only on working connections
3156  if (eStatus != CS_Works) return true;
3157  // prevent re-check (check floods)
3158  // instead, ask for other packets that are missing until recheck is allowed
3159  bool fNoReCheck = tNextReCheck > C4TimeMilliseconds::Now();
3160  if (!fNoReCheck) iLastPacketAsked = iLastMCPacketAsked = 0;
3161  unsigned int iStartAt = fNoReCheck ? std::max(iLastPacketAsked + 1, iIPacketCounter) : iIPacketCounter;
3162  unsigned int iStartAtMC = fNoReCheck ? std::max(iLastMCPacketAsked + 1, iIMCPacketCounter) : iIMCPacketCounter;
3163  // check if we have something to ask for
3164  const unsigned int iMaxAskCnt = 10;
3165  unsigned int i, iAskList[iMaxAskCnt], iAskCnt = 0, iMCAskCnt = 0;
3166  for (i = iStartAt; i < iRIPacketCounter; i++)
3167  if (!IPackets.FragmentPresent(i))
3168  if (iAskCnt < iMaxAskCnt)
3169  iLastPacketAsked = iAskList[iAskCnt++] = i;
3170  for (i = iStartAtMC; i < iRIMCPacketCounter; i++)
3171  if (!IMCPackets.FragmentPresent(i))
3172  if (iAskCnt + iMCAskCnt < iMaxAskCnt)
3173  iLastMCPacketAsked = iAskList[iAskCnt + iMCAskCnt++] = i;
3174  int iEAskCnt = iAskCnt + iMCAskCnt;
3175  // no re-check limit? set it
3176  if (!fNoReCheck)
3177  {
3178  if (iEAskCnt)
3179  tNextReCheck = C4TimeMilliseconds::Now() + iReCheckInterval;
3180  else
3181  tNextReCheck = C4TimeMilliseconds::NegativeInfinity;
3182  }
3183  // something to ask for? (or check forced?)
3184  if (iEAskCnt || fForceCheck)
3185  return DoCheck(iAskCnt, iMCAskCnt, iAskList);
3186  return true;
3187 }
3188 
3189 void C4NetIOUDP::Peer::OnRecv(const C4NetIOPacket &rPacket) // (mt-safe)
3190 {
3191  // statistics
3192  { CStdLock StatLock(&StatCSec); iIRate += rPacket.getSize() + iUDPHeaderSize; }
3193  // get packet header
3194  if (rPacket.getSize() < sizeof(PacketHdr)) return;
3195  const PacketHdr *pHdr = getBufPtr<PacketHdr>(rPacket);
3196  bool fBroadcasted = !!(pHdr->StatusByte & 0x80);
3197  // save packet nr
3198  (fBroadcasted ? iRIMCPacketCounter : iRIPacketCounter) = std::max<unsigned int>((fBroadcasted ? iRIMCPacketCounter : iRIPacketCounter), pHdr->Nr);
3199 #ifdef C4NETIOUDP_OPT_RECV_CHECK_IMMEDIATE
3200  // do check
3201  if (eStatus == CS_Works)
3202  Check(false);
3203 #endif
3204  // what type of packet is it?
3205  switch (pHdr->StatusByte & 0x7f)
3206  {
3207 
3208  case IPID_Conn:
3209  {
3210  // check size
3211  if (rPacket.getSize() != sizeof(ConnPacket)) break;
3212  const ConnPacket *pPkt = getBufPtr<ConnPacket>(rPacket);
3213  // right version?
3214  if (pPkt->ProtocolVer != pParent->iVersion) break;
3215  if (!fBroadcasted)
3216  {
3217  // Second connection attempt using different address?
3218  if (!PeerAddr.IsNull() && PeerAddr != pPkt->Addr)
3219  {
3220  // Notify peer that he has two addresses to reach this connection.
3221  AddAddrPacket Pkt;
3222  Pkt.StatusByte = IPID_AddAddr;
3223  Pkt.Nr = iOPacketCounter;
3224  Pkt.Addr = PeerAddr;
3225  Pkt.NewAddr = pPkt->Addr;
3226  SendDirect(C4NetIOPacket(&Pkt, sizeof(Pkt), false, addr));
3227  // But do nothing else - don't interfere with this connection
3228  break;
3229  }
3230  // reinit?
3231  else if (eStatus == CS_Works && iIPacketCounter != pPkt->Nr)
3232  {
3233  // close (callback!) ...
3234  OnClose("reconnect"); eStatus = CS_Closed;
3235  // ... and reconnect
3236  Connect(false);
3237  }
3238  // save back the address the peer is using
3239  PeerAddr = pPkt->Addr;
3240  }
3241  // set packet counter
3242  if (fBroadcasted)
3243  iRIMCPacketCounter = iIMCPacketCounter = pPkt->Nr;
3244  else
3245  iRIPacketCounter = iIPacketCounter = pPkt->Nr;
3246  // clear incoming packets
3247  IPackets.Clear();
3248  IMCPackets.Clear();
3249 
3250  tNextReCheck = C4TimeMilliseconds::NegativeInfinity;
3251 
3252  iLastPacketAsked = iLastMCPacketAsked = 0;
3253  // Activate Multicast?
3254  if (!pParent->fMultiCast)
3255  {
3256  addr_t MCAddr = pPkt->MCAddr;
3257  if (!MCAddr.IsNull())
3258  {
3259  // Init Broadcast (with delayed loopback test)
3260  pParent->fDelayedLoopbackTest = true;
3261  if (!pParent->InitBroadcast(&MCAddr))
3262  pParent->fDelayedLoopbackTest = false;
3263  }
3264  }
3265  // build ConnOk Packet
3266  ConnOKPacket nPack;
3267  bool fullyConnected = false;
3268 
3269  nPack.StatusByte = IPID_ConnOK; // (always du, no mc experiments here)
3270  nPack.Nr = fBroadcasted ? pParent->iOPacketCounter : iOPacketCounter;
3271  nPack.Addr = addr;
3272  if (fBroadcasted)
3273  nPack.MCMode = ConnOKPacket::MCM_MCOK; // multicast send ok
3274  else if (pParent->fMultiCast && addr.GetPort() == pParent->iPort)
3275  nPack.MCMode = ConnOKPacket::MCM_MC; // du ok, try multicast next
3276  else
3277  {
3278  nPack.MCMode = ConnOKPacket::MCM_NoMC; // du ok
3279  // no multicast => we're fully connected now
3280  fullyConnected = true;
3281  }
3282  // send it
3283  SendDirect(C4NetIOPacket(&nPack, sizeof(nPack), false, addr));
3284  // Clients will try sending data from OnConn, so send ConnOK before that.
3285  if (fullyConnected) OnConn();
3286  }
3287  break;
3288 
3289  case IPID_ConnOK:
3290  {
3291  if (eStatus != CS_Conn) break;
3292  // check size
3293  if (rPacket.getSize() != sizeof(ConnOKPacket)) break;
3294  const ConnOKPacket *pPkt = getBufPtr<ConnOKPacket>(rPacket);
3295  // save port
3296  PeerAddr = pPkt->Addr;
3297  // Needs another Conn/ConnOK-sequence?
3298  switch (pPkt->MCMode)
3299  {
3300  case ConnOKPacket::MCM_MC:
3301  // multicast has to be active
3302  if (pParent->fMultiCast)
3303  {
3304  // already trying to connect via multicast?
3305  if (fMultiCast) break;
3306  // Send another Conn packet back (this time broadcasted to check if multicast works)
3307  fMultiCast = true; DoConn(true);
3308  break;
3309  }
3310  // fallthru
3312  // Connection is established (no multicast support)
3313  fMultiCast = false; OnConn();
3314  break;
3316  // Connection is established (multicast support)
3317  fMultiCast = true; OnConn();
3318  break;
3319  }
3320  }
3321  break;
3322 
3323  case IPID_Data:
3324  {
3325  // get the packet header
3326  if (rPacket.getSize() < sizeof(DataPacketHdr)) return;
3327  const DataPacketHdr *pHdr = getBufPtr<DataPacketHdr>(rPacket);
3328  // already complet?
3329  if (pHdr->Nr < (fBroadcasted ? iIMCPacketCounter : iIPacketCounter)) break;
3330  // find or create packet
3331  bool fAddPacket = false;
3332  PacketList *pPacketList = fBroadcasted ? &IMCPackets : &IPackets;
3333  Packet *pPkt = pPacketList->GetPacket(pHdr->FNr);
3334  if (!pPkt) { pPkt = new Packet(); fAddPacket = true; }
3335  // add the fragment
3336  if (pPkt->AddFragment(rPacket, addr))
3337  {
3338  // add the packet to list
3339  if (fAddPacket) if (!pPacketList->AddPacket(pPkt)) { delete pPkt; break; }
3340  // check for complete packets
3341  CheckCompleteIPackets();
3342  }
3343  else
3344  // delete the packet
3345  if (fAddPacket) delete pPkt;
3346  }
3347  break;
3348 
3349  case IPID_Check:
3350  {
3351  // get the packet header
3352  if (rPacket.getSize() < sizeof(CheckPacketHdr)) break;
3353  const CheckPacketHdr *pPkt = getBufPtr<CheckPacketHdr>(rPacket);
3354  // check packet size
3355  if (rPacket.getSize() < sizeof(CheckPacketHdr) + (pPkt->AskCount + pPkt->MCAskCount) * sizeof(int)) break;
3356  // clear all acknowledged packets
3357  CStdLock OutLock(&OutCSec);
3358  OPackets.ClearPackets(pPkt->AckNr);
3359  if (pPkt->MCAckNr > iMCAckPacketCounter)
3360  {
3361  iMCAckPacketCounter = pPkt->MCAckNr;
3362  pParent->ClearMCPackets();
3363  }
3364  OutLock.Clear();
3365  // read ask list
3366  const int *pAskList = getBufPtr<int>(rPacket, sizeof(CheckPacketHdr));
3367  // send the packets he asks for
3368  unsigned int i;
3369  for (i = 0; i < pPkt->AskCount + pPkt->MCAskCount; i++)
3370  {
3371  // packet available?
3372  bool fMCPacket = i >= pPkt->AskCount;
3373  CStdLock OutLock(fMCPacket ? &pParent->OutCSec : &OutCSec);
3374  Packet *pPkt2Send = (fMCPacket ? pParent->OPackets : OPackets).GetPacketFrgm(pAskList[i]);
3375  if (!pPkt2Send) { Close("starvation"); break; }
3376  // send the fragment
3377  if (fMCPacket)
3378  pParent->BroadcastDirect(*pPkt2Send, pAskList[i]);
3379  else
3380  SendDirect(*pPkt2Send, pAskList[i]);
3381  }
3382  }
3383  break;
3384 
3385  case IPID_Close:
3386  {
3387  // check packet size
3388  if (rPacket.getSize() < sizeof(ClosePacket)) break;
3389  const ClosePacket *pPkt = getBufPtr<ClosePacket>(rPacket);
3390  // ignore if it's for another address
3391  if (!PeerAddr.IsNull() && PeerAddr != pPkt->Addr)
3392  break;
3393  // close
3394  OnClose("connection closed by peer");
3395  }
3396  break;
3397 
3398  }
3399 }
3400 
3401 void C4NetIOUDP::Peer::Close(const char *szReason) // (mt-safe)
3402 {
3403  // already closed?
3404  if (eStatus == CS_Closed)
3405  return;
3406  // send close-packet
3407  ClosePacket Pkt;
3408  Pkt.StatusByte = IPID_Close;
3409  Pkt.Nr = 0;
3410  Pkt.Addr = addr;
3411  SendDirect(C4NetIOPacket(&Pkt, sizeof(Pkt), false, addr));
3412  // callback
3413  OnClose(szReason);
3414 }
3415 
3417 {
3418  // check
3419  if (C4TimeMilliseconds::Now() > tTimeout)
3420  OnTimeout();
3421 }
3422 
3424 {
3425  CStdLock StatLock(&StatCSec);
3426  iIRate = iORate = 0;
3427  iLoss = 0;
3428 }
3429 
3430 bool C4NetIOUDP::Peer::DoConn(bool fMC) // (mt-safe)
3431 {
3432  // set status
3433  eStatus = CS_Conn;
3434  // set timeout
3435  SetTimeout(iStdTimeout, iConnectRetries);
3436  // send packet (include current outgoing packet counter and mc addr)
3437  ConnPacket Pkt;
3438  Pkt.StatusByte = uint8_t(IPID_Conn) | (fMC ? 0x80 : 0x00);
3439  Pkt.ProtocolVer = pParent->iVersion;
3440  Pkt.Nr = fMC ? pParent->iOPacketCounter : iOPacketCounter;
3441  Pkt.Addr = addr;
3442  if (pParent->fMultiCast)
3443  Pkt.MCAddr = pParent->C4NetIOSimpleUDP::getMCAddr();
3444  else
3445  Pkt.MCAddr = C4NetIO::addr_t();
3446  return SendDirect(C4NetIOPacket(&Pkt, sizeof(Pkt), false, addr));
3447 }
3448 
3449 bool C4NetIOUDP::Peer::DoCheck(int iAskCnt, int iMCAskCnt, unsigned int *pAskList)
3450 {
3451  // security
3452  if (!pAskList) iAskCnt = iMCAskCnt = 0;
3453  // statistics
3454  { CStdLock StatLock(&StatCSec); iLoss += iAskCnt + iMCAskCnt; }
3455  // alloc data
3456  int iAskListSize = (iAskCnt + iMCAskCnt) * sizeof(*pAskList);
3457  StdBuf Packet; Packet.New(sizeof(CheckPacketHdr) + iAskListSize);
3458  CheckPacketHdr *pChkPkt = getMBufPtr<CheckPacketHdr>(Packet);
3459  // set up header
3460  pChkPkt->StatusByte = IPID_Check; // (note: always du here, see C4NetIOUDP::DoCheck)
3461  pChkPkt->Nr = iOPacketCounter;
3462  pChkPkt->AckNr = iIPacketCounter;
3463  pChkPkt->MCAckNr = iIMCPacketCounter;
3464  // copy ask list
3465  pChkPkt->AskCount = iAskCnt;
3466  pChkPkt->MCAskCount = iMCAskCnt;
3467  if (pAskList)
3468  Packet.Write(pAskList, iAskListSize, sizeof(CheckPacketHdr));
3469  // send packet
3470  return SendDirect(C4NetIOPacket(Packet, addr));
3471 }
3472 
3473 bool C4NetIOUDP::Peer::SendDirect(const Packet &rPacket, unsigned int iNr)
3474 {
3475  // send one fragment only?
3476  if (iNr + 1)
3477  return SendDirect(rPacket.GetFragment(iNr - rPacket.GetNr()));
3478  // otherwise: send all fragments
3479  bool fSuccess = true;
3480  for (unsigned int i = 0; i < rPacket.FragmentCnt(); i++)
3481  fSuccess &= SendDirect(rPacket.GetFragment(i));
3482  return fSuccess;
3483 }
3484 
3485 bool C4NetIOUDP::Peer::SendDirect(C4NetIOPacket &&rPacket) // (mt-safe)
3486 {
3487  // insert correct addr
3488  C4NetIO::addr_t v6Addr(addr.AsIPv6());
3489  if (!(rPacket.getStatus() & 0x80)) rPacket.SetAddr(v6Addr);
3490  // count outgoing
3491  { CStdLock StatLock(&StatCSec); iORate += rPacket.getSize() + iUDPHeaderSize; }
3492  // forward call
3493  return pParent->SendDirect(std::move(rPacket));
3494 }
3495 
3497 {
3498  // reset timeout
3499  SetTimeout(TO_INF);
3500  // set status
3501  eStatus = CS_Works;
3502  // do callback
3503  C4NetIO::CBClass *pCB = pParent->pCB;
3504  if (pCB && !pCB->OnConn(addr, addr, &PeerAddr, pParent))
3505  {
3506  Close("closed");
3507  return;
3508  }
3509  // do packet callback (in case the peer sent data while the connection was in progress)
3510  CheckCompleteIPackets();
3511 }
3512 
3513 void C4NetIOUDP::Peer::OnClose(const char *szReason) // (mt-safe)
3514 {
3515  // do callback
3516  C4NetIO::CBClass *pCB = pParent->pCB;
3517  if (eStatus == CS_Works || (eStatus == CS_Conn && fConnFailCallback))
3518  if (pCB)
3519  pCB->OnDisconn(addr, pParent, szReason);
3520  // set status (this will schedule this peer for deletion)
3521  eStatus = CS_Closed;
3522 }
3523 
3525 {
3526  // only status CS_Works
3527  if (eStatus != CS_Works) return;
3528  // (If the status is CS_Conn, we'll have to wait until the connection in the
3529  // opposite direction is etablished. There is no problem in checking for
3530  // complete packets here, but the one using the interface may get very confused
3531  // if he gets a callback for a connection that hasn't been announced to him
3532  // yet)
3533 
3534  // check for complete incoming packets
3535  Packet *pPkt;
3536  while ((pPkt = IPackets.GetFirstPacketComplete()))
3537  {
3538  // missing packet?
3539  if (pPkt->GetNr() != iIPacketCounter) break;
3540  // do callback
3541  if (pParent->pCB)
3542  pParent->pCB->OnPacket(pPkt->GetData(), pParent);
3543  // advance packet counter
3544  iIPacketCounter = pPkt->GetNr() + pPkt->FragmentCnt();
3545  // remove packet from queue
3546  int iNr = pPkt->GetNr();
3547  IPackets.DeletePacket(pPkt);
3548  assert(!IPackets.GetPacketFrgm(iNr)); (void)iNr;
3549  }
3550  while ((pPkt = IMCPackets.GetFirstPacketComplete()))
3551  {
3552  // missing packet?
3553  if (pPkt->GetNr() != iIMCPacketCounter) break;
3554  // do callback
3555  if (pParent->pCB)
3556  pParent->pCB->OnPacket(pPkt->GetData(), pParent);
3557  // advance packet counter
3558  iIMCPacketCounter = pPkt->GetNr() + pPkt->FragmentCnt();
3559  // remove packet from queue
3560  int iNr = pPkt->GetNr();
3561  IMCPackets.DeletePacket(pPkt);
3562  assert(!IMCPackets.GetPacketFrgm(iNr)); (void)iNr;
3563  }
3564 }
3565 
3566 void C4NetIOUDP::Peer::SetTimeout(int iLength, int iRetryCnt) // (mt-safe)
3567 {
3568  if (iLength != TO_INF)
3569  {
3570  tTimeout = C4TimeMilliseconds::Now() + iLength;
3571  }
3572  else
3573  {
3575  }
3576  iRetries = iRetryCnt;
3577 }
3578 
3580 {
3581  // what state?
3582  if (eStatus == CS_Conn)
3583  {
3584  // retries left?
3585  if (iRetries)
3586  {
3587  int iRetryCnt = iRetries - 1;
3588  // call DoConn (will set timeout)
3589  DoConn(fMultiCast);
3590  // set retry count
3591  iRetries = iRetryCnt;
3592  return;
3593  }
3594  // connection timeout: close
3595  Close("connection timeout");
3596  }
3597  // reset timeout
3598  SetTimeout(TO_INF);
3599 }
3600 
3601 // * C4NetIOUDP: implementation
3602 
3603 bool C4NetIOUDP::BroadcastDirect(const Packet &rPacket, unsigned int iNr) // (mt-safe)
3604 {
3605  // only one fragment?
3606  if (iNr + 1)
3607  return SendDirect(rPacket.GetFragment(iNr - rPacket.GetNr(), true));
3608  // send all fragments
3609  bool fSuccess = true;
3610  for (unsigned int iFrgm = 0; iFrgm < rPacket.FragmentCnt(); iFrgm++)
3611  fSuccess &= SendDirect(rPacket.GetFragment(iFrgm, true));
3612  return fSuccess;
3613 }
3614 
3615 bool C4NetIOUDP::SendDirect(C4NetIOPacket &&rPacket) // (mt-safe)
3616 {
3617  addr_t toaddr = rPacket.getAddr();
3618  // packet meant to be broadcasted?
3619  if (rPacket.getStatus() & 0x80)
3620  {
3621  // set addr
3622  toaddr = C4NetIOSimpleUDP::getMCAddr();
3623  // statistics
3624  CStdLock StatLock(&StatCSec);
3625  iBroadcastRate += rPacket.getSize() + iUDPHeaderSize;
3626  }
3627 
3628  // debug
3629 #ifdef C4NETIO_DEBUG
3630  { C4NetIOPacket Pkt2 = rPacket; Pkt2.SetAddr(toaddr); DebugLogPkt(true, Pkt2); }
3631 #endif
3632 
3633 #ifdef C4NETIO_SIMULATE_PACKETLOSS
3634  if ((rPacket.getStatus() & 0x7F) != IPID_Test)
3635  if (UnsyncedRandom(100) < C4NETIO_SIMULATE_PACKETLOSS) return true;
3636 #endif
3637 
3638  // send it
3639  return C4NetIOSimpleUDP::Send(C4NetIOPacket(rPacket.getRef(), toaddr));
3640 }
3641 
3643 {
3644  // (try to) enable loopback
3646  // ensure loopback is activate
3647  if (!C4NetIOSimpleUDP::getMCLoopback()) return false;
3648 
3649  // send test packet
3650  const PacketHdr TestPacket = { uint8_t(IPID_Test | 0x80), UnsyncedRandom(UINT32_MAX) };
3651  if (!C4NetIOSimpleUDP::Broadcast(C4NetIOPacket(&TestPacket, sizeof(TestPacket))))
3652  return false;
3653 
3654  // wait for socket to become readable (should happen immediatly, do not expect packet loss)
3655  fSavePacket = true;
3657  {
3658  fSavePacket = false;
3659  if (!GetError()) SetError("Multicast disabled: loopback test failed");
3660  return false;
3661  }
3662  fSavePacket = false;
3663 
3664  // compare it to the packet that was sent
3665  if (LastPacket.getSize() != sizeof(TestPacket) ||
3666  LastPacket.Compare(&TestPacket, sizeof(TestPacket)))
3667  {
3668  SetError("Multicast disabled: loopback test failed");
3669  return false;
3670  }
3671 
3672  // save the loopback addr back
3674 
3675  // disable loopback
3677  // ok
3678  return true;
3679 }
3680 
3682 {
3683  CStdShareLock PeerListLock(&PeerListCSec);
3684  CStdLock OutLock(&OutCSec);
3685  // clear packets if no client is present
3686  if (!pPeerList)
3687  OPackets.Clear();
3688  else
3689  {
3690  // find minimum acknowledged packet number
3691  unsigned int iAckNr = pPeerList->GetMCAckPacketCounter();
3692  for (Peer *pPeer = pPeerList->Next; pPeer; pPeer = pPeer->Next)
3693  iAckNr = std::min(iAckNr, pPeerList->GetMCAckPacketCounter());
3694  // clear packets
3695  OPackets.ClearPackets(iAckNr);
3696  }
3697 }
3698 
3700 {
3701  // get locks
3702  CStdShareLock PeerListLock(&PeerListCSec);
3703  CStdLock PeerListAddLock(&PeerListAddCSec);
3704  // add
3705  pPeer->Next = pPeerList;
3706  pPeerList = pPeer;
3707  Changed();
3708 }
3709 
3711 {
3712  if (pCSec == &PeerListCSec)
3713  {
3714  Peer *pPeer = pPeerList, *pLast = nullptr;
3715  while (pPeer)
3716  {
3717  // delete?
3718  if (pPeer->Closed())
3719  {
3720  // unlink
3721  Peer *pDelete = pPeer;
3722  (pLast ? pLast->Next : pPeerList) = pPeer = pPeer->Next;
3723  // delete
3724  delete pDelete;
3725  }
3726  else
3727  {
3728  // next peer
3729  pLast = pPeer;
3730  pPeer = pPeer->Next;
3731  }
3732  }
3733  }
3734 }
3735 
3737 {
3738  CStdShareLock PeerListLock(&PeerListCSec);
3739  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
3740  if (!pPeer->Closed())
3741  if (pPeer->GetAddr() == addr || pPeer->GetAltAddr() == addr)
3742  return pPeer;
3743  return nullptr;
3744 }
3745 
3746 C4NetIOUDP::Peer *C4NetIOUDP::ConnectPeer(const addr_t &PeerAddr, bool fFailCallback) // (mt-safe)
3747 {
3748  CStdShareLock PeerListLock(&PeerListCSec);
3749  // lock so no new peer can be added after this point
3750  CStdLock PeerListAddLock(&PeerListAddCSec);
3751  // recheck: address already known?
3752  Peer *pnPeer = GetPeer(PeerAddr);
3753  if (pnPeer) return pnPeer;
3754  // create new Peer class
3755  pnPeer = new Peer(PeerAddr, this);
3756  if (!pnPeer) return nullptr;
3757  // add peer to list
3758  AddPeer(pnPeer);
3759  PeerListAddLock.Clear();
3760  // send connection request
3761  if (!pnPeer->Connect(fFailCallback)) { pnPeer->Close("connect failed"); return nullptr; }
3762  // ok (do not wait for peer)
3763  return pnPeer;
3764 }
3765 
3766 void C4NetIOUDP::DoCheck() // (mt-safe)
3767 {
3768  CStdShareLock PeerListLock(&PeerListCSec);
3769  // mc connection check?
3770  if (fMultiCast)
3771  {
3772  // only if a peer is connected via multicast
3773  Peer *pPeer;
3774  for (pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
3775  if (pPeer->Open() && pPeer->MultiCast())
3776  break;
3777  if (pPeer)
3778  {
3779  // set up packet
3780  CheckPacketHdr Pkt;
3781  Pkt.StatusByte = uint8_t(IPID_Check | 0x80);
3782  Pkt.Nr = iOPacketCounter;
3783  Pkt.AskCount = Pkt.MCAskCount = 0;
3784  // send it
3785  SendDirect(C4NetIOPacket(&Pkt, sizeof(Pkt)));
3786  }
3787  }
3788  // peer connection checks
3789  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
3790  if (pPeer->Open())
3791  pPeer->Check();
3792 
3793  // set time for next check
3795 }
3796 
3797 // debug
3798 #ifdef C4NETIO_DEBUG
3799 #ifndef _WIN32
3800 #define _O_SEQUENTIAL 0
3801 #define _O_TEXT 0
3802 #endif
3803 void C4NetIOUDP::OpenDebugLog()
3804 {
3805  const char *szFileBase = "NetIOUDP%d.log";
3806  char szFilePath[_MAX_PATH + 1];
3807  for (int i = 0; i < 1000; i++)
3808  {
3809  sprintf(szFilePath, szFileBase, i);
3810  hDebugLog = open(szFilePath, O_CREAT | O_EXCL | O_TRUNC | _O_SEQUENTIAL | _O_TEXT | O_WRONLY, S_IREAD | S_IWRITE);
3811  if (hDebugLog != -1) break;
3812  }
3813  // initial timestamp
3814  if (hDebugLog != -1)
3815  {
3816  char O[1024+1];
3817  time_t tTime; time(&tTime);
3818  struct tm *pLocalTime;
3819  pLocalTime=localtime(&tTime);
3820  if (pLocalTime)
3821  sprintf(O, "C4NetIOUDP debuglog starting at %d/%d/%d %d:%2d:%2d - (Daylight %d)\n",
3822  pLocalTime->tm_mon+1,
3823  pLocalTime->tm_mday,
3824  pLocalTime->tm_year+1900,
3825  pLocalTime->tm_hour,
3826  pLocalTime->tm_min,
3827  pLocalTime->tm_sec,
3828  pLocalTime->tm_isdst);
3829  else sprintf(O, "C4NetIOUDP debuglog; time not available\n");
3830  write(hDebugLog, O, strlen(O));
3831  }
3832 }
3833 
3834 void C4NetIOUDP::CloseDebugLog()
3835 {
3836  close(hDebugLog);
3837 }
3838 
3839 void C4NetIOUDP::DebugLogPkt(bool fOut, const C4NetIOPacket &Pkt)
3840 {
3841  StdStrBuf O;
3842  O.Format("%s %s %s:", fOut ? "out" : "in ",
3843  C4TimeMilliseconds::Now().AsString().getData(),
3844  Pkt.getAddr().ToString().getData());
3845 
3846  // header?
3847  if (Pkt.getSize() >= sizeof(PacketHdr))
3848  {
3849  const PacketHdr &Hdr = *getBufPtr<PacketHdr>(Pkt);
3850 
3851  switch (Hdr.StatusByte & 0x07f)
3852  {
3853  case IPID_Ping: O.Append(" PING"); break;
3854  case IPID_Test: O.Append(" TEST"); break;
3855  case IPID_Conn: O.Append(" CONN"); break;
3856  case IPID_ConnOK: O.Append(" CONO"); break;
3857  case IPID_Data: O.Append(" DATA"); break;
3858  case IPID_Check: O.Append(" CHCK"); break;
3859  case IPID_Close: O.Append(" CLSE"); break;
3860  default: O.Append(" UNKN"); break;
3861  }
3862  O.AppendFormat(" %s %04d", (Hdr.StatusByte & 0x80) ? "MC" : "DU", Hdr.Nr);
3863 
3864 #define UPACK(type) \
3865  const type &P = *getBufPtr<type>(Pkt);
3866 
3867  switch (Hdr.StatusByte)
3868  {
3869  case IPID_Test: { UPACK(TestPacket); O.AppendFormat(" (%d)", P.TestNr); break; }
3870  case IPID_Conn: { UPACK(ConnPacket); O.AppendFormat(" (Ver %d, MC: %s)", P.ProtocolVer, P.MCAddr.ToString().getData()); break; }
3871  case IPID_ConnOK:
3872  {
3873  UPACK(ConnOKPacket);
3874  switch (P.MCMode)
3875  {
3876  case ConnOKPacket::MCM_NoMC: O.Append(" (NoMC)"); break;
3877  case ConnOKPacket::MCM_MC: O.Append(" (MC)"); break;
3878  case ConnOKPacket::MCM_MCOK: O.Append(" (MCOK)"); break;
3879  default: O.Append(" (??""?)");
3880  }
3881  break;
3882  }
3883  case IPID_Data:
3884  {
3885  UPACK(DataPacketHdr); O.AppendFormat(" (f: %d s: %d)", P.FNr, P.Size);
3886  for (int iPos = sizeof(DataPacketHdr); iPos < std::min<int>(Pkt.getSize(), sizeof(DataPacketHdr) + 16); iPos++)
3887  O.AppendFormat(" %02x", *getBufPtr<unsigned char>(Pkt, iPos));
3888  break;
3889  }
3890  case IPID_Check:
3891  {
3892  UPACK(CheckPacketHdr);
3893  O.AppendFormat(" (ack: %d, mcack: %d, ask: %d mcask: %d, ", P.AckNr, P.MCAckNr, P.AskCount, P.MCAskCount);
3894  if (Pkt.getSize() < sizeof(CheckPacketHdr) + sizeof(unsigned int) * (P.AskCount + P.MCAskCount))
3895  O.AppendFormat("too small)");
3896  else
3897  {
3898  O.Append("[");
3899  for (unsigned int i = 0; i < P.AskCount + P.MCAskCount; i++)
3900  O.AppendFormat("%s%d", i ? ", " : "", *getBufPtr<unsigned int>(Pkt, sizeof(CheckPacketHdr) + i * sizeof(unsigned int)));
3901  O.Append("])");
3902  }
3903  break;
3904  }
3905  }
3906  }
3907  O.AppendFormat(" (%d bytes)\n", Pkt.getSize());
3908  write(hDebugLog, O.getData(), O.getLength());
3909 }
3910 #endif
3911 
3912 // *** C4NetIOMan
3913 
3915  : StdSchedulerThread()
3916 
3917 {
3918 }
3919 
3921 {
3922  Clear();
3923 }
3924 
3926 {
3927  delete[] ppNetIO; ppNetIO = nullptr;
3928  iNetIOCnt = iNetIOCapacity = 0;
3930 }
3931 
3932 void C4NetIOMan::AddIO(C4NetIO *pNetIO, bool fSetCallback)
3933 {
3934  // Set callback
3935  if (fSetCallback)
3936  pNetIO->SetCallback(this);
3937  // Add to i/o list
3938  if (iNetIOCnt + 1 > iNetIOCapacity)
3939  EnlargeIO(1);
3940  ppNetIO[iNetIOCnt++] = pNetIO;
3941  // Register with scheduler
3942  Add(pNetIO);
3943 }
3944 
3946 {
3947  // Search
3948  int i;
3949  for (i = 0; i < iNetIOCnt; i++)
3950  if (ppNetIO[i] == pNetIO)
3951  break;
3952  // Not found?
3953  if (i >= iNetIOCnt) return;
3954  // Remove
3955  for (i++; i < iNetIOCnt; i++)
3956  ppNetIO[i-1] = ppNetIO[i];
3957  iNetIOCnt--;
3958 }
3959 
3961 {
3962  for (int i = 0; i < iNetIOCnt; i++)
3963  if (pProc == ppNetIO[i])
3964  OnError(ppNetIO[i]->GetError(), ppNetIO[i]);
3965 }
3966 
3967 void C4NetIOMan::EnlargeIO(int iBy)
3968 {
3969  iNetIOCapacity += iBy;
3970  // Realloc
3971  C4NetIO **ppnNetIO = new C4NetIO *[iNetIOCapacity];
3972  // Set data
3973  for (int i = 0; i < iNetIOCnt; i++)
3974  ppnNetIO[i] = ppNetIO[i];
3975  delete[] ppNetIO;
3976  ppNetIO = ppnNetIO;
3977 }
bool Execute(int iMaxTime=TO_INF, pollfd *readyfds=nullptr) override
Definition: C4NetIO.cpp:919
const char * getData() const
Definition: StdBuf.h:442
const C4NetIO::addr_t & GetAddr() const
Definition: C4NetIO.h:413
C4NetIO::addr_t addr
Definition: C4NetIO.h:736
void ResetError()
Definition: C4NetIO.h:286
bool IsMulticast() const
Definition: C4NetIO.cpp:242
bool Open() const
Definition: C4NetIO.h:799
nr_t GetNr() const
Definition: C4NetIO.h:673
void ClearConnectWaits()
Definition: C4NetIO.cpp:1620
bool Send(const C4NetIOPacket &rPacket)
Definition: C4NetIO.cpp:3131
void SetBroadcast(bool fSet)
Definition: C4NetIO.h:815
C4NetIO::HostAddress AsIPv4() const
Definition: C4NetIO.cpp:325
void Any(T &keys)
bool Send(const C4NetIOPacket &rPacket) override
Definition: C4NetIO.cpp:1253
void CheckTimeout()
Definition: C4NetIO.cpp:3416
C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow) override
Definition: C4NetIO.cpp:2726
Definition: StdBuf.h:29
#define INVALID_SOCKET
Definition: C4NetIO.h:36
int GetIRate() const
Definition: C4NetIO.h:415
bool getMCLoopback() const
Definition: C4NetIO.h:559
bool doBroadcast() const
Definition: C4NetIO.h:813
void ClearStatistics()
Definition: C4NetIO.cpp:1822
bool DoLoopbackTest()
Definition: C4NetIO.cpp:3642
bool SetMCLoopback(int fLoopback)
Definition: C4NetIO.cpp:2233
C4NetIOPacket GetFragment(nr_t iFNr, bool fBroadcastFlag=false) const
Definition: C4NetIO.cpp:2895
BinAddr(const C4NetIO::addr_t &addr)
Definition: C4NetIO.cpp:2280
virtual bool InitBroadcast(addr_t *pBroadcastAddr)
Definition: C4NetIO.cpp:1929
bool InitBroadcast(addr_t *pBroadcastAddr) override
Definition: C4NetIO.cpp:2444
uint32_t UnsyncedRandom()
Definition: C4Random.cpp:58
void SetCallback(CBClass *pnCallback) override
Definition: C4NetIO.h:572
bool Close() override
Definition: C4NetIO.cpp:2582
#define sprintf
Definition: Standard.h:164
CStdCSecEx PeerListCSec
Definition: C4NetIO.h:854
const char * GetSocketErrorMsg(int iError)
Definition: C4NetIO.cpp:190
void SetError(const char *strnError, bool fSockErr=false)
Definition: C4NetIO.cpp:750
void ClearStatistic() override
Definition: C4NetIO.cpp:1362
int iBroadcastRate
Definition: C4NetIO.h:882
bool IsLocal() const
Definition: C4NetIO.cpp:260
friend class Packet
Definition: C4NetIO.h:688
void OnClose(const char *szReason)
Definition: C4NetIO.cpp:3513
PacketList OPackets
Definition: C4NetIO.h:878
Packet * Next
Definition: C4NetIO.h:686
void Clear()
Definition: StdBuf.h:190
C4NetIOPacket & GetData()
Definition: C4NetIO.h:671
int GetORate() const
Definition: C4NetIO.h:822
static const unsigned int iReCheckInterval
Definition: C4NetIO.h:730
~C4NetIOMan() override
Definition: C4NetIO.cpp:3920
StdStrBuf ToString(int flags=0) const
Definition: C4NetIO.cpp:588
virtual void OnError(const char *strError, C4NetIO *pNetIO)
Definition: C4NetIO.h:950
StdStrBuf ToString(int flags=0) const
Definition: C4NetIO.cpp:604
unsigned int GetMCAckPacketCounter() const
Definition: C4NetIO.h:806
bool Broadcast(const C4NetIOPacket &rPacket) override
Definition: C4NetIO.cpp:1275
CStdCSec OutCSec
Definition: C4NetIO.h:856
enum C4NetIOUDP::ConnOKPacket::@66 MCMode
void Clear()
Definition: StdSync.h:278
virtual const char * GetError() const
Definition: C4NetIO.h:285
static const unsigned int iMinIBufSize
Definition: C4NetIO.h:393
C4NetIOPacket getRef() const
Definition: C4NetIO.h:324
StdCopyStrBuf Error
Definition: C4NetIO.h:282
bool Close() override
Definition: C4NetIO.cpp:1984
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
bool AddPacket(Packet *pPacket)
Definition: C4NetIO.cpp:3037
void SetHost(const sockaddr *addr)
Definition: C4NetIO.cpp:346
static const unsigned int iUDPHeaderSize
Definition: C4NetIO.h:642
bool SetBroadcast(const addr_t &addr, bool fSet=true) override
Definition: C4NetIO.cpp:2715
bool GetStatistic(int *pBroadcastRate) override
Definition: C4NetIO.cpp:1342
#define _MAX_PATH
Peer * pPeerList
Definition: C4NetIO.h:864
#define O_BINARY
Definition: StdBuf.cpp:25
bool fSavePacket
Definition: C4NetIO.h:867
void Grow(size_t iGrow)
Definition: StdBuf.h:171
C4NetIO::HostAddress AsIPv6() const
Definition: C4NetIO.cpp:303
Peer * GetPeer(const addr_t &addr)
Definition: C4NetIO.cpp:3736
virtual void SetCallback(CBClass *pnCallback)=0
virtual void PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf)
Definition: C4NetIO.cpp:1631
void SetAddress(const sockaddr *addr)
Definition: C4NetIO.cpp:364
static const unsigned int iMaxOPacketBacklog
Definition: C4NetIO.h:640
bool isNull() const
Definition: StdBuf.h:98
void SetTimeout(int iLength=iStdTimeout, int iRetryCnt=0)
Definition: C4NetIO.cpp:3566
void ClearStatistic() override
Definition: C4NetIO.cpp:2761
virtual bool OnConn(const addr_t &AddrPeer, const addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO)
Definition: C4NetIO.h:220
const addr_t & getMCAddr() const
Definition: C4NetIO.h:555
#define ioctlsocket
Definition: C4NetIO.cpp:45
bool DoCheck(int iAskCnt=0, int iMCAskCnt=0, unsigned int *pAskList=nullptr)
Definition: C4NetIO.cpp:3449
bool HaveConnResetError()
Definition: C4NetIO.cpp:207
bool IsNull() const
Definition: C4NetIO.cpp:508
Packet * GetFirstPacketComplete()
Definition: C4NetIO.cpp:3024
bool Execute(int iMaxTime=TO_INF, pollfd *=nullptr) override
Definition: C4NetIO.cpp:2622
bool Execute(int iMaxTime=TO_INF, pollfd *=nullptr) override
Definition: C4NetIO.cpp:2043
bool Listen(uint16_t inListenPort)
Definition: C4NetIO.cpp:1481
size_t getSize() const
Definition: StdBuf.h:101
void SetSize(size_t inSize)
Definition: StdBuf.h:204
StdBuf getPart(size_t iStart, size_t inSize) const
Definition: StdBuf.h:107
bool InitIPv6Socket(SOCKET socket)
Definition: C4NetIO.cpp:730
C4NetIOPacket LastPacket
Definition: C4NetIO.h:868
bool IsLoopback() const
Definition: C4NetIO.cpp:251
bool Check(bool fForceCheck=true)
Definition: C4NetIO.cpp:3153
bool FragmentPresent(unsigned int iNr)
Definition: C4NetIO.cpp:3030
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:190
virtual bool InitBroadcast(addr_t *pBroadcastAddr)
Definition: C4NetIO.cpp:851
virtual void UnBlock()
Definition: C4NetIO.cpp:2186
int Compare(const void *pCData, size_t iCSize, size_t iAt=0) const
Definition: StdBuf.h:165
void SetBroadcast(bool fSet)
Definition: C4NetIO.h:434
void Clear()
Definition: C4NetIO.cpp:3925
Peer * pPeerList
Definition: C4NetIO.h:443
void Close(const char *szReason)
Definition: C4NetIO.cpp:3401
const C4NetIO::addr_t & getAddr() const
Definition: C4NetIO.h:316
void AddPeer(Peer *pPeer)
Definition: C4NetIO.cpp:3699
Peer * Accept(SOCKET nsock=INVALID_SOCKET, const addr_t &ConnectAddr=addr_t())
Definition: C4NetIO.cpp:1370
virtual void UnBlock()
Definition: C4NetIO.cpp:1286
static const size_t MaxDataSize
Definition: C4NetIO.h:653
~C4NetIOTCP() override
Definition: C4NetIO.cpp:806
bool DoConn(bool fMC)
Definition: C4NetIO.cpp:3430
int Pipe[2]
Definition: C4NetIO.h:470
bool operator==(const HostAddress &rhs) const
Definition: C4NetIO.cpp:558
void GetFDs(std::vector< struct pollfd > &FDs) override
Definition: C4NetIO.cpp:2195
int GetScopeId() const
Definition: C4NetIO.cpp:296
static const unsigned int iVersion
Definition: C4NetIO.h:632
bool GetStatistic(int *pBroadcastRate) override
Definition: C4NetIO.cpp:2741
bool CloseBroadcast() override
Definition: C4NetIO.cpp:2610
bool GetConnStatistic(const addr_t &addr, int *pIRate, int *pORate, int *pLoss) override
Definition: C4NetIO.cpp:2748
static std::vector< HostAddress > GetLocalAddresses()
Definition: C4NetIO.cpp:631
void ClearStatistics()
Definition: C4NetIO.cpp:3423
C4NetIO ** ppNetIO
Definition: C4NetIO.h:947
static const unsigned int iTCPHeaderSize
Definition: C4NetIO.h:392
void * GetRecvBuf(int iSize)
Definition: C4NetIO.cpp:1748
void Clear()
Definition: StdSync.h:178
CStdCSecEx PeerListCSec
Definition: C4NetIO.h:455
int GetORate() const
Definition: C4NetIO.h:416
bool fDelayedLoopbackTest
Definition: C4NetIO.h:872
void ResetSocketError()
Definition: C4NetIO.cpp:211
C4NetIO::addr_t addr
Definition: C4NetIO.h:312
void Copy(size_t inSize)
Definition: StdBuf.h:225
~C4NetIOSimpleUDP() override
Definition: C4NetIO.cpp:1836
uint16_t iPort
Definition: C4NetIO.h:861
Peer * GetPeer(const addr_t &addr)
Definition: C4NetIO.cpp:1536
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
void SetPort(uint16_t port)
Definition: C4NetIO.cpp:531
bool Send(const C4NetIOPacket &rPacket) override
Definition: C4NetIO.cpp:2677
bool Broadcast(const C4NetIOPacket &rPacket) override
Definition: C4NetIO.cpp:2143
void CompileFunc(StdCompiler *comp)
Definition: C4NetIO.cpp:618
int iNetIOCapacity
Definition: C4NetIO.h:946
bool Closed() const
Definition: C4NetIO.h:801
unsigned int TestNr
Definition: C4NetIO.cpp:2394
~C4NetIOUDP() override
Definition: C4NetIO.cpp:2410
friend class Peer
Definition: C4NetIO.h:441
int iNetIOCnt
Definition: C4NetIO.h:946
addr_t MCLoopbackAddr
Definition: C4NetIO.h:871
void AddConnectWait(SOCKET sock, const addr_t &addr)
Definition: C4NetIO.cpp:1594
unsigned int iOPacketCounter
Definition: C4NetIO.h:879
size_t GetAddrLen() const
Definition: C4NetIO.cpp:526
bool fInit
Definition: C4NetIO.h:859
void SetScopeId(int scopeId)
Definition: C4NetIO.cpp:289
ConnectWait * Next
Definition: C4NetIO.h:451
void SetReUseAddress(bool fAllow)
Definition: C4NetIO.cpp:2245
bool IsPrivate() const
Definition: C4NetIO.cpp:270
PacketList(unsigned int iMaxPacketCnt=~0)
Definition: C4NetIO.cpp:2991
#define SOCKET
Definition: C4NetIO.h:35
void CheckCompleteIPackets()
Definition: C4NetIO.cpp:3524
AddressFamily GetFamily() const
Definition: C4NetIO.cpp:520
void GetFDs(std::vector< struct pollfd > &FDs) override
Definition: C4NetIO.cpp:1307
void OnRecv(int iSize)
Definition: C4NetIO.cpp:1761
void Value(const T &rStruct)
Definition: StdCompiler.h:161
enum C4NetIOUDP::Peer::ConnStatus eStatus
bool BroadcastDirect(const Packet &rPacket, unsigned int iNr=~0u)
Definition: C4NetIO.cpp:3603
EndpointAddress addr_t
Definition: C4NetIO.h:212
bool HaveWouldBlockError()
Definition: C4NetIO.cpp:203
CStdCSec PeerListAddCSec
Definition: C4NetIO.h:456
#define SOCK_CLOEXEC
Definition: C4NetIO.h:50
int GetIRate() const
Definition: C4NetIO.h:821
bool FragmentPresent(nr_t iFNr) const
Definition: C4NetIO.cpp:2923
Packet * GetPacket(unsigned int iNr)
Definition: C4NetIO.cpp:3002
bool Close() override
Definition: C4NetIO.cpp:857
void New(size_t inSize)
Definition: StdBuf.h:146
bool fMultiCast
Definition: C4NetIO.h:860
const EndpointAddressPtr operator&() const
Definition: C4NetIO.cpp:228
static const int TO_INF
Definition: C4NetIO.h:66
void OnRecv(const C4NetIOPacket &Packet)
Definition: C4NetIO.cpp:3189
bool operator==(const EndpointAddress &rhs) const
Definition: C4NetIO.cpp:572
virtual bool isDeserializer()
Definition: StdCompiler.h:53
bool SetBroadcast(const addr_t &addr, bool fSet=true) override
Definition: C4NetIO.cpp:1264
void Write(const void *pnData, size_t inSize, size_t iAt=0)
Definition: StdBuf.h:153
uint32_t nr_t
Definition: C4NetIO.h:656
bool GetConnStatistic(const addr_t &addr, int *pIRate, int *pORate, int *pLoss) override
Definition: C4NetIO.cpp:1349
static const size_t MaxSize
Definition: C4NetIO.h:652
bool DeletePacket(Packet *pPacket)
Definition: C4NetIO.cpp:3061
bool Init(uint16_t iPort=addr_t::IPPORT_NONE) override
Definition: C4NetIO.cpp:811
bool Connect(const addr_t &addr) override
Definition: C4NetIO.cpp:2660
virtual bool CloseBroadcast()
Definition: C4NetIO.cpp:2025
void OnShareFree(CStdCSecEx *pCSec) override
Definition: C4NetIO.cpp:3710
bool Init(uint16_t iPort=addr_t::IPPORT_NONE) override
Definition: C4NetIO.cpp:1841
void ClearMCPackets()
Definition: C4NetIO.cpp:3681
bool Open() const
Definition: C4NetIO.h:428
#define closesocket
Definition: C4NetIO.cpp:46
bool MultiCast() const
Definition: C4NetIO.h:803
void OnShareFree(CStdCSecEx *pCSec) override
Definition: C4NetIO.cpp:1546
bool Send(const C4NetIOPacket &rPacket)
Definition: C4NetIO.cpp:1694
virtual size_t UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &Addr)
Definition: C4NetIO.cpp:1648
bool fInit
Definition: C4NetIO.h:459
static const uint16_t IPPORT_NONE
Definition: C4NetIO.h:137
void DoCheck()
Definition: C4NetIO.cpp:3766
Packet * GetPacketFrgm(unsigned int iNr)
Definition: C4NetIO.cpp:3013
bool IsInfinite() const
SOCKET lsock
Definition: C4NetIO.h:463
bool Complete() const
Definition: C4NetIO.cpp:2914
uint8_t getStatus() const
Definition: C4NetIO.h:318
bool isNull() const
Definition: StdBuf.h:441
Peer * ConnectPeer(const addr_t &PeerAddr, bool fFailCallback)
Definition: C4NetIO.cpp:3746
static const unsigned int iCheckInterval
Definition: C4NetIO.h:637
::size_t FragmentSize(nr_t iFNr) const
Definition: C4NetIO.cpp:2981
virtual bool CloseBroadcast()
Definition: C4NetIO.cpp:905
bool HaveSocketError()
Definition: C4NetIO.cpp:199
virtual void OnDisconn(const addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason)
Definition: C4NetIO.h:221
bool Send(const C4NetIOPacket &rPacket) override
Definition: C4NetIO.cpp:2123
bool AddFragment(const C4NetIOPacket &Packet, const C4NetIO::addr_t &addr)
Definition: C4NetIO.cpp:2928
C4TimeMilliseconds tNextCheck
Definition: C4NetIO.h:875
void RemoveIO(C4NetIO *pNetIO)
Definition: C4NetIO.cpp:3945
bool SendDirect(const Packet &rPacket, unsigned int iNr=~0)
Definition: C4NetIO.cpp:3473
bool IsNull() const
Definition: C4NetIO.cpp:503
size_t getLength() const
Definition: StdBuf.h:445
bool Connect(bool fFailCallback)
Definition: C4NetIO.cpp:3124
void Move(size_t iFrom, size_t inSize, size_t iTo=0)
Definition: StdBuf.h:159
virtual void OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO)=0
EndpointAddress AsIPv6() const
Definition: C4NetIO.cpp:336
EndpointAddress AsIPv4() const
Definition: C4NetIO.cpp:341
#define INFINITE
Definition: StdSync.h:58
Peer(const C4NetIO::addr_t &naddr, C4NetIOUDP *pnParent)
Definition: C4NetIO.cpp:3104
bool Broadcast(const C4NetIOPacket &rPacket) override
Definition: C4NetIO.cpp:2688
nr_t FragmentCnt() const
Definition: C4NetIO.cpp:2890
C4NetIO()
Definition: C4NetIO.cpp:723
void ClearPackets(unsigned int iUntil)
Definition: C4NetIO.cpp:3081
Peer(const C4NetIO::addr_t &naddr, SOCKET nsock, C4NetIOTCP *pnParent)
Definition: C4NetIO.cpp:1678
CStdCSec PeerListAddCSec
Definition: C4NetIO.h:855
C4NetIOPacket Duplicate() const
Definition: C4NetIO.h:325
void AddIO(C4NetIO *pNetIO, bool fSetCallback=true)
Definition: C4NetIO.cpp:3932
void Clear()
Definition: C4NetIO.cpp:789
bool SendDirect(C4NetIOPacket &&rPacket)
Definition: C4NetIO.cpp:3615
void SetDefaultPort(uint16_t port)
Definition: C4NetIO.cpp:541
uint32_t DWORD
static const unsigned int iStdTimeout
Definition: C4NetIO.h:637
CStdCSec ExecuteCSec
Definition: C4NetIO.h:907
uint16_t GetPort() const
Definition: C4NetIO.cpp:547
Packet * Prev
Definition: C4NetIO.h:686
void SetAddr(const C4NetIO::addr_t &naddr)
Definition: C4NetIO.h:327
void Copy()
Definition: StdBuf.h:467
#define s
ConnectWait * GetConnectWait(const addr_t &addr)
Definition: C4NetIO.cpp:1610
static C4TimeMilliseconds Now()
StdStrBuf ToString() const
Definition: C4NetIO.cpp:2334
bool Connect(const addr_t &addr) override
Definition: C4NetIO.cpp:1154
int iSize
Definition: TstC4NetIO.cpp:32
static const unsigned int iConnectRetries
Definition: C4NetIO.h:729
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
void Add(StdSchedulerProc *pProc)
CStdCSec StatCSec
Definition: C4NetIO.h:883
friend class Peer
Definition: C4NetIO.h:851
uint16_t iListenPort
Definition: C4NetIO.h:462
#define SOCKET_ERROR
Definition: C4NetIO.cpp:47
~C4NetIO() override
bool Init(uint16_t iPort=addr_t::IPPORT_NONE) override
Definition: C4NetIO.cpp:2415