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