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  UNREF2(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 }
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  }
418  if (ret->_compressframe) {
419  REF2(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 == -1 && errno == EPERM) {
464  g_info("%s.%d: Got a weird sendto EPERM error for %"G_GSSIZE_FORMAT" byte packet."
465  , __FUNCTION__, __LINE__, (gssize)length);
466  g_info("%s.%d: This only seems to happen under Docker..."
467  , __FUNCTION__, __LINE__);
468  return;
469  }
470  if (rc != length) {
471  char * tostring = destaddr->baseclass.toString(destaddr);
472  g_warning(
473  "%s: sendto returned %"G_GSSIZE_FORMAT " vs %"G_GSSIZE_FORMAT" with errno %s"
474  , __FUNCTION__, rc, (gssize)length, g_strerror(errno));
475  g_warning("%s: destaddr:[%s] ", __FUNCTION__, tostring);
476  g_free(tostring); tostring = NULL;
477  }
478  //g_return_if_fail(rc == length);
479  g_warn_if_fail(rc == length);
480 }
481 
486 FSTATIC void
488  const NetAddr* destaddr,
489  GSList* framesets)
490 {
491  GSList* curfsl;
492  g_return_if_fail(self != NULL);
493  g_return_if_fail(framesets != NULL);
494  g_return_if_fail(destaddr != NULL);
495  g_return_if_fail(self->_signframe != NULL);
496 
500  for (curfsl=framesets; curfsl != NULL; curfsl=curfsl->next) {
501  FrameSet* curfs = CASTTOCLASS(FrameSet, curfsl->data);
502  SignFrame* signframe = self->signframe(self);
503  Frame* cryptframe = self->cryptframe(self);
504  CompressFrame* compressframe = self->compressframe(self);
505  if (cryptframe) {
506  REF(cryptframe);
507  }
508  if (compressframe) {
509  REF2(compressframe);
510  }
511  frameset_construct_packet(curfs, signframe, cryptframe, compressframe);
512  _netio_sendapacket(self, curfs->packet, curfs->pktend, destaddr);
513  self->stats.fswritten++;
514 
515  }
516 }
517 FSTATIC void
519  const NetAddr* destaddr,
520  FrameSet* frameset)
521 {
522  SignFrame* signframe = self->signframe(self);
523  Frame* cryptframe = self->cryptframe(self);
524  CompressFrame* compressframe = self->compressframe(self);
525  g_return_if_fail(self != NULL);
526  g_return_if_fail(self->_signframe != NULL);
527  g_return_if_fail(frameset != NULL);
528  g_return_if_fail(destaddr != NULL);
529 
530  frameset_construct_packet(frameset, signframe, cryptframe, compressframe);
531  DEBUGMSG3("%s.%d: sent %ld byte packet", __FUNCTION__, __LINE__
532  , (long)(((guint8*)frameset->pktend-(guint8*)frameset->packet)));
533  _netio_sendapacket(self, frameset->packet, frameset->pktend, destaddr);
534 }
535 
543 #include <stdlib.h>
544 #include <memory.h>
545 FSTATIC gpointer
547  gpointer* pktend,
548  struct sockaddr_in6* srcaddr,
549  socklen_t* addrlen)
550 {
551  char dummy[8]; // Make GCC stack protection happy...
552 #ifndef __FUNCTION__
553 # define __FUNCTION__ "_netio_recvapacket"
554 #endif
555  gssize msglen;
556  gssize msglen2;
557  guint8* msgbuf;
558  const guint8 v4any[16] = CONST_IPV6_IPV4START;
559 
560  // First we peek and see how long the message is...
561  *addrlen = sizeof(*srcaddr);
562  memset(srcaddr, 0, sizeof(*srcaddr));
563  msglen = recvfrom(self->getfd(self), dummy, 1, MSG_DONTWAIT|MSG_PEEK|MSG_TRUNC,
564  (struct sockaddr*)srcaddr, addrlen);
565  self->stats.recvcalls ++;
566  if (msglen < 0) {
567  if (errno != EAGAIN) {
568  g_warning("recvfrom(%d, ... MSG_PEEK) failed: %s (in %s:%s:%d)",
569  self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
570  }
571  return NULL;
572  }
573  if (msglen == 0) {
574  g_warning("recvfrom(%d, ... MSG_PEEK) returned zero: %s (in %s:%s:%d)"
575  , self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
576  return NULL;
577  }
578 
579  // Allocate the right amount of memory
580  msgbuf = MALLOC(msglen);
581 
582  // Receive the message
583  *addrlen = sizeof(*srcaddr);
584  msglen2 = recvfrom(self->getfd(self), msgbuf, msglen, MSG_DONTWAIT|MSG_TRUNC,
585  (struct sockaddr *)srcaddr, addrlen);
586  self->stats.recvcalls ++;
587 
588  // Was there an error?
589  if (msglen2 < 0) {
590  g_warning("recvfrom(%d, ... MSG_DONTWAIT) failed: %s (in %s:%s:%d)"
591  , self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
592  FREE(msgbuf); msgbuf = NULL;
593  return NULL;
594  }
595  // Does everything look good?
596  if (msglen2 != msglen) {
597  g_warning("recvfrom(%d, ... MSG_DONTWAIT) returned %"G_GSSIZE_FORMAT" instead of %"G_GSSIZE_FORMAT" (in %s:%s:%d)"
598  , self->getfd(self), msglen2, msglen, __FILE__, __FUNCTION__ , __LINE__);
599  FREE(msgbuf); msgbuf = NULL;
600  return NULL;
601  }
602 
603 #ifdef WIN32
604 #define __in6_u u
605 #define __u6_addr8 Byte
606 #endif
607 
608  if (memcmp(srcaddr->sin6_addr.__in6_u.__u6_addr8, v4any, sizeof(v4any)) == 0) {
609  //const guint8 localhost[16] = CONST_IPV6_LOOPBACK;
610  const guint8 localhost[16] = {CONST_IPV6_IPV4SPACE, 127, 0, 0, 1};
611  // Both experience and RFC5735 say that this is basically "localhost"
612  memcpy(srcaddr->sin6_addr.__in6_u.__u6_addr8, localhost, sizeof(localhost));
613  }
614 
615  // Hah! Looks good!
616  *pktend = (void*) (msgbuf + msglen);
617  DEBUGMSG3("%s.%d: Received %zd byte message", __FUNCTION__, __LINE__, msglen);
618  if (self->_shouldlosepkts) {
619  if (g_random_double() < self->_rcvloss) {
620  g_message("%s: Threw away %"G_GSSIZE_FORMAT" byte input packet"
621  , __FUNCTION__, msglen);
622  FREE(msgbuf);
623  msgbuf = NULL;
624  }
625  }
626  self->stats.pktsread ++;
627  return msgbuf;
628 }
630 FSTATIC GSList*
632  NetAddr** src)
634 {
635  GSList* ret = NULL;
636  gpointer pkt;
637  gpointer pktend;
638  socklen_t addrlen;
639  struct sockaddr_in6 srcaddr;
640 
641  *src = NULL; // Make python happy in case we fail...
642  pkt = _netio_recvapacket(self, &pktend, &srcaddr, &addrlen);
643 
644  if (NULL != pkt) {
645  ret = self->_decoder->pktdata_to_framesetlist(self->_decoder, pkt, pktend);
646  if (NULL != ret) {
647  NetAddr* aliasaddr;
648  *src = netaddr_sockaddr_new(&srcaddr, addrlen);
649  // Some addresses can confuse our clients -- let's check our alias table...
650  if (NULL != (aliasaddr = g_hash_table_lookup(self->aliases, *src))) {
651  // This is a good-enough way to make a copy.
652  aliasaddr->toIPv6(aliasaddr);
653  // Keep the incoming port - since that's always right...
654  aliasaddr->_addrport = (*src)->_addrport;
655  UNREF(*src);
656  *src = aliasaddr;
657  }
658  }else{
659  g_warning("Received a %lu byte packet that didn't make any FrameSets"
660  , (unsigned long)((guint8*)pktend-(guint8*)pkt));
661  FREE(ret); ret = NULL;
662  }
663  FREE(pkt);
664  }
665  if (ret && *src) {
666  self->stats.fsreads += g_slist_length(ret);
667  }
668  return ret;
669 }
671 FSTATIC void
672 _netio_setpktloss (NetIO* self, double rcvloss, double xmitloss)
673 {
674  self->_rcvloss = rcvloss;
675  self->_xmitloss = xmitloss;
676 }
677 
679 FSTATIC void
680 _netio_enablepktloss (NetIO* self, gboolean enable)
681 {
682  self->_shouldlosepkts = enable;
683 }
684 
685 
686 
687 #ifdef IPV6_V6ONLY
688 #ifndef _MSC_VER
689 # include <netdb.h>
690 #endif
691 
695 gboolean
697 {
698  static gboolean computed_yet = FALSE;
699  static gboolean retval = FALSE;
700  gboolean optval;
701  int sockfd;
702  socklen_t optlen;
703  struct protoent*proto;
704 
705  if (computed_yet) {
706  return retval;
707  }
708  proto = getprotobyname("ipv6");
709 #ifdef HAVE_ENDPROTOENT
710  endprotoent();
711 #endif
712  g_return_val_if_fail(proto != NULL, FALSE);
713 
714  sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
715  g_return_val_if_fail(sockfd >= 0, FALSE);
716 
717  optlen = sizeof(retval);
718  optval = TRUE;
719  if (getsockopt(sockfd, proto->p_proto, IPV6_V6ONLY, (char *)&optval, &optlen) < 0) {
720  g_warning("%s.%d: getsockopt failed: %s", __FUNCTION__, __LINE__
721  , g_strerror(errno));
722  close(sockfd);
723  return FALSE;
724  }
725  if (optlen != sizeof(retval)) {
726  // Should never happen...
727  g_warning("%s.%d: getsockopt returned incorrect optlen: %d vs %zd"
728  , __FUNCTION__, __LINE__, optlen, sizeof(retval));
729  close(sockfd);
730  return FALSE;
731  }
732 #ifdef WIN32
733  // See http://msdn.microsoft.com/en-us/library/windows/desktop/bb513665%28v=vs.85%29.aspx
734  // This might be OK for other OSes too...
735  if (optval) {
736  optval = FALSE;
737  if (setsockopt(sockfd, proto->p_proto, IPV6_V6ONLY, (char *)&optval, optlen) < 0) {
740  optval = TRUE;
741  }
742  }
743 #endif
744  close(sockfd);
745  computed_yet = TRUE;
746  retval = !optval;
747  return retval;
748 }
749 #else /* IPV6_V6ONLY */
750 gboolean
752 {
753  return FALSE;
754 }
755 #endif
756 FSTATIC gboolean
757 _netio_sendareliablefs(NetIO*self, NetAddr*dest, guint16 queueid, FrameSet* frameset)
758 {
759  (void)self; (void)dest; (void)queueid; (void)frameset;
760  g_warn_if_reached();
761  return FALSE;
762 }
763 FSTATIC gboolean
764 _netio_sendreliablefs(NetIO*self, NetAddr* dest, guint16 queueid, GSList* fslist)
765 {
766  (void)self; (void)dest; (void)queueid; (void)fslist;
767  g_warn_if_reached();
768  return FALSE;
769 }
770 FSTATIC gboolean
771 _netio_ackmessage(NetIO* self, NetAddr* dest, FrameSet* frameset)
772 {
773  (void)self; (void)dest; (void)frameset;
774  g_warning("%s.%d: Object does not support ACKing of messages", __FUNCTION__, __LINE__);
775  return FALSE;
776 }
777 FSTATIC gboolean
779 {
780  (void)self;
781  return FALSE;
782 }
783 FSTATIC void
784  _netio_closeconn(NetIO* self, guint16 qid, const NetAddr* destaddr)
785 {
786  (void)self; (void)destaddr; (void)qid;
787  return;
788 }
790 FSTATIC void
791 _netio_netaddr_destroy(gpointer addrptr)
792 {
793  NetAddr* self = CASTTOCLASS(NetAddr, addrptr);
794  UNREF(self);
795 }
796 
798 FSTATIC void
800 , NetAddr * fromaddr
801 , NetAddr* toaddr)
802 {
803  DUMP3("Aliasing from this address", &fromaddr->baseclass, " to the next address");
804  DUMP3("Aliasing to this address", &toaddr->baseclass, " from the previous address");
805  REF(fromaddr);
806  REF(toaddr);
807  g_hash_table_insert(self->aliases, fromaddr, toaddr);
808 }
809 
void _assimobj_finalize(AssimObj *self)
Definition: assimobj.c:61
void setblockio(const NetIO *self, gboolean blocking)
<[in] Set blocking/non-blocking mode
guint16(* port)(const NetAddr *self)
Return port from this address.
Definition: netaddr.h:46
IETF/IANA Address family assignments.
NetAddr * destaddr
Definition: nanomain.c:75
gboolean sendreliablefs(NetIO *self, NetAddr *dest, guint16 queueid, GSList *fslist)
< Reliably send multiple FrameSets (if possible)
guint16(* addrtype)(const NetAddr *self)
Return IANA Address Family Numbers address type.
Definition: netaddr.h:47
#define REF2(obj)
Definition: assimobj.h:40
FSTATIC GSList * _netio_recvframesets(NetIO *self, NetAddr **src)
Member function to receive a collection of FrameSets (GSList*) out of our NetIO object.
Definition: netio.c:631
gboolean outputpending(NetIO *self)
< return TRUE if this object has output pending
FSTATIC void _netio_addalias(NetIO *self, NetAddr *fromaddr, NetAddr *toaddr)
Add an alias to our alias table.
Definition: netio.c:799
void setpktloss(NetIO *self, double rcv, double xmit)
< Set desired fraction of packet loss - TESTING ONLY!
void(* addalias)(NetIO *, NetAddr *, NetAddr *)
Add an alias to our received address alias table.
Definition: netio.h:88
FSTATIC void _netio_finalize(AssimObj *self)
Member function to free this NetIO object.
Definition: netio.c:305
NetAddr *(* toIPv6)(const NetAddr *)
Convert this NetAddr to the IPv6 equivalent It always returns a new object.
Definition: netaddr.h:56
Implements minimal client-oriented Frame and Frameset capabilities.
This is the base Frame class object (in-memory TLV (type, length, value)) for every general component...
Definition: frame.h:43
FSTATIC gboolean _netio_setmcast_ttl(NetIO *self, guint8 ttl)
Set up the multicast TTL for this NetIO object.
Definition: netio.c:229
#define CONFIGNAME_OUTSIG
SignFrame to use to sign/verify packets.
FSTATIC gboolean _netio_supportsreliable(NetIO *self)
Definition: netio.c:778
gboolean ackmessage(NetIO *self, NetAddr *dest, FrameSet *frameset)
< User-level ACK of a message sent reliably
FSTATIC gpointer _netio_recvapacket(NetIO *, gpointer *, struct sockaddr_in6 *, socklen_t *addrlen)
Internal function to receive a packet from our NetIO object General method:
Definition: netio.c:546
gboolean input_queued(const NetIO *self)
<[in] TRUE if input is queued ready to be read
struct sockaddr_in(* ipv4sockaddr)(const NetAddr *self)
Return the ipv4 sockaddr corresponding to this address.
Definition: netaddr.h:52
AssimObj baseclass
Definition: netaddr.h:44
#define CONFIGNAME_CRYPT
Frame to use for encrypting/decrypting packets.
guint16 _addrport
private: Address port (if applicable)
Definition: netaddr.h:61
FSTATIC gsize _netio_getmaxpktsize(const NetIO *self)
Get the max packet size for this NetIO transport.
Definition: netio.c:336
gboolean bindaddr(NetIO *self, const NetAddr *, gboolean silent)
<[in] Bind this NetIO to the given address
The SignFrame class object - implements digital signatures for FrameSets.
Definition: signframe.h:40
gpointer pktend
Last byte past the end of the packet.
Definition: frameset.h:50
#define FSTATIC
Definition: projectcommon.h:31
#define DEBUGMSG3(...)
Definition: proj_classes.h:91
NetAddr * netaddr_sockaddr_new(const struct sockaddr_in6 *sa_in6, socklen_t length)
Create new NetAddr from a struct sockaddr
Definition: netaddr.c:1043
Defines an abstract Network I/O class.
FSTATIC gboolean _netio_ackmessage(NetIO *self, NetAddr *dest, FrameSet *frameset)
Definition: netio.c:771
FSTATIC void _netio_sendaframeset(NetIO *self, const NetAddr *destaddr, FrameSet *frameset)
Definition: netio.c:518
ConfigContext * _configinfo
I/O and other configuration information.
Definition: netio.h:63
#define BINDDEBUG(Cclass)
BINDDEBUG is for telling the class system where the debug variable for this class is - put it in the ...
Definition: proj_classes.h:82
void closeconn(NetIO *self, guint16 qid, const NetAddr *destaddr)
< Flush packets in queues to this address
CompressFrame * _compressframe
Compression frame to use in compressing FrameSets.
Definition: netio.h:67
AssimObj baseclass
Definition: netio.h:59
This is our CompressFrame class object - used for representing a compression method.
Definition: compressframe.h:41
FSTATIC void _netio_sendframesets(NetIO *self, const NetAddr *destaddr, GSList *framesets)
NetIO member function to send a GSList of FrameSets.
Definition: netio.c:487
#define DUMP3(prefix, obj, suffix)
Definition: proj_classes.h:97
FSTATIC NetAddr * _netio_boundaddr(const NetIO *self)
Member function to return the bound NetAddr (with port) of this NetIO object.
Definition: netio.c:283
GHashTable * aliases
IP address aliases for received packets.
Definition: netio.h:68
FSTATIC gboolean _netio_bindaddr(NetIO *self, const NetAddr *src, gboolean silent)
Member function to bind this NewIO object to a NetAddr address.
Definition: netio.c:253
gboolean(* ismcast)(const NetAddr *self)
Return TRUE if this address is a multicast address.
Definition: netaddr.h:48
gboolean netio_is_dual_ipv4v6_stack(void)
Definition: netio.c:751
void frameset_construct_packet(FrameSet *fs, SignFrame *sigframe, Frame *cryptframe, CompressFrame *compressframe)
Construct packet to go correspond to this frameset.
Definition: frameset.c:159
void sendaframeset(NetIO *self, const NetAddr *dest, FrameSet *frameset)
< Send a FrameSet list to a NetIO class
#define FREE(m)
Our interface to free.
Definition: projectcommon.h:29
#define REF(obj)
Definition: assimobj.h:39
FSTATIC void _netio_netaddr_destroy(gpointer addrptr)
g_hash_table destructor for a NetAddr
Definition: netio.c:791
gint getfd(const NetIO *self)
<[in] Return file/socket descriptor
FSTATIC gint _netio_getfd(const NetIO *self)
Member function to return the file descriptor underlying this NetIO object.
Definition: netio.c:91
Frame * cryptframe(NetIO *self)
< return a copied encryption frame for sending
gpointer packet
Pointer to packet (when constructed)
Definition: frameset.h:49
const char * localaddr
Definition: nanomain.c:68
NetIOstats stats
Net I/O stats.
Definition: netio.h:60
FSTATIC void _netio_enablepktloss(NetIO *self, gboolean enable)
Enable (or disable) packet loss as requested.
Definition: netio.c:680
WINEXPORT gboolean netaddr_g_hash_equal(gconstpointer lhs, gconstpointer rhs)
g_hash_table equal comparator for a NetAddr
Definition: netaddr.c:388
#define ADDR_FAMILY_IPV6
IPv6.
CompressFrame * compressframe(NetIO *self)
< return a copied compression frame for sending
Project common header file.
FSTATIC Frame * _netio_cryptframe(NetIO *self)
Definition: netio.c:355
NetAddr *(* boundaddr)(const NetIO *self)
[in] Object to return bound address/port of
Definition: netio.h:79
#define CONST_IPV6_IPV4SPACE
Definition: netaddr.h:78
FSTATIC gboolean _netio_sendareliablefs(NetIO *self, NetAddr *dest, guint16 queueid, FrameSet *frameset)
Definition: netio.c:757
FSTATIC gboolean _netio_mcastjoin(NetIO *self, const NetAddr *src, const NetAddr *localaddr)
Set up a NetIO object to listen to (join) a particular multicast group.
Definition: netio.c:127
#define CONFIGNAME_COMPRESS
Frame to use for compressing/decompressing.
SignFrame * _signframe
Signature frame to use in signing FrameSets.
Definition: netio.h:65
FSTATIC SignFrame * _netio_signframe(NetIO *self)
Definition: netio.c:361
AssimObj * assimobj_new(guint objsize)
Definition: assimobj.c:74
gboolean sendareliablefs(NetIO *self, NetAddr *dest, guint16 queueid, FrameSet *frameset)
[out] source address of return result
void enablepktloss(NetIO *self, gboolean enable)
< enable packet loss (as set above)
void(* _finalize)(AssimObj *)
Free object (private)
Definition: assimobj.h:55
FSTATIC CompressFrame * _netio_compressframe(NetIO *self)
Definition: netio.c:350
PacketDecoder * _decoder
Decodes packets into FrameSets.
Definition: netio.h:64
The NetAddr class class represents a general network address - whether IP, MAC, or any other type of ...
Definition: netaddr.h:43
FSTATIC void _netio_setblockio(const NetIO *self, gboolean blocking)
Member function to set blocking/non-blocking mode on our sockets.
Definition: netio.c:100
gsize setmaxpktsize(NetIO *, gsize)
< Set maximum packet size
#define MALLOC(nbytes)
should it just call g_malloc?
Definition: projectcommon.h:26
#define g_info(...)
Definition: projectcommon.h:66
Defines interfaces a project Class system for class hierarchies in 'C'.
Frame *(* getframe)(const ConfigContext *, const char *)
Get Frame value.
Definition: configcontext.h:90
FSTATIC gboolean _netio_input_queued(const NetIO *self)
Member function that returns TRUE if input is ready to be read.
Definition: netio.c:245
FSTATIC void _netio_setpktloss(NetIO *self, double rcvloss, double xmitloss)
Set the desired level of packet loss - doesn't take effect from this call alone.
Definition: netio.c:672
FrameSet class - used for collecting Frames when not on the wire, and for marshalling/demarshalling t...
Definition: frameset.h:45
FSTATIC gsize _netio_setmaxpktsize(NetIO *self, gsize maxpktsize)
Set the max packet size for this NetIO transport.
Definition: netio.c:343
#define CONST_IPV6_IPV4START
Definition: netaddr.h:79
gchar *(* toString)(gconstpointer)
Produce malloc-ed string representation.
Definition: assimobj.h:58
gboolean supportsreliable(NetIO *self)
< return TRUE if this object supports reliable transport
NetIO * netio_new(gsize objsize, ConfigContext *config, PacketDecoder *decoder)
NetIO constructor.
Definition: netio.c:368
WINEXPORT guint netaddr_g_hash_hash(gconstpointer addrptr)
g_hash_table hash function for a NetAddr
Definition: netaddr.c:397
GSList * recvframesets(NetIO *, NetAddr **src)
< Receive a single datagram's framesets
#define __FUNCTION__
struct _NetIO NetIO
Definition: netio.h:53
gint _maxpktsize
Maximum packet size for this transport.
Definition: netio.h:62
#define DEBUGDECLARATIONS
Definition: proj_classes.h:79
gsize getmaxpktsize(const NetIO *self)
< Return maximum packet size for this NetIO
Frame * _cryptframe
Encryption frame to use in encrypting FrameSets.
Definition: netio.h:66
struct sockaddr_in6(* ipv6sockaddr)(const NetAddr *self)
Return the ipv6 sockaddr corresponding to this address.
Definition: netaddr.h:51
guint16 _addrtype
private: Address type
Definition: netaddr.h:59
FSTATIC void _netio_sendapacket(NetIO *self, gconstpointer packet, gconstpointer pktend, const NetAddr *destaddr)
NetIO internal function to send a packet (datagram)
Definition: netio.c:429
#define ADDR_FAMILY_IPV4
IPv4.
FSTATIC void _netio_closeconn(NetIO *self, guint16 qid, const NetAddr *destaddr)
Definition: netio.c:784
gboolean mcastjoin(NetIO *self, const NetAddr *, const NetAddr *)
<Join multicast group
This file defines a few functions and interfaces for unmarshalling packet data into FrameSets...
SignFrame * signframe(NetIO *self)
< return a copied SignFrame for use in sending
#define UNREF2(obj)
Definition: assimobj.h:36
#define CASTTOCLASS(Cclass, obj)
Safely cast 'obj' to C-class 'class' - verifying that it was registerd as being of type class ...
Definition: proj_classes.h:66
#define UNREF(obj)
Definition: assimobj.h:35
This is a basic NetIO class abstract class for doing network I/O.
Definition: netio.h:58
FSTATIC gboolean _netio_sendreliablefs(NetIO *self, NetAddr *dest, guint16 queueid, GSList *fslist)
Definition: netio.c:764
#define NEWSUBCLASS(Cclass, obj)
Definition: proj_classes.h:67
gboolean setmcast_ttl(NetIO *self, guint8 ttl)
< Set ipv4 multicast TTL
void sendframesets(NetIO *self, const NetAddr *dest, GSList *framesets)
< Send a FrameSet list to a NetIO class