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