better comments
[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  */
26
27 #include "platform.h"
28 #include "gnunet_util.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_transport.h"
31 #include "gnunet_stats_service.h"
32 #include "gnunet_upnp_service.h"
33 #include "ip.h"
34
35 #define DEBUG_UDP GNUNET_YES
36
37 /**
38  * The default maximum size of each outbound UDP message,
39  * optimal value for Ethernet (10 or 100 MBit).
40  */
41 #define MESSAGE_SIZE 1472
42
43 /**
44  * Message-Packet header.
45  */
46 typedef struct
47 {
48   /**
49    * size of the message, in bytes, including this header.
50    */
51   GNUNET_MessageHeader header;
52
53   /**
54    * What is the identity of the sender (GNUNET_hash of public key)
55    */
56   GNUNET_PeerIdentity sender;
57
58 } UDPMessage;
59
60 #define MY_TRANSPORT_NAME "UDP"
61 #include "common.c"
62
63 /* *********** globals ************* */
64
65 static int stat_bytesReceived;
66
67 static int stat_bytesSent;
68
69 static int stat_bytesDropped;
70
71 static int stat_udpConnected;
72
73 /**
74  * thread that listens for inbound messages
75  */
76 static struct GNUNET_SelectHandle *selector;
77
78 /**
79  * the socket that we transmit all data with
80  */
81 static struct GNUNET_SocketHandle *udp_sock;
82
83 static struct GNUNET_LoadMonitor *load_monitor;
84
85
86 /**
87  * The socket of session has data waiting, process!
88  *
89  * This function may only be called if the tcplock is
90  * already held by the caller.
91  */
92 static int
93 select_message_handler (void *mh_cls,
94                         struct GNUNET_SelectHandle *sh,
95                         struct GNUNET_SocketHandle *sock,
96                         void *sock_ctx, const GNUNET_MessageHeader * msg)
97 {
98   unsigned int len;
99   GNUNET_TransportPacket *mp;
100   const UDPMessage *um;
101
102   len = ntohs (msg->size);
103   if (len <= sizeof (UDPMessage))
104     {
105       GNUNET_GE_LOG (coreAPI->ectx,
106                      GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_BULK,
107                      _("Received malformed message via %s. Ignored.\n"),
108                      "UDP");
109       return GNUNET_SYSERR;
110     }
111   um = (const UDPMessage *) msg;
112   mp = GNUNET_malloc (sizeof (GNUNET_TransportPacket));
113   mp->msg = GNUNET_malloc (len - sizeof (UDPMessage));
114   memcpy (mp->msg, &um[1], len - sizeof (UDPMessage));
115   mp->sender = um->sender;
116   mp->size = len - sizeof (UDPMessage);
117   mp->tsession = NULL;
118   coreAPI->receive (mp);
119   if (stats != NULL)
120     stats->change (stat_bytesReceived, len);
121   return GNUNET_OK;
122 }
123
124 static void *
125 select_accept_handler (void *ah_cls,
126                        struct GNUNET_SelectHandle *sh,
127                        struct GNUNET_SocketHandle *sock,
128                        const void *addr, unsigned int addr_len)
129 {
130   static int nonnullpointer;
131
132   if (GNUNET_NO != is_rejected_tester (addr, addr_len))
133     return NULL;
134   return &nonnullpointer;
135 }
136
137 /**
138  * Select has been forced to close a connection.
139  * Free the associated context.
140  */
141 static void
142 select_close_handler (void *ch_cls,
143                       struct GNUNET_SelectHandle *sh,
144                       struct GNUNET_SocketHandle *sock, void *sock_ctx)
145 {
146   /* do nothing */
147 }
148
149 /**
150  * Establish a connection to a remote node.
151  *
152  * @param hello the hello-Message for the target node
153  * @param tsessionPtr the session handle that is to be set
154  * @param may_reuse are we allowed to re-use an existing connection (ignored for UDP)
155  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
156  */
157 static int
158 udp_connect (const GNUNET_MessageHello * hello,
159              GNUNET_TSession ** tsessionPtr, int may_reuse)
160 {
161   GNUNET_TSession *tsession;
162
163   tsession = GNUNET_malloc (sizeof (GNUNET_TSession));
164   memset (tsession, 0, sizeof (GNUNET_TSession));
165   tsession->internal = GNUNET_malloc (GNUNET_sizeof_hello (hello));
166   memcpy (tsession->internal, hello, GNUNET_sizeof_hello (hello));
167   tsession->ttype = myAPI.protocol_number;
168   tsession->peer = hello->senderIdentity;
169   *tsessionPtr = tsession;
170   if (stats != NULL)
171     stats->change (stat_udpConnected, 1);
172   return GNUNET_OK;
173 }
174
175 /**
176  * A (core) Session is to be associated with a transport session. The
177  * transport service may want to know in order to call back on the
178  * core if the connection is being closed.
179  *
180  * @param tsession the session handle passed along
181  *   from the call to receive that was made by the transport
182  *   layer
183  * @return GNUNET_OK if the session could be associated,
184  *         GNUNET_SYSERR if not.
185  */
186 int
187 udp_associate (GNUNET_TSession * tsession)
188 {
189   return GNUNET_SYSERR;         /* UDP connections can never be associated */
190 }
191
192 /**
193  * Disconnect from a remote node.
194  *
195  * @param tsession the session that is closed
196  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
197  */
198 static int
199 udp_disconnect (GNUNET_TSession * tsession)
200 {
201   if (tsession != NULL)
202     {
203       if (tsession->internal != NULL)
204         GNUNET_free (tsession->internal);
205       GNUNET_free (tsession);
206       if (stats != NULL)
207         stats->change (stat_udpConnected, -1);
208     }
209   return GNUNET_OK;
210 }
211
212 /**
213  * Shutdown the server process (stop receiving inbound traffic). Maybe
214  * restarted later!
215  */
216 static int
217 udp_transport_server_stop ()
218 {
219   GNUNET_GE_ASSERT (coreAPI->ectx, udp_sock != NULL);
220   if (selector != NULL)
221     {
222       GNUNET_select_destroy (selector);
223       selector = NULL;
224     }
225   GNUNET_socket_destroy (udp_sock);
226   udp_sock = NULL;
227   return GNUNET_OK;
228 }
229
230 /**
231  * Test if the transport would even try to send
232  * a message of the given size and importance
233  * for the given session.<br>
234  * This function is used to check if the core should
235  * even bother to construct (and encrypt) this kind
236  * of message.
237  *
238  * @return GNUNET_YES if the transport would try (i.e. queue
239  *         the message or call the OS to send),
240  *         GNUNET_NO if the transport would just drop the message,
241  *         GNUNET_SYSERR if the size/session is invalid
242  */
243 static int
244 udp_test_would_try (GNUNET_TSession * tsession, unsigned int size,
245                     int important)
246 {
247   const GNUNET_MessageHello *hello;
248
249   if (udp_sock == NULL)
250     return GNUNET_SYSERR;
251   if (size == 0)
252     {
253       GNUNET_GE_BREAK (coreAPI->ectx, 0);
254       return GNUNET_SYSERR;
255     }
256   if (size > myAPI.mtu)
257     {
258       GNUNET_GE_BREAK (coreAPI->ectx, 0);
259       return GNUNET_SYSERR;
260     }
261   hello = (const GNUNET_MessageHello *) tsession->internal;
262   if (hello == NULL)
263     return GNUNET_SYSERR;
264   return GNUNET_YES;
265 }
266
267 /**
268  * Create a UDP socket.  If possible, use IPv6, otherwise
269  * try IPv4.  Update available_protocols accordingly.
270  */
271 static struct GNUNET_NETWORK_Handle *
272 udp_create_socket ()
273 {
274   struct GNUNET_NETWORK_Handle *desc;
275
276   available_protocols = VERSION_AVAILABLE_NONE;
277   desc = NULL;
278   if (GNUNET_YES !=
279       GNUNET_GC_get_configuration_value_yesno (cfg, "GNUNETD", "DISABLE-IPV6",
280                                                GNUNET_YES))
281     {
282       desc = GNUNET_net_socket (PF_INET6, SOCK_DGRAM, 17);
283     }
284   if (NULL == desc)
285     {
286       desc = GNUNET_net_socket (PF_INET, SOCK_DGRAM, 17);
287       if (NULL == desc)
288         {
289           GNUNET_GE_LOG_STRERROR (coreAPI->ectx,
290                                   GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
291                                   GNUNET_GE_BULK, "socket");
292           return GNUNET_SYSERR;
293         }
294       available_protocols = VERSION_AVAILABLE_IPV4;
295     }
296   else
297     {
298       available_protocols = VERSION_AVAILABLE_IPV6 | VERSION_AVAILABLE_IPV4;
299     }
300   return desc;
301 }
302
303 /**
304  * Send a message to the specified remote node.
305  *
306  * @param tsession the GNUNET_MessageHello identifying the remote node
307  * @param message what to send
308  * @param size the size of the message
309  * @param important is this message "important" to override typical transmit limits?
310  * @return GNUNET_SYSERR on error, GNUNET_OK on success
311  */
312 static int
313 udp_send (GNUNET_TSession * tsession,
314           const void *message, const unsigned int size, int important)
315 {
316   const GNUNET_MessageHello *hello;
317   const HostAddress *haddr;
318   UDPMessage *mp;
319   struct sockaddr_in serverAddrv4;
320   struct sockaddr_in6 serverAddrv6;
321   struct sockaddr *serverAddr;
322   socklen_t addrlen;
323   unsigned short available;
324   int ok;
325   int ssize;
326   size_t sent;
327
328   GNUNET_GE_ASSERT (NULL, tsession != NULL);
329   if (udp_sock == NULL)
330     return GNUNET_SYSERR;
331   if (size == 0)
332     {
333       GNUNET_GE_BREAK (coreAPI->ectx, 0);
334       return GNUNET_SYSERR;
335     }
336   if (size > myAPI.mtu)
337     {
338       GNUNET_GE_BREAK (coreAPI->ectx, 0);
339       return GNUNET_SYSERR;
340     }
341   hello = (const GNUNET_MessageHello *) tsession->internal;
342   if (hello == NULL)
343     return GNUNET_SYSERR;
344
345   haddr = (const HostAddress *) &hello[1];
346   available = ntohs (haddr->availability) & available_protocols;
347   if (available == VERSION_AVAILABLE_NONE)
348     return GNUNET_SYSERR;
349   if (available == (VERSION_AVAILABLE_IPV4 | VERSION_AVAILABLE_IPV6))
350     {
351       if (GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, 2) == 0)
352         available = VERSION_AVAILABLE_IPV4;
353       else
354         available = VERSION_AVAILABLE_IPV6;
355     }
356   ssize = size + sizeof (UDPMessage);
357   mp = GNUNET_malloc (ssize);
358   mp->header.size = htons (ssize);
359   mp->header.type = 0;
360   mp->sender = *(coreAPI->my_identity);
361   memcpy (&mp[1], message, size);
362   ok = GNUNET_SYSERR;
363
364   if ((available & VERSION_AVAILABLE_IPV4) > 0)
365     {
366       memset (&serverAddrv4, 0, sizeof (serverAddrv4));
367 #if HAVE_SOCKADDR_IN_SIN_LEN
368       serverAddrv4.sin_len = sizeof (serverAddrv4);
369 #endif
370       serverAddrv4.sin_family = AF_INET;
371       serverAddrv4.sin_port = haddr->port;
372       memcpy (&serverAddrv4.sin_addr, &haddr->ipv4, sizeof (struct in_addr));
373       addrlen = sizeof (serverAddrv4);
374       serverAddr = (struct sockaddr *) &serverAddrv4;
375     }
376   else
377     {
378       memset (&serverAddrv6, 0, sizeof (serverAddrv6));
379 #if HAVE_SOCKADDR_IN_SIN_LEN
380       serverAddrv6.sin6_len = sizeof (serverAddrv6);
381 #endif
382       serverAddrv6.sin6_family = AF_INET;
383       serverAddrv6.sin6_port = haddr->port;
384       memcpy (&serverAddrv6.sin6_addr, &haddr->ipv6,
385               sizeof (struct in6_addr));
386       addrlen = sizeof (serverAddrv6);
387       serverAddr = (struct sockaddr *) &serverAddrv6;
388     }
389 #ifndef MINGW
390   if (GNUNET_YES == GNUNET_socket_send_to (udp_sock,
391                                            GNUNET_NC_NONBLOCKING,
392                                            mp,
393                                            ssize, &sent,
394                                            (const char *) serverAddr,
395                                            addrlen))
396 #else
397   sent =
398     win_ols_sendto (udp_sock, mp, ssize, (const char *) serverAddr, addrlen);
399   if (sent != SOCKET_ERROR)
400 #endif
401     {
402       ok = GNUNET_OK;
403       if (stats != NULL)
404         stats->change (stat_bytesSent, sent);
405     }
406   else
407     {
408       if (stats != NULL)
409         stats->change (stat_bytesDropped, ssize);
410     }
411   GNUNET_free (mp);
412   return ok;
413 }
414
415 /**
416  * Start the server process to receive inbound traffic.
417  *
418  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
419  */
420 static int
421 udp_transport_server_start ()
422 {
423   struct sockaddr_in serverAddrv4;
424   struct sockaddr_in6 serverAddrv6;
425   struct sockaddr *serverAddr;
426   socklen_t addrlen;
427   GNUNET_NETWORK_Handle *desc;
428   const int on = 1;
429   unsigned short port;
430
431   GNUNET_GE_ASSERT (coreAPI->ectx, selector == NULL);
432   /* initialize UDP network */
433   port = get_port ();
434   if (port != 0)
435     {
436       desc = udp_create_socket ();
437       if (NULL == desc)
438         return GNUNET_SYSERR;
439       if (GNUNET_net_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
440         {
441           GNUNET_GE_DIE_STRERROR (coreAPI->ectx,
442                                   GNUNET_GE_FATAL | GNUNET_GE_ADMIN |
443                                   GNUNET_GE_IMMEDIATE, "setsockopt");
444           return GNUNET_SYSERR;
445         }
446       if (available_protocols == VERSION_AVAILABLE_IPV4)
447         {
448           memset (&serverAddrv4, 0, sizeof (serverAddrv4));
449 #if HAVE_SOCKADDR_IN_SIN_LEN
450           serverAddrv4.sin_len = sizeof (serverAddrv4);
451 #endif
452           serverAddrv4.sin_family = AF_INET;
453           serverAddrv4.sin_addr.s_addr = INADDR_ANY;
454           serverAddrv4.sin_port = htons (port);
455           addrlen = sizeof (serverAddrv4);
456           serverAddr = (struct sockaddr *) &serverAddrv4;
457         }
458       else
459         {
460           memset (&serverAddrv6, 0, sizeof (serverAddrv6));
461 #if HAVE_SOCKADDR_IN_SIN_LEN
462           serverAddrv6.sin6_len = sizeof (serverAddrv6);
463 #endif
464           serverAddrv6.sin6_family = AF_INET6;
465           serverAddrv6.sin6_addr = in6addr_any;
466           serverAddrv6.sin6_port = htons (port);
467           addrlen = sizeof (serverAddrv6);
468           serverAddr = (struct sockaddr *) &serverAddrv6;
469         }
470       if (GNUNET_net_bind (desc, serverAddr, addrlen) < 0)
471         {
472           GNUNET_GE_LOG_STRERROR (coreAPI->ectx,
473                                   GNUNET_GE_FATAL | GNUNET_GE_ADMIN |
474                                   GNUNET_GE_IMMEDIATE, "bind");
475           GNUNET_GE_LOG (coreAPI->ectx,
476                          GNUNET_GE_FATAL | GNUNET_GE_ADMIN |
477                          GNUNET_GE_IMMEDIATE,
478                          _("Failed to bind to %s port %d.\n"),
479                          MY_TRANSPORT_NAME, port);
480           if (0 != GNUNET_net_close (&desc))
481             GNUNET_GE_LOG_STRERROR (coreAPI->ectx,
482                                     GNUNET_GE_ERROR | GNUNET_GE_USER |
483                                     GNUNET_GE_ADMIN | GNUNET_GE_BULK,
484                                     "close");
485           return GNUNET_SYSERR;
486         }
487       selector = GNUNET_select_create ("udp", GNUNET_YES, coreAPI->ectx, load_monitor, desc, addrlen, 0,        /* timeout */
488                                        &select_message_handler,
489                                        NULL,
490                                        &select_accept_handler,
491                                        NULL,
492                                        &select_close_handler,
493                                        NULL, 64 * 1024,
494                                        16 /* max sockets */ );
495       if (selector == NULL)
496         return GNUNET_SYSERR;
497     }
498   desc = udp_create_socket ();
499   if (NULL == desc)
500     {
501       GNUNET_GE_LOG_STRERROR (coreAPI->ectx,
502                               GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
503                               GNUNET_GE_BULK, "socket");
504       GNUNET_select_destroy (selector);
505       selector = NULL;
506       return GNUNET_SYSERR;
507     }
508   udp_sock = GNUNET_socket_create (coreAPI->ectx, load_monitor, desc);
509   GNUNET_GE_ASSERT (coreAPI->ectx, udp_sock != NULL);
510   return GNUNET_OK;
511 }
512
513 /**
514  * The exported method. Makes the core api available via a global and
515  * returns the udp transport API.
516  */
517 GNUNET_TransportAPI *
518 inittransport_udp (GNUNET_CoreAPIForTransport * core)
519 {
520   unsigned long long mtu;
521
522   cfg = core->cfg;
523   load_monitor = core->load_monitor;
524   GNUNET_GE_ASSERT (coreAPI->ectx, sizeof (UDPMessage) == 68);
525   GNUNET_GE_ASSERT (coreAPI->ectx, sizeof (HostAddress) == 24);
526   coreAPI = core;
527   if (-1 == GNUNET_GC_get_configuration_value_number (cfg,
528                                                       "UDP",
529                                                       "MTU",
530                                                       sizeof (UDPMessage)
531                                                       +
532                                                       GNUNET_P2P_MESSAGE_OVERHEAD
533                                                       +
534                                                       sizeof
535                                                       (GNUNET_MessageHeader) +
536                                                       32, 65500,
537                                                       MESSAGE_SIZE, &mtu))
538     {
539       return NULL;
540     }
541   if (mtu < 1200)
542     GNUNET_GE_LOG (coreAPI->ectx,
543                    GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE,
544                    _("MTU %llu for `%s' is probably too low!\n"), mtu, "UDP");
545   lock = GNUNET_mutex_create (GNUNET_NO);
546   if (0 !=
547       GNUNET_GC_attach_change_listener (cfg, &reload_configuration, NULL))
548     {
549       GNUNET_mutex_destroy (lock);
550       lock = NULL;
551       return NULL;
552     }
553   if (GNUNET_GC_get_configuration_value_yesno (cfg, "UDP", "UPNP", GNUNET_YES)
554       == GNUNET_YES)
555     {
556       upnp = coreAPI->service_request ("upnp");
557       if (upnp == NULL)
558         GNUNET_GE_LOG (coreAPI->ectx,
559                        GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE,
560                        "The UPnP service could not be loaded. To disable UPnP, set the "
561                        "configuration option \"UPNP\" in section \"%s\" to \"NO\"\n",
562                        "UDP");
563     }
564   stats = coreAPI->service_request ("stats");
565   if (stats != NULL)
566     {
567       stat_bytesReceived
568         = stats->create (gettext_noop ("# bytes received via UDP"));
569       stat_bytesSent = stats->create (gettext_noop ("# bytes sent via UDP"));
570       stat_bytesDropped
571         = stats->create (gettext_noop ("# bytes dropped by UDP (outgoing)"));
572       stat_udpConnected
573         = stats->create (gettext_noop ("# UDP connections (right now)"));
574     }
575   myAPI.protocol_number = GNUNET_TRANSPORT_PROTOCOL_NUMBER_UDP;
576   myAPI.mtu = mtu - sizeof (UDPMessage);
577   myAPI.cost = 20000;
578   myAPI.hello_verify = &verify_hello;
579   myAPI.hello_create = &create_hello;
580   myAPI.connect = &udp_connect;
581   myAPI.send = &udp_send;
582   myAPI.associate = &udp_associate;
583   myAPI.disconnect = &udp_disconnect;
584   myAPI.server_start = &udp_transport_server_start;
585   myAPI.server_stop = &udp_transport_server_stop;
586   myAPI.hello_to_address = &hello_to_address;
587   myAPI.send_now_test = &udp_test_would_try;
588
589   return &myAPI;
590 }
591
592 void
593 donetransport_udp ()
594 {
595   do_shutdown ();
596 }
597
598 /* end of udp.c */