4de3f2c442cf3afda154dbfa25f644604ade0e9c
[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   struct in6_addr ipv6_addr;
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 to the network service.
144    */
145   struct GNUNET_SERVICE_Context *service;
146
147   /**
148    * Handle for request of hostname resolution, non-NULL if pending.
149    */
150   struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
151
152   /**
153    * FD Read set
154    */
155   struct GNUNET_NETWORK_FDSet *rs;
156
157   /**
158    * ID of task used to update our addresses when one expires.
159    */
160   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
161
162   /**
163    * ID of select task
164    */
165   GNUNET_SCHEDULER_TaskIdentifier select_task;
166
167   /**
168    * Port that we are actually listening on.
169    */
170   uint16_t open_port;
171
172   /**
173    * Port that the user said we would have visible to the
174    * rest of the world.
175    */
176   uint16_t adv_port;
177
178 };
179
180 /* *********** globals ************* */
181
182 /**
183  * The socket that we transmit all data with
184  */
185 static struct GNUNET_NETWORK_Handle *udp_sock;
186
187 /**
188  * Disconnect from a remote node.
189  *
190  * @param cls closure ('struct Plugin'), unused
191  * @param target peer do disconnect
192  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
193  */
194 void
195 udp_disconnect (void *cls, 
196                 const struct GNUNET_PeerIdentity *target)
197 {
198   /* nothing to do, UDP is stateless */
199 }
200
201 /**
202  * Shutdown the server process (stop receiving inbound traffic). Maybe
203  * restarted later!
204  *
205  * @param cls closure, the 'struct Plugin*'
206  */
207 static int
208 udp_transport_server_stop (void *cls)
209 {
210   struct Plugin *plugin = cls;
211   int ret;
212
213   GNUNET_assert (udp_sock != NULL);
214   if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
215     {
216       GNUNET_SCHEDULER_cancel (plugin->env->sched, plugin->select_task);
217       plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
218     }
219
220   ret = GNUNET_NETWORK_socket_close (udp_sock);
221   if (ret != GNUNET_SYSERR)
222     udp_sock = NULL;
223   return ret;
224 }
225
226 /**
227  * Function that can be used by the transport service to transmit
228  * a message using the plugin.
229  *
230  * @param cls closure, the 'struct Plugin*'
231  * @param target who should receive this message (ignored by UDP)
232  * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
233  * @param msgbuf_size the size of the msgbuf to send
234  * @param priority how important is the message (ignored by UDP)
235  * @param timeout when should we time out (give up) if we can not transmit?
236  * @param session which session must be used (always NULL for UDP)
237  * @param addr the addr to send the message to, needs to be a sockaddr for us
238  * @param addrlen the len of addr
239  * @param force_address GNUNET_YES if the plugin MUST use the given address,
240  *                GNUNET_NO means the plugin may use any other address and
241  *                GNUNET_SYSERR means that only reliable existing
242  *                bi-directional connections should be used (regardless
243  *                of address)
244  * @param cont continuation to call once the message has
245  *        been transmitted (or if the transport is ready
246  *        for the next transmission call; or if the
247  *        peer disconnected...)
248  * @param cont_cls closure for cont
249  *
250  * @return the number of bytes written, -1 on error (in this case, cont is not called)
251  */
252 static ssize_t
253 udp_plugin_send (void *cls,
254                  const struct GNUNET_PeerIdentity *target,
255                  const char *msgbuf,
256                  size_t msgbuf_size,
257                  unsigned int priority,
258                  struct GNUNET_TIME_Relative timeout,
259                  struct Session *session,
260                  const void *addr,
261                  size_t addrlen,
262                  int force_address,
263                  GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
264 {
265   struct Plugin *plugin = cls;
266   struct UDPMessage *message;
267   int ssize;
268   ssize_t sent;
269   const void *sb;
270   size_t sbs;
271   struct sockaddr_in a4;
272   struct sockaddr_in6 a6;
273   const struct IPv4UdpAddress *t4;
274   const struct IPv6UdpAddress *t6;
275
276   GNUNET_assert (NULL == session);
277   GNUNET_assert(udp_sock != NULL);
278   if ( (addr == NULL) || (addrlen == 0) )
279     {
280 #if DEBUG_UDP
281   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
282                    ("udp_plugin_send called without address, returning!\n"));
283 #endif
284       return -1; /* Can never send if we don't have an address!! */
285     }
286   if (force_address == GNUNET_SYSERR)
287     return -1; /* never reliable */
288
289   if (addrlen == sizeof (struct IPv6UdpAddress))
290     {
291       t6 = addr;
292       memset (&a6, 0, sizeof (a6));
293 #if HAVE_SOCKADDR_IN_SIN_LEN
294       a6.sin6_len = sizeof (a6);
295 #endif
296       a6.sin6_family = AF_INET6;
297       a6.sin6_port = t6->u6_port;
298       memcpy (&a6.sin6_addr,
299               &t6->ipv6_addr,
300               sizeof (struct in6_addr));      
301       sb = &a6;
302       sbs = sizeof (a6);
303     }
304   else if (addrlen == sizeof (struct IPv4UdpAddress))
305     {
306       t4 = addr;
307       memset (&a4, 0, sizeof (a4));
308 #if HAVE_SOCKADDR_IN_SIN_LEN
309       a4.sin_len = sizeof (a4);
310 #endif
311       a4.sin_family = AF_INET;
312       a4.sin_port = t4->u_port;
313       a4.sin_addr.s_addr = t4->ipv4_addr;
314       sb = &a4;
315       sbs = sizeof (a4);
316     }
317   else
318     {
319       GNUNET_break_op (0);
320       return -1;
321     }
322
323   /* Build the message to be sent */
324   message = GNUNET_malloc (sizeof (struct UDPMessage) + msgbuf_size);
325   ssize = sizeof (struct UDPMessage) + msgbuf_size;
326
327 #if DEBUG_UDP
328   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", 
329                    "In udp_send, ssize is %d, sending message to `%s'\n", 
330                    ssize, 
331                    GNUNET_a2s(sb, sbs));
332 #endif
333   message->header.size = htons (ssize);
334   message->header.type = htons (0);
335   memcpy (&message->sender, plugin->env->my_identity,
336           sizeof (struct GNUNET_PeerIdentity));
337   memcpy (&message[1], msgbuf, msgbuf_size);
338   sent =
339     GNUNET_NETWORK_socket_sendto (udp_sock, message, ssize,
340                                   sb, sbs);
341   if ( (cont != NULL) &&
342        (sent != -1) )
343     cont (cont_cls, target, GNUNET_OK);
344   GNUNET_free (message);
345   return sent;
346 }
347
348
349 /**
350  * Add the IP of our network interface to the list of
351  * our external IP addresses.
352  *
353  * @param cls closure (the 'struct Plugin*')
354  * @param name name of the interface (can be NULL for unknown)
355  * @param isDefault is this presumably the default interface
356  * @param addr address of this interface (can be NULL for unknown or unassigned)
357  * @param addrlen length of the address
358  * @return GNUNET_OK to continue iterating
359  */
360 static int
361 process_interfaces (void *cls,
362                     const char *name,
363                     int isDefault,
364                     const struct sockaddr *addr, socklen_t addrlen)
365 {
366   struct Plugin *plugin = cls;
367   int af;
368   struct IPv4UdpAddress t4;
369   struct IPv6UdpAddress t6;
370   void *arg;
371   uint16_t args;
372
373   af = addr->sa_family;
374   if (af == AF_INET)
375     {
376       t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
377       t4.u_port = htons (plugin->adv_port);
378       arg = &t4;
379       args = sizeof (t4);
380     }
381   else if (af == AF_INET6)
382     {
383       if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
384         {
385           /* skip link local addresses */
386           return GNUNET_OK;
387         }
388       memcpy (&t6.ipv6_addr,
389               &((struct sockaddr_in6 *) addr)->sin6_addr,
390               sizeof (struct in6_addr));
391       t6.u6_port = htons (plugin->adv_port);
392       arg = &t6;
393       args = sizeof (t6);
394     }
395   else
396     {
397       GNUNET_break (0);
398       return GNUNET_OK;
399     }
400   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO |
401                    GNUNET_ERROR_TYPE_BULK,
402                    "udp", 
403                    _("Found address `%s' (%s)\n"),
404                    GNUNET_a2s (addr, addrlen), 
405                    name);
406   plugin->env->notify_address (plugin->env->cls,
407                                "udp",
408                                arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
409   return GNUNET_OK;
410 }
411
412
413 /**
414  * Function called by the resolver for each address obtained from DNS
415  * for our own hostname.  Add the addresses to the list of our
416  * external IP addresses.
417  *
418  * @param cls closure
419  * @param addr one of the addresses of the host, NULL for the last address
420  * @param addrlen length of the address
421  */
422 static void
423 process_hostname_ips (void *cls,
424                       const struct sockaddr *addr, socklen_t addrlen)
425 {
426   struct Plugin *plugin = cls;
427
428   if (addr == NULL)
429     {
430       plugin->hostname_dns = NULL;
431       return;
432     }
433   process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
434 }
435
436
437 /*
438  * @param cls the plugin handle
439  * @param tc the scheduling context (for rescheduling this function again)
440  *
441  * We have been notified that our writeset has something to read.  Presumably
442  * select has been called already, so we can go ahead and start reading from
443  * the socket immediately.  Then we check if there is more to be read by
444  * calling select ourselves while there is stuff on the wire.  Then reschedule
445  * this function to be called again once more is available.
446  *
447  */
448 static void
449 udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
450 {
451   struct Plugin *plugin = cls;
452   char *buf;
453   struct UDPMessage *msg;
454   struct GNUNET_PeerIdentity *sender;
455   unsigned int buflen;
456   socklen_t fromlen;
457   struct sockaddr_storage addr;
458   ssize_t ret;
459   int offset;
460   int count;
461   int tsize;
462   char *msgbuf;
463   const struct GNUNET_MessageHeader *currhdr;
464   struct IPv4UdpAddress t4;
465   struct IPv6UdpAddress t6;
466   const struct sockaddr_in *s4;
467   const struct sockaddr_in6 *s6;
468   const void *ca;
469   size_t calen;
470
471 #if DEBUG_UDP
472       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
473                        ("entered select...\n"));
474 #endif
475
476       buflen = GNUNET_NETWORK_socket_recvfrom_amount (udp_sock);
477
478 #if DEBUG_UDP
479       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
480                        ("we expect to read %u bytes\n"), buflen);
481 #endif
482
483     if (buflen == GNUNET_NO)
484       return;
485
486     buf = GNUNET_malloc (buflen);
487     fromlen = sizeof (addr);
488
489     memset (&addr, 0, fromlen);
490     ret =
491       GNUNET_NETWORK_socket_recvfrom (udp_sock, buf, buflen,
492                                       (struct sockaddr *) &addr, &fromlen);
493
494 #if DEBUG_UDP
495     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
496                      ("socket_recv returned %u, src_addr_len is %u\n"), ret,
497                      fromlen);
498 #endif
499
500     if (ret <= 0)
501       {
502         GNUNET_free (buf);
503         return;
504       }
505     msg = (struct UDPMessage *) buf;
506
507 #if DEBUG_UDP
508     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
509                      ("header reports message size of %d\n"),
510                      ntohs (msg->header.size));
511
512     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
513                      ("header reports message type of %d\n"),
514                      ntohs (msg->header.type));
515 #endif
516     if (ntohs (msg->header.size) < sizeof (struct UDPMessage))
517       {
518         GNUNET_free (buf);
519         GNUNET_NETWORK_fdset_zero (plugin->rs);
520         GNUNET_NETWORK_fdset_set (plugin->rs, udp_sock);
521         return;
522       }
523     msgbuf = (char *)&msg[1];
524     sender = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
525     memcpy (sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
526
527     offset = 0;
528     count = 0;
529     tsize = ntohs (msg->header.size) - sizeof(struct UDPMessage);
530 #if DEBUG_UDP
531     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UDP", _
532                      ("offset is %d, tsize is %d (UDPMessage size is %d)\n"),
533                      offset, tsize, sizeof(struct UDPMessage));
534 #endif
535
536     if (fromlen == sizeof (struct sockaddr_in))
537       {
538         s4 = (const struct sockaddr_in*) &addr;
539         t4.u_port = s4->sin_port;
540         t4.ipv4_addr = s4->sin_addr.s_addr;
541         ca = &t4;
542         calen = sizeof (struct IPv4UdpAddress);
543       }
544     else if (fromlen == sizeof (struct sockaddr_in6))
545       {
546         s6 = (const struct sockaddr_in6*) &addr;
547         t6.u6_port = s6->sin6_port;
548         memcpy (&t6.ipv6_addr,
549                 &s6->sin6_addr,
550                 sizeof (struct in6_addr));
551         ca = &t6;
552         calen = sizeof (struct IPv6UdpAddress);
553       }
554     else
555       {
556         GNUNET_break (0);
557         ca = NULL;
558         calen = 0;
559       }
560     while (offset < tsize)
561       {
562         currhdr = (struct GNUNET_MessageHeader *)&msgbuf[offset];
563 #if DEBUG_UDP
564     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
565                      ("processing msg %d: type %d, size %d at offset %d\n"),
566                      count, ntohs(currhdr->type), ntohs(currhdr->size), offset);
567 #endif
568         plugin->env->receive (plugin->env->cls,
569                               sender, currhdr, UDP_DIRECT_DISTANCE, 
570                               NULL, ca, calen);
571         offset += ntohs(currhdr->size);
572 #if DEBUG_UDP
573     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
574                      ("offset now %d, tsize %d\n"),
575                      offset, tsize);
576 #endif
577         count++;
578       }
579
580     GNUNET_free (sender);
581     GNUNET_free (buf);
582
583   plugin->select_task =
584     GNUNET_SCHEDULER_add_select (plugin->env->sched,
585                                  GNUNET_SCHEDULER_PRIORITY_DEFAULT,
586                                  GNUNET_SCHEDULER_NO_TASK,
587                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
588                                  NULL, &udp_plugin_select, plugin);
589
590 }
591
592 /**
593  * Create a UDP socket.  If possible, use IPv6, otherwise
594  * try IPv4.
595  * @param cls closure, the 'struct Plugin*'
596  */
597 static struct GNUNET_NETWORK_Handle *
598 udp_transport_server_start (void *cls)
599 {
600   struct Plugin *plugin = cls;
601   struct GNUNET_NETWORK_Handle *desc;
602   struct sockaddr_in serverAddrv4;
603   struct sockaddr_in6 serverAddrv6;
604   struct sockaddr *serverAddr;
605   socklen_t addrlen;
606
607   desc = NULL;
608   if (GNUNET_YES !=
609       GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, "GNUNETD",
610                                             "DISABLE-IPV6"))
611     {
612       desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 17);
613       if (desc != NULL)
614         {
615           memset (&serverAddrv6, 0, sizeof (serverAddrv6));
616 #if HAVE_SOCKADDR_IN_SIN_LEN
617           serverAddrv6.sin6_len = sizeof (serverAddrv6);
618 #endif
619           serverAddrv6.sin6_family = AF_INET6;
620           serverAddrv6.sin6_addr = in6addr_any;
621           serverAddrv6.sin6_port = htons (plugin->open_port);
622           addrlen = sizeof (serverAddrv6);
623           serverAddr = (struct sockaddr *) &serverAddrv6;
624         }
625     }
626   if (NULL == desc)
627     {
628       desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 17);
629       if (NULL == desc)
630         {
631           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", "socket");
632           return NULL;
633         }
634       else
635         {
636           memset (&serverAddrv4, 0, sizeof (serverAddrv4));
637 #if HAVE_SOCKADDR_IN_SIN_LEN
638           serverAddrv4.sin_len = sizeof (serverAddrv4);
639 #endif
640           serverAddrv4.sin_family = AF_INET;
641           serverAddrv4.sin_addr.s_addr = INADDR_ANY;
642           serverAddrv4.sin_port = htons (plugin->open_port);
643           addrlen = sizeof (serverAddrv4);
644           serverAddr = (struct sockaddr *) &serverAddrv4;
645         }
646     }
647
648   if (desc != NULL)
649     {
650       GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, serverAddr, addrlen) ==
651                      GNUNET_OK);
652     }
653
654   plugin->rs = GNUNET_NETWORK_fdset_create ();
655
656   GNUNET_NETWORK_fdset_zero (plugin->rs);
657   GNUNET_NETWORK_fdset_set (plugin->rs, desc);
658
659   plugin->select_task =
660     GNUNET_SCHEDULER_add_select (plugin->env->sched,
661                                  GNUNET_SCHEDULER_PRIORITY_DEFAULT,
662                                  GNUNET_SCHEDULER_NO_TASK,
663                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
664                                  NULL, &udp_plugin_select, plugin);
665
666   return desc;
667 }
668
669
670 /**
671  * Check if the given port is plausible (must be either
672  * our listen port or our advertised port).  If it is
673  * neither, we return one of these two ports at random.
674  *
675  * @return either in_port or a more plausible port
676  */
677 static uint16_t
678 check_port (struct Plugin *plugin, uint16_t in_port)
679 {
680   if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
681     return in_port;
682   return (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
683                                     2) == 0)
684     ? plugin->open_port : plugin->adv_port;
685 }
686
687
688 /**
689  * Another peer has suggested an address for this peer and transport
690  * plugin.  Check that this could be a valid address.  This function
691  * is not expected to 'validate' the address in the sense of trying to
692  * connect to it but simply to see if the binary format is technically
693  * legal for establishing a connection.
694  *
695  * @param cls handle to Plugin
696  * @param addr address to check
697  * @param addrlen length of addr
698  * @return GNUNET_OK if this is a plausible address for this peer
699  *         and transport, GNUNET_SYSERR if not
700  */
701 static int
702 udp_check_address (void *cls, void *addr, size_t addrlen)
703 {
704   struct Plugin *plugin = cls;
705   struct IPv4UdpAddress *v4;
706   struct IPv6UdpAddress *v6;
707
708   if ((addrlen != sizeof (struct IPv4UdpAddress)) &&
709       (addrlen != sizeof (struct IPv6UdpAddress)))
710     {
711       GNUNET_break_op (0);
712       return GNUNET_SYSERR;
713     }
714   if (addrlen == sizeof (struct IPv4UdpAddress))
715     {
716       v4 = (struct IPv4UdpAddress *) addr;
717       v4->u_port = htons (check_port (plugin, ntohs (v4->u_port)));
718     }
719   else
720     {
721       v6 = (struct IPv6UdpAddress *) addr;
722       if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
723         {
724           GNUNET_break_op (0);
725           return GNUNET_SYSERR;
726         }
727       v6->u6_port = htons (check_port (plugin, ntohs (v6->u6_port)));
728     }
729   return GNUNET_OK;
730 }
731
732
733 /**
734  * Append our port and forward the result.
735  */
736 static void
737 append_port (void *cls, const char *hostname)
738 {
739   struct PrettyPrinterContext *ppc = cls;
740   char *ret;
741
742   if (hostname == NULL)
743     {
744       ppc->asc (ppc->asc_cls, NULL);
745       GNUNET_free (ppc);
746       return;
747     }
748   GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
749   ppc->asc (ppc->asc_cls, ret);
750   GNUNET_free (ret);
751 }
752
753
754 /**
755  * Convert the transports address to a nice, human-readable
756  * format.
757  *
758  * @param cls closure
759  * @param type name of the transport that generated the address
760  * @param addr one of the addresses of the host, NULL for the last address
761  *        the specific address format depends on the transport
762  * @param addrlen length of the address
763  * @param numeric should (IP) addresses be displayed in numeric form?
764  * @param timeout after how long should we give up?
765  * @param asc function to call on each string
766  * @param asc_cls closure for asc
767  */
768 static void
769 udp_plugin_address_pretty_printer (void *cls,
770                                    const char *type,
771                                    const void *addr,
772                                    size_t addrlen,
773                                    int numeric,
774                                    struct GNUNET_TIME_Relative timeout,
775                                    GNUNET_TRANSPORT_AddressStringCallback asc,
776                                    void *asc_cls)
777 {
778   struct Plugin *plugin = cls;
779   struct PrettyPrinterContext *ppc;
780   const void *sb;
781   struct sockaddr_in a4;
782   struct sockaddr_in6 a6;
783   const struct IPv4UdpAddress *t4;
784   const struct IPv6UdpAddress *t6;
785   size_t sbs;
786   uint16_t port;
787
788   if (addrlen == sizeof (struct IPv6UdpAddress))
789     {
790       t6 = addr;
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,
796               &t6->ipv6_addr,
797               sizeof (struct in6_addr));      
798       sb = &a6;
799       sbs = sizeof (a6);
800     }
801   else if (addrlen == sizeof (struct IPv4UdpAddress))
802     {
803       t4 = addr;
804       memset (&a4, 0, sizeof (a4));
805       a4.sin_family = AF_INET;
806       a4.sin_port = t4->u_port;
807       a4.sin_addr.s_addr = t4->ipv4_addr;
808       port = ntohs (t4->u_port);
809       sb = &a4;
810       sbs = sizeof (a4);
811     }
812   else
813     {
814       /* invalid address */
815       GNUNET_break_op (0);
816       asc (asc_cls, NULL);
817       return;
818     }
819   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
820   ppc->asc = asc;
821   ppc->asc_cls = asc_cls;
822   ppc->port = port;
823   GNUNET_RESOLVER_hostname_get (plugin->env->sched,
824                                 plugin->env->cfg,
825                                 sb,
826                                 sbs,
827                                 !numeric, timeout, &append_port, ppc);
828 }
829
830
831
832 /**
833  * Function called for a quick conversion of the binary address to
834  * a numeric address.  Note that the caller must not free the 
835  * address and that the next call to this function is allowed
836  * to override the address again.
837  *
838  * @param cls closure
839  * @param addr binary address
840  * @param addrlen length of the address
841  * @return string representing the same address 
842  */
843 static const char* 
844 udp_address_to_string (void *cls,
845                        const void *addr,
846                        size_t addrlen)
847 {
848   static char rbuf[INET6_ADDRSTRLEN + 10];
849   char buf[INET6_ADDRSTRLEN];
850   const void *sb;
851   struct in_addr a4;
852   struct in6_addr a6;
853   const struct IPv4UdpAddress *t4;
854   const struct IPv6UdpAddress *t6;
855   int af;
856   uint16_t port;
857
858   if (addrlen == sizeof (struct IPv6UdpAddress))
859     {
860       t6 = addr;
861       af = AF_INET6;
862       port = ntohs (t6->u6_port);
863       memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
864       sb = &a6;
865     }
866   else if (addrlen == sizeof (struct IPv4UdpAddress))
867     {
868       t4 = addr;
869       af = AF_INET;
870       port = ntohs (t4->u_port);
871       memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
872       sb = &a4;
873     }
874   else
875     return NULL;
876   inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
877   GNUNET_snprintf (rbuf,
878                    sizeof (rbuf),
879                    "%s:%u",
880                    buf,
881                    port);
882   return rbuf;
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   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
948   api->cls = plugin;
949
950   api->send = &udp_plugin_send;
951   api->disconnect = &udp_disconnect;
952   api->address_pretty_printer = &udp_plugin_address_pretty_printer;
953   api->check_address = &udp_check_address;
954   api->address_to_string = &udp_address_to_string;
955   plugin->service = service;
956
957   /* FIXME: do the two calls below periodically again and
958      not just once (since the info we get might change...) */
959   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
960   plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->sched,
961                                                            env->cfg,
962                                                            AF_UNSPEC,
963                                                            HOSTNAME_RESOLVE_TIMEOUT,
964                                                            &process_hostname_ips,
965                                                            plugin);
966
967   udp_sock = udp_transport_server_start (plugin);
968
969   GNUNET_assert (udp_sock != NULL);
970
971   return api;
972 }
973
974 void *
975 libgnunet_plugin_transport_udp_done (void *cls)
976 {
977   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
978   struct Plugin *plugin = api->cls;
979
980   udp_transport_server_stop (plugin);
981   if (NULL != plugin->hostname_dns)
982     {
983       GNUNET_RESOLVER_request_cancel (plugin->hostname_dns);
984       plugin->hostname_dns = NULL;
985     }
986   GNUNET_SERVICE_stop (plugin->service);
987
988   GNUNET_NETWORK_fdset_destroy (plugin->rs);
989   GNUNET_free (plugin);
990   GNUNET_free (api);
991   return NULL;
992 }
993
994 /* end of plugin_transport_udp.c */