whiny christian fix
[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  * Handle for request of hostname resolution, non-NULL if pending.
47  */
48 static struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
49
50 /**
51  * Message-Packet header.
52  */
53 struct UDPMessage
54 {
55   /**
56    * size of the message, in bytes, including this header.
57    */
58   struct GNUNET_MessageHeader header;
59
60   /**
61    * What is the identity of the sender (GNUNET_hash of public key)
62    */
63   struct GNUNET_PeerIdentity sender;
64
65 };
66
67 /* Forward definition */
68 struct Plugin;
69
70 /**
71  * Session handle for UDP connections.
72  */
73 struct Session
74 {
75
76   /**
77    * Stored in a linked list.
78    */
79   struct Session *next;
80
81   /**
82    * Pointer to the global plugin struct.
83    */
84   struct Plugin *plugin;
85
86   /**
87    * To whom are we talking to (set to our identity
88    */
89   struct GNUNET_PeerIdentity target;
90
91   /**
92    * Address of the other peer if WE initiated the connection
93    * (and hence can be sure what it is), otherwise NULL.
94    */
95   void *connect_addr;
96
97   /**
98    * Length of connect_addr, can be 0.
99    */
100   size_t connect_alen;
101
102   /*
103    * Random challenge number for validation
104    */
105   int challenge;
106
107   /*
108    * Have we received validation (performed ping/pong) from this peer?
109    */
110   unsigned int validated;
111
112   /*
113    * What is the latency of this connection? (Time between ping and pong)
114    */
115   struct GNUNET_TIME_Relative latency;
116
117   /*
118    * At what GNUNET_TIME did we send a ping?
119    */
120   struct GNUNET_TIME_Absolute ping_sent;
121 };
122
123 /**
124  * Encapsulation of all of the state of the plugin.
125  */
126 struct Plugin
127 {
128   /**
129    * Our environment.
130    */
131   struct GNUNET_TRANSPORT_PluginEnvironment *env;
132
133   /**
134    * List of open TCP sessions.
135    */
136   struct Session *sessions;
137
138   /**
139    * Handle for the statistics service.
140    */
141   struct GNUNET_STATISTICS_Handle *statistics;
142
143   /**
144    * Handle to the network service.
145    */
146   struct GNUNET_SERVICE_Context *service;
147
148   /**
149    * ID of task used to update our addresses when one expires.
150    */
151   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
152
153   /**
154    * ID of select task
155    */
156   GNUNET_SCHEDULER_TaskIdentifier select_task;
157
158   /**
159    * Port that we are actually listening on.
160    */
161   uint16_t open_port;
162
163   /**
164    * Port that the user said we would have visible to the
165    * rest of the world.
166    */
167   uint16_t adv_port;
168
169   /*
170    * FD Read set
171    */
172   struct GNUNET_NETWORK_FDSet *rs;
173
174 };
175
176 /**
177  * Message used to ask a peer to validate receipt (to check an address
178  * from a HELLO).
179  */
180 struct UDPPingMessage
181 {
182
183   /**
184    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING
185    */
186   struct GNUNET_MessageHeader header;
187
188   /**
189    * Random challenge number (in network byte order).
190    */
191   uint32_t challenge GNUNET_PACKED;
192
193 };
194
195
196 /**
197  * Message used to validate a HELLO.  The challenge number
198  * is sent along with whatever address the peer received
199  * the ping from.  Used to validate our address (or at
200  * least give us a better idea where we look like we're
201  * coming from).
202  *
203  */
204 struct UDPPongMessage
205 {
206   /**
207    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG
208    */
209   struct GNUNET_MessageHeader header;
210
211   /**
212    * Random challenge number (in network byte order).
213    */
214   uint32_t challenge GNUNET_PACKED;
215
216   /* Length of addr, appended to end of message */
217   unsigned int addrlen;
218 };
219
220 /* *********** globals ************* */
221
222 /**
223  * the socket that we transmit all data with
224  */
225 static struct GNUNET_NETWORK_Handle *udp_sock;
226
227
228 /**
229  * A (core) Session is to be associated with a transport session. The
230  * transport service may want to know in order to call back on the
231  * core if the connection is being closed.
232  *
233  * @param session the session handle passed along
234  *   from the call to receive that was made by the transport
235  *   layer
236  * @return GNUNET_OK if the session could be associated,
237  *         GNUNET_SYSERR if not.
238  */
239 int
240 udp_associate (struct Session *session)
241 {
242   return GNUNET_SYSERR;         /* UDP connections can never be associated */
243 }
244
245 /**
246  * Disconnect from a remote node.
247  *
248  * @param tsession the session that is closed
249  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
250  */
251 void
252 udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
253 {
254   return;
255 }
256
257 /**
258  * Shutdown the server process (stop receiving inbound traffic). Maybe
259  * restarted later!
260  */
261 static int
262 udp_transport_server_stop (void *cls)
263 {
264   struct Plugin *plugin = cls;
265   GNUNET_assert (udp_sock != NULL);
266   if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
267     {
268       GNUNET_SCHEDULER_cancel (plugin->env->sched, plugin->select_task);
269       plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
270     }
271
272   GNUNET_NETWORK_socket_close (udp_sock);
273   udp_sock = NULL;
274   return GNUNET_OK;
275 }
276
277 static struct Session *
278 find_session (void *cls, const struct GNUNET_PeerIdentity *peer)
279 {
280   struct Plugin *plugin = cls;
281   struct Session *pos;
282   pos = plugin->sessions;
283
284   while (pos != NULL)
285     {
286       if (memcmp (peer, &pos->target, sizeof (struct GNUNET_PeerIdentity)) ==
287           0)
288         return pos;
289       pos = pos->next;
290     }
291
292   return NULL;
293 }
294
295 /**
296  * Function that can be used by the transport service to transmit
297  * a message using the plugin.
298  *
299  * @param cls closure
300  * @param service_context value passed to the transport-service
301  *        to identify the neighbour
302  * @param target who should receive this message
303  * @param priority how important is the message
304  * @param msg the message to transmit
305  * @param timeout when should we time out (give up) if we can not transmit?
306  * @param cont continuation to call once the message has
307  *        been transmitted (or if the transport is ready
308  *        for the next transmission call; or if the
309  *        peer disconnected...)
310  * @param cont_cls closure for cont
311  */
312 static void
313 udp_plugin_send (void *cls,
314                  const struct GNUNET_PeerIdentity *target,
315                  unsigned int priority,
316                  const struct GNUNET_MessageHeader *msg,
317                  struct GNUNET_TIME_Relative timeout,
318                  GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
319 {
320   struct Plugin *plugin = cls;
321   struct Session *session;
322   struct UDPMessage *message;
323   int ssize;
324   size_t sent;
325
326   session = find_session (plugin, target);
327
328   if ((session == NULL) || (udp_sock == NULL))
329     return;
330
331   /* Build the message to be sent */
332   message = GNUNET_malloc (sizeof (struct UDPMessage) + ntohs (msg->size));
333   ssize = sizeof (struct UDPMessage) + ntohs (msg->size);
334
335 #if DEBUG_UDP
336   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
337                    ("In udp_send, ssize is %d\n"), ssize);
338 #endif
339   message->header.size = htons (ssize);
340   message->header.type = htons (0);
341   memcpy (&message->sender, plugin->env->my_identity,
342           sizeof (struct GNUNET_PeerIdentity));
343   memcpy (&message[1], msg, ntohs (msg->size));
344
345   /* Actually send the message */
346   sent =
347     GNUNET_NETWORK_socket_sendto (udp_sock, message, ssize,
348                                   session->connect_addr,
349                                   session->connect_alen);
350
351   if (cont != NULL)
352     {
353       if (sent == GNUNET_SYSERR)
354         cont (cont_cls, target, GNUNET_SYSERR);
355       else
356         cont (cont_cls, target, GNUNET_OK);
357     }
358   GNUNET_free (message);
359   return;
360 }
361
362 /**
363  * We've received a PING from this peer via UDP.
364  * Send back our PONG.
365  *
366  * @param cls closure
367  * @param sender the Identity of the sender
368  * @param message the actual message
369  */
370 static void
371 handle_udp_ping (void *cls,
372                  struct GNUNET_PeerIdentity *sender,
373                  struct sockaddr_storage *addr, size_t addrlen,
374                  const struct GNUNET_MessageHeader *message)
375 {
376   struct Plugin *plugin = cls;
377   const struct UDPPingMessage *ping = (const struct UDPPingMessage *) message;
378   struct UDPPongMessage *pong;
379   struct Session *found;
380
381 #if DEBUG_UDP
382   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
383                    ("handling ping, challenge is %d\n"),
384                    ntohs (ping->challenge));
385 #endif
386   found = find_session (plugin, sender);
387   if (found != NULL)
388     {
389       pong = GNUNET_malloc (sizeof (struct UDPPongMessage) + addrlen);
390       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PONG);
391       pong->header.size = htons (sizeof (struct UDPPongMessage) + addrlen);
392       pong->challenge = ping->challenge;
393       memcpy (&pong[1], addr, addrlen);
394       pong->addrlen = htons (addrlen);
395
396       udp_plugin_send (plugin, sender, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
397                        &pong->header,
398                        GNUNET_TIME_relative_multiply
399                        (GNUNET_TIME_UNIT_SECONDS, 30), NULL, NULL);
400       GNUNET_free (pong);
401     }
402
403   return;
404
405 }
406
407 /**
408  * We've received a PONG from this peer via UDP.
409  * Great. Call validate func if we haven't already
410  * received a PONG.
411  *
412  * @param cls closure
413  * @param client identification of the client
414  * @param message the actual message
415  */
416 static void
417 handle_udp_pong (void *cls,
418                  struct GNUNET_PeerIdentity *sender,
419                  const struct GNUNET_MessageHeader *message)
420 {
421   struct Plugin *plugin = cls;
422   const struct UDPPongMessage *pong = (struct UDPPongMessage *) message;
423   struct Session *found;
424   unsigned int addr_len;
425   struct sockaddr_storage addr;
426
427 #if DEBUG_UDP
428   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _("handling pong\n"));
429 #endif
430   found = find_session (plugin, sender);
431 #if DEBUG_UDP
432   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
433                    ("found->challenge %d, pong->challenge %d\n"),
434                    found->challenge, ntohs (pong->challenge));
435 #endif
436   if ((found != NULL) && (found->challenge == ntohs (pong->challenge)))
437     {
438       found->validated = GNUNET_YES;
439       found->latency =
440         GNUNET_TIME_absolute_get_difference (found->ping_sent,
441                                              GNUNET_TIME_absolute_get ());
442       addr_len = ntohs (pong->addrlen);
443 #if DEBUG_UDP
444       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
445                        ("found associated ping, addr is %u bytes\n"),
446                        addr_len);
447 #endif
448       memcpy (&addr, &pong[1], addr_len);
449       plugin->env->notify_validation (plugin->env->cls, "udp", sender,
450                                       ntohs (pong->challenge),
451                                       (char *) &addr);
452     }
453   else
454     {
455
456 #if DEBUG_UDP
457       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
458                        ("Session not found!\n"));
459 #endif
460     }
461   return;
462 }
463
464 static void
465 udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
466 {
467   struct Plugin *plugin = cls;
468   struct GNUNET_TIME_Relative timeout =
469     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500);
470   char *buf;
471   struct UDPMessage *msg;
472   const struct GNUNET_MessageHeader *hdr;
473   struct GNUNET_PeerIdentity *sender;
474   unsigned int buflen;
475   socklen_t fromlen;
476   struct sockaddr_storage addr;
477   ssize_t ret;
478   struct Session *found;
479
480   do
481     {
482       buflen = GNUNET_NETWORK_socket_recvfrom_amount (udp_sock);
483
484 #if DEBUG_UDP
485       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
486                        ("we expect to read %u bytes\n"), buflen);
487 #endif
488
489       if (buflen == GNUNET_NO)
490         return;
491
492       buf = GNUNET_malloc (buflen);
493       fromlen = sizeof (addr);
494 #if DEBUG_UDP
495       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
496                        ("src_addr_len is %u\n"), fromlen);
497 #endif
498       memset (&addr, 0, fromlen);
499       ret =
500         GNUNET_NETWORK_socket_recvfrom (udp_sock, buf, buflen,
501                                         (struct sockaddr *) &addr, &fromlen);
502
503 #if DEBUG_UDP
504       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
505                        ("socket_recv returned %u, src_addr_len is %u\n"), ret,
506                        fromlen);
507 #endif
508
509       if (ret <= 0)
510         {
511           GNUNET_free (buf);
512           return;
513         }
514       msg = (struct UDPMessage *) buf;
515
516 #if DEBUG_UDP
517       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
518                        ("header reports message size of %d\n"),
519                        ntohs (msg->header.size));
520
521       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
522                        ("header reports message type of %d\n"),
523                        ntohs (msg->header.type));
524 #endif
525       if (ntohs (msg->header.size) < sizeof (struct UDPMessage))
526         {
527           GNUNET_free (buf);
528           GNUNET_NETWORK_fdset_zero (plugin->rs);
529           GNUNET_NETWORK_fdset_set (plugin->rs, udp_sock);
530           break;
531         }
532       hdr = (const struct GNUNET_MessageHeader *) &msg[1];
533       sender = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
534       memcpy (sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
535
536 #if DEBUG_UDP
537       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
538                        ("msg reports message size of %d\n"),
539                        ntohs (hdr->size));
540
541       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
542                        ("msg reports message type of %d\n"),
543                        ntohs (hdr->type));
544 #endif
545
546       if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PING)
547         {
548           handle_udp_ping (plugin, sender, &addr, fromlen, hdr);
549         }
550       else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PONG)
551         {
552           handle_udp_pong (plugin, sender, hdr);
553         }
554       else
555         {
556           found = find_session (plugin, sender);
557           if (found != NULL)
558             plugin->env->receive (plugin->env->cls, found->latency, sender,
559                                   &msg->header);
560           else
561             plugin->env->receive (plugin->env->cls,
562                                   GNUNET_TIME_relative_get_forever (), sender,
563                                   &msg->header);
564         }
565       GNUNET_free (sender);
566       GNUNET_free (buf);
567
568     }
569   while (GNUNET_NETWORK_socket_select (plugin->rs,
570                                        NULL,
571                                        NULL,
572                                        timeout) > 0
573          && GNUNET_NETWORK_fdset_isset (plugin->rs, udp_sock));
574
575   plugin->select_task =
576     GNUNET_SCHEDULER_add_select (plugin->env->sched,
577                                  GNUNET_SCHEDULER_PRIORITY_DEFAULT,
578                                  GNUNET_SCHEDULER_NO_TASK,
579                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
580                                  NULL, &udp_plugin_select, plugin);
581
582 }
583
584 /**
585  * Create a UDP socket.  If possible, use IPv6, otherwise
586  * try IPv4.
587  */
588 static struct GNUNET_NETWORK_Handle *
589 udp_transport_server_start (void *cls)
590 {
591   struct Plugin *plugin = cls;
592   struct GNUNET_NETWORK_Handle *desc;
593   struct sockaddr_in serverAddrv4;
594   struct sockaddr_in6 serverAddrv6;
595   struct sockaddr *serverAddr;
596   socklen_t addrlen;
597
598   desc = NULL;
599   if (GNUNET_YES !=
600       GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, "GNUNETD",
601                                             "DISABLE-IPV6"))
602     {
603       desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 17);
604       if (desc != NULL)
605         {
606           memset (&serverAddrv6, 0, sizeof (serverAddrv6));
607 #if HAVE_SOCKADDR_IN_SIN_LEN
608           serverAddrv6.sin6_len = sizeof (serverAddrv6);
609 #endif
610           serverAddrv6.sin6_family = AF_INET6;
611           serverAddrv6.sin6_addr = in6addr_any;
612           serverAddrv6.sin6_port = htons (plugin->open_port);
613           addrlen = sizeof (serverAddrv6);
614           serverAddr = (struct sockaddr *) &serverAddrv6;
615         }
616     }
617   if (NULL == desc)
618     {
619       desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 17);
620       if (NULL == desc)
621         {
622           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", "socket");
623           return NULL;
624         }
625       else
626         {
627           memset (&serverAddrv4, 0, sizeof (serverAddrv4));
628 #if HAVE_SOCKADDR_IN_SIN_LEN
629           serverAddrv4.sin_len = sizeof (serverAddrv4);
630 #endif
631           serverAddrv4.sin_family = AF_INET;
632           serverAddrv4.sin_addr.s_addr = INADDR_ANY;
633           serverAddrv4.sin_port = htons (plugin->open_port);
634           addrlen = sizeof (serverAddrv4);
635           serverAddr = (struct sockaddr *) &serverAddrv4;
636         }
637     }
638
639   if (desc != NULL)
640     {
641       GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, serverAddr, addrlen) ==
642                      GNUNET_OK);
643     }
644
645   plugin->rs = GNUNET_NETWORK_fdset_create ();
646
647   GNUNET_NETWORK_fdset_zero (plugin->rs);
648   GNUNET_NETWORK_fdset_set (plugin->rs, desc);
649
650   plugin->select_task =
651     GNUNET_SCHEDULER_add_select (plugin->env->sched,
652                                  GNUNET_SCHEDULER_PRIORITY_DEFAULT,
653                                  GNUNET_SCHEDULER_NO_TASK,
654                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
655                                  NULL, &udp_plugin_select, plugin);
656
657   return desc;
658 }
659
660 /**
661  * Function that can be used by the transport service to validate that
662  * another peer is reachable at a particular address (even if we
663  * already have a connection to this peer, this function is required
664  * to establish a new one).
665  *
666  * @param cls closure
667  * @param target who should receive this message
668  * @param challenge challenge code to use
669  * @param addrlen length of the address
670  * @param addr the address
671  * @param timeout how long should we try to transmit these?
672  * @return GNUNET_OK if the transmission has been scheduled
673  */
674 static int
675 udp_plugin_validate (void *cls,
676                      const struct GNUNET_PeerIdentity *target,
677                      uint32_t challenge,
678                      struct GNUNET_TIME_Relative timeout,
679                      const void *addr, size_t addrlen)
680 {
681   struct Plugin *plugin = cls;
682   struct Session *new_session;
683   struct UDPPingMessage *msg;
684
685   if (addrlen <= 0)
686     return GNUNET_SYSERR;
687
688   new_session = GNUNET_malloc (sizeof (struct Session));
689   new_session->connect_addr = GNUNET_malloc (addrlen);
690   memcpy (new_session->connect_addr, addr, addrlen);
691   new_session->connect_alen = addrlen;
692 #if DEBUG_UDP
693   if (memcmp
694       (target, plugin->env->my_identity,
695        sizeof (struct GNUNET_PeerIdentity)) == 0)
696     {
697       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
698                        ("definitely adding self to session list... hmmm\n"));
699     }
700 #endif
701   memcpy (&new_session->target, target, sizeof (struct GNUNET_PeerIdentity));
702   new_session->challenge = challenge;
703   new_session->validated = GNUNET_NO;
704   new_session->latency = GNUNET_TIME_relative_get_zero ();
705   new_session->ping_sent = GNUNET_TIME_absolute_get ();
706   new_session->next = plugin->sessions;
707   plugin->sessions = new_session;
708
709   msg = GNUNET_malloc (sizeof (struct UDPPingMessage));
710   msg->header.size = htons (sizeof (struct UDPPingMessage));
711   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PING);
712   msg->challenge = htons (challenge);
713 #if DEBUG_UDP
714   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
715                    ("In validate, header size is %d, type %d, challenge %u\n"),
716                    ntohs (msg->header.size), ntohs (msg->header.type),
717                    ntohl (msg->challenge));
718 #endif
719   udp_plugin_send (plugin, target, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
720                    &msg->header, timeout, NULL, NULL);
721
722   GNUNET_free (msg);
723   return GNUNET_OK;
724 }
725
726 /**
727  * Convert the transports address to a nice, human-readable
728  * format.
729  *
730  * @param cls closure
731  * @param type name of the transport that generated the address
732  * @param addr one of the addresses of the host, NULL for the last address
733  *        the specific address format depends on the transport
734  * @param addrlen length of the address
735  * @param numeric should (IP) addresses be displayed in numeric form?
736  * @param timeout after how long should we give up?
737  * @param asc function to call on each string
738  * @param asc_cls closure for asc
739  */
740 static void
741 udp_plugin_address_pretty_printer (void *cls,
742                                    const char *type,
743                                    const void *addr,
744                                    size_t addrlen,
745                                    int numeric,
746                                    struct GNUNET_TIME_Relative timeout,
747                                    GNUNET_TRANSPORT_AddressStringCallback asc,
748                                    void *asc_cls)
749 {
750
751 }
752
753 /**
754  * Set a quota for receiving data from the given peer; this is a
755  * per-transport limit.  The transport should limit its read/select
756  * calls to stay below the quota (in terms of incoming data).
757  *
758  * @param cls closure
759  * @param target the peer for whom the quota is given
760  * @param quota_in quota for receiving/sending data in bytes per ms
761  */
762 static void
763 udp_plugin_set_receive_quota (void *cls,
764                               const struct GNUNET_PeerIdentity *target,
765                               uint32_t quota_in)
766 {
767
768 }
769
770 /**
771  * Another peer has suggested an address for this
772  * peer and transport plugin.  Check that this could be a valid
773  * address.  If so, consider adding it to the list
774  * of addresses.
775  *
776  * @param cls closure
777  * @param addr pointer to the address
778  * @param addrlen length of addr
779  * @return GNUNET_OK if this is a plausible address for this peer
780  *         and transport
781  */
782 static int
783 udp_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
784 {
785
786   return GNUNET_SYSERR;
787 }
788
789
790 /**
791  * The exported method. Makes the core api available via a global and
792  * returns the udp transport API.
793  */
794 void *
795 libgnunet_plugin_transport_udp_init (void *cls)
796 {
797   unsigned long long mtu;
798
799   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
800   struct GNUNET_TRANSPORT_PluginFunctions *api;
801   struct Plugin *plugin;
802   struct GNUNET_SERVICE_Context *service;
803   unsigned long long aport;
804   unsigned long long bport;
805
806   service = GNUNET_SERVICE_start ("transport-udp", env->sched, env->cfg);
807   if (service == NULL)
808     {
809       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "udp", _
810                        ("Failed to start service for `%s' transport plugin.\n"),
811                        "udp");
812       return NULL;
813     }
814   aport = 0;
815   if ((GNUNET_OK !=
816        GNUNET_CONFIGURATION_get_value_number (env->cfg,
817                                               "transport-udp",
818                                               "PORT",
819                                               &bport)) ||
820       (bport > 65535) ||
821       ((GNUNET_OK ==
822         GNUNET_CONFIGURATION_get_value_number (env->cfg,
823                                                "transport-udp",
824                                                "ADVERTISED-PORT",
825                                                &aport)) && (aport > 65535)))
826     {
827       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
828                        "udp",
829                        _
830                        ("Require valid port number for service `%s' in configuration!\n"),
831                        "transport-udp");
832       GNUNET_SERVICE_stop (service);
833       return NULL;
834     }
835   if (aport == 0)
836     aport = bport;
837
838   mtu = 1240;
839   if (mtu < 1200)
840     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
841                      "udp",
842                      _("MTU %llu for `%s' is probably too low!\n"), mtu,
843                      "UDP");
844
845   plugin = GNUNET_malloc (sizeof (struct Plugin));
846   plugin->open_port = bport;
847   plugin->adv_port = aport;
848   plugin->env = env;
849   plugin->statistics = NULL;
850   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
851   plugin->sessions = NULL;
852   api->cls = plugin;
853
854   api->validate = &udp_plugin_validate;
855   api->send = &udp_plugin_send;
856   api->disconnect = &udp_disconnect;
857   api->address_pretty_printer = &udp_plugin_address_pretty_printer;
858   api->set_receive_quota = &udp_plugin_set_receive_quota;
859   api->address_suggested = &udp_plugin_address_suggested;
860   api->cost_estimate = 17;      /* TODO: ATS */
861   plugin->service = service;
862
863   udp_sock = udp_transport_server_start (plugin);
864
865   GNUNET_assert (udp_sock != NULL);
866
867   return api;
868 }
869
870 void *
871 libgnunet_plugin_transport_udp_done (void *cls)
872 {
873   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
874   struct Plugin *plugin = api->cls;
875   struct Session *pos;
876   struct Session *oldpos;
877
878   udp_transport_server_stop (plugin);
879   if (NULL != hostname_dns)
880     {
881       GNUNET_RESOLVER_request_cancel (hostname_dns);
882       hostname_dns = NULL;
883     }
884   GNUNET_SERVICE_stop (plugin->service);
885
886   pos = plugin->sessions;
887   while (pos != NULL)
888     {
889       GNUNET_free (pos->connect_addr);
890       oldpos = pos;
891       pos = pos->next;
892       GNUNET_free (oldpos);
893     }
894
895   GNUNET_NETWORK_fdset_destroy (plugin->rs);
896   GNUNET_free (plugin);
897   GNUNET_free (api);
898   return NULL;
899 }
900
901 /* end of plugin_transport_udp.c */