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