Set the oft-forgotten sin_len.
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
1 /*
2      This file is part of GNUnet
3      (C) 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file transport/plugin_transport_udp.c
23  * @brief Implementation of the UDP transport service
24  * @author Christian Grothoff
25  * @author Nathan Evans
26  */
27
28 #include "platform.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_connection_lib.h"
31 #include "gnunet_os_lib.h"
32 #include "gnunet_peerinfo_service.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_resolver_service.h"
35 #include "gnunet_server_lib.h"
36 #include "gnunet_service_lib.h"
37 #include "gnunet_signatures.h"
38 #include "gnunet_statistics_service.h"
39 #include "gnunet_transport_service.h"
40 #include "plugin_transport.h"
41 #include "transport.h"
42
43 #define DEBUG_UDP GNUNET_NO
44
45 /**
46  * Transport cost to peer, always 1 for UDP (direct connection)
47  */
48 #define UDP_DIRECT_DISTANCE 1
49
50 /**
51  * How long until we give up on transmitting the welcome message?
52  */
53 #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
54
55
56 /**
57  * Message-Packet header.
58  */
59 struct UDPMessage
60 {
61   /**
62    * size of the message, in bytes, including this header.
63    */
64   struct GNUNET_MessageHeader header;
65
66   /**
67    * What is the identity of the sender (GNUNET_hash of public key)
68    */
69   struct GNUNET_PeerIdentity sender;
70
71 };
72
73
74 /**
75  * Network format for IPv4 addresses.
76  */
77 struct IPv4UdpAddress
78 {
79   /**
80    * IPv4 address, in network byte order.
81    */
82   uint32_t ipv4_addr;
83
84   /**
85    * Port number, in network byte order.
86    */
87   uint16_t u_port;
88
89 };
90
91
92 /**
93  * Network format for IPv6 addresses.
94  */
95 struct IPv6UdpAddress
96 {
97   /**
98    * IPv6 address.
99    */
100   unsigned char ipv6_addr[16];
101
102   /**
103    * Port number, in network byte order.
104    */
105   uint16_t u6_port;
106
107 };
108
109
110 /**
111  *
112  */
113 struct PrettyPrinterContext
114 {
115   /**
116    *
117    */
118   GNUNET_TRANSPORT_AddressStringCallback asc;
119
120   /**
121    * Closure for 'asc'.
122    */
123   void *asc_cls;
124
125   /**
126    *
127    */
128   uint16_t port;
129 };
130
131
132 /**
133  * Encapsulation of all of the state of the plugin.
134  */
135 struct Plugin
136 {
137   /**
138    * Our environment.
139    */
140   struct GNUNET_TRANSPORT_PluginEnvironment *env;
141
142   /**
143    * Handle for the statistics service.
144    */
145   struct GNUNET_STATISTICS_Handle *statistics;
146
147   /**
148    * Handle to the network service.
149    */
150   struct GNUNET_SERVICE_Context *service;
151
152   /**
153    * Handle for request of hostname resolution, non-NULL if pending.
154    */
155   struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
156
157   /**
158    * FD Read set
159    */
160   struct GNUNET_NETWORK_FDSet *rs;
161
162   /**
163    * ID of task used to update our addresses when one expires.
164    */
165   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
166
167   /**
168    * ID of select task
169    */
170   GNUNET_SCHEDULER_TaskIdentifier select_task;
171
172   /**
173    * Port that we are actually listening on.
174    */
175   uint16_t open_port;
176
177   /**
178    * Port that the user said we would have visible to the
179    * rest of the world.
180    */
181   uint16_t adv_port;
182
183 };
184
185 /* *********** globals ************* */
186
187 /**
188  * The socket that we transmit all data with
189  */
190 static struct GNUNET_NETWORK_Handle *udp_sock;
191
192 /**
193  * Disconnect from a remote node.
194  *
195  * @param cls closure ('struct Plugin'), unused
196  * @param target peer do disconnect
197  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
198  */
199 void
200 udp_disconnect (void *cls, 
201                 const struct GNUNET_PeerIdentity *target)
202 {
203   /* nothing to do, UDP is stateless */
204 }
205
206 /**
207  * Shutdown the server process (stop receiving inbound traffic). Maybe
208  * restarted later!
209  *
210  * @param cls closure, the 'struct Plugin*'
211  */
212 static int
213 udp_transport_server_stop (void *cls)
214 {
215   struct Plugin *plugin = cls;
216   int ret;
217
218   GNUNET_assert (udp_sock != NULL);
219   if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
220     {
221       GNUNET_SCHEDULER_cancel (plugin->env->sched, plugin->select_task);
222       plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
223     }
224
225   ret = GNUNET_NETWORK_socket_close (udp_sock);
226   if (ret != GNUNET_SYSERR)
227     udp_sock = NULL;
228   return ret;
229 }
230
231 /**
232  * Function that can be used by the transport service to transmit
233  * a message using the plugin.
234  *
235  * @param cls closure, the 'struct Plugin*'
236  * @param target who should receive this message (ignored by UDP)
237  * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
238  * @param msgbuf_size the size of the msgbuf to send
239  * @param priority how important is the message (ignored by UDP)
240  * @param timeout when should we time out (give up) if we can not transmit?
241  * @param session which session must be used (always NULL for UDP)
242  * @param addr the addr to send the message to, needs to be a sockaddr for us
243  * @param addrlen the len of addr
244  * @param force_address GNUNET_YES if the plugin MUST use the given address,
245  *                GNUNET_NO means the plugin may use any other address and
246  *                GNUNET_SYSERR means that only reliable existing
247  *                bi-directional connections should be used (regardless
248  *                of address)
249  * @param cont continuation to call once the message has
250  *        been transmitted (or if the transport is ready
251  *        for the next transmission call; or if the
252  *        peer disconnected...)
253  * @param cont_cls closure for cont
254  *
255  * @return the number of bytes written, -1 on error (in this case, cont is not called)
256  */
257 static ssize_t
258 udp_plugin_send (void *cls,
259                  const struct GNUNET_PeerIdentity *target,
260                  const char *msgbuf,
261                  size_t msgbuf_size,
262                  unsigned int priority,
263                  struct GNUNET_TIME_Relative timeout,
264                  struct Session *session,
265                  const void *addr,
266                  size_t addrlen,
267                  int force_address,
268                  GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
269 {
270   struct Plugin *plugin = cls;
271   struct UDPMessage *message;
272   int ssize;
273   ssize_t sent;
274   int af;
275   const void *sb;
276   size_t sbs;
277   struct sockaddr_in a4;
278   struct sockaddr_in6 a6;
279   const struct IPv4UdpAddress *t4;
280   const struct IPv6UdpAddress *t6;
281
282   GNUNET_assert (NULL == session);
283   GNUNET_assert(udp_sock != NULL);
284   if ( (addr == NULL) || (addrlen == 0) )
285     {
286 #if DEBUG_UDP
287   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
288                    ("udp_plugin_send called without address, returning!\n"));
289 #endif
290       return -1; /* Can never send if we don't have an address!! */
291     }
292   if (force_address == GNUNET_SYSERR)
293     return -1; /* never reliable */
294
295   if (addrlen == sizeof (struct IPv6UdpAddress))
296     {
297       t6 = addr;
298       af = AF_INET6;
299       memset (&a6, 0, sizeof (a6));
300 #if HAVE_SOCKADDR_IN_SIN_LEN
301       a6.sin6_len = sizeof (a6);
302 #endif
303       a6.sin6_family = AF_INET6;
304       a6.sin6_port = t6->u6_port;
305       memcpy (a6.sin6_addr.s6_addr,
306               t6->ipv6_addr,
307               16);      
308       sb = &a6;
309       sbs = sizeof (a6);
310     }
311   else if (addrlen == sizeof (struct IPv4UdpAddress))
312     {
313       t4 = addr;
314       af = AF_INET;
315       memset (&a4, 0, sizeof (a4));
316 #if HAVE_SOCKADDR_IN_SIN_LEN
317       a4.sin_len = sizeof (a4);
318 #endif
319       a4.sin_family = AF_INET;
320       a4.sin_port = t4->u_port;
321       a4.sin_addr.s_addr = t4->ipv4_addr;
322       sb = &a4;
323       sbs = sizeof (a4);
324     }
325   else
326     {
327       GNUNET_break_op (0);
328       return -1;
329     }
330
331   /* Build the message to be sent */
332   message = GNUNET_malloc (sizeof (struct UDPMessage) + msgbuf_size);
333   ssize = sizeof (struct UDPMessage) + msgbuf_size;
334
335 #if DEBUG_UDP
336   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", 
337                    "In udp_send, ssize is %d, sending message to `%s'\n", 
338                    ssize, 
339                    GNUNET_a2s(sb, sbs));
340 #endif
341   message->header.size = htons (ssize);
342   message->header.type = htons (0);
343   memcpy (&message->sender, plugin->env->my_identity,
344           sizeof (struct GNUNET_PeerIdentity));
345   memcpy (&message[1], msgbuf, msgbuf_size);
346   sent =
347     GNUNET_NETWORK_socket_sendto (udp_sock, message, ssize,
348                                   sb, sbs);
349   if ( (cont != NULL) &&
350        (sent != -1) )
351     cont (cont_cls, target, GNUNET_OK);
352   GNUNET_free (message);
353   return sent;
354 }
355
356
357 /**
358  * Add the IP of our network interface to the list of
359  * our external IP addresses.
360  *
361  * @param cls closure (the 'struct Plugin*')
362  * @param name name of the interface (can be NULL for unknown)
363  * @param isDefault is this presumably the default interface
364  * @param addr address of this interface (can be NULL for unknown or unassigned)
365  * @param addrlen length of the address
366  * @return GNUNET_OK to continue iterating
367  */
368 static int
369 process_interfaces (void *cls,
370                     const char *name,
371                     int isDefault,
372                     const struct sockaddr *addr, socklen_t addrlen)
373 {
374   struct Plugin *plugin = cls;
375   int af;
376   struct IPv4UdpAddress t4;
377   struct IPv6UdpAddress t6;
378   void *arg;
379   uint16_t args;
380
381   af = addr->sa_family;
382   if (af == AF_INET)
383     {
384       t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
385       t4.u_port = htons (plugin->adv_port);
386       arg = &t4;
387       args = sizeof (t4);
388     }
389   else if (af == AF_INET6)
390     {
391       memcpy (t6.ipv6_addr,
392               ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr,
393               16);
394       t6.u6_port = htons (plugin->adv_port);
395       arg = &t6;
396       args = sizeof (t6);
397     }
398   else
399     {
400       GNUNET_break (0);
401       return GNUNET_OK;
402     }
403   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO |
404                    GNUNET_ERROR_TYPE_BULK,
405                    "udp", 
406                    _("Found address `%s' (%s)\n"),
407                    GNUNET_a2s (addr, addrlen), 
408                    name);
409   plugin->env->notify_address (plugin->env->cls,
410                                "udp",
411                                arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
412   return GNUNET_OK;
413 }
414
415
416 /**
417  * Function called by the resolver for each address obtained from DNS
418  * for our own hostname.  Add the addresses to the list of our
419  * external IP addresses.
420  *
421  * @param cls closure
422  * @param addr one of the addresses of the host, NULL for the last address
423  * @param addrlen length of the address
424  */
425 static void
426 process_hostname_ips (void *cls,
427                       const struct sockaddr *addr, socklen_t addrlen)
428 {
429   struct Plugin *plugin = cls;
430
431   if (addr == NULL)
432     {
433       plugin->hostname_dns = NULL;
434       return;
435     }
436   process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
437 }
438
439
440 /*
441  * @param cls the plugin handle
442  * @param tc the scheduling context (for rescheduling this function again)
443  *
444  * We have been notified that our writeset has something to read.  Presumably
445  * select has been called already, so we can go ahead and start reading from
446  * the socket immediately.  Then we check if there is more to be read by
447  * calling select ourselves while there is stuff on the wire.  Then reschedule
448  * this function to be called again once more is available.
449  *
450  */
451 static void
452 udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
453 {
454   struct Plugin *plugin = cls;
455   char *buf;
456   struct UDPMessage *msg;
457   struct GNUNET_PeerIdentity *sender;
458   unsigned int buflen;
459   socklen_t fromlen;
460   struct sockaddr_storage addr;
461   ssize_t ret;
462   int offset;
463   int count;
464   int tsize;
465   char *msgbuf;
466   const struct GNUNET_MessageHeader *currhdr;
467   struct IPv4UdpAddress t4;
468   struct IPv6UdpAddress t6;
469   const struct sockaddr_in *s4;
470   const struct sockaddr_in6 *s6;
471   const void *ca;
472   size_t calen;
473
474 #if DEBUG_UDP
475       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
476                        ("entered select...\n"));
477 #endif
478
479       buflen = GNUNET_NETWORK_socket_recvfrom_amount (udp_sock);
480
481 #if DEBUG_UDP
482       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
483                        ("we expect to read %u bytes\n"), buflen);
484 #endif
485
486     if (buflen == GNUNET_NO)
487       return;
488
489     buf = GNUNET_malloc (buflen);
490     fromlen = sizeof (addr);
491
492     memset (&addr, 0, fromlen);
493     ret =
494       GNUNET_NETWORK_socket_recvfrom (udp_sock, buf, buflen,
495                                       (struct sockaddr *) &addr, &fromlen);
496
497 #if DEBUG_UDP
498     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
499                      ("socket_recv returned %u, src_addr_len is %u\n"), ret,
500                      fromlen);
501 #endif
502
503     if (ret <= 0)
504       {
505         GNUNET_free (buf);
506         return;
507       }
508     msg = (struct UDPMessage *) buf;
509
510 #if DEBUG_UDP
511     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
512                      ("header reports message size of %d\n"),
513                      ntohs (msg->header.size));
514
515     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
516                      ("header reports message type of %d\n"),
517                      ntohs (msg->header.type));
518 #endif
519     if (ntohs (msg->header.size) < sizeof (struct UDPMessage))
520       {
521         GNUNET_free (buf);
522         GNUNET_NETWORK_fdset_zero (plugin->rs);
523         GNUNET_NETWORK_fdset_set (plugin->rs, udp_sock);
524         return;
525       }
526     msgbuf = (char *)&msg[1];
527     sender = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
528     memcpy (sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
529
530     offset = 0;
531     count = 0;
532     tsize = ntohs (msg->header.size) - sizeof(struct UDPMessage);
533 #if DEBUG_UDP
534     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UDP", _
535                      ("offset is %d, tsize is %d (UDPMessage size is %d)\n"),
536                      offset, tsize, sizeof(struct UDPMessage));
537 #endif
538
539     if (fromlen == sizeof (struct sockaddr_in))
540       {
541         s4 = (const struct sockaddr_in*) &addr;
542         t4.u_port = s4->sin_port;
543         t4.ipv4_addr = s4->sin_addr.s_addr;
544         ca = &t4;
545         calen = sizeof (struct IPv4UdpAddress);
546       }
547     else if (fromlen == sizeof (struct sockaddr_in6))
548       {
549         s6 = (const struct sockaddr_in6*) &addr;
550         t6.u6_port = s6->sin6_port;
551         memcpy (t6.ipv6_addr,
552                 s6->sin6_addr.s6_addr,
553                 16);
554         ca = &t6;
555         calen = sizeof (struct IPv6UdpAddress);
556       }
557     else
558       {
559         GNUNET_break (0);
560         ca = NULL;
561         calen = 0;
562       }
563     while (offset < tsize)
564       {
565         currhdr = (struct GNUNET_MessageHeader *)&msgbuf[offset];
566 #if DEBUG_UDP
567     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
568                      ("processing msg %d: type %d, size %d at offset %d\n"),
569                      count, ntohs(currhdr->type), ntohs(currhdr->size), offset);
570 #endif
571         plugin->env->receive (plugin->env->cls,
572                               sender, currhdr, UDP_DIRECT_DISTANCE, 
573                               NULL, ca, calen);
574         offset += ntohs(currhdr->size);
575 #if DEBUG_UDP
576     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
577                      ("offset now %d, tsize %d\n"),
578                      offset, tsize);
579 #endif
580         count++;
581       }
582
583     GNUNET_free (sender);
584     GNUNET_free (buf);
585
586   plugin->select_task =
587     GNUNET_SCHEDULER_add_select (plugin->env->sched,
588                                  GNUNET_SCHEDULER_PRIORITY_DEFAULT,
589                                  GNUNET_SCHEDULER_NO_TASK,
590                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
591                                  NULL, &udp_plugin_select, plugin);
592
593 }
594
595 /**
596  * Create a UDP socket.  If possible, use IPv6, otherwise
597  * try IPv4.
598  * @param cls closure, the 'struct Plugin*'
599  */
600 static struct GNUNET_NETWORK_Handle *
601 udp_transport_server_start (void *cls)
602 {
603   struct Plugin *plugin = cls;
604   struct GNUNET_NETWORK_Handle *desc;
605   struct sockaddr_in serverAddrv4;
606   struct sockaddr_in6 serverAddrv6;
607   struct sockaddr *serverAddr;
608   socklen_t addrlen;
609
610   desc = NULL;
611   if (GNUNET_YES !=
612       GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, "GNUNETD",
613                                             "DISABLE-IPV6"))
614     {
615       desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 17);
616       if (desc != NULL)
617         {
618           memset (&serverAddrv6, 0, sizeof (serverAddrv6));
619 #if HAVE_SOCKADDR_IN_SIN_LEN
620           serverAddrv6.sin6_len = sizeof (serverAddrv6);
621 #endif
622           serverAddrv6.sin6_family = AF_INET6;
623           serverAddrv6.sin6_addr = in6addr_any;
624           serverAddrv6.sin6_port = htons (plugin->open_port);
625           addrlen = sizeof (serverAddrv6);
626           serverAddr = (struct sockaddr *) &serverAddrv6;
627         }
628     }
629   if (NULL == desc)
630     {
631       desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 17);
632       if (NULL == desc)
633         {
634           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", "socket");
635           return NULL;
636         }
637       else
638         {
639           memset (&serverAddrv4, 0, sizeof (serverAddrv4));
640 #if HAVE_SOCKADDR_IN_SIN_LEN
641           serverAddrv4.sin_len = sizeof (serverAddrv4);
642 #endif
643           serverAddrv4.sin_family = AF_INET;
644           serverAddrv4.sin_addr.s_addr = INADDR_ANY;
645           serverAddrv4.sin_port = htons (plugin->open_port);
646           addrlen = sizeof (serverAddrv4);
647           serverAddr = (struct sockaddr *) &serverAddrv4;
648         }
649     }
650
651   if (desc != NULL)
652     {
653       GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, serverAddr, addrlen) ==
654                      GNUNET_OK);
655     }
656
657   plugin->rs = GNUNET_NETWORK_fdset_create ();
658
659   GNUNET_NETWORK_fdset_zero (plugin->rs);
660   GNUNET_NETWORK_fdset_set (plugin->rs, desc);
661
662   plugin->select_task =
663     GNUNET_SCHEDULER_add_select (plugin->env->sched,
664                                  GNUNET_SCHEDULER_PRIORITY_DEFAULT,
665                                  GNUNET_SCHEDULER_NO_TASK,
666                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
667                                  NULL, &udp_plugin_select, plugin);
668
669   return desc;
670 }
671
672
673 /**
674  * Check if the given port is plausible (must be either
675  * our listen port or our advertised port).  If it is
676  * neither, we return one of these two ports at random.
677  *
678  * @return either in_port or a more plausible port
679  */
680 static uint16_t
681 check_port (struct Plugin *plugin, uint16_t in_port)
682 {
683   if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
684     return in_port;
685   return (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
686                                     2) == 0)
687     ? plugin->open_port : plugin->adv_port;
688 }
689
690
691 /**
692  * Another peer has suggested an address for this peer and transport
693  * plugin.  Check that this could be a valid address.  This function
694  * is not expected to 'validate' the address in the sense of trying to
695  * connect to it but simply to see if the binary format is technically
696  * legal for establishing a connection.
697  *
698  * @param cls handle to Plugin
699  * @param addr address to check
700  * @param addrlen length of addr
701  * @return GNUNET_OK if this is a plausible address for this peer
702  *         and transport, GNUNET_SYSERR if not
703  */
704 static int
705 udp_check_address (void *cls, void *addr, size_t addrlen)
706 {
707   struct Plugin *plugin = cls;
708   struct IPv4UdpAddress *v4;
709   struct IPv6UdpAddress *v6;
710
711   if ((addrlen != sizeof (struct IPv4UdpAddress)) &&
712       (addrlen != sizeof (struct IPv6UdpAddress)))
713     {
714       GNUNET_break_op (0);
715       return GNUNET_SYSERR;
716     }
717   if (addrlen == sizeof (struct IPv4UdpAddress))
718     {
719       v4 = (struct IPv4UdpAddress *) addr;
720       v4->u_port = htons (check_port (plugin, ntohs (v4->u_port)));
721     }
722   else
723     {
724       v6 = (struct IPv6UdpAddress *) addr;
725       v6->u6_port = htons (check_port (plugin, ntohs (v6->u6_port)));
726     }
727   return GNUNET_OK;
728 }
729
730
731 /**
732  * Append our port and forward the result.
733  */
734 static void
735 append_port (void *cls, const char *hostname)
736 {
737   struct PrettyPrinterContext *ppc = cls;
738   char *ret;
739
740   if (hostname == NULL)
741     {
742       ppc->asc (ppc->asc_cls, NULL);
743       GNUNET_free (ppc);
744       return;
745     }
746   GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
747   ppc->asc (ppc->asc_cls, ret);
748   GNUNET_free (ret);
749 }
750
751
752 /**
753  * Convert the transports address to a nice, human-readable
754  * format.
755  *
756  * @param cls closure
757  * @param type name of the transport that generated the address
758  * @param addr one of the addresses of the host, NULL for the last address
759  *        the specific address format depends on the transport
760  * @param addrlen length of the address
761  * @param numeric should (IP) addresses be displayed in numeric form?
762  * @param timeout after how long should we give up?
763  * @param asc function to call on each string
764  * @param asc_cls closure for asc
765  */
766 static void
767 udp_plugin_address_pretty_printer (void *cls,
768                                    const char *type,
769                                    const void *addr,
770                                    size_t addrlen,
771                                    int numeric,
772                                    struct GNUNET_TIME_Relative timeout,
773                                    GNUNET_TRANSPORT_AddressStringCallback asc,
774                                    void *asc_cls)
775 {
776   struct Plugin *plugin = cls;
777   struct PrettyPrinterContext *ppc;
778   const void *sb;
779   struct sockaddr_in a4;
780   struct sockaddr_in6 a6;
781   const struct IPv4UdpAddress *t4;
782   const struct IPv6UdpAddress *t6;
783   int af;
784   size_t sbs;
785   uint16_t port;
786
787   if (addrlen == sizeof (struct IPv6UdpAddress))
788     {
789       t6 = addr;
790       af = AF_INET6;
791       memset (&a6, 0, sizeof (a6));
792       a6.sin6_family = AF_INET6;
793       a6.sin6_port = t6->u6_port;
794       port = ntohs (t6->u6_port);
795       memcpy (a6.sin6_addr.s6_addr,
796               t6->ipv6_addr,
797               16);      
798       sb = &a6;
799       sbs = sizeof (a6);
800     }
801   else if (addrlen == sizeof (struct IPv4UdpAddress))
802     {
803       t4 = addr;
804       af = AF_INET;
805       memset (&a4, 0, sizeof (a4));
806       a4.sin_family = AF_INET;
807       a4.sin_port = t4->u_port;
808       a4.sin_addr.s_addr = t4->ipv4_addr;
809       port = ntohs (t4->u_port);
810       sb = &a4;
811       sbs = sizeof (a4);
812     }
813   else
814     {
815       /* invalid address */
816       GNUNET_break_op (0);
817       asc (asc_cls, NULL);
818       return;
819     }
820   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
821   ppc->asc = asc;
822   ppc->asc_cls = asc_cls;
823   ppc->port = port;
824   GNUNET_RESOLVER_hostname_get (plugin->env->sched,
825                                 plugin->env->cfg,
826                                 sb,
827                                 sbs,
828                                 !numeric, timeout, &append_port, ppc);
829 }
830
831
832
833 /**
834  * Function called for a quick conversion of the binary address to
835  * a numeric address.  Note that the caller must not free the 
836  * address and that the next call to this function is allowed
837  * to override the address again.
838  *
839  * @param cls closure
840  * @param addr binary address
841  * @param addrlen length of the address
842  * @return string representing the same address 
843  */
844 static const char* 
845 udp_address_to_string (void *cls,
846                        const void *addr,
847                        size_t addrlen)
848 {
849   static char buf[INET6_ADDRSTRLEN];
850   const void *sb;
851   struct sockaddr_in a4;
852   struct sockaddr_in6 a6;
853   const struct IPv4UdpAddress *t4;
854   const struct IPv6UdpAddress *t6;
855   int af;
856
857   if (addrlen == sizeof (struct IPv6UdpAddress))
858     {
859       t6 = addr;
860       af = AF_INET6;
861       memset (&a6, 0, sizeof (a6));
862       a6.sin6_family = AF_INET6;
863       a6.sin6_port = t6->u6_port;
864       memcpy (a6.sin6_addr.s6_addr,
865               t6->ipv6_addr,
866               16);      
867       sb = &a6;
868     }
869   else if (addrlen == sizeof (struct IPv4UdpAddress))
870     {
871       t4 = addr;
872       af = AF_INET;
873       memset (&a4, 0, sizeof (a4));
874       a4.sin_family = AF_INET;
875       a4.sin_port = t4->u_port;
876       a4.sin_addr.s_addr = t4->ipv4_addr;
877       sb = &a4;
878     }
879   else
880     return NULL;
881   
882   return inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
883 }
884
885
886 /**
887  * The exported method. Makes the core api available via a global and
888  * returns the udp transport API.
889  *
890  * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
891  * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
892  */
893 void *
894 libgnunet_plugin_transport_udp_init (void *cls)
895 {
896   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
897   struct GNUNET_TRANSPORT_PluginFunctions *api;
898   struct Plugin *plugin;
899   struct GNUNET_SERVICE_Context *service;
900   unsigned long long aport;
901   unsigned long long bport;
902   unsigned long long mtu;
903
904   service = GNUNET_SERVICE_start ("transport-udp", env->sched, env->cfg);
905   if (service == NULL)
906     {
907       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "udp", _
908                        ("Failed to start service for `%s' transport plugin.\n"),
909                        "udp");
910       return NULL;
911     }
912   aport = 0;
913   if ((GNUNET_OK !=
914        GNUNET_CONFIGURATION_get_value_number (env->cfg,
915                                               "transport-udp",
916                                               "PORT",
917                                               &bport)) ||
918       (bport > 65535) ||
919       ((GNUNET_OK ==
920         GNUNET_CONFIGURATION_get_value_number (env->cfg,
921                                                "transport-udp",
922                                                "ADVERTISED-PORT",
923                                                &aport)) && (aport > 65535)))
924     {
925       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
926                        "udp",
927                        _
928                        ("Require valid port number for service `%s' in configuration!\n"),
929                        "transport-udp");
930       GNUNET_SERVICE_stop (service);
931       return NULL;
932     }
933   if (aport == 0)
934     aport = bport;
935
936   mtu = 1240;
937   if (mtu < 1200)
938     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
939                      "udp",
940                      _("MTU %llu for `%s' is probably too low!\n"), mtu,
941                      "UDP");
942
943   plugin = GNUNET_malloc (sizeof (struct Plugin));
944   plugin->open_port = bport;
945   plugin->adv_port = aport;
946   plugin->env = env;
947   plugin->statistics = NULL;
948   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
949   api->cls = plugin;
950
951   api->send = &udp_plugin_send;
952   api->disconnect = &udp_disconnect;
953   api->address_pretty_printer = &udp_plugin_address_pretty_printer;
954   api->check_address = &udp_check_address;
955   api->address_to_string = &udp_address_to_string;
956   plugin->service = service;
957
958   /* FIXME: do the two calls below periodically again and
959      not just once (since the info we get might change...) */
960   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
961   plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->sched,
962                                                            env->cfg,
963                                                            AF_UNSPEC,
964                                                            HOSTNAME_RESOLVE_TIMEOUT,
965                                                            &process_hostname_ips,
966                                                            plugin);
967
968   udp_sock = udp_transport_server_start (plugin);
969
970   GNUNET_assert (udp_sock != NULL);
971
972   return api;
973 }
974
975 void *
976 libgnunet_plugin_transport_udp_done (void *cls)
977 {
978   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
979   struct Plugin *plugin = api->cls;
980
981   udp_transport_server_stop (plugin);
982   if (NULL != plugin->hostname_dns)
983     {
984       GNUNET_RESOLVER_request_cancel (plugin->hostname_dns);
985       plugin->hostname_dns = NULL;
986     }
987   GNUNET_SERVICE_stop (plugin->service);
988
989   GNUNET_NETWORK_fdset_destroy (plugin->rs);
990   GNUNET_free (plugin);
991   GNUNET_free (api);
992   return NULL;
993 }
994
995 /* end of plugin_transport_udp.c */