The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules 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 #include <frametypes.h>
53 #include <misc.h>
54 FSTATIC gint _netio_getfd(const NetIO* self);
55 FSTATIC int _netio_getsockbufsize(const NetIO* self, gboolean forinput);
56 FSTATIC int _netio_setsockbufsize(const NetIO* self, gboolean forinput, gsize bufsize);
57 FSTATIC void _netio_maximize_sockbufsize(const NetIO* self, gboolean forinput, int desiredsize);
58 FSTATIC void _netio_setblockio(const NetIO* self, gboolean blocking);
59 FSTATIC gboolean _netio_bindaddr(NetIO* self, const NetAddr* src, gboolean silent);
60 FSTATIC gboolean _netio_input_queued(const NetIO* self);
62 FSTATIC void _netio_sendframesets(NetIO* self, const NetAddr* destaddr, GSList* framesets);
63 FSTATIC void _netio_sendaframeset(NetIO* self, const NetAddr* destaddr, FrameSet* frameset);
64 FSTATIC void _netio_finalize(AssimObj* self);
65 FSTATIC void _netio_sendapacket(NetIO* self, gconstpointer packet, gconstpointer pktend, const NetAddr* destaddr);
66 FSTATIC gpointer _netio_recvapacket(NetIO*, gpointer*, struct sockaddr_in6*, socklen_t*addrlen);
67 FSTATIC gsize _netio_getmaxpktsize(const NetIO* self);
68 FSTATIC gsize _netio_setmaxpktsize(NetIO* self, gsize maxpktsize);
69 FSTATIC GSList* _netio_recvframesets(NetIO*self , NetAddr** src);
72 FSTATIC gboolean _netio_mcastjoin(NetIO* self, const NetAddr* src, const NetAddr*localaddr);
73 FSTATIC gboolean _netio_setmcast_ttl(NetIO* self, guint8 ttl);
74 FSTATIC void _netio_enablepktloss(NetIO* self, gboolean enable);
75 FSTATIC void _netio_setpktloss(NetIO* self, double rcvloss, double xmitloss);
76 FSTATIC gboolean _netio_sendareliablefs(NetIO*self, NetAddr*dest, guint16 queueid, FrameSet* frameset);
77 FSTATIC gboolean _netio_sendreliablefs(NetIO*self, NetAddr* dest, guint16 queueid, GSList* fslist);
78 FSTATIC gboolean _netio_ackmessage(NetIO* self, NetAddr* dest, FrameSet* frameset);
79 FSTATIC gboolean _netio_supportsreliable(NetIO* self);
80 FSTATIC void _netio_closeconn(NetIO* self, guint16 qid, const NetAddr* destaddr);
81 FSTATIC void _netio_netaddr_destroy(gpointer addrptr);
82 FSTATIC void _netio_addalias(NetIO* self, NetAddr * fromaddr, NetAddr* toaddr);
83 
85 
92 
94 FSTATIC gint
95 _netio_getfd(const NetIO* self)
96 {
97  g_return_val_if_fail(NULL != self, -1);
98  g_return_val_if_fail(NULL != self->giosock, -1);
99  return g_io_channel_unix_get_fd(self->giosock);
100 }
101 
103 FSTATIC void
104 _netio_setblockio(const NetIO* self, gboolean blocking)
105 {
106  int chanflags = g_io_channel_get_flags(self->giosock);
107 #ifndef WIN32
108  int fcntlflags = fcntl (self->getfd(self), F_GETFL, 0);
109  if (blocking) {
110  fcntlflags |= O_NONBLOCK;
111  }else{
112  fcntlflags &= ~O_NONBLOCK;
113  }
114  if (fcntl(self->getfd(self), F_SETFL, fcntlflags) < 0) {
115  g_critical("%s.%d: fcntl(F_SETFL, 0x%x) failed: %s", __FUNCTION__, __LINE__
116  , fcntlflags, g_strerror(errno));
117  return;
118  }
119 #endif
120  if (blocking) {
121  chanflags |= G_IO_FLAG_NONBLOCK;
122  }else{
123  chanflags &= ~G_IO_FLAG_NONBLOCK;
124  }
125  g_io_channel_set_flags(self->giosock, chanflags, NULL);
126 }
127 
128 
130 FSTATIC gboolean
131 _netio_mcastjoin(NetIO* self, const NetAddr* src, const NetAddr*localaddr)
132 {
133  int rc = -1;
134  NetAddr* genlocal = NULL;
135 
136 
137  errno = 0;
138 
139  if (!src->ismcast(src)) {
140  g_warning("%s: Cannot join multicast group with non-multicast address"
141  , __FUNCTION__);
142  goto getout;
143  }
144  if (localaddr != NULL && src->_addrtype != localaddr->_addrtype) {
145  g_warning("%s: Cannot join multicast group with differing address types"
146  , __FUNCTION__);
147  goto getout;
148  }
149 
150  if (ADDR_FAMILY_IPV6 == src->_addrtype ) {
151  struct ipv6_mreq multicast_request;
152  struct sockaddr_in6 saddr;
153  saddr = src->ipv6sockaddr(src);
154  memset(&multicast_request, 0, sizeof(multicast_request));
155  memcpy(&multicast_request.ipv6mr_multiaddr, &saddr
156  , sizeof(multicast_request.ipv6mr_multiaddr));
157 
158  if (localaddr == NULL) {
159  genlocal = self->boundaddr(self);
160  localaddr = genlocal;
161  if (localaddr->addrtype(localaddr) != ADDR_FAMILY_IPV6) {
162  localaddr = NULL;
163  }
164  }
165 
166  if (localaddr != NULL) {
167  struct sockaddr_in6 laddr;
168  laddr = localaddr->ipv6sockaddr(localaddr);
169  memcpy(&multicast_request.ipv6mr_interface, &laddr.sin6_addr
170  , sizeof(multicast_request.ipv6mr_interface));
171  }
172  if (localaddr && localaddr->addrtype(localaddr) != ADDR_FAMILY_IPV6) {
173  g_warning("%s: Cannot join v6 multicast group - local address not IPv6"
174  , __FUNCTION__);
175  goto getout;
176  }
177 
178  rc = setsockopt(self->getfd(self), IPPROTO_IPV6, IPV6_JOIN_GROUP
179  , (gpointer)&multicast_request, sizeof(multicast_request));
180  if (rc != 0) {
181  g_warning("%s: Cannot join v6 multicast group [%s (errno:%d)]"
182  , __FUNCTION__, g_strerror(errno), errno);
183  }
184  }else if (ADDR_FAMILY_IPV4 == src->_addrtype) {
185  struct ip_mreqn multicast_request;
186  struct sockaddr_in saddr;
187  memset(&multicast_request, 0, sizeof(multicast_request));
188  saddr = src->ipv4sockaddr(src);
189  memcpy(&multicast_request.imr_multiaddr, &saddr.sin_addr
190  , sizeof(multicast_request.imr_multiaddr));
191 
192  if (localaddr == NULL) {
193  genlocal = self->boundaddr(self);
194  localaddr = genlocal;
195  if (localaddr->addrtype(localaddr) != ADDR_FAMILY_IPV4) {
196  localaddr = NULL;
197  }
198  }
199  if (localaddr && localaddr->addrtype(localaddr) != ADDR_FAMILY_IPV4) {
200  g_warning("%s: Cannot join v4 multicast group - local address not IPv4"
201  , __FUNCTION__);
202  goto getout;
203  }
204 
205  if (localaddr != NULL) {
206  struct sockaddr_in laddr;
207  laddr = localaddr->ipv4sockaddr(localaddr);
208  memcpy(&multicast_request.imr_address, &laddr.sin_addr
209  , sizeof(multicast_request.imr_address));
210  }
211 
212  rc = setsockopt(self->getfd(self), IPPROTO_IP, IP_ADD_MEMBERSHIP
213  , (gpointer)&multicast_request, sizeof(multicast_request));
214  if (rc != 0) {
215  g_warning("%s: Cannot join v4 multicast group [%s (errno:%d)]"
216  , __FUNCTION__, g_strerror(errno), errno);
217  }else{
218  // Default to the largest organizational scope defined...
219  self->setmcast_ttl(self, 31);
220  }
221  }
222 getout:
223  if (genlocal) {
224  UNREF(genlocal);
225  genlocal = NULL;
226  }
227 
228  return (rc == 0);
229 }
230 
232 gboolean
234  guint8 ttlin)
235 {
243  int ttl = ttlin;
244  return setsockopt(self->getfd(self), IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl) == 0);
245 }
246 
248 FSTATIC int
249 _netio_getsockbufsize(const NetIO* self, gboolean forinput)
250 {
251  int optname = (forinput ? SO_RCVBUF : SO_SNDBUF);
252  int retval;
253  socklen_t retvalsize = sizeof(retval);
254 
255  errno = 0;
256  if (getsockopt(self->getfd(self), SOL_SOCKET, optname, &retval, &retvalsize) < 0
257  || retvalsize != sizeof(retval)) {
258  g_warning("%s.%d: getsockopt(%d, IPPROTO_UDP, %d, &retval, %d) failed [%s]"
259  , __FUNCTION__, __LINE__
260  , self->getfd(self), optname, retvalsize, g_strerror(errno));
261  return -1;
262  }
263  return (gsize)retval;
264 }
267 FSTATIC int
268 _netio_setsockbufsize(const NetIO* self, gboolean forinput, gsize bufsize)
269 {
270  int optname = (forinput ? SO_RCVBUF : SO_SNDBUF);
271  int retval;
272  socklen_t retvalsize = sizeof(retval);
273 
274  retval = bufsize;
275  DEBUGMSG2("%s.%d: trying to set %sput buffer size to %d", __FUNCTION__, __LINE__
276  , (forinput ? "in" : "out"), retval);
277 
278  if (setsockopt(self->getfd(self), SOL_SOCKET, optname, &retval, retvalsize) < 0) {
279 #ifdef SO_RCVBUFFORCE
280  int forcename = (forinput ? SO_RCVBUFFORCE : SO_SNDBUFFORCE);
281 
282  if (setsockopt(self->getfd(self), SOL_SOCKET, forcename, &retval, retvalsize) >= 0) {
283  return _netio_getsockbufsize(self, forinput);
284  }
285 #endif
286  }
287  retval = _netio_getsockbufsize(self, forinput);
288  if (retval < (int)bufsize) {
289  _netio_maximize_sockbufsize(self, forinput, bufsize);
290  retval = _netio_getsockbufsize(self, forinput);
291  }
292  return retval;
293 }
294 
296 FSTATIC void
297 _netio_maximize_sockbufsize(const NetIO* self, gboolean forinput, int desiredsize)
298 {
299  int optname = (forinput ? SO_RCVBUF : SO_SNDBUF);
300  int lowval = _netio_getsockbufsize(self, forinput)/2;
301  int highval = desiredsize;
302 
303  if (lowval >= desiredsize) {
304  return;
305  }
306  // This is your basic binary search...
307  while (lowval < highval) {
308  int midpoint = (lowval + highval) / 2;
309  int retval;
310  const socklen_t retvalsize = sizeof(retval);
311  if (midpoint == lowval) {
312  break;
313  }
314  retval = midpoint;
315  DEBUGMSG2("%s.%d: trying %sput buffer size %d", __FUNCTION__, __LINE__
316  , (forinput ? "in" : "out"), retval);
317  if (setsockopt(self->getfd(self), IPPROTO_UDP, optname, &retval, retvalsize) < 0) {
318 #ifdef SO_RCVBUFFORCE
319  int forcename = (forinput ? SO_RCVBUFFORCE : SO_SNDBUFFORCE);
320  if (setsockopt(self->getfd(self), SOL_SOCKET, forcename, &retval, retvalsize) >= 0){
321  lowval = midpoint;
322  continue;
323  }
324 #endif
325  highval = midpoint;
326  }else{
327  lowval = midpoint;
328  }
329  }
330 }
331 
332 
334 FSTATIC gboolean
336 {
337  (void)self;
338  return FALSE; // By default we don't have any input queues
339 }
340 
342 FSTATIC gboolean
344  const NetAddr* src,
345  gboolean silent)
346 {
347  gint sockfd;
348  struct sockaddr_in6 saddr;
349  int rc;
350  g_return_val_if_fail(NULL != self, FALSE);
351  g_return_val_if_fail(NULL != self->giosock, FALSE);
352  sockfd = self->getfd(self);
353 
354  if (src->ismcast(src)) {
355  g_warning("%s: Attempt to bind to multicast address.", __FUNCTION__);
356  return FALSE;
357  }
358  memset(&saddr, 0x00, sizeof(saddr));
359  saddr.sin6_family = AF_INET6;
360  saddr.sin6_port = src->port(src);
361  g_return_val_if_fail(src->addrtype(src) == ADDR_FAMILY_IPV4 || src->addrtype(src) == ADDR_FAMILY_IPV6, FALSE);
362 
363  saddr = src->ipv6sockaddr(src);
364  rc = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
365  if (rc != 0 && !silent) {
366  g_warning("%s: Cannot bind to address [%s (errno:%d)]"
367  , __FUNCTION__, g_strerror(errno), errno);
368  }
369  return rc == 0;
370 }
373 _netio_boundaddr(const NetIO* self)
374 {
375  gint sockfd = self->getfd(self);
376  struct sockaddr_in6 saddr;
377  socklen_t saddrlen = sizeof(saddr);
378  socklen_t retsize = saddrlen;
379 
380 
381  if (getsockname(sockfd, (struct sockaddr*)&saddr, &retsize) < 0) {
382  g_warning("%s: Cannot retrieve bound address [%s]", __FUNCTION__, g_strerror(errno));
383  return NULL;
384  }
385  if (retsize != saddrlen) {
386  g_warning("%s: Truncated getsockname() return [%d/%d bytes]", __FUNCTION__, retsize, saddrlen);
387  return NULL;
388  }
389  return netaddr_sockaddr_new(&saddr, saddrlen);
390 
391 }
392 
394 FSTATIC void
396 {
397  NetIO* self = CASTTOCLASS(NetIO, aself);
398  if (self->giosock) {
399  g_io_channel_shutdown(self->giosock, TRUE, NULL);
400  g_io_channel_unref(self->giosock);
401  self->giosock = NULL;
402  }
403  if (self->_signframe) {
404  UNREF2(self->_signframe);
405  }
406  if (self->_compressframe) {
407  UNREF2(self->_compressframe);
408  }
409  if (self->_decoder) {
410  UNREF(self->_decoder);
411  }
412 
413  // Free up our hash table of aliases
414  if (self->aliases) {
415  g_hash_table_destroy(self->aliases); // It will free the NetAddrs contained therein
416  self->aliases = NULL;
417  }
418  _assimobj_finalize(aself); self = NULL; aself = NULL;
419 }
420 
422 FSTATIC gsize
424 {
425  return self->_maxpktsize;
426 }
427 
429 FSTATIC gsize
431  gsize maxpktsize)
432 {
433  self->_maxpktsize = maxpktsize;
434  return self->getmaxpktsize(self);
435 }
438 {
439  return self->_compressframe;
440 }
441 
444 {
445  return self->_signframe;
446 }
447 
449 NetIO*
450 netio_new(gsize objsize
452  , PacketDecoder*decoder)
453 {
454  NetIO* ret;
455  Frame* f;
456 
457  BINDDEBUG(NetIO);
458  if (objsize < sizeof(NetIO)) {
459  objsize = sizeof(NetIO);
460  }
461  ret = NEWSUBCLASS(NetIO, assimobj_new(objsize));
463  ret->getfd = _netio_getfd;
466  ret->bindaddr = _netio_bindaddr;
482  ret->supportsreliable = _netio_supportsreliable; // It just returns FALSE
483  ret->outputpending = _netio_supportsreliable; // It just returns FALSE
484  ret->addalias = _netio_addalias;
488  ret->_maxpktsize = 65300;
489  ret->_configinfo = config;
490  ret->_decoder = decoder;
491  REF(decoder);
492  f = config->getframe(config, CONFIGNAME_OUTSIG);
493  g_return_val_if_fail(f != NULL, NULL);
494  REF(f);
495  ret->_signframe = CASTTOCLASS(SignFrame, f);
497  if (ret->_compressframe) {
498  REF2(ret->_compressframe);
499  }
500  ret->aliases = g_hash_table_new_full(netaddr_g_hash_hash, netaddr_g_hash_equal
501  , _netio_netaddr_destroy, _netio_netaddr_destroy); // Keys and data are same type...
502  memset(&ret->stats, 0, sizeof(ret->stats));
503  return ret;
504 }
505 
507 FSTATIC void
509  gconstpointer packet,
510  gconstpointer pktend,
511  const NetAddr* destaddr)
512 {
513  struct sockaddr_in6 v6addr = destaddr->ipv6sockaddr(destaddr);
514  gssize length = (const guint8*)pktend - (const guint8*)packet;
515  gssize rc;
516  guint flags = 0x00;
517  g_return_if_fail(length > 0);
518 
519  DUMP3(__FUNCTION__, &destaddr->baseclass, " is destination address");
520  DUMP3(__FUNCTION__, &self->baseclass, " is NetIO object");
521  if (self->_shouldlosepkts) {
522  if (g_random_double() < self->_xmitloss) {
523  g_message("%s.%d: Threw away %"G_GSSIZE_FORMAT" byte output packet"
524  , __FUNCTION__, __LINE__, length);
525  return;
526  }
527  }
528 
529  rc = sendto(self->getfd(self), packet, (size_t)length, flags, (const struct sockaddr*)&v6addr, sizeof(v6addr));
530  DEBUGMSG3("%s.%d: sendto(%d, %ld, [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x], port=%d) returned %ld"
531  , __FUNCTION__, __LINE__, self->getfd(self), (long)length
532  , ntohs(v6addr.sin6_addr.s6_addr16[0])
533  , ntohs(v6addr.sin6_addr.s6_addr16[1])
534  , ntohs(v6addr.sin6_addr.s6_addr16[2])
535  , ntohs(v6addr.sin6_addr.s6_addr16[3])
536  , ntohs(v6addr.sin6_addr.s6_addr16[4])
537  , ntohs(v6addr.sin6_addr.s6_addr16[5])
538  , ntohs(v6addr.sin6_addr.s6_addr16[6])
539  , ntohs(v6addr.sin6_addr.s6_addr16[7])
540  , ntohs(v6addr.sin6_port)
541  , (long)rc);
542  self->stats.sendcalls ++;
543  self->stats.pktswritten ++;
544  if (rc == -1 && errno == EPERM) {
545  g_info("%s.%d: Got a weird sendto EPERM error for %"G_GSSIZE_FORMAT" byte packet."
546  , __FUNCTION__, __LINE__, (gssize)length);
547  g_info("%s.%d: This only seems to happen under Docker..."
548  , __FUNCTION__, __LINE__);
549  return;
550  }
551  if (rc != length) {
552  char * tostring = destaddr->baseclass.toString(destaddr);
553  g_warning(
554  "%s: sendto returned %"G_GSSIZE_FORMAT " vs %"G_GSSIZE_FORMAT" with errno %s"
555  , __FUNCTION__, rc, (gssize)length, g_strerror(errno));
556  g_warning("%s: destaddr:[%s] ", __FUNCTION__, tostring);
557  g_free(tostring); tostring = NULL;
558  }
559  //g_return_if_fail(rc == length);
560  g_warn_if_fail(rc == length);
561 }
562 
567 FSTATIC void
569  const NetAddr* destaddr,
570  GSList* framesets)
571 {
572  GSList* curfsl;
573  g_return_if_fail(self != NULL);
574  g_return_if_fail(framesets != NULL);
575  g_return_if_fail(destaddr != NULL);
576  g_return_if_fail(self->_signframe != NULL);
577 
581  for (curfsl=framesets; curfsl != NULL; curfsl=curfsl->next) {
582  FrameSet* curfs = CASTTOCLASS(FrameSet, curfsl->data);
583  SignFrame* signframe = self->signframe(self);
584  CryptFrame* cryptframe = NULL;
585  CompressFrame* compressframe = self->compressframe(self);
586  if (compressframe) {
587  REF2(compressframe);
588  }
589  cryptframe = cryptframe_new_by_destaddr(destaddr);
590  DEBUGMSG3("%s.%d: cryptframe: %p", __FUNCTION__, __LINE__, cryptframe);
591  frameset_construct_packet(curfs, signframe, cryptframe, compressframe);
592  if (cryptframe) {
593  DEBUGMSG3("%s.%d: Sending encrypted packet.", __FUNCTION__, __LINE__);
594  UNREF2(cryptframe);
595  }
596  DUMP3(__FUNCTION__, &curfs->baseclass, "is the frameset being sent");
597  _netio_sendapacket(self, curfs->packet, curfs->pktend, destaddr);
598  self->stats.fswritten++;
599  }
600 }
601 FSTATIC void
603  const NetAddr* destaddr,
604  FrameSet* frameset)
605 {
606  SignFrame* signframe = self->signframe(self);
607  CryptFrame* cryptframe;
608  CompressFrame* compressframe = self->compressframe(self);
609  g_return_if_fail(self != NULL);
610  g_return_if_fail(self->_signframe != NULL);
611  g_return_if_fail(frameset != NULL);
612  g_return_if_fail(destaddr != NULL);
613 
614  cryptframe = cryptframe_new_by_destaddr(destaddr);
615  DEBUGMSG3("%s.%d: cryptframe: %p", __FUNCTION__, __LINE__, cryptframe);
616  frameset_construct_packet(frameset, signframe, cryptframe, compressframe);
617  DEBUGMSG3("%s.%d: packet constructed (marshalled)", __FUNCTION__, __LINE__);
618  if (cryptframe) {
619  DEBUGMSG3("%s.%d: Sending encrypted packet.", __FUNCTION__, __LINE__);
620  UNREF2(cryptframe);
621  }
622  DEBUGMSG3("%s.%d: sending %ld byte packet", __FUNCTION__, __LINE__
623  , (long)(((guint8*)frameset->pktend-(guint8*)frameset->packet)));
624  DUMP3(__FUNCTION__, &frameset->baseclass, "is the frameset being sent");
625  _netio_sendapacket(self, frameset->packet, frameset->pktend, destaddr);
626 }
627 
635 #include <stdlib.h>
636 #include <memory.h>
637 FSTATIC gpointer
639  gpointer* pktend,
640  struct sockaddr_in6* srcaddr,
641  socklen_t* addrlen)
642 {
643  char dummy[8]; // Make GCC stack protection happy...
644 #ifndef __FUNCTION__
645 # define __FUNCTION__ "_netio_recvapacket"
646 #endif
647  gssize msglen;
648  gssize msglen2;
649  guint8* msgbuf;
650  const guint8 v4any[16] = CONST_IPV6_IPV4START;
651 
652  // First we peek and see how long the message is...
653  *addrlen = sizeof(*srcaddr);
654  memset(srcaddr, 0, sizeof(*srcaddr));
655  msglen = recvfrom(self->getfd(self), dummy, 1, MSG_DONTWAIT|MSG_PEEK|MSG_TRUNC,
656  (struct sockaddr*)srcaddr, addrlen);
657  self->stats.recvcalls ++;
658  if (msglen < 0) {
659  if (errno != EAGAIN) {
660  g_warning("recvfrom(%d, ... MSG_PEEK) failed: %s (in %s:%s:%d)",
661  self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
662  }
663  return NULL;
664  }
665  if (msglen == 0) {
666  g_warning("recvfrom(%d, ... MSG_PEEK) returned zero: %s (in %s:%s:%d)"
667  , self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
668  return NULL;
669  }
670 
671  // Allocate the right amount of memory
672  msgbuf = MALLOC(msglen);
673 
674  // Receive the message
675  *addrlen = sizeof(*srcaddr);
676  msglen2 = recvfrom(self->getfd(self), msgbuf, msglen, MSG_DONTWAIT|MSG_TRUNC,
677  (struct sockaddr *)srcaddr, addrlen);
678  self->stats.recvcalls ++;
679 
680  // Was there an error?
681  if (msglen2 < 0) {
682  g_warning("recvfrom(%d, ... MSG_DONTWAIT) failed: %s (in %s:%s:%d)"
683  , self->getfd(self), g_strerror(errno), __FILE__, __FUNCTION__, __LINE__);
684  FREE(msgbuf); msgbuf = NULL;
685  return NULL;
686  }
687  // Does everything look good?
688  if (msglen2 != msglen) {
689  g_warning("recvfrom(%d, ... MSG_DONTWAIT) returned %"G_GSSIZE_FORMAT" instead of %"G_GSSIZE_FORMAT" (in %s:%s:%d)"
690  , self->getfd(self), msglen2, msglen, __FILE__, __FUNCTION__ , __LINE__);
691  FREE(msgbuf); msgbuf = NULL;
692  return NULL;
693  }
694 
695 #ifdef WIN32
696 #define __in6_u u
697 #define __u6_addr8 Byte
698 #endif
699 
700  if (memcmp(srcaddr->sin6_addr.__in6_u.__u6_addr8, v4any, sizeof(v4any)) == 0) {
701  //const guint8 localhost[16] = CONST_IPV6_LOOPBACK;
702  const guint8 localhost[16] = {CONST_IPV6_IPV4SPACE, 127, 0, 0, 1};
703  // Both experience and RFC5735 say that this is basically "localhost"
704  memcpy(srcaddr->sin6_addr.__in6_u.__u6_addr8, localhost, sizeof(localhost));
705  }
706 
707  // Hah! Looks good!
708  *pktend = (void*) (msgbuf + msglen);
709  DEBUGMSG3("%s.%d: Received %zd byte message", __FUNCTION__, __LINE__, msglen);
710  if (self->_shouldlosepkts) {
711  if (g_random_double() < self->_rcvloss) {
712  g_message("%s: Threw away %"G_GSSIZE_FORMAT" byte input packet"
713  , __FUNCTION__, msglen);
714  FREE(msgbuf);
715  msgbuf = NULL;
716  }
717  }
718  self->stats.pktsread ++;
719  return msgbuf;
720 }
722 FSTATIC GSList*
724  NetAddr** src)
726 {
727  GSList* ret = NULL;
728  gpointer pkt;
729  gpointer pktend;
730  socklen_t addrlen;
731  struct sockaddr_in6 srcaddr;
732 
733  *src = NULL; // Make python happy in case we fail...
734  pkt = _netio_recvapacket(self, &pktend, &srcaddr, &addrlen);
735 
736  if (NULL != pkt) {
737  ret = self->_decoder->pktdata_to_framesetlist(self->_decoder, pkt, pktend);
738  if (NULL != ret) {
739  NetAddr* aliasaddr;
740  *src = netaddr_sockaddr_new(&srcaddr, addrlen);
741  // Some addresses can confuse our clients -- let's check our alias table...
742  if (NULL != (aliasaddr = g_hash_table_lookup(self->aliases, *src))) {
743  // This is a good-enough way to make a copy.
744  NetAddr* aliascopy = aliasaddr->toIPv6(aliasaddr);
745  // Keep the incoming port - since that's always right...
746  aliascopy->_addrport = (*src)->_addrport;
747  UNREF(*src);
748  *src = aliascopy;
749  }
750  if (DEBUG >= 3) {
751  char * srcstr = (*src)->baseclass.toString(&(*src)->baseclass);
752  DEBUGMSG("%s.%d: Received %d bytes making %d FrameSets from %s"
753  , __FUNCTION__, __LINE__, (int)((guint8*)pktend-(guint8*)pkt)
754  , g_slist_length(ret), srcstr);
755  FREE(srcstr); srcstr = NULL;
756  }
757  }else{
758  g_warning("%s.%d: Received a %lu byte packet from that didn't make any FrameSets"
759  , __FUNCTION__, __LINE__, (unsigned long)((guint8*)pktend-(guint8*)pkt));
760  goto badret;
761  }
762  FREE(pkt);
763  }
764  if (ret && *src) {
765  self->stats.fsreads += g_slist_length(ret);
766  }
767  return ret;
768 badret:
770  ret = NULL;
771  return ret;
772 }
774 FSTATIC void
775 _netio_setpktloss (NetIO* self, double rcvloss, double xmitloss)
776 {
777  self->_rcvloss = rcvloss;
778  self->_xmitloss = xmitloss;
779 }
780 
782 FSTATIC void
783 _netio_enablepktloss (NetIO* self, gboolean enable)
784 {
785  self->_shouldlosepkts = enable;
786 }
787 
788 
789 
790 #ifdef IPV6_V6ONLY
791 #ifndef _MSC_VER
792 # include <netdb.h>
793 #endif
794 
798 gboolean
800 {
801  static gboolean computed_yet = FALSE;
802  static gboolean retval = FALSE;
803  gboolean optval;
804  int sockfd;
805  socklen_t optlen;
806  struct protoent*proto;
807 
808  if (computed_yet) {
809  return retval;
810  }
811  proto = getprotobyname("ipv6");
812 #ifdef HAVE_ENDPROTOENT
813  endprotoent();
814 #endif
815  g_return_val_if_fail(proto != NULL, FALSE);
816 
817  sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
818  g_return_val_if_fail(sockfd >= 0, FALSE);
819 
820  optlen = sizeof(retval);
821  optval = TRUE;
822  if (getsockopt(sockfd, proto->p_proto, IPV6_V6ONLY, (char *)&optval, &optlen) < 0) {
823  g_warning("%s.%d: getsockopt failed: %s", __FUNCTION__, __LINE__
824  , g_strerror(errno));
825  close(sockfd);
826  return FALSE;
827  }
828  if (optlen != sizeof(retval)) {
829  // Should never happen...
830  g_warning("%s.%d: getsockopt returned incorrect optlen: %d vs %zd"
831  , __FUNCTION__, __LINE__, optlen, sizeof(retval));
832  close(sockfd);
833  return FALSE;
834  }
835 #ifdef WIN32
836  // See http://msdn.microsoft.com/en-us/library/windows/desktop/bb513665%28v=vs.85%29.aspx
837  // This might be OK for other OSes too...
838  if (optval) {
839  optval = FALSE;
840  if (setsockopt(sockfd, proto->p_proto, IPV6_V6ONLY, (char *)&optval, optlen) < 0) {
843  optval = TRUE;
844  }
845  }
846 #endif
847  close(sockfd);
848  computed_yet = TRUE;
849  retval = !optval;
850  return retval;
851 }
852 #else /* IPV6_V6ONLY */
853 gboolean
855 {
856  return FALSE;
857 }
858 #endif
859 FSTATIC gboolean
860 _netio_sendareliablefs(NetIO*self, NetAddr*dest, guint16 queueid, FrameSet* frameset)
861 {
862  (void)self; (void)dest; (void)queueid; (void)frameset;
863  g_warn_if_reached();
864  return FALSE;
865 }
866 FSTATIC gboolean
867 _netio_sendreliablefs(NetIO*self, NetAddr* dest, guint16 queueid, GSList* fslist)
868 {
869  (void)self; (void)dest; (void)queueid; (void)fslist;
870  g_warn_if_reached();
871  return FALSE;
872 }
873 FSTATIC gboolean
874 _netio_ackmessage(NetIO* self, NetAddr* dest, FrameSet* frameset)
875 {
876  (void)self; (void)dest; (void)frameset;
877  g_warning("%s.%d: Object does not support ACKing of messages", __FUNCTION__, __LINE__);
878  return FALSE;
879 }
880 FSTATIC gboolean
882 {
883  (void)self;
884  return FALSE;
885 }
886 FSTATIC void
887  _netio_closeconn(NetIO* self, guint16 qid, const NetAddr* destaddr)
888 {
889  (void)self; (void)destaddr; (void)qid;
890  return;
891 }
893 FSTATIC void
894 _netio_netaddr_destroy(gpointer addrptr)
895 {
896  NetAddr* self = CASTTOCLASS(NetAddr, addrptr);
897  UNREF(self);
898 }
899 
901 FSTATIC void
903 , NetAddr * fromaddr
904 , NetAddr* toaddr)
905 {
906  DUMP3("Aliasing from this address", &fromaddr->baseclass, " to the next address");
907  DUMP3("Aliasing to this address", &toaddr->baseclass, " from the previous address");
908  REF(fromaddr);
909  REF(toaddr);
910  g_hash_table_insert(self->aliases, fromaddr, toaddr);
911 }
912 
int setsockbufsize(const NetIO *self, gboolean forinput, gsize bufsize)
< Set socket buffer size - return new size or -1
void _assimobj_finalize(AssimObj *self)
Definition: assimobj.c:61
void setblockio(const NetIO *self, gboolean blocking)
< Set blocking/non-blocking mode
AssimObj baseclass
Definition: frameset.h:47
guint16(* port)(const NetAddr *self)
Return port from this address.
Definition: netaddr.h:46
IETF/IANA Address family assignments.
Defines miscellaneous interfaces.
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:723
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:902
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:87
FSTATIC void _netio_finalize(AssimObj *self)
Member function to free this NetIO object.
Definition: netio.c:395
#define DEBUGMSG(...)
Definition: proj_classes.h:87
NetAddr *(* toIPv6)(const NetAddr *)
Convert this NetAddr to the IPv6 equivalent It always returns a new object.
Definition: netaddr.h:56
FSTATIC void _netio_maximize_sockbufsize(const NetIO *self, gboolean forinput, int desiredsize)
Maximize the socket buffer size as requested - as best we can...
Definition: netio.c:297
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:233
#define CONFIGNAME_OUTSIG
SignFrame to use to sign/verify packets.
FSTATIC gboolean _netio_supportsreliable(NetIO *self)
Definition: netio.c:881
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:638
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
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:423
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:47
gpointer pktend
Last byte past the end of the packet.
Definition: frameset.h:51
#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:874
FSTATIC void _netio_sendaframeset(NetIO *self, const NetAddr *destaddr, FrameSet *frameset)
Definition: netio.c:602
ConfigContext * _configinfo
I/O and other configuration information.
Definition: netio.h:63
WINEXPORT CryptFrame * cryptframe_new_by_destaddr(const NetAddr *destaddr)
Construct a CryptFrame class appropriate for encrypting messages to destaddr
Definition: cryptframe.c:488
#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:66
AssimObj baseclass
Definition: netio.h:59
#define DEBUG
Definition: proj_classes.h:85
This is our CompressFrame class object - used for representing a compression method.
Definition: compressframe.h:41
WINEXPORT void assim_g_notify_unref(gpointer assimobj)
Unref for glib notify.
Definition: misc.c:725
FSTATIC void _netio_sendframesets(NetIO *self, const NetAddr *destaddr, GSList *framesets)
NetIO member function to send a GSList of FrameSets.
Definition: netio.c:568
#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:373
GHashTable * aliases
IP address aliases for received packets.
Definition: netio.h:67
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:343
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:854
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:894
gint getfd(const NetIO *self)
< 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:95
gpointer packet
Pointer to packet (when constructed)
Definition: frameset.h:50
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:783
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.
Header file defining the data layouts for our Frames.
NetAddr *(* boundaddr)(const NetIO *self)
[in] Object to return bound address/port of
Definition: netio.h:78
#define CONST_IPV6_IPV4SPACE
Definition: netaddr.h:78
FSTATIC gboolean _netio_sendareliablefs(NetIO *self, NetAddr *dest, guint16 queueid, FrameSet *frameset)
Definition: netio.c:860
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:131
#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:443
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)
int getsockbufsize(const NetIO *self, gboolean forinput)
< Return socket buffer size: -1 on failure
void(* _finalize)(AssimObj *)
Free object (private)
Definition: assimobj.h:55
FSTATIC CompressFrame * _netio_compressframe(NetIO *self)
Definition: netio.c:437
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:104
gsize setmaxpktsize(NetIO *, gsize)
< Set maximum packet size
#define g_slist_free_full
Definition: projectcommon.h:73
#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:335
void frameset_construct_packet(FrameSet *fs, SignFrame *sigframe, CryptFrame *cryptframe, CompressFrame *compressframe)
Construct packet to go correspond to this frameset.
Definition: frameset.c:159
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:775
FrameSet class - used for collecting Frames when not on the wire, and for marshalling/demarshalling t...
Definition: frameset.h:46
FSTATIC gsize _netio_setmaxpktsize(NetIO *self, gsize maxpktsize)
Set the max packet size for this NetIO transport.
Definition: netio.c:430
#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:450
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
struct sockaddr_in6(* ipv6sockaddr)(const NetAddr *self)
Return the ipv6 sockaddr corresponding to this address.
Definition: netaddr.h:51
#define DEBUGMSG2(...)
Definition: proj_classes.h:90
This is our CryptFrame class object - representing an encryption method.
Definition: cryptframe.h:53
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:508
#define ADDR_FAMILY_IPV4
IPv4.
FSTATIC void _netio_closeconn(NetIO *self, guint16 qid, const NetAddr *destaddr)
Definition: netio.c:887
gboolean mcastjoin(NetIO *self, const NetAddr *, const NetAddr *)
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 int _netio_getsockbufsize(const NetIO *self, gboolean forinput)
Return the kernel's idea of what our input or output socket buffer size is.
Definition: netio.c:249
FSTATIC gboolean _netio_sendreliablefs(NetIO *self, NetAddr *dest, guint16 queueid, GSList *fslist)
Definition: netio.c:867
#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
FSTATIC int _netio_setsockbufsize(const NetIO *self, gboolean forinput, gsize bufsize)
Set the kernel's idea of what our input or output socket buffer size as close as we can We'll even do...
Definition: netio.c:268