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