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