glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / transport / plugin_transport_udp_broadcasting.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2010, 2011 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15
16 /**
17  * @file transport/plugin_transport_udp_broadcasting.c
18  * @brief Neighbour discovery with UDP
19  * @author Christian Grothoff
20  * @author Matthias Wachs
21  */
22 #include "platform.h"
23 #include "plugin_transport_udp.h"
24 #include "gnunet_hello_lib.h"
25 #include "gnunet_util_lib.h"
26 #include "gnunet_fragmentation_lib.h"
27 #include "gnunet_protocols.h"
28 #include "gnunet_resolver_service.h"
29 #include "gnunet_signatures.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_transport_plugin.h"
34 #include "transport.h"
35
36 #define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
37
38 /* *********** Cryogenic ********** */
39 #if LINUX
40 #include <sys/stat.h>
41 #include <fcntl.h>
42
43 #include <sys/ioctl.h>
44 #include <sys/select.h>
45 #include <sys/time.h>
46
47 #define PM_MAGIC 'k'
48 #define PM_SET_DELAY_AND_TIMEOUT _IOW(PM_MAGIC, 1, struct pm_times)
49
50 struct pm_times {
51         unsigned long delay_msecs;
52         unsigned long timeout_msecs;
53 };
54 #endif
55 /************************************/
56
57
58 struct UDP_Beacon_Message
59 {
60  /**
61   * Message header.
62   */
63   struct GNUNET_MessageHeader header;
64
65  /**
66   * What is the identity of the sender
67   */
68   struct GNUNET_PeerIdentity sender;
69 };
70
71
72 struct BroadcastAddress
73 {
74   struct BroadcastAddress *next;
75
76   struct BroadcastAddress *prev;
77
78   /**
79    * ID of select broadcast task
80    */
81   struct GNUNET_SCHEDULER_Task * broadcast_task;
82
83   struct Plugin *plugin;
84
85   struct sockaddr *addr;
86
87   socklen_t addrlen;
88
89 #if LINUX
90   /**
91    * Cryogenic handle.
92    */
93   struct GNUNET_DISK_FileHandle *cryogenic_fd;
94
95   /**
96    * Time out for cryogenic.
97    */
98   struct pm_times cryogenic_times;
99 #endif
100 };
101
102
103 /**
104  * Client-specific context for #broadcast_mst_cb().
105  */
106 struct MstContext
107 {
108   struct Plugin *plugin;
109
110   const union UdpAddress *udp_addr;
111
112   size_t udp_addr_len;
113
114   /**
115    * ATS network type.
116    */
117   enum GNUNET_ATS_Network_Type ats_address_network_type;
118 };
119
120
121 /**
122  * Parse broadcast message received.
123  *
124  * @param cls the `struct Plugin`
125  * @param client the `struct MstContext` with sender address
126  * @param message the message we received
127  * @return #GNUNET_OK (always)
128  */
129 static int
130 broadcast_mst_cb (void *cls,
131                   const struct GNUNET_MessageHeader *message)
132 {
133   struct MstContext *mc = cls;
134   struct Plugin *plugin = mc->plugin;
135   struct GNUNET_HELLO_Address *address;
136   const struct GNUNET_MessageHeader *hello;
137   const struct UDP_Beacon_Message *msg;
138
139   msg = (const struct UDP_Beacon_Message *) message;
140
141   if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON !=
142       ntohs (msg->header.type))
143     return GNUNET_OK;
144   LOG (GNUNET_ERROR_TYPE_DEBUG,
145        "Received beacon with %u bytes from peer `%s' via address `%s'\n",
146        ntohs (msg->header.size),
147        GNUNET_i2s (&msg->sender),
148        udp_address_to_string (NULL,
149                               mc->udp_addr,
150                               mc->udp_addr_len));
151   hello = (struct GNUNET_MessageHeader *) &msg[1];
152   address = GNUNET_HELLO_address_allocate (&msg->sender,
153                                            PLUGIN_NAME,
154                                            mc->udp_addr,
155                                            mc->udp_addr_len,
156                                            GNUNET_HELLO_ADDRESS_INFO_NONE);
157   plugin->env->receive (plugin->env->cls,
158                         address,
159                         NULL,
160                         hello);
161   GNUNET_HELLO_address_free (address);
162   GNUNET_STATISTICS_update (plugin->env->stats,
163                             _("# Multicast HELLO beacons received via UDP"),
164                             1, GNUNET_NO);
165   return GNUNET_OK;
166 }
167
168
169 /**
170  * We received a broadcast message.  Process it and all subsequent
171  * messages in the same packet.
172  *
173  * @param plugin the UDP plugin
174  * @param buf the buffer with the message(s)
175  * @param size number of bytes in @a buf
176  * @param udp_addr address of the sender
177  * @param udp_addr_len number of bytes in @a udp_addr
178  * @param network_type network type of the sender's address
179  */
180 void
181 udp_broadcast_receive (struct Plugin *plugin,
182                        const char *buf,
183                        ssize_t size,
184                        const union UdpAddress *udp_addr,
185                        size_t udp_addr_len,
186                        enum GNUNET_ATS_Network_Type network_type)
187 {
188   struct GNUNET_MessageStreamTokenizer *broadcast_mst;
189   struct MstContext mc;
190
191   broadcast_mst = GNUNET_MST_create (&broadcast_mst_cb,
192                                      &mc);
193   mc.plugin = plugin;
194   mc.udp_addr = udp_addr;
195   mc.udp_addr_len = udp_addr_len;
196   mc.ats_address_network_type = network_type;
197   GNUNET_MST_from_buffer (broadcast_mst,
198                           buf, size,
199                           GNUNET_NO,
200                           GNUNET_NO);
201   GNUNET_MST_destroy (broadcast_mst);
202 }
203
204
205 static unsigned int
206 prepare_beacon (struct Plugin *plugin,
207                 struct UDP_Beacon_Message *msg)
208 {
209   uint16_t hello_size;
210   uint16_t msg_size;
211
212   const struct GNUNET_MessageHeader *hello;
213   hello = plugin->env->get_our_hello ();
214   if (NULL == hello)
215     return 0;
216   hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
217   msg_size = hello_size + sizeof (struct UDP_Beacon_Message);
218
219   if (hello_size < (sizeof (struct GNUNET_MessageHeader)) ||
220       (msg_size > (UDP_MTU)))
221     return 0;
222
223   msg->sender = *(plugin->env->my_identity);
224   msg->header.size = htons (msg_size);
225   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON);
226   GNUNET_memcpy (&msg[1], hello, hello_size);
227   return msg_size;
228 }
229
230
231 static void
232 udp_ipv4_broadcast_send (void *cls)
233 {
234   struct BroadcastAddress *baddr = cls;
235   struct Plugin *plugin = baddr->plugin;
236   int sent;
237   uint16_t msg_size;
238   char buf[65536] GNUNET_ALIGN;
239
240   baddr->broadcast_task = NULL;
241
242   msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf);
243   if (0 != msg_size)
244   {
245     struct sockaddr_in *addr = (struct sockaddr_in *) baddr->addr;
246
247     addr->sin_port = htons (plugin->port);
248     sent = GNUNET_NETWORK_socket_sendto (plugin->sockv4, &buf, msg_size,
249                                       (const struct sockaddr *) addr,
250                                       baddr->addrlen);
251     if (sent == GNUNET_SYSERR)
252     {
253       if ((ENETUNREACH == errno) || (ENETDOWN == errno))
254       {
255         /* "Network unreachable" or "Network down"
256          *
257          * This indicates that we just do not have network connectivity
258          */
259         GNUNET_log (GNUNET_ERROR_TYPE_BULK | GNUNET_ERROR_TYPE_WARNING,
260             "Network connectivity is down, cannot send beacon!\n");
261       }
262       else
263         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto");
264     }
265     else
266     {
267       LOG (GNUNET_ERROR_TYPE_DEBUG,
268            "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent,
269            GNUNET_a2s (baddr->addr, baddr->addrlen));
270     }
271   }
272
273 #if LINUX
274   /*
275    * Cryogenic
276    */
277   if (NULL != baddr->cryogenic_fd)
278   {
279     baddr->cryogenic_times.delay_msecs = (plugin->broadcast_interval.rel_value_us/1000.0)*0.5;
280     baddr->cryogenic_times.timeout_msecs = (plugin->broadcast_interval.rel_value_us/1000.0)*1.5;
281
282     if (ioctl(baddr->cryogenic_fd->fd,
283                   PM_SET_DELAY_AND_TIMEOUT,
284                   &baddr->cryogenic_times) < 0)
285     {
286       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl");
287       baddr->broadcast_task =
288           GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
289                                         &udp_ipv4_broadcast_send, baddr);
290     }
291     else
292       GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
293                                            baddr->cryogenic_fd,
294                                                &udp_ipv4_broadcast_send,
295                                                baddr);
296
297   }
298   else
299 #endif
300     baddr->broadcast_task =
301         GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
302                                           &udp_ipv4_broadcast_send, baddr);
303 }
304
305
306 static void
307 udp_ipv6_broadcast_send (void *cls)
308 {
309   struct BroadcastAddress *baddr = cls;
310   struct Plugin *plugin = baddr->plugin;
311   ssize_t sent;
312   uint16_t msg_size;
313   char buf[65536] GNUNET_ALIGN;
314   const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) baddr->addr;
315
316   baddr->broadcast_task = NULL;
317
318   msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf);
319   /* Note: unclear if this actually works to limit the multicast to
320      the specified interface as we're not (necessarily) using a
321      link-local multicast group and the kernel suggests that the
322      scope ID is only respected for link-local addresses; however,
323      if the scope ID is ignored, the kernel should just multicast
324      on ALL interfaces, which is merely slightly less efficient;
325      in that case, we might want to revert to only doing this
326      once, and not per interface (hard to test...) */
327   plugin->ipv6_multicast_address.sin6_scope_id = s6->sin6_scope_id;
328   sent = GNUNET_NETWORK_socket_sendto (plugin->sockv6, &buf, msg_size,
329                                     (const struct sockaddr *)
330                                     &plugin->ipv6_multicast_address,
331                                     sizeof (struct sockaddr_in6));
332   plugin->ipv6_multicast_address.sin6_scope_id = 0;
333   if (sent == GNUNET_SYSERR)
334   {
335     if ((ENETUNREACH == errno) || (ENETDOWN == errno))
336     {
337       /* "Network unreachable" or "Network down"
338        *
339        * This indicates that this system is IPv6 enabled, but does not
340        * have a valid global IPv6 address assigned
341        */
342       GNUNET_log (GNUNET_ERROR_TYPE_BULK | GNUNET_ERROR_TYPE_WARNING,
343           "Network connectivity is down, cannot send beacon!\n");
344     }
345     else
346       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto");
347   }
348   else
349   {
350     LOG (GNUNET_ERROR_TYPE_DEBUG,
351          "Sending IPv6 HELLO beacon broadcast with %d bytes to address %s\n",
352          (int) sent,
353          GNUNET_a2s ((const struct sockaddr *) &plugin->ipv6_multicast_address,
354                      sizeof (struct sockaddr_in6)));
355   }
356 #if LINUX
357   /*
358    * Cryogenic
359    */
360   if (NULL != baddr->cryogenic_fd)
361   {
362     baddr->cryogenic_times.delay_msecs = (plugin->broadcast_interval.rel_value_us/1000.0)*0.5;
363     baddr->cryogenic_times.timeout_msecs = (plugin->broadcast_interval.rel_value_us/1000.0)*1.5;
364
365     if (ioctl(baddr->cryogenic_fd->fd,
366                   PM_SET_DELAY_AND_TIMEOUT,
367                   &baddr->cryogenic_times) < 0)
368     {
369       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl");
370       baddr->broadcast_task =
371           GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
372                                         &udp_ipv6_broadcast_send, baddr);
373     }
374     else
375       GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
376                                        baddr->cryogenic_fd,
377                                        &udp_ipv6_broadcast_send,
378                                        baddr);
379   }
380   else
381 #endif
382     baddr->broadcast_task =
383         GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
384                                       &udp_ipv6_broadcast_send, baddr);
385 }
386
387
388 /**
389  * Callback function invoked for each interface found.
390  *
391  * @param cls closure with the `struct Plugin`
392  * @param name name of the interface (can be NULL for unknown)
393  * @param isDefault is this presumably the default interface
394  * @param addr address of this interface (can be NULL for unknown or unassigned)
395  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
396  * @param netmask the network mask (can be NULL for unknown or unassigned)
397  * @param addrlen length of the address
398  * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
399  */
400 static int
401 iface_proc (void *cls,
402             const char *name,
403             int isDefault,
404             const struct sockaddr *addr,
405             const struct sockaddr *broadcast_addr,
406             const struct sockaddr *netmask, socklen_t addrlen)
407 {
408   struct Plugin *plugin = cls;
409   struct BroadcastAddress *ba;
410   enum GNUNET_ATS_Network_Type network;
411
412   if (NULL == addr)
413     return GNUNET_OK;
414   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
415               "address %s for interface %s %p\n ",
416               GNUNET_a2s (addr, addrlen), name, addr);
417   if (NULL == broadcast_addr)
418     return GNUNET_OK;
419   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
420               "broadcast address %s for interface %s %p\n ",
421               GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr);
422   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ",
423               GNUNET_a2s (netmask, addrlen), name, netmask);
424
425   network = plugin->env->get_address_type (plugin->env->cls, broadcast_addr, addrlen);
426   if (GNUNET_ATS_NET_LOOPBACK == network)
427   {
428     /* Broadcasting on loopback does not make sense */
429     return GNUNET_YES;
430   }
431
432   ba = GNUNET_new (struct BroadcastAddress);
433   ba->plugin = plugin;
434   ba->addr = GNUNET_malloc (addrlen);
435   GNUNET_memcpy (ba->addr, broadcast_addr, addrlen);
436   ba->addrlen = addrlen;
437
438   if ( (GNUNET_YES == plugin->enable_ipv4) &&
439        (NULL != plugin->sockv4) &&
440        (addrlen == sizeof (struct sockaddr_in)) )
441   {
442 #if LINUX
443     /*
444      * setup Cryogenic FD for ipv4 broadcasting
445      */
446     char *filename;
447
448     GNUNET_asprintf (&filename,
449                      "/dev/cryogenic/%s",
450                      name);
451     if (0 == ACCESS (name, R_OK))
452     {
453       ba->cryogenic_fd =
454         GNUNET_DISK_file_open (filename,
455                                GNUNET_DISK_OPEN_WRITE,
456                                GNUNET_DISK_PERM_NONE);
457     }
458     GNUNET_free (filename);
459 #endif
460     ba->broadcast_task =
461         GNUNET_SCHEDULER_add_now (&udp_ipv4_broadcast_send, ba);
462   }
463   if ((GNUNET_YES == plugin->enable_ipv6) &&
464       (NULL != plugin->sockv6) &&
465       (addrlen == sizeof (struct sockaddr_in6)))
466   {
467     /* Create IPv6 multicast request */
468     struct ipv6_mreq multicastRequest;
469     const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) broadcast_addr;
470
471     multicastRequest.ipv6mr_multiaddr =
472         plugin->ipv6_multicast_address.sin6_addr;
473     /* http://tools.ietf.org/html/rfc2553#section-5.2:
474      *
475      * IPV6_JOIN_GROUP
476      *
477      * Join a multicast group on a specified local interface.  If the
478      * interface index is specified as 0, the kernel chooses the local
479      * interface.  For example, some kernels look up the multicast
480      * group in the normal IPv6 routing table and using the resulting
481      * interface; we do this for each interface, so no need to use
482      * zero (anymore...).
483      */
484     multicastRequest.ipv6mr_interface = s6->sin6_scope_id;
485
486     /* Join the multicast group */
487     if (GNUNET_OK !=
488         GNUNET_NETWORK_socket_setsockopt
489         (plugin->sockv6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
490          &multicastRequest, sizeof (multicastRequest)))
491     {
492       LOG (GNUNET_ERROR_TYPE_WARNING,
493       "Failed to join IPv6 multicast group: IPv6 broadcasting not running\n");
494     }
495     else
496     {
497 #if LINUX
498       /*
499        * setup Cryogenic FD for ipv6 broadcasting
500        */
501       char *filename;
502
503       GNUNET_asprintf (&filename,
504                        "/dev/cryogenic/%s",
505                        name);
506       if (0 == ACCESS (name, R_OK))
507       {
508         ba->cryogenic_fd =
509           GNUNET_DISK_file_open (filename,
510                                  GNUNET_DISK_OPEN_WRITE,
511                                  GNUNET_DISK_PERM_NONE);
512       }
513       GNUNET_free (filename);
514 #endif
515       ba->broadcast_task =
516           GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, ba);
517     }
518   }
519   GNUNET_CONTAINER_DLL_insert (plugin->broadcast_head,
520                                plugin->broadcast_tail, ba);
521   return GNUNET_OK;
522 }
523
524
525 /**
526  * Setup broadcasting subsystem.
527  *
528  * @param plugin
529  * @param server_addrv6
530  * @param server_addrv4
531  */
532 void
533 setup_broadcast (struct Plugin *plugin,
534                  struct sockaddr_in6 *server_addrv6,
535                  struct sockaddr_in *server_addrv4)
536 {
537   if (GNUNET_YES ==
538       GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
539                                             "topology",
540                                             "FRIENDS-ONLY"))
541   {
542     LOG (GNUNET_ERROR_TYPE_WARNING,
543          _("Disabling HELLO broadcasting due to friend-to-friend only configuration!\n"));
544     return;
545   }
546
547   if (GNUNET_YES != plugin->enable_broadcasting)
548     return; /* We do not send, just receive */
549
550   /* create IPv4 broadcast socket */
551   if ((GNUNET_YES == plugin->enable_ipv4) && (NULL != plugin->sockv4))
552   {
553     static int yes = 1;
554
555     if (GNUNET_NETWORK_socket_setsockopt
556         (plugin->sockv4, SOL_SOCKET, SO_BROADCAST, &yes,
557          sizeof (int)) != GNUNET_OK)
558     {
559       LOG (GNUNET_ERROR_TYPE_WARNING,
560            _("Failed to set IPv4 broadcast option for broadcast socket on port %d\n"),
561            ntohs (server_addrv4->sin_port));
562     }
563   }
564   /* create IPv6 multicast socket */
565   if ((GNUNET_YES == plugin->enable_ipv6) && (plugin->sockv6 != NULL))
566   {
567     memset (&plugin->ipv6_multicast_address, 0, sizeof (struct sockaddr_in6));
568     GNUNET_assert (1 ==
569                    inet_pton (AF_INET6, "FF05::13B",
570                               &plugin->ipv6_multicast_address.sin6_addr));
571     plugin->ipv6_multicast_address.sin6_family = AF_INET6;
572     plugin->ipv6_multicast_address.sin6_port = htons (plugin->port);
573   }
574   GNUNET_OS_network_interfaces_list (&iface_proc, plugin);
575 }
576
577
578 /**
579  * Stop broadcasting subsystem.
580  *
581  * @param plugin
582  */
583 void
584 stop_broadcast (struct Plugin *plugin)
585 {
586   if (GNUNET_YES == plugin->enable_broadcasting)
587   {
588     /* Disable broadcasting */
589     while (plugin->broadcast_head != NULL)
590     {
591       struct BroadcastAddress *p = plugin->broadcast_head;
592
593       if (p->broadcast_task != NULL)
594       {
595         GNUNET_SCHEDULER_cancel (p->broadcast_task);
596         p->broadcast_task = NULL;
597       }
598       if ((GNUNET_YES == plugin->enable_ipv6) &&
599           (NULL != plugin->sockv6) &&
600           (p->addrlen == sizeof (struct sockaddr_in6)))
601       {
602         /* Create IPv6 multicast request */
603         struct ipv6_mreq multicastRequest;
604         const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) p->addr;
605
606         multicastRequest.ipv6mr_multiaddr =
607           plugin->ipv6_multicast_address.sin6_addr;
608         multicastRequest.ipv6mr_interface = s6->sin6_scope_id;
609
610         /* Leave the multicast group */
611         if (GNUNET_OK ==
612             GNUNET_NETWORK_socket_setsockopt
613             (plugin->sockv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
614              &multicastRequest, sizeof (multicastRequest)))
615         {
616           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
617         }
618         else
619         {
620           LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 multicasting stopped\n");
621         }
622       }
623
624 #if LINUX
625     GNUNET_DISK_file_close(p->cryogenic_fd);
626 #endif
627       GNUNET_CONTAINER_DLL_remove (plugin->broadcast_head,
628                                    plugin->broadcast_tail, p);
629       GNUNET_free (p->addr);
630       GNUNET_free (p);
631     }
632   }
633 }
634
635 /* end of plugin_transport_udp_broadcasting.c */