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 }
480 
485 FSTATIC void
487  const NetAddr* destaddr,
488  GSList* framesets)
489 {
490  GSList* curfsl;
491  g_return_if_fail(self != NULL);
492  g_return_if_fail(framesets != NULL);
493  g_return_if_fail(destaddr != NULL);
494  g_return_if_fail(self->_signframe != NULL);
495 
499  for (curfsl=framesets; curfsl != NULL; curfsl=curfsl->next) {
500  FrameSet* curfs = CASTTOCLASS(FrameSet, curfsl->data);
501  SignFrame* signframe = self->signframe(self);
502  Frame* cryptframe = self->cryptframe(self);
503  CompressFrame* compressframe = self->compressframe(self);
504  if (cryptframe) {
505  REF(cryptframe);
506  }
507  if (compressframe) {
508  REF2(compressframe);
509  }
510  frameset_construct_packet(curfs, signframe, cryptframe, compressframe);
511  _netio_sendapacket(self, curfs->packet, curfs->pktend, destaddr);
512  self->stats.fswritten++;
513 
514  }
515 }
516 FSTATIC void
518  const NetAddr* destaddr,
519  FrameSet* frameset)
520 {
521  SignFrame* signframe = self->signframe(self);
522  Frame* cryptframe = self->cryptframe(self);
523  CompressFrame* compressframe = self->compressframe(self);
524  g_return_if_fail(self != NULL);
525  g_return_if_fail(self->_signframe != NULL);
526  g_return_if_fail(frameset != NULL);
527  g_return_if_fail(destaddr != NULL);
528 
529  frameset_construct_packet(frameset, signframe, cryptframe, compressframe);
530  DEBUGMSG3("%s.%d: sent %ld byte packet", __FUNCTION__, __LINE__
531  , (long)(((guint8*)frameset->pktend-(guint8*)frameset->packet)));
532  _netio_sendapacket(self, frameset->packet, frameset->pktend, destaddr);
533 }
534 
542 #include <stdlib.h>
543 #include <memory.h>
544 FSTATIC gpointer
546  gpointer* pktend,
547  struct sockaddr_in6* srcaddr,
548  socklen_t* addrlen)
549 {
550  char dummy[8]; // Make GCC stack protection happy...
551 #ifndef __FUNCTION__
552 # define __FUNCTION__ "_netio_recvapacket"
553 #endif
554  gssize msglen;
555  gssize msglen2;
556  guint8* msgbuf;
557  const guint8 v4any[16] = CONST_IPV6_IPV4START;
558 
559  // First we peek and see how long the message is...
560  *addrlen = sizeof(*srcaddr);
561  memset(srcaddr, 0, sizeof(*srcaddr));
562  msglen = recvfrom(self->getfd(self), dummy, 1, MSG_DONTWAIT|MSG_PEEK|MSG_TRUNC,
563  (struct sockaddr*)srcaddr, addrlen);
564  self->stats.recvcalls ++;
565  if (msglen < 0) {
566  if (errno != EAGAIN) {
567  g_warning("recvfrom(%d, ... MSG_PEEK) failed: %s (in %s:%s:%d)",
568  self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
569  }
570  return NULL;
571  }
572  if (msglen == 0) {
573  g_warning("recvfrom(%d, ... MSG_PEEK) returned zero: %s (in %s:%s:%d)"
574  , self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
575  return NULL;
576  }
577 
578  // Allocate the right amount of memory
579  msgbuf = MALLOC(msglen);
580 
581  // Receive the message
582  *addrlen = sizeof(*srcaddr);
583  msglen2 = recvfrom(self->getfd(self), msgbuf, msglen, MSG_DONTWAIT|MSG_TRUNC,
584  (struct sockaddr *)srcaddr, addrlen);
585  self->stats.recvcalls ++;
586 
587  // Was there an error?
588  if (msglen2 < 0) {
589  g_warning("recvfrom(%d, ... MSG_DONTWAIT) failed: %s (in %s:%s:%d)"
590  , self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
591  FREE(msgbuf); msgbuf = NULL;
592  return NULL;
593  }
594  // Does everything look good?
595  if (msglen2 != msglen) {
596  g_warning("recvfrom(%d, ... MSG_DONTWAIT) returned %"G_GSSIZE_FORMAT" instead of %"G_GSSIZE_FORMAT" (in %s:%s:%d)"
597  , self->getfd(self), msglen2, msglen, __FILE__, __FUNCTION__ , __LINE__);
598  FREE(msgbuf); msgbuf = NULL;
599  return NULL;
600  }
601 
602 #ifdef WIN32
603 #define __in6_u u
604 #define __u6_addr8 Byte
605 #endif
606 
607  if (memcmp(srcaddr->sin6_addr.__in6_u.__u6_addr8, v4any, sizeof(v4any)) == 0) {
608  //const guint8 localhost[16] = CONST_IPV6_LOOPBACK;
609  const guint8 localhost[16] = {CONST_IPV6_IPV4SPACE, 127, 0, 0, 1};
610  // Both experience and RFC5735 say that this is basically "localhost"
611  memcpy(srcaddr->sin6_addr.__in6_u.__u6_addr8, localhost, sizeof(localhost));
612  }
613 
614  // Hah! Looks good!
615  *pktend = (void*) (msgbuf + msglen);
616  DEBUGMSG3("%s.%d: Received %zd byte message", __FUNCTION__, __LINE__, msglen);
617  if (self->_shouldlosepkts) {
618  if (g_random_double() < self->_rcvloss) {
619  g_message("%s: Threw away %"G_GSSIZE_FORMAT" byte input packet"
620  , __FUNCTION__, msglen);
621  FREE(msgbuf);
622  msgbuf = NULL;
623  }
624  }
625  self->stats.pktsread ++;
626  return msgbuf;
627 }
629 FSTATIC GSList*
631  NetAddr** src)
633 {
634  GSList* ret = NULL;
635  gpointer pkt;
636  gpointer pktend;
637  socklen_t addrlen;
638  struct sockaddr_in6 srcaddr;
639 
640  *src = NULL; // Make python happy in case we fail...
641  pkt = _netio_recvapacket(self, &pktend, &srcaddr, &addrlen);
642 
643  if (NULL != pkt) {
644  ret = self->_decoder->pktdata_to_framesetlist(self->_decoder, pkt, pktend);
645  if (NULL != ret) {
646  NetAddr* aliasaddr;
647  *src = netaddr_sockaddr_new(&srcaddr, addrlen);
648  // Some addresses can confuse our clients -- let's check our alias table...
649  if (NULL != (aliasaddr = g_hash_table_lookup(self->aliases, *src))) {
650  // This is a good-enough way to make a copy.
651  aliasaddr->toIPv6(aliasaddr);
652  // Keep the incoming port - since that's always right...
653  aliasaddr->_addrport = (*src)->_addrport;
654  UNREF(*src);
655  *src = aliasaddr;
656  }
657  }else{
658  g_warning("Received a %lu byte packet that didn't make any FrameSets"
659  , (unsigned long)((guint8*)pktend-(guint8*)pkt));
660  FREE(ret); ret = NULL;
661  }
662  FREE(pkt);
663  }
664  if (ret && *src) {
665  self->stats.fsreads += g_slist_length(ret);
666  }
667  return ret;
668 }
670 FSTATIC void
671 _netio_setpktloss (NetIO* self, double rcvloss, double xmitloss)
672 {
673  self->_rcvloss = rcvloss;
674  self->_xmitloss = xmitloss;
675 }
676 
678 FSTATIC void
679 _netio_enablepktloss (NetIO* self, gboolean enable)
680 {
681  self->_shouldlosepkts = enable;
682 }
683 
684 
685 
686 #ifdef IPV6_V6ONLY
687 #ifndef _MSC_VER
688 # include <netdb.h>
689 #endif
690 
694 gboolean
696 {
697  static gboolean computed_yet = FALSE;
698  static gboolean retval = FALSE;
699  gboolean optval;
700  int sockfd;
701  socklen_t optlen;
702  struct protoent*proto;
703 
704  if (computed_yet) {
705  return retval;
706  }
707  proto = getprotobyname("ipv6");
708 #ifdef HAVE_ENDPROTOENT
709  endprotoent();
710 #endif
711  g_return_val_if_fail(proto != NULL, FALSE);
712 
713  sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
714  g_return_val_if_fail(sockfd >= 0, FALSE);
715 
716  optlen = sizeof(retval);
717  optval = TRUE;
718  if (getsockopt(sockfd, proto->p_proto, IPV6_V6ONLY, (char *)&optval, &optlen) < 0) {
719  g_warning("%s.%d: getsockopt failed: %s", __FUNCTION__, __LINE__
720  , g_strerror(errno));
721  close(sockfd);
722  return FALSE;
723  }
724  if (optlen != sizeof(retval)) {
725  // Should never happen...
726  g_warning("%s.%d: getsockopt returned incorrect optlen: %d vs %zd"
727  , __FUNCTION__, __LINE__, optlen, sizeof(retval));
728  close(sockfd);
729  return FALSE;
730  }
731 #ifdef WIN32
732  // See http://msdn.microsoft.com/en-us/library/windows/desktop/bb513665%28v=vs.85%29.aspx
733  // This might be OK for other OSes too...
734  if (optval) {
735  optval = FALSE;
736  if (setsockopt(sockfd, proto->p_proto, IPV6_V6ONLY, (char *)&optval, optlen) < 0) {
739  optval = TRUE;
740  }
741  }
742 #endif
743  close(sockfd);
744  computed_yet = TRUE;
745  retval = !optval;
746  return retval;
747 }
748 #else /* IPV6_V6ONLY */
749 gboolean
751 {
752  return FALSE;
753 }
754 #endif
755 FSTATIC gboolean
756 _netio_sendareliablefs(NetIO*self, NetAddr*dest, guint16 queueid, FrameSet* frameset)
757 {
758  (void)self; (void)dest; (void)queueid; (void)frameset;
759  g_warn_if_reached();
760  return FALSE;
761 }
762 FSTATIC gboolean
763 _netio_sendreliablefs(NetIO*self, NetAddr* dest, guint16 queueid, GSList* fslist)
764 {
765  (void)self; (void)dest; (void)queueid; (void)fslist;
766  g_warn_if_reached();
767  return FALSE;
768 }
769 FSTATIC gboolean
770 _netio_ackmessage(NetIO* self, NetAddr* dest, FrameSet* frameset)
771 {
772  (void)self; (void)dest; (void)frameset;
773  g_warning("%s.%d: Object does not support ACKing of messages", __FUNCTION__, __LINE__);
774  return FALSE;
775 }
776 FSTATIC gboolean
778 {
779  (void)self;
780  return FALSE;
781 }
782 FSTATIC void
783  _netio_closeconn(NetIO* self, guint16 qid, const NetAddr* destaddr)
784 {
785  (void)self; (void)destaddr; (void)qid;
786  return;
787 }
789 FSTATIC void
790 _netio_netaddr_destroy(gpointer addrptr)
791 {
792  NetAddr* self = CASTTOCLASS(NetAddr, addrptr);
793  UNREF(self);
794 }
795 
797 FSTATIC void
799 , NetAddr * fromaddr
800 , NetAddr* toaddr)
801 {
802  DUMP3("Aliasing from this address", &fromaddr->baseclass, " to the next address");
803  DUMP3("Aliasing to this address", &toaddr->baseclass, " from the previous address");
804  REF(fromaddr);
805  REF(toaddr);
806  g_hash_table_insert(self->aliases, fromaddr, toaddr);
807 }
808 
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:72
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:630
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:798
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:777
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:545
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:770
FSTATIC void _netio_sendaframeset(NetIO *self, const NetAddr *destaddr, FrameSet *frameset)
Definition: netio.c:517
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:486
#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:750
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:790
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:65
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:679
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:756
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:671
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:783
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:763
#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