The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
netio.c
Go to the documentation of this file.
1 
25 #include <projectcommon.h>
26 #include <errno.h>
27 #include <memory.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #ifdef _MSC_VER
35 # include <winsock2.h>
36 # include <ws2tcpip.h>
37 #include <ws2ipdef.h>
38 #define ip_mreqn ip_mreq
39 #define imr_address imr_multiaddr
40 #define s6_addr16 u.Word
41 #define close closesocket
42 #else
43 # include <sys/socket.h>
44 # include <netinet/in.h>
45 #endif
46 #include <glib.h>
47 #include <packetdecoder.h>
48 #include <address_family_numbers.h>
49 #include <proj_classes.h>
50 #include <netio.h>
51 #include <frameset.h>
52 FSTATIC gint _netio_getfd(const NetIO* self);
53 FSTATIC void _netio_setblockio(const NetIO* self, gboolean blocking);
54 FSTATIC gboolean _netio_bindaddr(NetIO* self, const NetAddr* src, gboolean silent);
55 FSTATIC gboolean _netio_input_queued(const NetIO* self);
57 FSTATIC void _netio_sendframesets(NetIO* self, const NetAddr* destaddr, GSList* framesets);
58 FSTATIC void _netio_sendaframeset(NetIO* self, const NetAddr* destaddr, FrameSet* frameset);
59 FSTATIC void _netio_finalize(AssimObj* self);
60 FSTATIC void _netio_sendapacket(NetIO* self, gconstpointer packet, gconstpointer pktend, const NetAddr* destaddr);
61 FSTATIC gpointer _netio_recvapacket(NetIO*, gpointer*, struct sockaddr_in6*, socklen_t*addrlen);
62 FSTATIC gsize _netio_getmaxpktsize(const NetIO* self);
63 FSTATIC gsize _netio_setmaxpktsize(NetIO* self, gsize maxpktsize);
64 FSTATIC GSList* _netio_recvframesets(NetIO*self , NetAddr** src);
68 FSTATIC gboolean _netio_mcastjoin(NetIO* self, const NetAddr* src, const NetAddr*localaddr);
69 FSTATIC gboolean _netio_setmcast_ttl(NetIO* self, guint8 ttl);
70 FSTATIC void _netio_enablepktloss(NetIO* self, gboolean enable);
71 FSTATIC void _netio_setpktloss(NetIO* self, double rcvloss, double xmitloss);
72 FSTATIC gboolean _netio_sendareliablefs(NetIO*self, NetAddr*dest, guint16 queueid, FrameSet* frameset);
73 FSTATIC gboolean _netio_sendreliablefs(NetIO*self, NetAddr* dest, guint16 queueid, GSList* fslist);
74 FSTATIC gboolean _netio_ackmessage(NetIO* self, NetAddr* dest, FrameSet* frameset);
75 FSTATIC gboolean _netio_supportsreliable(NetIO* self);
76 FSTATIC void _netio_closeconn(NetIO* self, guint16 qid, const NetAddr* destaddr);
77 FSTATIC void _netio_netaddr_destroy(gpointer addrptr);
78 FSTATIC void _netio_addalias(NetIO* self, NetAddr * fromaddr, NetAddr* toaddr);
79 
81 
88 
90 FSTATIC gint
91 _netio_getfd(const NetIO* self)
92 {
93  g_return_val_if_fail(NULL != self, -1);
94  g_return_val_if_fail(NULL != self->giosock, -1);
95  return g_io_channel_unix_get_fd(self->giosock);
96 }
97 
99 FSTATIC void
100 _netio_setblockio(const NetIO* self, gboolean blocking)
101 {
102  int chanflags = g_io_channel_get_flags(self->giosock);
103 #ifndef WIN32
104  int fcntlflags = fcntl (self->getfd(self), F_GETFL, 0);
105  if (blocking) {
106  fcntlflags |= O_NONBLOCK;
107  }else{
108  fcntlflags &= ~O_NONBLOCK;
109  }
110  if (fcntl(self->getfd(self), F_SETFL, fcntlflags) < 0) {
111  g_critical("%s.%d: fcntl(F_SETFL, 0x%x) failed: %s", __FUNCTION__, __LINE__
112  , fcntlflags, g_strerror(errno));
113  return;
114  }
115 #endif
116  if (blocking) {
117  chanflags |= G_IO_FLAG_NONBLOCK;
118  }else{
119  chanflags &= ~G_IO_FLAG_NONBLOCK;
120  }
121  g_io_channel_set_flags(self->giosock, chanflags, NULL);
122 }
123 
124 
126 FSTATIC gboolean
127 _netio_mcastjoin(NetIO* self, const NetAddr* src, const NetAddr*localaddr)
128 {
129  int rc = -1;
130  NetAddr* genlocal = NULL;
131 
132 
133  errno = 0;
134 
135  if (!src->ismcast(src)) {
136  g_warning("%s: Cannot join multicast group with non-multicast address"
137  , __FUNCTION__);
138  goto getout;
139  }
140  if (localaddr != NULL && src->_addrtype != localaddr->_addrtype) {
141  g_warning("%s: Cannot join multicast group with differing address types"
142  , __FUNCTION__);
143  goto getout;
144  }
145 
146  if (ADDR_FAMILY_IPV6 == src->_addrtype ) {
147  struct ipv6_mreq multicast_request;
148  struct sockaddr_in6 saddr;
149  saddr = src->ipv6sockaddr(src);
150  memset(&multicast_request, 0, sizeof(multicast_request));
151  memcpy(&multicast_request.ipv6mr_multiaddr, &saddr
152  , sizeof(multicast_request.ipv6mr_multiaddr));
153 
154  if (localaddr == NULL) {
155  genlocal = self->boundaddr(self);
156  localaddr = genlocal;
157  if (localaddr->addrtype(localaddr) != ADDR_FAMILY_IPV6) {
158  localaddr = NULL;
159  }
160  }
161 
162  if (localaddr != NULL) {
163  struct sockaddr_in6 laddr;
164  laddr = localaddr->ipv6sockaddr(localaddr);
165  memcpy(&multicast_request.ipv6mr_interface, &laddr.sin6_addr
166  , sizeof(multicast_request.ipv6mr_interface));
167  }
168  if (localaddr && localaddr->addrtype(localaddr) != ADDR_FAMILY_IPV6) {
169  g_warning("%s: Cannot join v6 multicast group - local address not IPv6"
170  , __FUNCTION__);
171  goto getout;
172  }
173 
174  rc = setsockopt(self->getfd(self), IPPROTO_IPV6, IPV6_JOIN_GROUP
175  , (gpointer)&multicast_request, sizeof(multicast_request));
176  if (rc != 0) {
177  g_warning("%s: Cannot join v6 multicast group [%s (errno:%d)]"
178  , __FUNCTION__, g_strerror(errno), errno);
179  }
180  }else if (ADDR_FAMILY_IPV4 == src->_addrtype) {
181  struct ip_mreqn multicast_request;
182  struct sockaddr_in saddr;
183  memset(&multicast_request, 0, sizeof(multicast_request));
184  saddr = src->ipv4sockaddr(src);
185  memcpy(&multicast_request.imr_multiaddr, &saddr.sin_addr
186  , sizeof(multicast_request.imr_multiaddr));
187 
188  if (localaddr == NULL) {
189  genlocal = self->boundaddr(self);
190  localaddr = genlocal;
191  if (localaddr->addrtype(localaddr) != ADDR_FAMILY_IPV4) {
192  localaddr = NULL;
193  }
194  }
195  if (localaddr && localaddr->addrtype(localaddr) != ADDR_FAMILY_IPV4) {
196  g_warning("%s: Cannot join v4 multicast group - local address not IPv4"
197  , __FUNCTION__);
198  goto getout;
199  }
200 
201  if (localaddr != NULL) {
202  struct sockaddr_in laddr;
203  laddr = localaddr->ipv4sockaddr(localaddr);
204  memcpy(&multicast_request.imr_address, &laddr.sin_addr
205  , sizeof(multicast_request.imr_address));
206  }
207 
208  rc = setsockopt(self->getfd(self), IPPROTO_IP, IP_ADD_MEMBERSHIP
209  , (gpointer)&multicast_request, sizeof(multicast_request));
210  if (rc != 0) {
211  g_warning("%s: Cannot join v4 multicast group [%s (errno:%d)]"
212  , __FUNCTION__, g_strerror(errno), errno);
213  }else{
214  // Default to the largest organizational scope defined...
215  self->setmcast_ttl(self, 31);
216  }
217  }
218 getout:
219  if (genlocal) {
220  UNREF(genlocal);
221  genlocal = NULL;
222  }
223 
224  return (rc == 0);
225 }
226 
228 gboolean
230  guint8 ttlin)
231 {
239  int ttl = ttlin;
240  return setsockopt(self->getfd(self), IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl) == 0);
241 }
242 
244 FSTATIC gboolean
246 {
247  (void)self;
248  return FALSE; // By default we don't have any input queues
249 }
250 
252 FSTATIC gboolean
254  const NetAddr* src,
255  gboolean silent)
256 {
257  gint sockfd;
258  struct sockaddr_in6 saddr;
259  int rc;
260  g_return_val_if_fail(NULL != self, FALSE);
261  g_return_val_if_fail(NULL != self->giosock, FALSE);
262  sockfd = self->getfd(self);
263 
264  if (src->ismcast(src)) {
265  g_warning("%s: Attempt to bind to multicast address.", __FUNCTION__);
266  return FALSE;
267  }
268  memset(&saddr, 0x00, sizeof(saddr));
269  saddr.sin6_family = AF_INET6;
270  saddr.sin6_port = src->port(src);
271  g_return_val_if_fail(src->addrtype(src) == ADDR_FAMILY_IPV4 || src->addrtype(src) == ADDR_FAMILY_IPV6, FALSE);
272 
273  saddr = src->ipv6sockaddr(src);
274  rc = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
275  if (rc != 0 && !silent) {
276  g_warning("%s: Cannot bind to address [%s (errno:%d)]"
277  , __FUNCTION__, g_strerror(errno), errno);
278  }
279  return rc == 0;
280 }
283 _netio_boundaddr(const NetIO* self)
284 {
285  gint sockfd = self->getfd(self);
286  struct sockaddr_in6 saddr;
287  socklen_t saddrlen = sizeof(saddr);
288  socklen_t retsize = saddrlen;
289 
290 
291  if (getsockname(sockfd, (struct sockaddr*)&saddr, &retsize) < 0) {
292  g_warning("%s: Cannot retrieve bound address [%s]", __FUNCTION__, g_strerror(errno));
293  return NULL;
294  }
295  if (retsize != saddrlen) {
296  g_warning("%s: Truncated getsockname() return [%d/%d bytes]", __FUNCTION__, retsize, saddrlen);
297  return NULL;
298  }
299  return netaddr_sockaddr_new(&saddr, saddrlen);
300 
301 }
302 
304 FSTATIC void
306 {
307  NetIO* self = CASTTOCLASS(NetIO, aself);
308  if (self->giosock) {
309  g_io_channel_shutdown(self->giosock, TRUE, NULL);
310  g_io_channel_unref(self->giosock);
311  self->giosock = NULL;
312  }
313  if (self->_signframe) {
314  UNREF2(self->_signframe);
315  }
316  if (self->_cryptframe) {
317  UNREF(self->_cryptframe);
318  }
319  if (self->_compressframe) {
320  UNREF(self->_compressframe);
321  }
322  if (self->_decoder) {
323  UNREF(self->_decoder);
324  }
325 
326  // Free up our hash table of aliases
327  if (self->aliases) {
328  g_hash_table_destroy(self->aliases); // It will free the NetAddrs contained therein
329  self->aliases = NULL;
330  }
331  _assimobj_finalize(aself); self = NULL; aself = NULL;
332 }
333 
335 FSTATIC gsize
337 {
338  return self->_maxpktsize;
339 }
340 
342 FSTATIC gsize
344  gsize maxpktsize)
345 {
346  self->_maxpktsize = maxpktsize;
347  return self->getmaxpktsize(self);
348 }
349 FSTATIC Frame*
351 {
352  return self->_compressframe;
353 }
354 FSTATIC Frame*
356 {
357  return self->_cryptframe;
358 }
359 
362 {
363  return self->_signframe;
364 }
365 
367 NetIO*
368 netio_new(gsize objsize
370  , PacketDecoder*decoder)
371 {
372  NetIO* ret;
373  Frame* f;
374 
375  BINDDEBUG(NetIO);
376  if (objsize < sizeof(NetIO)) {
377  objsize = sizeof(NetIO);
378  }
379  ret = NEWSUBCLASS(NetIO, assimobj_new(objsize));
381  ret->getfd = _netio_getfd;
384  ret->bindaddr = _netio_bindaddr;
401  ret->supportsreliable = _netio_supportsreliable; // It just returns FALSE
402  ret->outputpending = _netio_supportsreliable; // It just returns FALSE
403  ret->addalias = _netio_addalias;
405  ret->_maxpktsize = 65300;
406  ret->_configinfo = config;
407  ret->_decoder = decoder;
408  REF(decoder);
409  f = config->getframe(config, CONFIGNAME_OUTSIG);
410  g_return_val_if_fail(f != NULL, NULL);
411  REF(f);
412  ret->_signframe = CASTTOCLASS(SignFrame, f);
413  ret->_cryptframe = config->getframe(config, CONFIGNAME_CRYPT);
414  if (ret->_cryptframe) {
415  REF(ret->_cryptframe);
416  }
417  ret->_compressframe = config->getframe(config, CONFIGNAME_COMPRESS);
418  if (ret->_compressframe) {
419  REF(ret->_compressframe);
420  }
421  ret->aliases = g_hash_table_new_full(netaddr_g_hash_hash, netaddr_g_hash_equal
422  , _netio_netaddr_destroy, _netio_netaddr_destroy); // Keys and data are same type...
423  memset(&ret->stats, 0, sizeof(ret->stats));
424  return ret;
425 }
426 
428 FSTATIC void
430  gconstpointer packet,
431  gconstpointer pktend,
432  const NetAddr* destaddr)
433 {
434  struct sockaddr_in6 v6addr = destaddr->ipv6sockaddr(destaddr);
435  gssize length = (const guint8*)pktend - (const guint8*)packet;
436  gssize rc;
437  guint flags = 0x00;
438  g_return_if_fail(length > 0);
439 
440  if (self->_shouldlosepkts) {
441  if (g_random_double() < self->_xmitloss) {
442  g_message("%s.%d: Threw away %"G_GSSIZE_FORMAT" byte output packet"
443  , __FUNCTION__, __LINE__, length);
444  return;
445  }
446  }
447 
448  rc = sendto(self->getfd(self), packet, (size_t)length, flags, (const struct sockaddr*)&v6addr, sizeof(v6addr));
449  DEBUGMSG3("%s.%d: sendto(%d, %ld, [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x], port=%d) returned %ld"
450  , __FUNCTION__, __LINE__, self->getfd(self), (long)length
451  , ntohs(v6addr.sin6_addr.s6_addr16[0])
452  , ntohs(v6addr.sin6_addr.s6_addr16[1])
453  , ntohs(v6addr.sin6_addr.s6_addr16[2])
454  , ntohs(v6addr.sin6_addr.s6_addr16[3])
455  , ntohs(v6addr.sin6_addr.s6_addr16[4])
456  , ntohs(v6addr.sin6_addr.s6_addr16[5])
457  , ntohs(v6addr.sin6_addr.s6_addr16[6])
458  , ntohs(v6addr.sin6_addr.s6_addr16[7])
459  , ntohs(v6addr.sin6_port)
460  , (long)rc);
461  self->stats.sendcalls ++;
462  self->stats.pktswritten ++;
463  if (rc != length) {
464  char * tostring = destaddr->baseclass.toString(destaddr);
465  g_warning(
466  "%s: sendto returned %"G_GSSIZE_FORMAT " vs %"G_GSSIZE_FORMAT" with errno %s"
467  , __FUNCTION__, rc, (gssize)length, g_strerror(errno));
468  g_warning("%s: destaddr:[%s] ", __FUNCTION__, tostring);
469  g_free(tostring); tostring = NULL;
470  }
471  g_return_if_fail(rc == length);
472 }
473 
478 FSTATIC void
480  const NetAddr* destaddr,
481  GSList* framesets)
482 {
483  GSList* curfsl;
484  g_return_if_fail(self != NULL);
485  g_return_if_fail(framesets != NULL);
486  g_return_if_fail(destaddr != NULL);
487  g_return_if_fail(self->_signframe != NULL);
488 
492  for (curfsl=framesets; curfsl != NULL; curfsl=curfsl->next) {
493  FrameSet* curfs = CASTTOCLASS(FrameSet, curfsl->data);
494  SignFrame* signframe = self->signframe(self);
495  Frame* cryptframe = self->cryptframe(self);
496  Frame* compressframe = self->compressframe(self);
497  if (cryptframe) {
498  REF(cryptframe);
499  }
500  if (compressframe) {
501  REF(compressframe);
502  }
503  frameset_construct_packet(curfs, signframe, cryptframe, compressframe);
504  _netio_sendapacket(self, curfs->packet, curfs->pktend, destaddr);
505  self->stats.fswritten++;
506 
507  }
508 }
509 FSTATIC void
511  const NetAddr* destaddr,
512  FrameSet* frameset)
513 {
514  SignFrame* signframe = self->signframe(self);
515  Frame* cryptframe = self->cryptframe(self);
516  Frame* compressframe = self->compressframe(self);
517  g_return_if_fail(self != NULL);
518  g_return_if_fail(self->_signframe != NULL);
519  g_return_if_fail(frameset != NULL);
520  g_return_if_fail(destaddr != NULL);
521 
522  if (cryptframe) {
523  REF(cryptframe);
524  }
525  if (compressframe) {
526  REF(compressframe);
527  }
528  frameset_construct_packet(frameset, signframe, cryptframe, compressframe);
529  DEBUGMSG3("%s.%d: sent %ld byte packet", __FUNCTION__, __LINE__
530  , (long)(((guint8*)frameset->pktend-(guint8*)frameset->packet)));
531  _netio_sendapacket(self, frameset->packet, frameset->pktend, destaddr);
532 }
533 
541 #include <stdlib.h>
542 #include <memory.h>
543 FSTATIC gpointer
545  gpointer* pktend,
546  struct sockaddr_in6* srcaddr,
547  socklen_t* addrlen)
548 {
549  char dummy[8]; // Make GCC stack protection happy...
550 #ifndef __FUNCTION__
551 # define __FUNCTION__ "_netio_recvapacket"
552 #endif
553  gssize msglen;
554  gssize msglen2;
555  guint8* msgbuf;
556  const guint8 v4any[16] = CONST_IPV6_IPV4START;
557 
558  // First we peek and see how long the message is...
559  *addrlen = sizeof(*srcaddr);
560  memset(srcaddr, 0, sizeof(*srcaddr));
561  msglen = recvfrom(self->getfd(self), dummy, 1, MSG_DONTWAIT|MSG_PEEK|MSG_TRUNC,
562  (struct sockaddr*)srcaddr, addrlen);
563  self->stats.recvcalls ++;
564  if (msglen < 0) {
565  if (errno != EAGAIN) {
566  g_warning("recvfrom(%d, ... MSG_PEEK) failed: %s (in %s:%s:%d)",
567  self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
568  }
569  return NULL;
570  }
571  if (msglen == 0) {
572  g_warning("recvfrom(%d, ... MSG_PEEK) returned zero: %s (in %s:%s:%d)"
573  , self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
574  return NULL;
575  }
576 
577  // Allocate the right amount of memory
578  msgbuf = MALLOC(msglen);
579 
580  // Receive the message
581  *addrlen = sizeof(*srcaddr);
582  msglen2 = recvfrom(self->getfd(self), msgbuf, msglen, MSG_DONTWAIT|MSG_TRUNC,
583  (struct sockaddr *)srcaddr, addrlen);
584  self->stats.recvcalls ++;
585 
586  // Was there an error?
587  if (msglen2 < 0) {
588  g_warning("recvfrom(%d, ... MSG_DONTWAIT) failed: %s (in %s:%s:%d)"
589  , self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
590  FREE(msgbuf); msgbuf = NULL;
591  return NULL;
592  }
593  // Does everything look good?
594  if (msglen2 != msglen) {
595  g_warning("recvfrom(%d, ... MSG_DONTWAIT) returned %"G_GSSIZE_FORMAT" instead of %"G_GSSIZE_FORMAT" (in %s:%s:%d)"
596  , self->getfd(self), msglen2, msglen, __FILE__, __FUNCTION__ , __LINE__);
597  FREE(msgbuf); msgbuf = NULL;
598  return NULL;
599  }
600 
601 #ifdef WIN32
602 #define __in6_u u
603 #define __u6_addr8 Byte
604 #endif
605 
606  if (memcmp(srcaddr->sin6_addr.__in6_u.__u6_addr8, v4any, sizeof(v4any)) == 0) {
607  //const guint8 localhost[16] = CONST_IPV6_LOOPBACK;
608  const guint8 localhost[16] = {CONST_IPV6_IPV4SPACE, 127, 0, 0, 1};
609  // Both experience and RFC5735 say that this is basically "localhost"
610  memcpy(srcaddr->sin6_addr.__in6_u.__u6_addr8, localhost, sizeof(localhost));
611  }
612 
613  // Hah! Looks good!
614  *pktend = (void*) (msgbuf + msglen);
615  DEBUGMSG3("%s.%d: Received %zd byte message", __FUNCTION__, __LINE__, msglen);
616  if (self->_shouldlosepkts) {
617  if (g_random_double() < self->_rcvloss) {
618  g_message("%s: Threw away %"G_GSSIZE_FORMAT" byte input packet"
619  , __FUNCTION__, msglen);
620  FREE(msgbuf);
621  msgbuf = NULL;
622  }
623  }
624  self->stats.pktsread ++;
625  return msgbuf;
626 }
628 FSTATIC GSList*
630  NetAddr** src)
632 {
633  GSList* ret = NULL;
634  gpointer pkt;
635  gpointer pktend;
636  socklen_t addrlen;
637  struct sockaddr_in6 srcaddr;
638 
639  *src = NULL; // Make python happy in case we fail...
640  pkt = _netio_recvapacket(self, &pktend, &srcaddr, &addrlen);
641 
642  if (NULL != pkt) {
643  ret = self->_decoder->pktdata_to_framesetlist(self->_decoder, pkt, pktend);
644  if (NULL != ret) {
645  NetAddr* aliasaddr;
646  *src = netaddr_sockaddr_new(&srcaddr, addrlen);
647  // Some addresses can confuse our clients -- let's check our alias table...
648  if (NULL != (aliasaddr = g_hash_table_lookup(self->aliases, *src))) {
649  // This is a good-enough way to make a copy.
650  aliasaddr->toIPv6(aliasaddr);
651  // Keep the incoming port - since that's always right...
652  aliasaddr->_addrport = (*src)->_addrport;
653  UNREF(*src);
654  *src = aliasaddr;
655  }
656  }else{
657  g_warning("Received a %lu byte packet that didn't make any FrameSets"
658  , (unsigned long)((guint8*)pktend-(guint8*)pkt));
659  FREE(ret); ret = NULL;
660  }
661  FREE(pkt);
662  }
663  if (ret && *src) {
664  self->stats.fsreads += g_slist_length(ret);
665  }
666  return ret;
667 }
669 FSTATIC void
670 _netio_setpktloss (NetIO* self, double rcvloss, double xmitloss)
671 {
672  self->_rcvloss = rcvloss;
673  self->_xmitloss = xmitloss;
674 }
675 
677 FSTATIC void
678 _netio_enablepktloss (NetIO* self, gboolean enable)
679 {
680  self->_shouldlosepkts = enable;
681 }
682 
683 
684 
685 #ifdef IPV6_V6ONLY
686 #ifndef _MSC_VER
687 # include <netdb.h>
688 #endif
689 
693 gboolean
695 {
696  static gboolean computed_yet = FALSE;
697  static gboolean retval = FALSE;
698  gboolean optval;
699  int sockfd;
700  socklen_t optlen;
701  struct protoent*proto;
702 
703  if (computed_yet) {
704  return retval;
705  }
706  proto = getprotobyname("ipv6");
707 #ifdef HAVE_ENDPROTOENT
708  endprotoent();
709 #endif
710  g_return_val_if_fail(proto != NULL, FALSE);
711 
712  sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
713  g_return_val_if_fail(sockfd >= 0, FALSE);
714 
715  optlen = sizeof(retval);
716  optval = TRUE;
717  if (getsockopt(sockfd, proto->p_proto, IPV6_V6ONLY, (char *)&optval, &optlen) < 0) {
718  g_warning("%s.%d: getsockopt failed: %s", __FUNCTION__, __LINE__
719  , g_strerror(errno));
720  close(sockfd);
721  return FALSE;
722  }
723  if (optlen != sizeof(retval)) {
724  // Should never happen...
725  g_warning("%s.%d: getsockopt returned incorrect optlen: %d vs %zd"
726  , __FUNCTION__, __LINE__, optlen, sizeof(retval));
727  close(sockfd);
728  return FALSE;
729  }
730 #ifdef WIN32
731  // See http://msdn.microsoft.com/en-us/library/windows/desktop/bb513665%28v=vs.85%29.aspx
732  // This might be OK for other OSes too...
733  if (optval) {
734  optval = FALSE;
735  if (setsockopt(sockfd, proto->p_proto, IPV6_V6ONLY, (char *)&optval, optlen) < 0) {
738  optval = TRUE;
739  }
740  }
741 #endif
742  close(sockfd);
743  computed_yet = TRUE;
744  retval = !optval;
745  return retval;
746 }
747 #else /* IPV6_V6ONLY */
748 gboolean
750 {
751  return FALSE;
752 }
753 #endif
754 FSTATIC gboolean
755 _netio_sendareliablefs(NetIO*self, NetAddr*dest, guint16 queueid, FrameSet* frameset)
756 {
757  (void)self; (void)dest; (void)queueid; (void)frameset;
758  g_warn_if_reached();
759  return FALSE;
760 }
761 FSTATIC gboolean
762 _netio_sendreliablefs(NetIO*self, NetAddr* dest, guint16 queueid, GSList* fslist)
763 {
764  (void)self; (void)dest; (void)queueid; (void)fslist;
765  g_warn_if_reached();
766  return FALSE;
767 }
768 FSTATIC gboolean
769 _netio_ackmessage(NetIO* self, NetAddr* dest, FrameSet* frameset)
770 {
771  (void)self; (void)dest; (void)frameset;
772  g_warning("%s.%d: Object does not support ACKing of messages", __FUNCTION__, __LINE__);
773  return FALSE;
774 }
775 FSTATIC gboolean
777 {
778  (void)self;
779  return FALSE;
780 }
781 FSTATIC void
782  _netio_closeconn(NetIO* self, guint16 qid, const NetAddr* destaddr)
783 {
784  (void)self; (void)destaddr; (void)qid;
785  return;
786 }
788 FSTATIC void
789 _netio_netaddr_destroy(gpointer addrptr)
790 {
791  NetAddr* self = CASTTOCLASS(NetAddr, addrptr);
792  UNREF(self);
793 }
794 
796 FSTATIC void
798 , NetAddr * fromaddr
799 , NetAddr* toaddr)
800 {
801  DUMP3("Aliasing from this address", &fromaddr->baseclass, " to the next address");
802  DUMP3("Aliasing to this address", &toaddr->baseclass, " from the previous address");
803  REF(fromaddr);
804  REF(toaddr);
805  g_hash_table_insert(self->aliases, fromaddr, toaddr);
806 }
807