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