c1975e68647ee76b2290930cde664273f0c6abb7
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses.c
1 /*
2      This file is part of GNUnet.
3      (C) 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 ats/gnunet-service-ats_addresses.c
23  * @brief ats service address management
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_ats_service.h"
29 #include "gnunet-service-ats.h"
30 #include "gnunet-service-ats_addresses.h"
31 #include "gnunet-service-ats_performance.h"
32 #include "gnunet-service-ats_scheduling.h"
33 #include "gnunet-service-ats_reservations.h"
34
35 struct ATS_Address
36 {
37   struct GNUNET_PeerIdentity peer;
38
39   size_t addr_len;
40
41   uint32_t session_id;
42
43   uint32_t ats_count;
44
45   const void *addr;
46
47   char *plugin;
48
49   struct GNUNET_ATS_Information *ats;
50
51   struct GNUNET_TIME_Relative atsp_latency;
52
53   struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in;
54
55   struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out;
56
57   uint32_t atsp_distance;
58
59   uint32_t atsp_cost_wan;
60
61   uint32_t atsp_cost_lan;
62
63   uint32_t atsp_cost_wlan;
64
65   struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_in;
66
67   struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out;
68
69   /**
70    * Is this the active address for this peer?
71    */
72   int active;
73
74 };
75
76 struct ATS_Network
77 {
78   struct ATS_Network * next;
79
80   struct ATS_Network * prev;
81
82   struct sockaddr *network;
83   struct sockaddr *netmask;
84   socklen_t length;
85 };
86
87
88 struct ATS_Network * net_head;
89
90 struct ATS_Network * net_tail;
91
92 static struct GNUNET_CONTAINER_MultiHashMap *addresses;
93
94 static unsigned long long wan_quota_in;
95
96 static unsigned long long wan_quota_out;
97
98 static unsigned int active_addr_count;
99
100 static GNUNET_SCHEDULER_TaskIdentifier interface_task;
101
102
103 /**
104  * Update a bandwidth assignment for a peer.  This trivial method currently
105  * simply assigns the same share to all active connections.
106  *
107  * @param cls unused
108  * @param key unused
109  * @param value the 'struct ATS_Address'
110  * @return GNUNET_OK (continue to iterate)
111  */
112 static int
113 update_bw_it (void *cls, const GNUNET_HashCode * key, void *value)
114 {
115   struct ATS_Address *aa = value;
116
117   if (GNUNET_YES != aa->active)
118     return GNUNET_OK;
119   GNUNET_assert (active_addr_count > 0);
120   aa->assigned_bw_in.value__ = htonl (wan_quota_in / active_addr_count);
121   aa->assigned_bw_out.value__ = htonl (wan_quota_out / active_addr_count);
122   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n",
123               GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__),
124               ntohl (aa->assigned_bw_out.value__));
125   GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr,
126                                               aa->addr_len, aa->session_id,
127                                               aa->ats, aa->ats_count,
128                                               aa->assigned_bw_out,
129                                               aa->assigned_bw_in);
130   GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in);
131   GAS_performance_notify_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len,
132                                   aa->ats, aa->ats_count, aa->assigned_bw_out,
133                                   aa->assigned_bw_in);
134   return GNUNET_OK;
135 }
136
137
138 /**
139  * Some (significant) input changed, recalculate bandwidth assignment
140  * for all peers.
141  */
142 static void
143 recalculate_assigned_bw ()
144 {
145   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146               "Recalculating bandwidth for all active connections\n");
147   GNUNET_STATISTICS_update (GSA_stats, "# bandwidth recalculations performed",
148                             1, GNUNET_NO);
149   GNUNET_STATISTICS_set (GSA_stats, "# active addresses", active_addr_count,
150                          GNUNET_NO);
151   GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_it, NULL);
152 }
153
154
155 /**
156  * Destroy the given address.
157  *
158  * @param addr address to destroy
159  * @return GNUNET_YES if bandwidth allocations should be recalcualted
160  */
161 static int
162 destroy_address (struct ATS_Address *addr)
163 {
164   int ret;
165
166   ret = GNUNET_NO;
167   GNUNET_assert (GNUNET_YES ==
168                  GNUNET_CONTAINER_multihashmap_remove (addresses,
169                                                        &addr->peer.hashPubKey,
170                                                        addr));
171   if (GNUNET_YES == addr->active)
172   {
173     active_addr_count--;
174     addr->active = GNUNET_NO;
175     ret = GNUNET_YES;
176   }
177   GNUNET_free_non_null (addr->ats);
178   GNUNET_free (addr->plugin);
179   GNUNET_free (addr);
180   return ret;
181 }
182
183
184 struct CompareAddressContext
185 {
186   const struct ATS_Address *search;
187   struct ATS_Address *result;
188 };
189
190
191 static int
192 compare_address_it (void *cls, const GNUNET_HashCode * key, void *value)
193 {
194   struct CompareAddressContext *cac = cls;
195   struct ATS_Address *aa = value;
196
197   if (((aa->addr_len != cac->search->addr_len) ||
198        (0 != strcmp (aa->plugin, cac->search->plugin)) ||
199        (0 != memcmp (aa->addr, cac->search->addr, aa->addr_len))) &&
200       ((aa->session_id != cac->search->session_id) ||
201        (cac->search->session_id == 0)))
202     return GNUNET_YES;
203   cac->result = aa;
204   return GNUNET_NO;
205 }
206
207
208 /**
209  * Find an existing equivalent address record.
210  * Compares by peer identity and network address OR by session ID
211  * (one of the two must match).
212  *
213  * @param peer peer to lookup addresses for
214  * @param addr existing address record
215  * @return existing address record, NULL for none
216  */
217 struct ATS_Address *
218 find_address (const struct GNUNET_PeerIdentity *peer,
219               const struct ATS_Address *addr)
220 {
221   struct CompareAddressContext cac;
222
223   cac.result = NULL;
224   cac.search = addr;
225   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
226                                               &compare_address_it, &cac);
227   return cac.result;
228 }
229
230
231 void
232 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
233                       const char *plugin_name, const void *plugin_addr,
234                       size_t plugin_addr_len, uint32_t session_id,
235                       const struct GNUNET_ATS_Information *atsi,
236                       uint32_t atsi_count)
237 {
238   struct ATS_Address *aa;
239   struct ATS_Address *old;
240   uint32_t i;
241
242   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
243   aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
244   aa->peer = *peer;
245   aa->addr_len = plugin_addr_len;
246   aa->ats_count = atsi_count;
247   memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
248   aa->addr = &aa[1];
249   memcpy (&aa[1], plugin_addr, plugin_addr_len);
250   aa->plugin = GNUNET_strdup (plugin_name);
251   aa->session_id = session_id;
252   old = find_address (peer, aa);
253   if (old == NULL)
254   {
255     GNUNET_assert (GNUNET_OK ==
256                    GNUNET_CONTAINER_multihashmap_put (addresses,
257                                                       &peer->hashPubKey, aa,
258                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
259     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' %X\n",
260                 GNUNET_i2s (peer), aa);
261     old = aa;
262   }
263   else
264   {
265     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
266                 "Updated existing address for peer `%s' %X \n",
267                 GNUNET_i2s (peer), old);
268     GNUNET_free_non_null (old->ats);
269     old->session_id = session_id;
270     old->ats = NULL;
271     old->ats_count = 0;
272     old->ats = aa->ats;
273     old->ats_count = aa->ats_count;
274     GNUNET_free (aa->plugin);
275     GNUNET_free (aa);
276   }
277   for (i = 0; i < atsi_count; i++)
278     switch (ntohl (atsi[i].type))
279     {
280     case GNUNET_ATS_UTILIZATION_UP:
281       old->atsp_utilization_out.value__ = atsi[i].value;
282       break;
283     case GNUNET_ATS_UTILIZATION_DOWN:
284       old->atsp_utilization_in.value__ = atsi[i].value;
285       break;
286     case GNUNET_ATS_QUALITY_NET_DELAY:
287       old->atsp_latency.rel_value = ntohl (atsi[i].value);
288       break;
289     case GNUNET_ATS_QUALITY_NET_DISTANCE:
290       old->atsp_distance = ntohl (atsi[i].value);
291       break;
292     case GNUNET_ATS_COST_WAN:
293       old->atsp_cost_wan = ntohl (atsi[i].value);
294       break;
295     case GNUNET_ATS_COST_LAN:
296       old->atsp_cost_lan = ntohl (atsi[i].value);
297       break;
298     case GNUNET_ATS_COST_WLAN:
299       old->atsp_cost_wlan = ntohl (atsi[i].value);
300       break;
301     default:
302       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
303                   "Received unsupported ATS type %u\n", ntohl (atsi[i].type));
304       GNUNET_break (0);
305       break;
306     }
307 }
308
309
310 /**
311  * Update a bandwidth assignment for a peer.  This trivial method currently
312  * simply assigns the same share to all active connections.
313  *
314  * @param cls unused
315  * @param key unused
316  * @param value the 'struct ATS_Address'
317  * @return GNUNET_OK (continue to iterate)
318  */
319 static int
320 destroy_by_session_id (void *cls, const GNUNET_HashCode * key, void *value)
321 {
322   const struct ATS_Address *info = cls;
323   struct ATS_Address *aa = value;
324
325   GNUNET_assert (0 ==
326                  memcmp (&aa->peer, &info->peer,
327                          sizeof (struct GNUNET_PeerIdentity)));
328   if ((info->session_id == 0) && (0 == strcmp (info->plugin, aa->plugin)) &&
329       (aa->addr_len == info->addr_len) &&
330       (0 == memcmp (info->addr, aa->addr, aa->addr_len)))
331   {
332     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333                 "Deleting address for peer `%s': `%s'\n",
334                 GNUNET_i2s (&aa->peer), aa->plugin);
335     if (GNUNET_YES == destroy_address (aa))
336       recalculate_assigned_bw ();
337     return GNUNET_OK;
338   }
339   if (aa->session_id != info->session_id)
340     return GNUNET_OK;           /* irrelevant */
341   if (aa->session_id != 0)
342     GNUNET_break (0 == strcmp (info->plugin, aa->plugin));
343   /* session died */
344   aa->session_id = 0;
345
346   if (GNUNET_YES == aa->active)
347   {
348     aa->active = GNUNET_NO;
349     active_addr_count--;
350     recalculate_assigned_bw ();
351   }
352
353   /* session == 0 and addrlen == 0 : destroy address */
354   if (aa->addr_len == 0)
355     (void) destroy_address (aa);
356
357   return GNUNET_OK;
358 }
359
360
361 void
362 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
363                        const char *plugin_name, const void *plugin_addr,
364                        size_t plugin_addr_len, uint32_t session_id)
365 {
366   struct ATS_Address aa;
367
368   GNUNET_break (0 < strlen (plugin_name));
369   aa.peer = *peer;
370   aa.addr_len = plugin_addr_len;
371   aa.addr = plugin_addr;
372   aa.plugin = (char *) plugin_name;
373   aa.session_id = session_id;
374   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
375                                               &destroy_by_session_id, &aa);
376 }
377
378
379 /**
380  * Find a "good" address to use for a peer.  If we already have an existing
381  * address, we stick to it.  Otherwise, we pick by lowest distance and then
382  * by lowest latency.
383  *
384  * @param cls the 'struct ATS_Address**' where we store the result
385  * @param key unused
386  * @param value another 'struct ATS_Address*' to consider using
387  * @return GNUNET_OK (continue to iterate)
388  */
389 static int
390 find_address_it (void *cls, const GNUNET_HashCode * key, void *value)
391 {
392   struct ATS_Address **ap = cls;
393   struct ATS_Address *aa = (struct ATS_Address *) value;
394   struct ATS_Address *ab = *ap;
395
396   if (NULL == ab)
397   {
398     *ap = aa;
399     return GNUNET_OK;
400   }
401   if ((ntohl (ab->assigned_bw_in.value__) == 0) &&
402       (ntohl (aa->assigned_bw_in.value__) > 0))
403   {
404     /* stick to existing connection */
405     *ap = aa;
406     return GNUNET_OK;
407   }
408   if (ab->atsp_distance > aa->atsp_distance)
409   {
410     /* user shorter distance */
411     *ap = aa;
412     return GNUNET_OK;
413   }
414   if (ab->atsp_latency.rel_value > aa->atsp_latency.rel_value)
415   {
416     /* user lower latency */
417     *ap = aa;
418     return GNUNET_OK;
419   }
420   /* don't care */
421   return GNUNET_OK;
422 }
423
424
425 void
426 GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer,
427                       const char *plugin_name, const void *plugin_addr,
428                       size_t plugin_addr_len, uint32_t session_id, int in_use)
429 {
430
431   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432               "Received `%s' message for peer `%s': %i\n", "ADDRESS_IN_USE",
433               GNUNET_i2s (peer), in_use);
434 }
435
436 void
437 GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
438 {
439   struct ATS_Address *aa;
440
441   aa = NULL;
442   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
443                                               &find_address_it, &aa);
444   if (aa == NULL)
445   {
446     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447                 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
448     return;
449   }
450   if (aa->active == GNUNET_NO)
451   {
452     aa->active = GNUNET_YES;
453     active_addr_count++;
454     recalculate_assigned_bw ();
455   }
456   else
457   {
458     /* just to be sure... */
459     GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
460                                                 aa->addr_len, aa->session_id,
461                                                 aa->ats, aa->ats_count,
462                                                 aa->assigned_bw_out,
463                                                 aa->assigned_bw_in);
464   }
465 }
466
467
468 // FIXME: this function should likely end up in the LP-subsystem and
469 // not with 'addresses' in the future...
470 void
471 GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
472                                  enum GNUNET_ATS_PreferenceKind kind,
473                                  float score)
474 {
475   // do nothing for now...
476 }
477
478 /**
479  * Returns where the address is located: LAN or WAN or ...
480  * @param addr address
481  * @param addrlen address length
482  * @return location as GNUNET_ATS_Information
483  */
484
485 struct GNUNET_ATS_Information
486 GAS_addresses_type (const struct sockaddr * addr, socklen_t addrlen)
487 {
488   struct GNUNET_ATS_Information ats;
489   struct ATS_Network * cur = net_head;
490   int type = GNUNET_ATS_NET_UNSPECIFIED;
491
492   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Checking type of address `%s'\n", GNUNET_a2s(addr, addrlen));
493
494   /* IPv4 loopback check */
495   if  (addr->sa_family == AF_INET)
496   {
497     struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
498
499     if (((a4->sin_addr.s_addr & htonl(0xff000000)) & htonl (0x7f000000)) == htonl (0x7f000000))
500       type = GNUNET_ATS_NET_LOOPBACK;
501   }
502   /* IPv6 loopback check */
503   if  (addr->sa_family == AF_INET6)
504   {
505     struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
506     if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
507       type = GNUNET_ATS_NET_LOOPBACK;
508   }
509
510   /* Check local networks */
511   while ((cur != NULL) && (type == GNUNET_ATS_NET_UNSPECIFIED))
512   {
513     if (addrlen != cur->length)
514     {
515       cur = cur->next;
516       continue;
517     }
518
519     if (addr->sa_family == AF_INET)
520     {
521       struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
522       struct sockaddr_in * net4 = (struct sockaddr_in *) cur->network;
523       struct sockaddr_in * mask4 = (struct sockaddr_in *) cur->netmask;
524
525       if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr) & net4->sin_addr.s_addr) == net4->sin_addr.s_addr)
526       {
527         char * net = strdup (GNUNET_a2s ((const struct sockaddr *) net4, addrlen));
528         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n",
529             GNUNET_a2s ((const struct sockaddr *)a4, addrlen),
530             net);
531         GNUNET_free (net);
532         type = GNUNET_ATS_NET_LAN;
533       }
534     }
535     if (addr->sa_family == AF_INET6)
536     {
537       struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
538       struct sockaddr_in6 * net6 = (struct sockaddr_in6 *) cur->network;
539       struct sockaddr_in6 * mask6 = (struct sockaddr_in6 *) cur->netmask;
540
541       int res = GNUNET_YES;
542       int c = 0;
543       for (c = 0; c < 4; c++)
544       {
545         if (((a6->sin6_addr.__in6_u.__u6_addr32[c] & mask6->sin6_addr.__in6_u.__u6_addr32[c]) | net6->sin6_addr.__in6_u.__u6_addr32[c]) != net6->sin6_addr.__in6_u.__u6_addr32[c])
546           res = GNUNET_NO;
547       }
548
549       if (res == GNUNET_YES)
550       {
551         char * net = strdup (GNUNET_a2s ((const struct sockaddr *) net6, addrlen));
552         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n",
553               GNUNET_a2s ((const struct sockaddr *) a6, addrlen),
554               net);
555         GNUNET_free (net);
556         type = GNUNET_ATS_NET_LAN;
557       }
558     }
559     cur = cur->next;
560   }
561
562   /* local network found for this address, default: WAN */
563   if (type == GNUNET_ATS_NET_UNSPECIFIED)
564     type = GNUNET_ATS_NET_WAN;
565
566   ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
567   ats.value = htonl (type);
568   return ats;
569 }
570
571 static int
572 interface_proc (void *cls, const char *name,
573                 int isDefault,
574                 const struct sockaddr *
575                 addr,
576                 const struct sockaddr *
577                 broadcast_addr,
578                 const struct sockaddr *
579                 netmask, socklen_t addrlen)
580 {
581   /* Calculate network */
582   struct ATS_Network *net = NULL;
583   if (addr->sa_family == AF_INET)
584   {
585     struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
586     struct sockaddr_in *netmask4 = (struct sockaddr_in *) netmask;
587     struct sockaddr_in *tmp = NULL;
588     struct sockaddr_in network4;
589
590     net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in));
591     tmp = (struct sockaddr_in *) &net[1];
592     net->network = (struct sockaddr *) &tmp[0];
593     net->netmask = (struct sockaddr *) &tmp[1];
594     net->length = addrlen;
595
596     network4.sin_family = AF_INET;
597     network4.sin_port = htons (0);
598 #if HAVE_SOCKADDR_IN_SIN_LEN
599     network4.sin_len = sizeof (network4);
600 #endif
601     network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr);
602
603     memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in));
604     memcpy (net->network, &network4, sizeof (struct sockaddr_in));
605
606     char * netmask = strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen));
607     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n",
608         GNUNET_a2s((struct sockaddr *) net->network, addrlen),
609         netmask);
610     GNUNET_free (netmask);
611
612   }
613
614   if (addr->sa_family == AF_INET6)
615   {
616     struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
617     struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) netmask;
618     struct sockaddr_in6 * tmp = NULL;
619     struct sockaddr_in6 network6;
620
621     net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6));
622     tmp = (struct sockaddr_in6 *) &net[1];
623     net->network = (struct sockaddr *) &tmp[0];
624     net->netmask = (struct sockaddr *) &tmp[1];
625     net->length = addrlen;
626
627     network6.sin6_family = AF_INET6;
628     network6.sin6_port = htons (0);
629 #if HAVE_SOCKADDR_IN_SIN_LEN
630     network6.sin6_len = sizeof (network6);
631 #endif
632     int c = 0;
633     for (c = 0; c < 4; c++)
634     {
635       network6.sin6_addr.__in6_u.__u6_addr32[c] = addr6->sin6_addr.__in6_u.__u6_addr32[c] & netmask6->sin6_addr.__in6_u.__u6_addr32[c];
636     }
637
638     memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6));
639     memcpy (net->network, &network6, sizeof (struct sockaddr_in6));
640
641     char * netmask = strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen));
642     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n",
643         GNUNET_a2s((struct sockaddr *) net->network, addrlen),
644         netmask);
645     GNUNET_free (netmask);
646   }
647
648   /* Store in list */
649   if (net != NULL)
650     GNUNET_CONTAINER_DLL_insert(net_head, net_tail, net);
651
652   return GNUNET_OK;
653 }
654
655 static void
656 delete_networks ()
657 {
658   struct ATS_Network * cur = net_head;
659   while (cur != NULL)
660   {
661     GNUNET_CONTAINER_DLL_remove(net_head, net_tail, cur);
662     GNUNET_free (cur);
663     cur = net_head;
664   }
665 }
666
667 static void
668 get_addresses (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
669 {
670   interface_task = GNUNET_SCHEDULER_NO_TASK;
671   delete_networks ();
672   GNUNET_OS_network_interfaces_list(interface_proc, NULL);
673
674   interface_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, get_addresses, NULL);
675 }
676
677 /**
678  * Initialize address subsystem.
679  *
680  * @param cfg configuration to use
681  */
682 void
683 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
684 {
685   GNUNET_assert (GNUNET_OK ==
686                  GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
687                                                       "WAN_QUOTA_IN",
688                                                       &wan_quota_in));
689   GNUNET_assert (GNUNET_OK ==
690                  GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
691                                                       "WAN_QUOTA_OUT",
692                                                       &wan_quota_out));
693   addresses = GNUNET_CONTAINER_multihashmap_create (128);
694
695   interface_task = GNUNET_SCHEDULER_add_now(get_addresses, NULL);
696 }
697
698
699 /**
700  * Free memory of address.
701  *
702  * @param cls NULL
703  * @param key peer identity (unused)
704  * @param value the 'struct ATS_Address' to free
705  * @return GNUNET_OK (continue to iterate)
706  */
707 static int
708 free_address_it (void *cls, const GNUNET_HashCode * key, void *value)
709 {
710   struct ATS_Address *aa = value;
711
712   destroy_address (aa);
713   return GNUNET_OK;
714 }
715
716
717 void
718 GAS_addresses_destroy_all ()
719 {
720   if (addresses != NULL)
721     GNUNET_CONTAINER_multihashmap_iterate (addresses, &free_address_it, NULL);
722   GNUNET_assert (active_addr_count == 0);
723 }
724
725
726 /**
727  * Shutdown address subsystem.
728  */
729 void
730 GAS_addresses_done ()
731 {
732   delete_networks ();
733   if (interface_task != GNUNET_SCHEDULER_NO_TASK)
734   {
735     GNUNET_SCHEDULER_cancel(interface_task);
736     interface_task = GNUNET_SCHEDULER_NO_TASK;
737   }
738   GAS_addresses_destroy_all ();
739   GNUNET_CONTAINER_multihashmap_destroy (addresses);
740   addresses = NULL;
741 }
742
743
744 /* end of gnunet-service-ats_addresses.c */