merge benchmark changes
[oweals/gnunet.git] / src / transport / plugin_transport_xu.c
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2010-2017 GNUnet e.V.
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  option) any later version.
9
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file transport/plugin_transport_xu.c
23  * @brief Implementation of the XU transport protocol
24  * @author Christian Grothoff
25  * @author Nathan Evans
26  * @author Matthias Wachs
27  */
28 #include "platform.h"
29 #include "plugin_transport_xu.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_fragmentation_lib.h"
33 #include "gnunet_nat_service.h"
34 #include "gnunet_protocols.h"
35 #include "gnunet_resolver_service.h"
36 #include "gnunet_signatures.h"
37 #include "gnunet_constants.h"
38 #include "gnunet_statistics_service.h"
39 #include "gnunet_transport_service.h"
40 #include "gnunet_transport_plugin.h"
41 #include "transport.h"
42
43 #define LOG(kind,...) GNUNET_log_from (kind, "transport-xu", __VA_ARGS__)
44
45 /**
46  * After how much inactivity should a XU session time out?
47  */
48 #define XU_SESSION_TIME_OUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
49
50
51 /**
52  * XU Message-Packet header (after defragmentation).
53  */
54 struct XUMessage
55 {
56   /**
57    * Message header.
58    */
59   struct GNUNET_MessageHeader header;
60
61   /**
62    * Always zero for now.
63    */
64   uint32_t reserved;
65
66   /**
67    * What is the identity of the sender
68    */
69   struct GNUNET_PeerIdentity sender;
70
71 };
72
73
74 /**
75  * Closure for #append_port().
76  */
77 struct PrettyPrinterContext
78 {
79   /**
80    * DLL
81    */
82   struct PrettyPrinterContext *next;
83
84   /**
85    * DLL
86    */
87   struct PrettyPrinterContext *prev;
88
89   /**
90    * Our plugin.
91    */
92   struct Plugin *plugin;
93
94   /**
95    * Resolver handle
96    */
97   struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
98
99   /**
100    * Function to call with the result.
101    */
102   GNUNET_TRANSPORT_AddressStringCallback asc;
103
104   /**
105    * Clsoure for @e asc.
106    */
107   void *asc_cls;
108
109   /**
110    * Timeout task
111    */
112   struct GNUNET_SCHEDULER_Task *timeout_task;
113
114   /**
115    * Is this an IPv6 address?
116    */
117   int ipv6;
118
119   /**
120    * Options
121    */
122   uint32_t options;
123
124   /**
125    * Port to add after the IP address.
126    */
127   uint16_t port;
128
129 };
130
131
132 /**
133  * Session with another peer.
134  */
135 struct GNUNET_ATS_Session
136 {
137   /**
138    * Which peer is this session for?
139    */
140   struct GNUNET_PeerIdentity target;
141
142   /**
143    * Tokenizer for inbound messages.
144    */
145   struct GNUNET_MessageStreamTokenizer *mst;
146
147   /**
148    * Plugin this session belongs to.
149    */
150   struct Plugin *plugin;
151
152   /**
153    * Session timeout task
154    */
155   struct GNUNET_SCHEDULER_Task *timeout_task;
156
157   /**
158    * When does this session time out?
159    */
160   struct GNUNET_TIME_Absolute timeout;
161
162   /**
163    * What time did we last transmit?
164    */
165   struct GNUNET_TIME_Absolute last_transmit_time;
166
167   /**
168    * expected delay for ACKs
169    */
170   struct GNUNET_TIME_Relative last_expected_ack_delay;
171
172   /**
173    * desired delay between XU messages
174    */
175   struct GNUNET_TIME_Relative last_expected_msg_delay;
176   
177   /**
178    */
179   struct GNUNET_TIME_Relative flow_delay_for_other_peer;
180   struct GNUNET_TIME_Relative flow_delay_from_other_peer;
181
182   /**
183    * Our own address.
184    */
185   struct GNUNET_HELLO_Address *address;
186
187   /**
188    * Number of bytes waiting for transmission to this peer.
189    */
190   unsigned long long bytes_in_queue;
191
192   /**
193    * Number of messages waiting for transmission to this peer.
194    */
195   unsigned int msgs_in_queue;
196
197   /**
198    * Reference counter to indicate that this session is
199    * currently being used and must not be destroyed;
200    * setting @e in_destroy will destroy it as soon as
201    * possible.
202    */
203   unsigned int rc;
204
205   /**
206    * Network type of the address.
207    */
208   enum GNUNET_ATS_Network_Type scope;
209
210   /**
211    * Is this session about to be destroyed (sometimes we cannot
212    * destroy a session immediately as below us on the stack
213    * there might be code that still uses it; in this case,
214    * @e rc is non-zero).
215    */
216   int in_destroy;
217 };
218
219
220
221 /**
222  * If a session monitor is attached, notify it about the new
223  * session state.
224  *
225  * @param plugin our plugin
226  * @param session session that changed state
227  * @param state new state of the session
228  */
229 static void
230 notify_session_monitor (struct Plugin *plugin,
231                         struct GNUNET_ATS_Session *session,
232                         enum GNUNET_TRANSPORT_SessionState state)
233 {
234   struct GNUNET_TRANSPORT_SessionInfo info;
235
236   if (NULL == plugin->sic)
237     return;
238   if (GNUNET_YES == session->in_destroy)
239     return; /* already destroyed, just RC>0 left-over actions */
240   memset (&info,
241           0,
242           sizeof (info));
243   info.state = state;
244   info.is_inbound = GNUNET_SYSERR; /* hard to say */
245   info.num_msg_pending = session->msgs_in_queue;
246   info.num_bytes_pending = session->bytes_in_queue;
247   /* info.receive_delay remains zero as this is not supported by XU
248      (cannot selectively not receive from 'some' peer while continuing
249      to receive from others) */
250   info.session_timeout = session->timeout;
251   info.address = session->address;
252   plugin->sic (plugin->sic_cls,
253                session,
254                &info);
255 }
256
257
258 /**
259  * Return information about the given session to the monitor callback.
260  *
261  * @param cls the `struct Plugin` with the monitor callback (`sic`)
262  * @param peer peer we send information about
263  * @param value our `struct GNUNET_ATS_Session` to send information about
264  * @return #GNUNET_OK (continue to iterate)
265  */
266 static int
267 send_session_info_iter (void *cls,
268                         const struct GNUNET_PeerIdentity *peer,
269                         void *value)
270 {
271   struct Plugin *plugin = cls;
272   struct GNUNET_ATS_Session *session = value;
273
274   (void) peer;
275   notify_session_monitor (plugin,
276                           session,
277                           GNUNET_TRANSPORT_SS_INIT);
278   notify_session_monitor (plugin,
279                           session,
280                           GNUNET_TRANSPORT_SS_UP);
281   return GNUNET_OK;
282 }
283
284
285 /**
286  * Begin monitoring sessions of a plugin.  There can only
287  * be one active monitor per plugin (i.e. if there are
288  * multiple monitors, the transport service needs to
289  * multiplex the generated events over all of them).
290  *
291  * @param cls closure of the plugin
292  * @param sic callback to invoke, NULL to disable monitor;
293  *            plugin will being by iterating over all active
294  *            sessions immediately and then enter monitor mode
295  * @param sic_cls closure for @a sic
296  */
297 static void
298 xu_plugin_setup_monitor (void *cls,
299                           GNUNET_TRANSPORT_SessionInfoCallback sic,
300                           void *sic_cls)
301 {
302   struct Plugin *plugin = cls;
303
304   plugin->sic = sic;
305   plugin->sic_cls = sic_cls;
306   if (NULL != sic)
307   {
308     GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
309                                            &send_session_info_iter,
310                                            plugin);
311     /* signal end of first iteration */
312     sic (sic_cls,
313          NULL,
314          NULL);
315   }
316 }
317
318
319 /* ****************** Little Helpers ****************** */
320
321
322 /**
323  * Function to free last resources associated with a session.
324  *
325  * @param s session to free
326  */
327 static void
328 free_session (struct GNUNET_ATS_Session *s)
329 {
330   if (NULL != s->address)
331   {
332     GNUNET_HELLO_address_free (s->address);
333     s->address = NULL;
334   }
335   if (NULL != s->mst)
336   {
337     GNUNET_MST_destroy (s->mst);
338     s->mst = NULL;
339   }
340   GNUNET_free (s);
341 }
342
343
344 /**
345  * Function that is called to get the keepalive factor.
346  * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
347  * calculate the interval between keepalive packets.
348  *
349  * @param cls closure with the `struct Plugin`
350  * @return keepalive factor
351  */
352 static unsigned int
353 xu_query_keepalive_factor (void *cls)
354 {
355   (void) cls;
356   return 15;
357 }
358
359
360 /**
361  * Function obtain the network type for a session
362  *
363  * @param cls closure (`struct Plugin *`)
364  * @param session the session
365  * @return the network type
366  */
367 static enum GNUNET_ATS_Network_Type
368 xu_plugin_get_network (void *cls,
369                        struct GNUNET_ATS_Session *session)
370 {
371   (void) cls;
372   return session->scope;
373 }
374
375
376 /**
377  * Function obtain the network type for an address.
378  *
379  * @param cls closure (`struct Plugin *`)
380  * @param address the address
381  * @return the network type
382  */
383 static enum GNUNET_ATS_Network_Type
384 xu_plugin_get_network_for_address (void *cls,
385                                    const struct GNUNET_HELLO_Address *address)
386 {
387   struct Plugin *plugin = cls;
388   size_t addrlen;
389   struct sockaddr_in a4;
390   struct sockaddr_in6 a6;
391   const struct IPv4XuAddress *u4;
392   const struct IPv6XuAddress *u6;
393   const void *sb;
394   size_t sbs;
395
396   addrlen = address->address_length;
397   if (addrlen == sizeof(struct IPv6XuAddress))
398   {
399     GNUNET_assert (NULL != address->address); /* make static analysis happy */
400     u6 = address->address;
401     memset (&a6, 0, sizeof(a6));
402 #if HAVE_SOCKADDR_IN_SIN_LEN
403     a6.sin6_len = sizeof (a6);
404 #endif
405     a6.sin6_family = AF_INET6;
406     a6.sin6_port = u6->u6_port;
407     GNUNET_memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof(struct in6_addr));
408     sb = &a6;
409     sbs = sizeof(a6);
410   }
411   else if (addrlen == sizeof(struct IPv4XuAddress))
412   {
413     GNUNET_assert (NULL != address->address); /* make static analysis happy */
414     u4 = address->address;
415     memset (&a4, 0, sizeof(a4));
416 #if HAVE_SOCKADDR_IN_SIN_LEN
417     a4.sin_len = sizeof (a4);
418 #endif
419     a4.sin_family = AF_INET;
420     a4.sin_port = u4->u4_port;
421     a4.sin_addr.s_addr = u4->ipv4_addr;
422     sb = &a4;
423     sbs = sizeof(a4);
424   }
425   else
426   {
427     GNUNET_break (0);
428     return GNUNET_ATS_NET_UNSPECIFIED;
429   }
430   return plugin->env->get_address_type (plugin->env->cls,
431                                         sb,
432                                         sbs);
433 }
434
435
436 /* ******************* Event loop ******************** */
437
438 /**
439  * We have been notified that our readset has something to read.  We don't
440  * know which socket needs to be read, so we have to check each one
441  * Then reschedule this function to be called again once more is available.
442  *
443  * @param cls the plugin handle
444  */
445 static void
446 xu_plugin_select_v4 (void *cls);
447
448
449 /**
450  * We have been notified that our readset has something to read.  We don't
451  * know which socket needs to be read, so we have to check each one
452  * Then reschedule this function to be called again once more is available.
453  *
454  * @param cls the plugin handle
455  */
456 static void
457 xu_plugin_select_v6 (void *cls);
458
459
460 /**
461  * (re)schedule IPv4-select tasks for this plugin.
462  *
463  * @param plugin plugin to reschedule
464  */
465 static void
466 schedule_select_v4 (struct Plugin *plugin)
467 {
468   if ( (GNUNET_YES != plugin->enable_ipv4) ||
469        (NULL == plugin->sockv4) )
470     return;
471   if (NULL != plugin->select_task_v4)
472     GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
473   plugin->select_task_v4
474     = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
475                                      plugin->sockv4,
476                                      &xu_plugin_select_v4,
477                                      plugin);
478 }
479
480
481 /**
482  * (re)schedule IPv6-select tasks for this plugin.
483  *
484  * @param plugin plugin to reschedule
485  */
486 static void
487 schedule_select_v6 (struct Plugin *plugin)
488 {
489   if ( (GNUNET_YES != plugin->enable_ipv6) ||
490        (NULL == plugin->sockv6) )
491     return;
492   if (NULL != plugin->select_task_v6)
493     GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
494   plugin->select_task_v6
495     = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
496                                      plugin->sockv6,
497                                      &xu_plugin_select_v6,
498                                      plugin);
499 }
500
501
502 /* ******************* Address to string and back ***************** */
503
504
505 /**
506  * Function called for a quick conversion of the binary address to
507  * a numeric address.  Note that the caller must not free the
508  * address and that the next call to this function is allowed
509  * to override the address again.
510  *
511  * @param cls closure
512  * @param addr binary address (a `union XuAddress`)
513  * @param addrlen length of the @a addr
514  * @return string representing the same address
515  */
516 const char *
517 xu_address_to_string (void *cls,
518                        const void *addr,
519                        size_t addrlen)
520 {
521   static char rbuf[INET6_ADDRSTRLEN + 10];
522   char buf[INET6_ADDRSTRLEN];
523   const void *sb;
524   struct in_addr a4;
525   struct in6_addr a6;
526   const struct IPv4XuAddress *t4;
527   const struct IPv6XuAddress *t6;
528   int af;
529   uint16_t port;
530   uint32_t options;
531
532   (void) cls;
533   if (NULL == addr)
534   {
535     GNUNET_break_op (0);
536     return NULL;
537   }
538
539   if (addrlen == sizeof(struct IPv6XuAddress))
540   {
541     t6 = addr;
542     af = AF_INET6;
543     options = ntohl (t6->options);
544     port = ntohs (t6->u6_port);
545     a6 = t6->ipv6_addr;
546     sb = &a6;
547   }
548   else if (addrlen == sizeof(struct IPv4XuAddress))
549   {
550     t4 = addr;
551     af = AF_INET;
552     options = ntohl (t4->options);
553     port = ntohs (t4->u4_port);
554     a4.s_addr = t4->ipv4_addr;
555     sb = &a4;
556   }
557   else
558   {
559     GNUNET_break_op (0);
560     return NULL;
561   }
562   inet_ntop (af,
563              sb,
564              buf,
565              INET6_ADDRSTRLEN);
566   GNUNET_snprintf (rbuf,
567                    sizeof(rbuf),
568                    (af == AF_INET6)
569                    ? "%s.%u.[%s]:%u"
570                    : "%s.%u.%s:%u",
571                    PLUGIN_NAME,
572                    options,
573                    buf,
574                    port);
575   return rbuf;
576 }
577
578
579 /**
580  * Function called to convert a string address to a binary address.
581  *
582  * @param cls closure (`struct Plugin *`)
583  * @param addr string address
584  * @param addrlen length of the address
585  * @param buf location to store the buffer
586  * @param added location to store the number of bytes in the buffer.
587  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
588  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
589  */
590 static int
591 xu_string_to_address (void *cls,
592                       const char *addr,
593                       uint16_t addrlen,
594                       void **buf,
595                       size_t *added)
596 {
597   struct sockaddr_storage socket_address;
598   char *address;
599   char *plugin;
600   char *optionstr;
601   uint32_t options;
602
603   (void) cls;
604   /* Format tcp.options.address:port */
605   address = NULL;
606   plugin = NULL;
607   optionstr = NULL;
608
609   if ((NULL == addr) || (0 == addrlen))
610   {
611     GNUNET_break (0);
612     return GNUNET_SYSERR;
613   }
614   if ('\0' != addr[addrlen - 1])
615   {
616     GNUNET_break (0);
617     return GNUNET_SYSERR;
618   }
619   if (strlen (addr) + 1 != (size_t) addrlen)
620   {
621     GNUNET_break (0);
622     return GNUNET_SYSERR;
623   }
624   plugin = GNUNET_strdup (addr);
625   optionstr = strchr (plugin, '.');
626   if (NULL == optionstr)
627   {
628     GNUNET_break (0);
629     GNUNET_free (plugin);
630     return GNUNET_SYSERR;
631   }
632   optionstr[0] = '\0';
633   optionstr++;
634   options = atol (optionstr);
635   address = strchr (optionstr, '.');
636   if (NULL == address)
637   {
638     GNUNET_break (0);
639     GNUNET_free (plugin);
640     return GNUNET_SYSERR;
641   }
642   address[0] = '\0';
643   address++;
644
645   if (GNUNET_OK !=
646       GNUNET_STRINGS_to_address_ip (address,
647                                     strlen (address),
648                                     &socket_address))
649   {
650     GNUNET_break (0);
651     GNUNET_free (plugin);
652     return GNUNET_SYSERR;
653   }
654   GNUNET_free(plugin);
655
656   switch (socket_address.ss_family)
657   {
658   case AF_INET:
659     {
660       struct IPv4XuAddress *u4;
661       const struct sockaddr_in *in4 = (const struct sockaddr_in *) &socket_address;
662
663       u4 = GNUNET_new (struct IPv4XuAddress);
664       u4->options = htonl (options);
665       u4->ipv4_addr = in4->sin_addr.s_addr;
666       u4->u4_port = in4->sin_port;
667       *buf = u4;
668       *added = sizeof (struct IPv4XuAddress);
669       return GNUNET_OK;
670     }
671   case AF_INET6:
672     {
673       struct IPv6XuAddress *u6;
674       const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) &socket_address;
675
676       u6 = GNUNET_new (struct IPv6XuAddress);
677       u6->options = htonl (options);
678       u6->ipv6_addr = in6->sin6_addr;
679       u6->u6_port = in6->sin6_port;
680       *buf = u6;
681       *added = sizeof (struct IPv6XuAddress);
682       return GNUNET_OK;
683     }
684   default:
685     GNUNET_break (0);
686     return GNUNET_SYSERR;
687   }
688 }
689
690
691 /**
692  * Append our port and forward the result.
693  *
694  * @param cls a `struct PrettyPrinterContext *`
695  * @param hostname result from DNS resolver
696  */
697 static void
698 append_port (void *cls,
699              const char *hostname)
700 {
701   struct PrettyPrinterContext *ppc = cls;
702   struct Plugin *plugin = ppc->plugin;
703   char *ret;
704
705   if (NULL == hostname)
706   {
707     /* Final call, done */
708     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
709                                  plugin->ppc_dll_tail,
710                                  ppc);
711     ppc->resolver_handle = NULL;
712     ppc->asc (ppc->asc_cls,
713               NULL,
714               GNUNET_OK);
715     GNUNET_free (ppc);
716     return;
717   }
718   if (GNUNET_YES == ppc->ipv6)
719     GNUNET_asprintf (&ret,
720                      "%s.%u.[%s]:%d",
721                      PLUGIN_NAME,
722                      ppc->options,
723                      hostname,
724                      ppc->port);
725   else
726     GNUNET_asprintf (&ret,
727                      "%s.%u.%s:%d",
728                      PLUGIN_NAME,
729                      ppc->options,
730                      hostname,
731                      ppc->port);
732   ppc->asc (ppc->asc_cls,
733             ret,
734             GNUNET_OK);
735   GNUNET_free (ret);
736 }
737
738
739 /**
740  * Convert the transports address to a nice, human-readable format.
741  *
742  * @param cls closure with the `struct Plugin *`
743  * @param type name of the transport that generated the address
744  * @param addr one of the addresses of the host, NULL for the last address
745  *        the specific address format depends on the transport;
746  *        a `union XuAddress`
747  * @param addrlen length of the address
748  * @param numeric should (IP) addresses be displayed in numeric form?
749  * @param timeout after how long should we give up?
750  * @param asc function to call on each string
751  * @param asc_cls closure for @a asc
752  */
753 static void
754 xu_plugin_address_pretty_printer (void *cls,
755                                    const char *type,
756                                    const void *addr,
757                                    size_t addrlen,
758                                    int numeric,
759                                    struct GNUNET_TIME_Relative timeout,
760                                    GNUNET_TRANSPORT_AddressStringCallback asc,
761                                    void *asc_cls)
762 {
763   struct Plugin *plugin = cls;
764   struct PrettyPrinterContext *ppc;
765   const struct sockaddr *sb;
766   size_t sbs;
767   struct sockaddr_in a4;
768   struct sockaddr_in6 a6;
769   const struct IPv4XuAddress *u4;
770   const struct IPv6XuAddress *u6;
771   uint16_t port;
772   uint32_t options;
773
774   (void) type;
775   if (addrlen == sizeof(struct IPv6XuAddress))
776   {
777     u6 = addr;
778     memset (&a6,
779             0,
780             sizeof (a6));
781     a6.sin6_family = AF_INET6;
782 #if HAVE_SOCKADDR_IN_SIN_LEN
783     a6.sin6_len = sizeof (a6);
784 #endif
785     a6.sin6_port = u6->u6_port;
786     a6.sin6_addr = u6->ipv6_addr;
787     port = ntohs (u6->u6_port);
788     options = ntohl (u6->options);
789     sb = (const struct sockaddr *) &a6;
790     sbs = sizeof (a6);
791   }
792   else if (addrlen == sizeof (struct IPv4XuAddress))
793   {
794     u4 = addr;
795     memset (&a4,
796             0,
797             sizeof(a4));
798     a4.sin_family = AF_INET;
799 #if HAVE_SOCKADDR_IN_SIN_LEN
800     a4.sin_len = sizeof (a4);
801 #endif
802     a4.sin_port = u4->u4_port;
803     a4.sin_addr.s_addr = u4->ipv4_addr;
804     port = ntohs (u4->u4_port);
805     options = ntohl (u4->options);
806     sb = (const struct sockaddr *) &a4;
807     sbs = sizeof(a4);
808   }
809   else
810   {
811     /* invalid address */
812     GNUNET_break_op (0);
813     asc (asc_cls,
814          NULL,
815          GNUNET_SYSERR);
816     asc (asc_cls,
817          NULL,
818          GNUNET_OK);
819     return;
820   }
821   ppc = GNUNET_new (struct PrettyPrinterContext);
822   ppc->plugin = plugin;
823   ppc->asc = asc;
824   ppc->asc_cls = asc_cls;
825   ppc->port = port;
826   ppc->options = options;
827   if (addrlen == sizeof (struct IPv6XuAddress))
828     ppc->ipv6 = GNUNET_YES;
829   else
830     ppc->ipv6 = GNUNET_NO;
831   GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
832                                plugin->ppc_dll_tail,
833                                ppc);
834   ppc->resolver_handle
835     = GNUNET_RESOLVER_hostname_get (sb,
836                                     sbs,
837                                     ! numeric,
838                                     timeout,
839                                     &append_port,
840                                     ppc);
841 }
842
843
844 /**
845  * Check if the given port is plausible (must be either our listen
846  * port or our advertised port).  If it is neither, we return
847  * #GNUNET_SYSERR.
848  *
849  * @param plugin global variables
850  * @param in_port port number to check
851  * @return #GNUNET_OK if port is either our open or advertised port
852  */
853 static int
854 check_port (const struct Plugin *plugin,
855             uint16_t in_port)
856 {
857   if ( (plugin->port == in_port) ||
858        (plugin->aport == in_port) )
859     return GNUNET_OK;
860   return GNUNET_SYSERR;
861 }
862
863
864 /**
865  * Function that will be called to check if a binary address for this
866  * plugin is well-formed and corresponds to an address for THIS peer
867  * (as per our configuration).  Naturally, if absolutely necessary,
868  * plugins can be a bit conservative in their answer, but in general
869  * plugins should make sure that the address does not redirect
870  * traffic to a 3rd party that might try to man-in-the-middle our
871  * traffic.
872  *
873  * @param cls closure, should be our handle to the Plugin
874  * @param addr pointer to a `union XuAddress`
875  * @param addrlen length of @a addr
876  * @return #GNUNET_OK if this is a plausible address for this peer
877  *         and transport, #GNUNET_SYSERR if not
878  */
879 static int
880 xu_plugin_check_address (void *cls,
881                          const void *addr,
882                          size_t addrlen)
883 {
884   struct Plugin *plugin = cls;
885   const struct IPv4XuAddress *v4;
886   const struct IPv6XuAddress *v6;
887
888   if (sizeof(struct IPv4XuAddress) == addrlen)
889   {
890     struct sockaddr_in s4;
891
892     v4 = (const struct IPv4XuAddress *) addr;
893     if (GNUNET_OK != check_port (plugin,
894                                  ntohs (v4->u4_port)))
895       return GNUNET_SYSERR;
896     memset (&s4, 0, sizeof (s4));
897     s4.sin_family = AF_INET;
898 #if HAVE_SOCKADDR_IN_SIN_LEN
899     s4.sin_len = sizeof (s4);
900 #endif
901     s4.sin_port = v4->u4_port;
902     s4.sin_addr.s_addr = v4->ipv4_addr;
903
904     if (GNUNET_OK !=
905         GNUNET_NAT_test_address (plugin->nat,
906                                  &s4,
907                                  sizeof (struct sockaddr_in)))
908       return GNUNET_SYSERR;
909   }
910   else if (sizeof(struct IPv6XuAddress) == addrlen)
911   {
912     struct sockaddr_in6 s6;
913
914     v6 = (const struct IPv6XuAddress *) addr;
915     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
916       return GNUNET_OK; /* plausible, if unlikely... */
917     memset (&s6, 0, sizeof (s6));
918     s6.sin6_family = AF_INET6;
919 #if HAVE_SOCKADDR_IN_SIN_LEN
920     s6.sin6_len = sizeof (s6);
921 #endif
922     s6.sin6_port = v6->u6_port;
923     s6.sin6_addr = v6->ipv6_addr;
924
925     if (GNUNET_OK !=
926         GNUNET_NAT_test_address (plugin->nat,
927                                  &s6,
928                                  sizeof(struct sockaddr_in6)))
929       return GNUNET_SYSERR;
930   }
931   else
932   {
933     GNUNET_break_op (0);
934     return GNUNET_SYSERR;
935   }
936   return GNUNET_OK;
937 }
938
939
940 /**
941  * Our external IP address/port mapping has changed.
942  *
943  * @param cls closure, the `struct Plugin`
944  * @param add_remove #GNUNET_YES to mean the new public IP address,
945  *                   #GNUNET_NO to mean the previous (now invalid) one
946  * @param ac address class the address belongs to
947  * @param addr either the previous or the new public IP address
948  * @param addrlen actual length of the @a addr
949  */
950 static void
951 xu_nat_port_map_callback (void *cls,
952                            int add_remove,
953                            enum GNUNET_NAT_AddressClass ac,
954                            const struct sockaddr *addr,
955                            socklen_t addrlen)
956 {
957   struct Plugin *plugin = cls;
958   struct GNUNET_HELLO_Address *address;
959   struct IPv4XuAddress u4;
960   struct IPv6XuAddress u6;
961   void *arg;
962   size_t args;
963
964   if (GNUNET_NAT_AC_LOOPBACK == ac)
965     return;
966   if (GNUNET_NAT_AC_LAN == ac)
967     return;
968   if (GNUNET_NAT_AC_LAN_PRIVATE == ac)
969     return;
970   LOG (GNUNET_ERROR_TYPE_DEBUG,
971        (GNUNET_YES == add_remove)
972        ? "NAT notification to add address `%s'\n"
973        : "NAT notification to remove address `%s'\n",
974        GNUNET_a2s (addr,
975                    addrlen));
976   /* convert 'address' to our internal format */
977   switch (addr->sa_family)
978   {
979   case AF_INET:
980     {
981       const struct sockaddr_in *i4;
982
983       GNUNET_assert (sizeof(struct sockaddr_in) == addrlen);
984       i4 = (const struct sockaddr_in *) addr;
985       if (0 == ntohs (i4->sin_port))
986         return; /* Port = 0 means unmapped, ignore these for XU. */
987       memset (&u4,
988               0,
989               sizeof(u4));
990       u4.options = htonl (plugin->myoptions);
991       u4.ipv4_addr = i4->sin_addr.s_addr;
992       u4.u4_port = i4->sin_port;
993       arg = &u4;
994       args = sizeof (struct IPv4XuAddress);
995       break;
996     }
997   case AF_INET6:
998     {
999       const struct sockaddr_in6 *i6;
1000
1001       GNUNET_assert (sizeof(struct sockaddr_in6) == addrlen);
1002       i6 = (const struct sockaddr_in6 *) addr;
1003       if (0 == ntohs (i6->sin6_port))
1004         return; /* Port = 0 means unmapped, ignore these for XU. */
1005       memset (&u6,
1006               0,
1007               sizeof(u6));
1008       u6.options = htonl (plugin->myoptions);
1009       u6.ipv6_addr = i6->sin6_addr;
1010       u6.u6_port = i6->sin6_port;
1011       arg = &u6;
1012       args = sizeof (struct IPv6XuAddress);
1013       break;
1014     }
1015   default:
1016     GNUNET_break (0);
1017     return;
1018   }
1019   /* modify our published address list */
1020   /* TODO: use 'ac' here in the future... */
1021   address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1022                                            PLUGIN_NAME,
1023                                            arg,
1024                                            args,
1025                                            GNUNET_HELLO_ADDRESS_INFO_NONE);
1026   plugin->env->notify_address (plugin->env->cls,
1027                                add_remove,
1028                                address);
1029   GNUNET_HELLO_address_free (address);
1030 }
1031
1032
1033 /* ********************* Finding sessions ******************* */
1034
1035
1036 /**
1037  * Closure for #session_cmp_it().
1038  */
1039 struct GNUNET_ATS_SessionCompareContext
1040 {
1041   /**
1042    * Set to session matching the address.
1043    */
1044   struct GNUNET_ATS_Session *res;
1045
1046   /**
1047    * Address we are looking for.
1048    */
1049   const struct GNUNET_HELLO_Address *address;
1050 };
1051
1052
1053 /**
1054  * Find a session with a matching address.
1055  *
1056  * @param cls the `struct GNUNET_ATS_SessionCompareContext *`
1057  * @param key peer identity (unused)
1058  * @param value the `struct GNUNET_ATS_Session *`
1059  * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
1060  */
1061 static int
1062 session_cmp_it (void *cls,
1063                 const struct GNUNET_PeerIdentity *key,
1064                 void *value)
1065 {
1066   struct GNUNET_ATS_SessionCompareContext *cctx = cls;
1067   struct GNUNET_ATS_Session *s = value;
1068
1069   (void) key;
1070   if (0 == GNUNET_HELLO_address_cmp (s->address,
1071                                      cctx->address))
1072   {
1073     GNUNET_assert (GNUNET_NO == s->in_destroy);
1074     cctx->res = s;
1075     return GNUNET_NO;
1076   }
1077   return GNUNET_OK;
1078 }
1079
1080
1081 /**
1082  * Locate an existing session the transport service is using to
1083  * send data to another peer.  Performs some basic sanity checks
1084  * on the address and then tries to locate a matching session.
1085  *
1086  * @param cls the plugin
1087  * @param address the address we should locate the session by
1088  * @return the session if it exists, or NULL if it is not found
1089  */
1090 static struct GNUNET_ATS_Session *
1091 xu_plugin_lookup_session (void *cls,
1092                            const struct GNUNET_HELLO_Address *address)
1093 {
1094   struct Plugin *plugin = cls;
1095   const struct IPv6XuAddress *xu_a6;
1096   const struct IPv4XuAddress *xu_a4;
1097   struct GNUNET_ATS_SessionCompareContext cctx;
1098
1099   if (NULL == address->address)
1100   {
1101     GNUNET_break (0);
1102     return NULL;
1103   }
1104   if (sizeof(struct IPv4XuAddress) == address->address_length)
1105   {
1106     if (NULL == plugin->sockv4)
1107       return NULL;
1108     xu_a4 = (const struct IPv4XuAddress *) address->address;
1109     if (0 == xu_a4->u4_port)
1110     {
1111       GNUNET_break (0);
1112       return NULL;
1113     }
1114   }
1115   else if (sizeof(struct IPv6XuAddress) == address->address_length)
1116   {
1117     if (NULL == plugin->sockv6)
1118       return NULL;
1119     xu_a6 = (const struct IPv6XuAddress *) address->address;
1120     if (0 == xu_a6->u6_port)
1121     {
1122       GNUNET_break (0);
1123       return NULL;
1124     }
1125   }
1126   else
1127   {
1128     GNUNET_break (0);
1129     return NULL;
1130   }
1131
1132   /* check if session already exists */
1133   cctx.address = address;
1134   cctx.res = NULL;
1135   LOG (GNUNET_ERROR_TYPE_DEBUG,
1136        "Looking for existing session for peer `%s' with address `%s'\n",
1137        GNUNET_i2s (&address->peer),
1138        xu_address_to_string (plugin,
1139                               address->address,
1140                               address->address_length));
1141   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1142                                               &address->peer,
1143                                               &session_cmp_it,
1144                                               &cctx);
1145   if (NULL == cctx.res)
1146     return NULL;
1147   LOG (GNUNET_ERROR_TYPE_DEBUG,
1148        "Found existing session %p\n",
1149        cctx.res);
1150   return cctx.res;
1151 }
1152
1153
1154 /* ********************** Timeout ****************** */
1155
1156
1157 /**
1158  * Increment session timeout due to activity.
1159  *
1160  * @param s session to reschedule timeout activity for
1161  */
1162 static void
1163 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1164 {
1165   if (GNUNET_YES == s->in_destroy)
1166     return;
1167   GNUNET_assert (NULL != s->timeout_task);
1168   s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT);
1169 }
1170
1171
1172
1173 /**
1174  * Function that will be called whenever the transport service wants to
1175  * notify the plugin that a session is still active and in use and
1176  * therefore the session timeout for this session has to be updated
1177  *
1178  * @param cls closure with the `struct Plugin`
1179  * @param peer which peer was the session for
1180  * @param session which session is being updated
1181  */
1182 static void
1183 xu_plugin_update_session_timeout (void *cls,
1184                                    const struct GNUNET_PeerIdentity *peer,
1185                                    struct GNUNET_ATS_Session *session)
1186 {
1187   struct Plugin *plugin = cls;
1188
1189   if (GNUNET_YES !=
1190       GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1191                                                     peer,
1192                                                     session))
1193   {
1194     GNUNET_break (0);
1195     return;
1196   }
1197   /* Reschedule session timeout */
1198   reschedule_session_timeout (session);
1199 }
1200
1201
1202 /* ************************* Sending ************************ */
1203
1204
1205 /**
1206  * We failed to transmit a message via XU. Generate
1207  * a descriptive error message.
1208  *
1209  * @param plugin our plugin
1210  * @param sa target address we were trying to reach
1211  * @param slen number of bytes in @a sa
1212  * @param error the errno value returned from the sendto() call
1213  */
1214 static void
1215 analyze_send_error (struct Plugin *plugin,
1216                     const struct sockaddr *sa,
1217                     socklen_t slen,
1218                     int error)
1219 {
1220   enum GNUNET_ATS_Network_Type type;
1221
1222   type = plugin->env->get_address_type (plugin->env->cls,
1223                                         sa,
1224                                         slen);
1225   if ( ( (GNUNET_ATS_NET_LAN == type) ||
1226          (GNUNET_ATS_NET_WAN == type) ) &&
1227        ( (ENETUNREACH == errno) ||
1228          (ENETDOWN == errno) ) )
1229   {
1230     if (slen == sizeof (struct sockaddr_in))
1231     {
1232       /* IPv4: "Network unreachable" or "Network down"
1233        *
1234        * This indicates we do not have connectivity
1235        */
1236       LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1237            _("XU could not transmit message to `%s': "
1238              "Network seems down, please check your network configuration\n"),
1239            GNUNET_a2s (sa,
1240                        slen));
1241     }
1242     if (slen == sizeof (struct sockaddr_in6))
1243     {
1244       /* IPv6: "Network unreachable" or "Network down"
1245        *
1246        * This indicates that this system is IPv6 enabled, but does not
1247        * have a valid global IPv6 address assigned or we do not have
1248        * connectivity
1249        */
1250       LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1251            _("XU could not transmit IPv6 message! "
1252              "Please check your network configuration and disable IPv6 if your "
1253              "connection does not have a global IPv6 address\n"));
1254     }
1255   }
1256   else
1257   {
1258     LOG (GNUNET_ERROR_TYPE_WARNING,
1259          "XU could not transmit message to `%s': `%s'\n",
1260          GNUNET_a2s (sa,
1261                      slen),
1262          STRERROR (error));
1263   }
1264 }
1265
1266
1267
1268
1269 /**
1270  * Function that can be used by the transport service to transmit a
1271  * message using the plugin.  Note that in the case of a peer
1272  * disconnecting, the continuation MUST be called prior to the
1273  * disconnect notification itself.  This function will be called with
1274  * this peer's HELLO message to initiate a fresh connection to another
1275  * peer.
1276  *
1277  * @param cls closure
1278  * @param s which session must be used
1279  * @param msgbuf the message to transmit
1280  * @param msgbuf_size number of bytes in @a msgbuf
1281  * @param priority how important is the message (most plugins will
1282  *                 ignore message priority and just FIFO)
1283  * @param to how long to wait at most for the transmission (does not
1284  *                require plugins to discard the message after the timeout,
1285  *                just advisory for the desired delay; most plugins will ignore
1286  *                this as well)
1287  * @param cont continuation to call once the message has
1288  *        been transmitted (or if the transport is ready
1289  *        for the next transmission call; or if the
1290  *        peer disconnected...); can be NULL
1291  * @param cont_cls closure for @a cont
1292  * @return number of bytes used (on the physical network, with overheads);
1293  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1294  *         and does NOT mean that the message was not transmitted (DV)
1295  */
1296 static ssize_t
1297 xu_plugin_send (void *cls,
1298                 struct GNUNET_ATS_Session *s,
1299                 const char *msgbuf,
1300                 size_t msgbuf_size,
1301                 unsigned int priority,
1302                 struct GNUNET_TIME_Relative to,
1303                 GNUNET_TRANSPORT_TransmitContinuation cont,
1304                 void *cont_cls)
1305 {
1306   struct Plugin *plugin = cls;
1307   size_t xumlen = msgbuf_size + sizeof(struct XUMessage);
1308   struct XUMessage *xu;
1309   char mbuf[xumlen] GNUNET_ALIGN;
1310   ssize_t sent;
1311   socklen_t slen;
1312   const struct sockaddr *a;
1313   const struct IPv4XuAddress *u4;
1314   struct sockaddr_in a4;
1315   const struct IPv6XuAddress *u6;
1316   struct sockaddr_in6 a6;
1317   struct GNUNET_NETWORK_Handle *sock;
1318
1319   (void) priority;
1320   (void) to;
1321   if ( (sizeof(struct IPv6XuAddress) == s->address->address_length) &&
1322        (NULL == plugin->sockv6) )
1323     return GNUNET_SYSERR;
1324   if ( (sizeof(struct IPv4XuAddress) == s->address->address_length) &&
1325        (NULL == plugin->sockv4) )
1326     return GNUNET_SYSERR;
1327   if (xumlen >= GNUNET_MAX_MESSAGE_SIZE)
1328   {
1329     GNUNET_break (0);
1330     return GNUNET_SYSERR;
1331   }
1332   if (GNUNET_YES !=
1333       GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1334                                                     &s->target,
1335                                                     s))
1336   {
1337     GNUNET_break (0);
1338     return GNUNET_SYSERR;
1339   }
1340   LOG (GNUNET_ERROR_TYPE_DEBUG,
1341        "XU transmits %u-byte message to `%s' using address `%s'\n",
1342        xumlen,
1343        GNUNET_i2s (&s->target),
1344        xu_address_to_string (plugin,
1345                               s->address->address,
1346                               s->address->address_length));
1347   xu = (struct XUMessage *) mbuf;
1348   xu->header.size = htons (xumlen);
1349   xu->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE);
1350   xu->reserved = htonl (0);
1351   xu->sender = *plugin->env->my_identity;
1352   GNUNET_memcpy (&xu[1],
1353                  msgbuf,
1354                  msgbuf_size);
1355   
1356   if (sizeof (struct IPv4XuAddress) == s->address->address_length)
1357   {
1358     u4 = s->address->address;
1359     memset (&a4,
1360             0,
1361             sizeof(a4));
1362     a4.sin_family = AF_INET;
1363 #if HAVE_SOCKADDR_IN_SIN_LEN
1364     a4.sin_len = sizeof (a4);
1365 #endif
1366     a4.sin_port = u4->u4_port;
1367     a4.sin_addr.s_addr = u4->ipv4_addr;
1368     a = (const struct sockaddr *) &a4;
1369     slen = sizeof (a4);
1370     sock = plugin->sockv4;
1371   }
1372   else if (sizeof (struct IPv6XuAddress) == s->address->address_length)
1373   {
1374     u6 = s->address->address;
1375     memset (&a6,
1376             0,
1377             sizeof(a6));
1378     a6.sin6_family = AF_INET6;
1379 #if HAVE_SOCKADDR_IN_SIN_LEN
1380     a6.sin6_len = sizeof (a6);
1381 #endif
1382     a6.sin6_port = u6->u6_port;
1383     a6.sin6_addr = u6->ipv6_addr;
1384     a = (const struct sockaddr *) &a6;
1385     slen = sizeof (a6);
1386     sock = plugin->sockv6;
1387   }
1388   else
1389   {
1390     GNUNET_break (0);
1391     return GNUNET_SYSERR;
1392   }
1393     
1394   sent = GNUNET_NETWORK_socket_sendto (sock,
1395                                        mbuf,
1396                                        xumlen,
1397                                        a,
1398                                        slen);
1399   s->last_transmit_time
1400     = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_get (),
1401                                 s->last_transmit_time);
1402   
1403   if (GNUNET_SYSERR == sent)
1404   {
1405     /* Failure */
1406     analyze_send_error (plugin,
1407                         a,
1408                         slen,
1409                         errno);
1410     GNUNET_STATISTICS_update (plugin->env->stats,
1411                               "# XU, total, bytes, sent, failure",
1412                               sent,
1413                               GNUNET_NO);
1414     GNUNET_STATISTICS_update (plugin->env->stats,
1415                               "# XU, total, messages, sent, failure",
1416                               1,
1417                               GNUNET_NO);
1418     return GNUNET_SYSERR;
1419   }
1420   /* Success */
1421   LOG (GNUNET_ERROR_TYPE_DEBUG,
1422        "XU transmitted %u-byte message to  `%s' `%s' (%d: %s)\n",
1423        (unsigned int) (msgbuf_size),
1424        GNUNET_i2s (&s->target),
1425        GNUNET_a2s (a,
1426                    slen),
1427        (int ) sent,
1428        (sent < 0) ? STRERROR (errno) : "ok");
1429   GNUNET_STATISTICS_update (plugin->env->stats,
1430                             "# XU, total, bytes, sent, success",
1431                             sent,
1432                             GNUNET_NO);
1433   GNUNET_STATISTICS_update (plugin->env->stats,
1434                             "# XU, total, messages, sent, success",
1435                             1,
1436                             GNUNET_NO);
1437   cont (cont_cls,
1438         &s->target,
1439         GNUNET_OK,
1440         msgbuf_size,
1441         xumlen);
1442   notify_session_monitor (s->plugin,
1443                           s,
1444                           GNUNET_TRANSPORT_SS_UPDATE);
1445   return xumlen;
1446 }
1447
1448
1449 /* ********************** Receiving ********************** */
1450
1451
1452 /**
1453  * Functions with this signature are called whenever we need to close
1454  * a session due to a disconnect or failure to establish a connection.
1455  *
1456  * @param cls closure with the `struct Plugin`
1457  * @param s session to close down
1458  * @return #GNUNET_OK on success
1459  */
1460 static int
1461 xu_disconnect_session (void *cls,
1462                         struct GNUNET_ATS_Session *s)
1463 {
1464   struct Plugin *plugin = cls;
1465
1466   GNUNET_assert (GNUNET_YES != s->in_destroy);
1467   LOG (GNUNET_ERROR_TYPE_DEBUG,
1468        "Session %p to peer `%s' at address %s ended\n",
1469        s,
1470        GNUNET_i2s (&s->target),
1471        xu_address_to_string (plugin,
1472                               s->address->address,
1473                               s->address->address_length));
1474   if (NULL != s->timeout_task)
1475   {
1476     GNUNET_SCHEDULER_cancel (s->timeout_task);
1477     s->timeout_task = NULL;
1478   }
1479   GNUNET_assert (GNUNET_YES ==
1480                  GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
1481                                                        &s->target,
1482                                                        s));
1483   s->in_destroy = GNUNET_YES;
1484   notify_session_monitor (s->plugin,
1485                           s,
1486                           GNUNET_TRANSPORT_SS_DONE);
1487   plugin->env->session_end (plugin->env->cls,
1488                             s->address,
1489                             s);
1490   GNUNET_STATISTICS_set (plugin->env->stats,
1491                          "# XU sessions active",
1492                          GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
1493                          GNUNET_NO);
1494   if (0 == s->rc)
1495     free_session (s);
1496   return GNUNET_OK;
1497 }
1498
1499
1500 /**
1501  * Message tokenizer has broken up an incomming message. Pass it on
1502  * to the service.
1503  *
1504  * @param cls the `struct GNUNET_ATS_Session *`
1505  * @param hdr the actual message
1506  * @return #GNUNET_OK (always)
1507  */
1508 static int
1509 process_inbound_tokenized_messages (void *cls,
1510                                     const struct GNUNET_MessageHeader *hdr)
1511 {
1512   struct GNUNET_ATS_Session *session = cls;
1513   struct Plugin *plugin = session->plugin;
1514
1515   if (GNUNET_YES == session->in_destroy)
1516     return GNUNET_OK;
1517   reschedule_session_timeout (session);
1518   session->flow_delay_for_other_peer
1519     = plugin->env->receive (plugin->env->cls,
1520                             session->address,
1521                             session,
1522                             hdr);
1523   return GNUNET_OK;
1524 }
1525
1526
1527 /**
1528  * Destroy a session, plugin is being unloaded.
1529  *
1530  * @param cls the `struct Plugin`
1531  * @param key hash of public key of target peer
1532  * @param value a `struct PeerSession *` to clean up
1533  * @return #GNUNET_OK (continue to iterate)
1534  */
1535 static int
1536 disconnect_and_free_it (void *cls,
1537                         const struct GNUNET_PeerIdentity *key,
1538                         void *value)
1539 {
1540   struct Plugin *plugin = cls;
1541
1542   (void) key;
1543   xu_disconnect_session (plugin,
1544                          value);
1545   return GNUNET_OK;
1546 }
1547
1548
1549 /**
1550  * Disconnect from a remote node.  Clean up session if we have one for
1551  * this peer.
1552  *
1553  * @param cls closure for this call (should be handle to Plugin)
1554  * @param target the peeridentity of the peer to disconnect
1555  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed
1556  */
1557 static void
1558 xu_disconnect (void *cls,
1559                 const struct GNUNET_PeerIdentity *target)
1560 {
1561   struct Plugin *plugin = cls;
1562
1563   LOG (GNUNET_ERROR_TYPE_DEBUG,
1564        "Disconnecting from peer `%s'\n",
1565        GNUNET_i2s (target));
1566   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1567                                               target,
1568                                               &disconnect_and_free_it,
1569                                               plugin);
1570 }
1571
1572
1573 /**
1574  * Session was idle, so disconnect it.
1575  *
1576  * @param cls the `struct GNUNET_ATS_Session` to time out
1577  */
1578 static void
1579 session_timeout (void *cls)
1580 {
1581   struct GNUNET_ATS_Session *s = cls;
1582   struct Plugin *plugin = s->plugin;
1583   struct GNUNET_TIME_Relative left;
1584
1585   s->timeout_task = NULL;
1586   left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1587   if (left.rel_value_us > 0)
1588   {
1589     /* not actually our turn yet, but let's at least update
1590        the monitor, it may think we're about to die ... */
1591     notify_session_monitor (s->plugin,
1592                             s,
1593                             GNUNET_TRANSPORT_SS_UPDATE);
1594     s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1595                                                     &session_timeout,
1596                                                     s);
1597     return;
1598   }
1599   LOG (GNUNET_ERROR_TYPE_DEBUG,
1600        "Session %p was idle for %s, disconnecting\n",
1601        s,
1602        GNUNET_STRINGS_relative_time_to_string (XU_SESSION_TIME_OUT,
1603                                                GNUNET_YES));
1604   /* call session destroy function */
1605   xu_disconnect_session (plugin,
1606                           s);
1607 }
1608
1609
1610 /**
1611  * Allocate a new session for the given endpoint address.
1612  * Note that this function does not inform the service
1613  * of the new session, this is the responsibility of the
1614  * caller (if needed).
1615  *
1616  * @param cls the `struct Plugin`
1617  * @param address address of the other peer to use
1618  * @param network_type network type the address belongs to
1619  * @return NULL on error, otherwise session handle
1620  */
1621 static struct GNUNET_ATS_Session *
1622 xu_plugin_create_session (void *cls,
1623                            const struct GNUNET_HELLO_Address *address,
1624                            enum GNUNET_ATS_Network_Type network_type)
1625 {
1626   struct Plugin *plugin = cls;
1627   struct GNUNET_ATS_Session *s;
1628
1629   s = GNUNET_new (struct GNUNET_ATS_Session);
1630   s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages,
1631                               s);
1632   s->plugin = plugin;
1633   s->address = GNUNET_HELLO_address_copy (address);
1634   s->target = address->peer;
1635   s->last_transmit_time = GNUNET_TIME_absolute_get ();
1636   s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1637                                                               250);
1638   s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1639   s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO;
1640   s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
1641   s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT);
1642   s->timeout_task = GNUNET_SCHEDULER_add_delayed (XU_SESSION_TIME_OUT,
1643                                                   &session_timeout,
1644                                                   s);
1645   s->scope = network_type;
1646
1647   LOG (GNUNET_ERROR_TYPE_DEBUG,
1648        "Creating new session %p for peer `%s' address `%s'\n",
1649        s,
1650        GNUNET_i2s (&address->peer),
1651        xu_address_to_string (plugin,
1652                               address->address,
1653                               address->address_length));
1654   GNUNET_assert (GNUNET_OK ==
1655                  GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
1656                                                     &s->target,
1657                                                     s,
1658                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
1659   GNUNET_STATISTICS_set (plugin->env->stats,
1660                          "# XU sessions active",
1661                          GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
1662                          GNUNET_NO);
1663   notify_session_monitor (plugin,
1664                           s,
1665                           GNUNET_TRANSPORT_SS_INIT);
1666   return s;
1667 }
1668
1669
1670 /**
1671  * Creates a new outbound session the transport service will use to
1672  * send data to the peer.
1673  *
1674  * @param cls the `struct Plugin *`
1675  * @param address the address
1676  * @return the session or NULL of max connections exceeded
1677  */
1678 static struct GNUNET_ATS_Session *
1679 xu_plugin_get_session (void *cls,
1680                         const struct GNUNET_HELLO_Address *address)
1681 {
1682   struct Plugin *plugin = cls;
1683   struct GNUNET_ATS_Session *s;
1684   enum GNUNET_ATS_Network_Type network_type = GNUNET_ATS_NET_UNSPECIFIED;
1685   const struct IPv4XuAddress *xu_v4;
1686   const struct IPv6XuAddress *xu_v6;
1687
1688   if (NULL == address)
1689   {
1690     GNUNET_break (0);
1691     return NULL;
1692   }
1693   if ( (address->address_length != sizeof(struct IPv4XuAddress)) &&
1694        (address->address_length != sizeof(struct IPv6XuAddress)) )
1695   {
1696     GNUNET_break_op (0);
1697     return NULL;
1698   }
1699   if (NULL != (s = xu_plugin_lookup_session (cls,
1700                                               address)))
1701     return s;
1702
1703   /* need to create new session */
1704   if (sizeof (struct IPv4XuAddress) == address->address_length)
1705   {
1706     struct sockaddr_in v4;
1707
1708     xu_v4 = (const struct IPv4XuAddress *) address->address;
1709     memset (&v4, '\0', sizeof (v4));
1710     v4.sin_family = AF_INET;
1711 #if HAVE_SOCKADDR_IN_SIN_LEN
1712     v4.sin_len = sizeof (struct sockaddr_in);
1713 #endif
1714     v4.sin_port = xu_v4->u4_port;
1715     v4.sin_addr.s_addr = xu_v4->ipv4_addr;
1716     network_type = plugin->env->get_address_type (plugin->env->cls,
1717                                                   (const struct sockaddr *) &v4,
1718                                                   sizeof (v4));
1719   }
1720   if (sizeof (struct IPv6XuAddress) == address->address_length)
1721   {
1722     struct sockaddr_in6 v6;
1723
1724     xu_v6 = (const struct IPv6XuAddress *) address->address;
1725     memset (&v6, '\0', sizeof (v6));
1726     v6.sin6_family = AF_INET6;
1727 #if HAVE_SOCKADDR_IN_SIN_LEN
1728     v6.sin6_len = sizeof (struct sockaddr_in6);
1729 #endif
1730     v6.sin6_port = xu_v6->u6_port;
1731     v6.sin6_addr = xu_v6->ipv6_addr;
1732     network_type = plugin->env->get_address_type (plugin->env->cls,
1733                                                   (const struct sockaddr *) &v6,
1734                                                   sizeof (v6));
1735   }
1736   GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network_type);
1737   return xu_plugin_create_session (cls,
1738                                     address,
1739                                     network_type);
1740 }
1741
1742
1743 /**
1744  * We've received a XU Message.  Process it (pass contents to main service).
1745  *
1746  * @param plugin plugin context
1747  * @param msg the message
1748  * @param xu_addr sender address
1749  * @param xu_addr_len number of bytes in @a xu_addr
1750  * @param network_type network type the address belongs to
1751  */
1752 static void
1753 process_xu_message (struct Plugin *plugin,
1754                      const struct XUMessage *msg,
1755                      const union XuAddress *xu_addr,
1756                      size_t xu_addr_len,
1757                      enum GNUNET_ATS_Network_Type network_type)
1758 {
1759   struct GNUNET_ATS_Session *s;
1760   struct GNUNET_HELLO_Address *address;
1761
1762   GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network_type);
1763   if (0 != ntohl (msg->reserved))
1764   {
1765     GNUNET_break_op(0);
1766     return;
1767   }
1768   if (ntohs (msg->header.size)
1769       < sizeof(struct GNUNET_MessageHeader) + sizeof(struct XUMessage))
1770   {
1771     GNUNET_break_op(0);
1772     return;
1773   }
1774
1775   address = GNUNET_HELLO_address_allocate (&msg->sender,
1776                                            PLUGIN_NAME,
1777                                            xu_addr,
1778                                            xu_addr_len,
1779                                            GNUNET_HELLO_ADDRESS_INFO_NONE);
1780   if (NULL ==
1781       (s = xu_plugin_lookup_session (plugin,
1782                                       address)))
1783   {
1784     s = xu_plugin_create_session (plugin,
1785                                    address,
1786                                    network_type);
1787     plugin->env->session_start (plugin->env->cls,
1788                                 address,
1789                                 s,
1790                                 s->scope);
1791     notify_session_monitor (plugin,
1792                             s,
1793                             GNUNET_TRANSPORT_SS_UP);
1794   }
1795   GNUNET_free (address);
1796
1797   s->rc++;
1798   GNUNET_MST_from_buffer (s->mst,
1799                           (const char *) &msg[1],
1800                           ntohs (msg->header.size) - sizeof(struct XUMessage),
1801                           GNUNET_YES,
1802                           GNUNET_NO);
1803   s->rc--;
1804   if ( (0 == s->rc) &&
1805        (GNUNET_YES == s->in_destroy) )
1806     free_session (s);
1807 }
1808
1809
1810 /**
1811  * Read and process a message from the given socket.
1812  *
1813  * @param plugin the overall plugin
1814  * @param rsock socket to read from
1815  */
1816 static void
1817 xu_select_read (struct Plugin *plugin,
1818                  struct GNUNET_NETWORK_Handle *rsock)
1819 {
1820   socklen_t fromlen;
1821   struct sockaddr_storage addr;
1822   char buf[65536] GNUNET_ALIGN;
1823   ssize_t size;
1824   const struct GNUNET_MessageHeader *msg;
1825   struct IPv4XuAddress v4;
1826   struct IPv6XuAddress v6;
1827   const struct sockaddr *sa;
1828   const struct sockaddr_in *sa4;
1829   const struct sockaddr_in6 *sa6;
1830   const union XuAddress *int_addr;
1831   size_t int_addr_len;
1832   enum GNUNET_ATS_Network_Type network_type;
1833
1834   fromlen = sizeof (addr);
1835   memset (&addr,
1836           0,
1837           sizeof(addr));
1838   size = GNUNET_NETWORK_socket_recvfrom (rsock,
1839                                          buf,
1840                                          sizeof (buf),
1841                                          (struct sockaddr *) &addr,
1842                                          &fromlen);
1843   sa = (const struct sockaddr *) &addr;
1844 #if MINGW
1845   /* On SOCK_DGRAM XU sockets recvfrom might fail with a
1846    * WSAECONNRESET error to indicate that previous sendto() (yes, sendto!)
1847    * on this socket has failed.
1848    * Quote from MSDN:
1849    *   WSAECONNRESET - The virtual circuit was reset by the remote side
1850    *   executing a hard or abortive close. The application should close
1851    *   the socket; it is no longer usable. On a XU-datagram socket this
1852    *   error indicates a previous send operation resulted in an ICMP Port
1853    *   Unreachable message.
1854    */
1855   if ( (-1 == size) &&
1856        (ECONNRESET == errno) )
1857     return;
1858 #endif
1859   if (-1 == size)
1860   {
1861     LOG (GNUNET_ERROR_TYPE_DEBUG,
1862          "XU failed to receive data: %s\n",
1863          STRERROR (errno));
1864     /* Connection failure or something. Not a protocol violation. */
1865     return;
1866   }
1867
1868   /* Check if this is a STUN packet */
1869   if (GNUNET_NO !=
1870       GNUNET_NAT_stun_handle_packet (plugin->nat,
1871                                      (const struct sockaddr *) &addr,
1872                                      fromlen,
1873                                      buf,
1874                                      size))
1875     return; /* was STUN, do not process further */
1876
1877   if (((size_t) size) < sizeof(struct GNUNET_MessageHeader))
1878   {
1879     LOG (GNUNET_ERROR_TYPE_WARNING,
1880          "XU got %u bytes from %s, which is not enough for a GNUnet message header\n",
1881          (unsigned int ) size,
1882          GNUNET_a2s (sa,
1883                      fromlen));
1884     /* _MAY_ be a connection failure (got partial message) */
1885     /* But it _MAY_ also be that the other side uses non-GNUnet protocol. */
1886     GNUNET_break_op (0);
1887     return;
1888   }
1889
1890   msg = (const struct GNUNET_MessageHeader *) buf;
1891   LOG (GNUNET_ERROR_TYPE_DEBUG,
1892        "XU received %u-byte message from `%s' type %u\n",
1893        (unsigned int) size,
1894        GNUNET_a2s (sa,
1895                    fromlen),
1896        ntohs (msg->type));
1897   if (size != ntohs (msg->size))
1898   {
1899     LOG (GNUNET_ERROR_TYPE_WARNING,
1900          "XU malformed message (size %u) header from %s\n",
1901          (unsigned int) size,
1902          GNUNET_a2s (sa,
1903                      fromlen));
1904     GNUNET_break_op (0);
1905     return;
1906   }
1907   GNUNET_STATISTICS_update (plugin->env->stats,
1908                             "# XU, total bytes received",
1909                             size,
1910                             GNUNET_NO);
1911   network_type = plugin->env->get_address_type (plugin->env->cls,
1912                                                 sa,
1913                                                 fromlen);
1914   switch (sa->sa_family)
1915   {
1916   case AF_INET:
1917     sa4 = (const struct sockaddr_in *) &addr;
1918     v4.options = 0;
1919     v4.ipv4_addr = sa4->sin_addr.s_addr;
1920     v4.u4_port = sa4->sin_port;
1921     int_addr = (union XuAddress *) &v4;
1922     int_addr_len = sizeof (v4);
1923     break;
1924   case AF_INET6:
1925     sa6 = (const struct sockaddr_in6 *) &addr;
1926     v6.options = 0;
1927     v6.ipv6_addr = sa6->sin6_addr;
1928     v6.u6_port = sa6->sin6_port;
1929     int_addr = (union XuAddress *) &v6;
1930     int_addr_len = sizeof (v6);
1931     break;
1932   default:
1933     GNUNET_break (0);
1934     return;
1935   }
1936
1937   switch (ntohs (msg->type))
1938   {
1939   case GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE:
1940     if (ntohs (msg->size) < sizeof(struct XUMessage))
1941     {
1942       GNUNET_break_op(0);
1943       return;
1944     }
1945     process_xu_message (plugin,
1946                          (const struct XUMessage *) msg,
1947                          int_addr,
1948                          int_addr_len,
1949                          network_type);
1950     return;
1951   default:
1952     GNUNET_break_op(0);
1953     return;
1954   }
1955 }
1956
1957
1958 /* ***************** Event loop (part 2) *************** */
1959
1960
1961 /**
1962  * We have been notified that our readset has something to read.  We don't
1963  * know which socket needs to be read, so we have to check each one
1964  * Then reschedule this function to be called again once more is available.
1965  *
1966  * @param cls the plugin handle
1967  */
1968 static void
1969 xu_plugin_select_v4 (void *cls)
1970 {
1971   struct Plugin *plugin = cls;
1972   const struct GNUNET_SCHEDULER_TaskContext *tc;
1973
1974   plugin->select_task_v4 = NULL;
1975   if (NULL == plugin->sockv4)
1976     return;
1977   tc = GNUNET_SCHEDULER_get_task_context ();
1978   if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1979        (GNUNET_NETWORK_fdset_isset (tc->read_ready,
1980                                     plugin->sockv4)) )
1981     xu_select_read (plugin,
1982                      plugin->sockv4);
1983   schedule_select_v4 (plugin);
1984 }
1985
1986
1987 /**
1988  * We have been notified that our readset has something to read.  We don't
1989  * know which socket needs to be read, so we have to check each one
1990  * Then reschedule this function to be called again once more is available.
1991  *
1992  * @param cls the plugin handle
1993  */
1994 static void
1995 xu_plugin_select_v6 (void *cls)
1996 {
1997   struct Plugin *plugin = cls;
1998   const struct GNUNET_SCHEDULER_TaskContext *tc;
1999
2000   plugin->select_task_v6 = NULL;
2001   if (NULL == plugin->sockv6)
2002     return;
2003   tc = GNUNET_SCHEDULER_get_task_context ();
2004   if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
2005        (GNUNET_NETWORK_fdset_isset (tc->read_ready,
2006                                     plugin->sockv6)) )
2007     xu_select_read (plugin,
2008                      plugin->sockv6);
2009   schedule_select_v6 (plugin);
2010 }
2011
2012
2013 /* ******************* Initialization *************** */
2014
2015
2016 /**
2017  * Setup the XU sockets (for IPv4 and IPv6) for the plugin.
2018  *
2019  * @param plugin the plugin to initialize
2020  * @param bind_v6 IPv6 address to bind to (can be NULL, for 'any')
2021  * @param bind_v4 IPv4 address to bind to (can be NULL, for 'any')
2022  * @return number of sockets that were successfully bound
2023  */
2024 static unsigned int
2025 setup_sockets (struct Plugin *plugin,
2026                const struct sockaddr_in6 *bind_v6,
2027                const struct sockaddr_in *bind_v4)
2028 {
2029   int tries;
2030   unsigned int sockets_created = 0;
2031   struct sockaddr_in6 server_addrv6;
2032   struct sockaddr_in server_addrv4;
2033   const struct sockaddr *server_addr;
2034   const struct sockaddr *addrs[2];
2035   socklen_t addrlens[2];
2036   socklen_t addrlen;
2037   int eno;
2038
2039   /* Create IPv6 socket */
2040   eno = EINVAL;
2041   if (GNUNET_YES == plugin->enable_ipv6)
2042   {
2043     plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6,
2044                                                    SOCK_DGRAM,
2045                                                    0);
2046     if (NULL == plugin->sockv6)
2047     {
2048       LOG (GNUNET_ERROR_TYPE_INFO,
2049            _("Disabling IPv6 since it is not supported on this system!\n"));
2050       plugin->enable_ipv6 = GNUNET_NO;
2051     }
2052     else
2053     {
2054       memset (&server_addrv6,
2055               0,
2056               sizeof(struct sockaddr_in6));
2057 #if HAVE_SOCKADDR_IN_SIN_LEN
2058       server_addrv6.sin6_len = sizeof (struct sockaddr_in6);
2059 #endif
2060       server_addrv6.sin6_family = AF_INET6;
2061       if (NULL != bind_v6)
2062         server_addrv6.sin6_addr = bind_v6->sin6_addr;
2063       else
2064         server_addrv6.sin6_addr = in6addr_any;
2065
2066       if (0 == plugin->port) /* autodetect */
2067         server_addrv6.sin6_port
2068           = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2069                                              33537)
2070                    + 32000);
2071       else
2072         server_addrv6.sin6_port = htons (plugin->port);
2073       addrlen = sizeof (struct sockaddr_in6);
2074       server_addr = (const struct sockaddr *) &server_addrv6;
2075
2076       tries = 0;
2077       while (tries < 10)
2078       {
2079         LOG(GNUNET_ERROR_TYPE_DEBUG,
2080             "Binding to IPv6 `%s'\n",
2081             GNUNET_a2s (server_addr,
2082                         addrlen));
2083         /* binding */
2084         if (GNUNET_OK ==
2085             GNUNET_NETWORK_socket_bind (plugin->sockv6,
2086                                         server_addr,
2087                                         addrlen))
2088           break;
2089         eno = errno;
2090         if (0 != plugin->port)
2091         {
2092           tries = 10; /* fail immediately */
2093           break; /* bind failed on specific port */
2094         }
2095         /* autodetect */
2096         server_addrv6.sin6_port
2097           = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2098                                              33537)
2099                    + 32000);
2100         tries++;
2101       }
2102       if (tries >= 10)
2103       {
2104         GNUNET_NETWORK_socket_close (plugin->sockv6);
2105         plugin->enable_ipv6 = GNUNET_NO;
2106         plugin->sockv6 = NULL;
2107       }
2108       else
2109       {
2110         plugin->port = ntohs (server_addrv6.sin6_port);
2111       }
2112       if (NULL != plugin->sockv6)
2113       {
2114         LOG (GNUNET_ERROR_TYPE_DEBUG,
2115              "IPv6 XU socket created listinging at %s\n",
2116              GNUNET_a2s (server_addr,
2117                          addrlen));
2118         addrs[sockets_created] = server_addr;
2119         addrlens[sockets_created] = addrlen;
2120         sockets_created++;
2121       }
2122       else
2123       {
2124         LOG (GNUNET_ERROR_TYPE_WARNING,
2125              _("Failed to bind XU socket to %s: %s\n"),
2126              GNUNET_a2s (server_addr,
2127                          addrlen),
2128              STRERROR (eno));
2129       }
2130     }
2131   }
2132
2133   /* Create IPv4 socket */
2134   eno = EINVAL;
2135   plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET,
2136                                                  SOCK_DGRAM,
2137                                                  0);
2138   if (NULL == plugin->sockv4)
2139   {
2140     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
2141                          "socket");
2142     LOG (GNUNET_ERROR_TYPE_INFO,
2143          _("Disabling IPv4 since it is not supported on this system!\n"));
2144     plugin->enable_ipv4 = GNUNET_NO;
2145   }
2146   else
2147   {
2148     memset (&server_addrv4,
2149             0,
2150             sizeof(struct sockaddr_in));
2151 #if HAVE_SOCKADDR_IN_SIN_LEN
2152     server_addrv4.sin_len = sizeof (struct sockaddr_in);
2153 #endif
2154     server_addrv4.sin_family = AF_INET;
2155     if (NULL != bind_v4)
2156       server_addrv4.sin_addr = bind_v4->sin_addr;
2157     else
2158       server_addrv4.sin_addr.s_addr = INADDR_ANY;
2159
2160     if (0 == plugin->port)
2161       /* autodetect */
2162       server_addrv4.sin_port
2163         = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2164                                            33537)
2165                  + 32000);
2166     else
2167       server_addrv4.sin_port = htons (plugin->port);
2168
2169     addrlen = sizeof (struct sockaddr_in);
2170     server_addr = (const struct sockaddr *) &server_addrv4;
2171
2172     tries = 0;
2173     while (tries < 10)
2174     {
2175       LOG (GNUNET_ERROR_TYPE_DEBUG,
2176            "Binding to IPv4 `%s'\n",
2177            GNUNET_a2s (server_addr,
2178                        addrlen));
2179
2180       /* binding */
2181       if (GNUNET_OK ==
2182           GNUNET_NETWORK_socket_bind (plugin->sockv4,
2183                                       server_addr,
2184                                       addrlen))
2185         break;
2186       eno = errno;
2187       if (0 != plugin->port)
2188       {
2189         tries = 10; /* fail */
2190         break; /* bind failed on specific port */
2191       }
2192
2193       /* autodetect */
2194       server_addrv4.sin_port
2195         = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2196                                            33537)
2197                  + 32000);
2198       tries++;
2199     }
2200     if (tries >= 10)
2201     {
2202       GNUNET_NETWORK_socket_close (plugin->sockv4);
2203       plugin->enable_ipv4 = GNUNET_NO;
2204       plugin->sockv4 = NULL;
2205     }
2206     else
2207     {
2208       plugin->port = ntohs (server_addrv4.sin_port);
2209     }
2210
2211     if (NULL != plugin->sockv4)
2212     {
2213       LOG (GNUNET_ERROR_TYPE_DEBUG,
2214            "IPv4 socket created on port %s\n",
2215            GNUNET_a2s (server_addr,
2216                        addrlen));
2217       addrs[sockets_created] = server_addr;
2218       addrlens[sockets_created] = addrlen;
2219       sockets_created++;
2220     }
2221     else
2222     {
2223       LOG (GNUNET_ERROR_TYPE_ERROR,
2224            _("Failed to bind XU socket to %s: %s\n"),
2225            GNUNET_a2s (server_addr,
2226                        addrlen),
2227            STRERROR (eno));
2228     }
2229   }
2230
2231   if (0 == sockets_created)
2232   {
2233     LOG (GNUNET_ERROR_TYPE_WARNING,
2234          _("Failed to open XU sockets\n"));
2235     return 0; /* No sockets created, return */
2236   }
2237   schedule_select_v4 (plugin);
2238   schedule_select_v6 (plugin);
2239   plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
2240                                      "transport-xu",
2241                                      IPPROTO_UDP,
2242                                      sockets_created,
2243                                      addrs,
2244                                      addrlens,
2245                                      &xu_nat_port_map_callback,
2246                                      NULL,
2247                                      plugin);
2248   return sockets_created;
2249 }
2250
2251
2252 /**
2253  * The exported method. Makes the core api available via a global and
2254  * returns the xu transport API.
2255  *
2256  * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
2257  * @return our `struct GNUNET_TRANSPORT_PluginFunctions`
2258  */
2259 void *
2260 libgnunet_plugin_transport_xu_init (void *cls)
2261 {
2262   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2263   struct GNUNET_TRANSPORT_PluginFunctions *api;
2264   struct Plugin *p;
2265   unsigned long long port;
2266   unsigned long long aport;
2267   int enable_v6;
2268   char *bind4_address;
2269   char *bind6_address;
2270   struct sockaddr_in server_addrv4;
2271   struct sockaddr_in6 server_addrv6;
2272   unsigned int res;
2273   int have_bind4;
2274   int have_bind6;
2275
2276   if (NULL == env->receive)
2277   {
2278     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2279      initialze the plugin or the API */
2280     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2281     api->cls = NULL;
2282     api->address_pretty_printer = &xu_plugin_address_pretty_printer;
2283     api->address_to_string = &xu_address_to_string;
2284     api->string_to_address = &xu_string_to_address;
2285     return api;
2286   }
2287
2288   /* Get port number: port == 0 : autodetect a port,
2289    * > 0 : use this port, not given : 2086 default */
2290   if (GNUNET_OK !=
2291       GNUNET_CONFIGURATION_get_value_number (env->cfg,
2292                                              "transport-xu",
2293                                              "PORT",
2294                                              &port))
2295     port = 2086;
2296   if (port > 65535)
2297   {
2298     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2299                                "transport-xu",
2300                                "PORT",
2301                                _("must be in [0,65535]"));
2302     return NULL;
2303   }
2304   if (GNUNET_OK !=
2305       GNUNET_CONFIGURATION_get_value_number (env->cfg,
2306                                              "transport-xu",
2307                                              "ADVERTISED_PORT",
2308                                              &aport))
2309     aport = port;
2310   if (aport > 65535)
2311   {
2312     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2313                                "transport-xu",
2314                                "ADVERTISED_PORT",
2315                                _("must be in [0,65535]"));
2316     return NULL;
2317   }
2318
2319   if (GNUNET_YES ==
2320       GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2321                                             "nat",
2322                                             "DISABLEV6"))
2323     enable_v6 = GNUNET_NO;
2324   else
2325     enable_v6 = GNUNET_YES;
2326
2327   have_bind4 = GNUNET_NO;
2328   memset (&server_addrv4,
2329           0,
2330           sizeof (server_addrv4));
2331   if (GNUNET_YES ==
2332       GNUNET_CONFIGURATION_get_value_string (env->cfg,
2333                                              "transport-xu",
2334                                              "BINDTO",
2335                                              &bind4_address))
2336   {
2337     LOG (GNUNET_ERROR_TYPE_DEBUG,
2338          "Binding XU plugin to specific address: `%s'\n",
2339          bind4_address);
2340     if (1 != inet_pton (AF_INET,
2341                         bind4_address,
2342                         &server_addrv4.sin_addr))
2343     {
2344       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2345                                  "transport-xu",
2346                                  "BINDTO",
2347                                  _("must be valid IPv4 address"));
2348       GNUNET_free (bind4_address);
2349       return NULL;
2350     }
2351     have_bind4 = GNUNET_YES;
2352   }
2353   GNUNET_free_non_null (bind4_address);
2354   have_bind6 = GNUNET_NO;
2355   memset (&server_addrv6,
2356           0,
2357           sizeof (server_addrv6));
2358   if (GNUNET_YES ==
2359       GNUNET_CONFIGURATION_get_value_string (env->cfg,
2360                                              "transport-xu",
2361                                              "BINDTO6",
2362                                              &bind6_address))
2363   {
2364     LOG (GNUNET_ERROR_TYPE_DEBUG,
2365          "Binding xu plugin to specific address: `%s'\n",
2366          bind6_address);
2367     if (1 != inet_pton (AF_INET6,
2368                         bind6_address,
2369                         &server_addrv6.sin6_addr))
2370     {
2371       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2372                                  "transport-xu",
2373                                  "BINDTO6",
2374                                  _("must be valid IPv6 address"));
2375       GNUNET_free (bind6_address);
2376       return NULL;
2377     }
2378     have_bind6 = GNUNET_YES;
2379   }
2380   GNUNET_free_non_null (bind6_address);
2381
2382   p = GNUNET_new (struct Plugin);
2383   p->port = port;
2384   p->aport = aport;
2385   p->enable_ipv6 = enable_v6;
2386   p->enable_ipv4 = GNUNET_YES; /* default */
2387   p->env = env;
2388   p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
2389                                                       GNUNET_NO);
2390   res = setup_sockets (p,
2391                        (GNUNET_YES == have_bind6) ? &server_addrv6 : NULL,
2392                        (GNUNET_YES == have_bind4) ? &server_addrv4 : NULL);
2393   if ( (0 == res) ||
2394        ( (NULL == p->sockv4) &&
2395          (NULL == p->sockv6) ) )
2396   {
2397     LOG (GNUNET_ERROR_TYPE_ERROR,
2398         _("Failed to create XU network sockets\n"));
2399     GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
2400     if (NULL != p->nat)
2401       GNUNET_NAT_unregister (p->nat);
2402     GNUNET_free (p);
2403     return NULL;
2404   }
2405
2406   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2407   api->cls = p;
2408   api->disconnect_session = &xu_disconnect_session;
2409   api->query_keepalive_factor = &xu_query_keepalive_factor;
2410   api->disconnect_peer = &xu_disconnect;
2411   api->address_pretty_printer = &xu_plugin_address_pretty_printer;
2412   api->address_to_string = &xu_address_to_string;
2413   api->string_to_address = &xu_string_to_address;
2414   api->check_address = &xu_plugin_check_address;
2415   api->get_session = &xu_plugin_get_session;
2416   api->send = &xu_plugin_send;
2417   api->get_network = &xu_plugin_get_network;
2418   api->get_network_for_address = &xu_plugin_get_network_for_address;
2419   api->update_session_timeout = &xu_plugin_update_session_timeout;
2420   api->setup_monitor = &xu_plugin_setup_monitor;
2421   return api;
2422 }
2423
2424
2425 /**
2426  * The exported method. Makes the core api available via a global and
2427  * returns the xu transport API.
2428  *
2429  * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
2430  * @return NULL
2431  */
2432 void *
2433 libgnunet_plugin_transport_xu_done (void *cls)
2434 {
2435   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2436   struct Plugin *plugin = api->cls;
2437   struct PrettyPrinterContext *cur;
2438
2439   if (NULL == plugin)
2440   {
2441     GNUNET_free (api);
2442     return NULL;
2443   }
2444   if (NULL != plugin->select_task_v4)
2445   {
2446     GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
2447     plugin->select_task_v4 = NULL;
2448   }
2449   if (NULL != plugin->select_task_v6)
2450   {
2451     GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
2452     plugin->select_task_v6 = NULL;
2453   }
2454   if (NULL != plugin->sockv4)
2455   {
2456     GNUNET_break (GNUNET_OK ==
2457                   GNUNET_NETWORK_socket_close (plugin->sockv4));
2458     plugin->sockv4 = NULL;
2459   }
2460   if (NULL != plugin->sockv6)
2461   {
2462     GNUNET_break (GNUNET_OK ==
2463                   GNUNET_NETWORK_socket_close (plugin->sockv6));
2464     plugin->sockv6 = NULL;
2465   }
2466   if (NULL != plugin->nat)
2467   {
2468     GNUNET_NAT_unregister (plugin->nat);
2469     plugin->nat = NULL;
2470   }
2471   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
2472
2473   while (NULL != (cur = plugin->ppc_dll_head))
2474   {
2475     GNUNET_break (0);
2476     GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2477                                  plugin->ppc_dll_tail,
2478                                  cur);
2479     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
2480     if (NULL != cur->timeout_task)
2481     {
2482       GNUNET_SCHEDULER_cancel (cur->timeout_task);
2483       cur->timeout_task = NULL;
2484     }
2485     GNUNET_free (cur);
2486   }
2487   GNUNET_free (plugin);
2488   GNUNET_free (api);
2489   return NULL;
2490 }
2491
2492 /* end of plugin_transport_xu.c */