- improved configuration and statistics handling
[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 #if HAVE_LIBGLPK
35 #include "gnunet-service-ats_addresses_mlp.h"
36 #endif
37
38 #define VERBOSE GNUNET_NO
39
40 enum ATS_Mode
41 {
42   /*
43    * Assign each peer an equal amount of bandwidth (bw)
44    *
45    * bw_per_peer = bw_total / #active addresses
46    */
47   SIMPLE,
48
49   /*
50    * Use MLP solver to assign bandwidth
51    */
52   MLP
53 };
54
55 static struct GNUNET_CONTAINER_MultiHashMap *addresses;
56
57 #if HAVE_LIBGLPK
58 static struct GAS_MLP_Handle *mlp;
59 #endif
60
61 static unsigned long long wan_quota_in;
62
63 static unsigned long long wan_quota_out;
64
65 static unsigned int active_addr_count;
66
67 static int ats_mode;
68
69
70 static void
71 send_bw_notification (struct ATS_Address *aa)
72 {
73   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n",
74               GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__),
75               ntohl (aa->assigned_bw_out.value__));
76   GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr,
77                                               aa->addr_len, aa->session_id,
78                                               aa->ats, aa->ats_count,
79                                               aa->assigned_bw_out,
80                                               aa->assigned_bw_in);
81   GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in);
82   GAS_performance_notify_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len,
83                                   aa->ats, aa->ats_count, aa->assigned_bw_out,
84                                   aa->assigned_bw_in);
85 }
86
87 /**
88  * Update a bandwidth assignment for a peer.  This trivial method currently
89  * simply assigns the same share to all active connections.
90  *
91  * @param cls unused
92  * @param key unused
93  * @param value the 'struct ATS_Address'
94  * @return GNUNET_OK (continue to iterate)
95  */
96 static int
97 update_bw_simple_it (void *cls, const GNUNET_HashCode * key, void *value)
98 {
99   struct ATS_Address *aa = value;
100
101   if (GNUNET_YES != aa->active)
102     return GNUNET_OK;
103   GNUNET_assert (active_addr_count > 0);
104
105
106   /* Simple method */
107   aa->assigned_bw_in.value__ = htonl (wan_quota_in / active_addr_count);
108   aa->assigned_bw_out.value__ = htonl (wan_quota_out / active_addr_count);
109
110   send_bw_notification (aa);
111
112   return GNUNET_OK;
113 }
114
115
116 /**
117  * Some (significant) input changed, recalculate bandwidth assignment
118  * for all peers.
119  */
120 static void
121 recalculate_assigned_bw ()
122 {
123   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
124               "Recalculating bandwidth for all active connections\n");
125   GNUNET_STATISTICS_update (GSA_stats, "# bandwidth recalculations performed",
126                             1, GNUNET_NO);
127   GNUNET_STATISTICS_set (GSA_stats, "# active addresses", active_addr_count,
128                          GNUNET_NO);
129
130   GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, NULL);
131 }
132
133 /**
134  * Free the given address
135  * @param addr address to destroy
136  */
137 static void
138 free_address (struct ATS_Address *addr)
139 {
140   GNUNET_free_non_null (addr->ats);
141   GNUNET_free (addr->plugin);
142   GNUNET_free (addr);
143 }
144
145 /**
146  * Create a ATS_address with the given information
147  * @param peer peer
148  * @param plugin_name plugin
149  * @param plugin_addr address
150  * @param plugin_addr_len address length
151  * @param session_id session
152  * @return the ATS_Address
153  */
154 static struct ATS_Address *
155 create_address (const struct GNUNET_PeerIdentity *peer,
156                 const char *plugin_name,
157                 const void *plugin_addr, size_t plugin_addr_len,
158                 uint32_t session_id)
159 {
160   struct ATS_Address *aa = NULL;
161
162   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
163   aa->peer = *peer;
164   aa->addr_len = plugin_addr_len;
165   aa->addr = &aa[1];
166   memcpy (&aa[1], plugin_addr, plugin_addr_len);
167   aa->plugin = GNUNET_strdup (plugin_name);
168   aa->session_id = session_id;
169   aa->mlp_information = NULL;
170   aa->next = NULL;
171   aa->prev = NULL;
172   return aa;
173 }
174
175
176 /**
177  * Destroy the given address.
178  *
179  * @param addr address to destroy
180  * @return GNUNET_YES if bandwidth allocations should be recalcualted
181  */
182 static int
183 destroy_address (struct ATS_Address *addr)
184 {
185   int ret;
186
187   ret = GNUNET_NO;
188   GNUNET_assert (GNUNET_YES ==
189                  GNUNET_CONTAINER_multihashmap_remove (addresses,
190                                                        &addr->peer.hashPubKey,
191                                                        addr));
192
193 #if HAVE_LIBGLPK
194   if (ats_mode == MLP)
195     GAS_mlp_address_delete (mlp, addresses, addr);
196 #endif
197
198   if (GNUNET_YES == addr->active)
199   {
200     active_addr_count--;
201     addr->active = GNUNET_NO;
202     ret = GNUNET_YES;
203   }
204   free_address (addr);
205   return ret;
206 }
207
208
209 struct CompareAddressContext
210 {
211   const struct ATS_Address *search;
212
213   /* exact_address != NULL if address and session is equal */
214   struct ATS_Address *exact_address;
215   /* exact_address != NULL if address and session is 0 */
216   struct ATS_Address *base_address;
217 };
218
219
220 static int
221 compare_address_it (void *cls, const GNUNET_HashCode * key, void *value)
222 {
223   struct CompareAddressContext *cac = cls;
224   struct ATS_Address *aa = value;
225 /*
226   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
227               "Comparing to: %s %s %u session %u\n",
228               GNUNET_i2s (&aa->peer), aa->plugin, aa->addr_len, aa->session_id);
229
230 */
231   /* find an exact matching address: aa->addr == cac->search->addr && aa->session == cac->search->session */
232   if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
233   {
234       if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
235       {
236         cac->exact_address = aa;
237       }
238   }
239
240   /* find an matching address: aa->addr == cac->search->addr && aa->session == 0 */
241   /* this address can be used to be updated */
242   if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
243   {
244       if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0))
245       {
246         cac->base_address = aa;
247       }
248   }
249
250   if (cac->exact_address == NULL)
251     return GNUNET_YES;
252   else
253     return GNUNET_NO;
254 }
255
256
257 /**
258  * Find an existing equivalent address record.
259  * Compares by peer identity and network address OR by session ID
260  * (one of the two must match).
261  *
262  * @param peer peer to lookup addresses for
263  * @param addr existing address record
264  * @return existing address record, NULL for none
265  */
266 struct ATS_Address *
267 find_address (const struct GNUNET_PeerIdentity *peer,
268               const struct ATS_Address *addr)
269 {
270   struct CompareAddressContext cac;
271
272   cac.exact_address = NULL;
273   cac.base_address = NULL;
274   cac.search = addr;
275   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
276                                               &compare_address_it, &cac);
277
278 /*
279   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
280               "exact address: %s           base address: %s\n",
281               (cac.exact_address != NULL) ? "YES" : "NO",
282               (cac.base_address != NULL) ? "YES" : "NO");
283 */
284   if (cac.exact_address == NULL)
285     return cac.base_address;
286   return cac.exact_address;
287 }
288
289
290 static int
291 compare_address_session_it (void *cls, const GNUNET_HashCode * key, void *value)
292 {
293   struct CompareAddressContext *cac = cls;
294   struct ATS_Address *aa = value;
295
296   if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
297   {
298       if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
299       {
300         cac->exact_address = aa;
301         return GNUNET_NO;
302       }
303   }
304   return GNUNET_YES;
305 }
306
307
308 /**
309  * Find an existing equivalent address record.
310  * Compares by peer identity and network address AND by session ID
311  * (one of the two must match).
312  *
313  * @param peer peer to lookup addresses for
314  * @param addr existing address record
315  * @return existing address record, NULL for none
316  */
317 struct ATS_Address *
318 find_exact_address (const struct GNUNET_PeerIdentity *peer,
319               const struct ATS_Address *addr)
320 {
321   struct CompareAddressContext cac;
322
323   cac.exact_address = NULL;
324   cac.search = addr;
325   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
326                                               &compare_address_session_it, &cac);
327   return cac.exact_address;
328 }
329
330
331 void
332 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
333                       const char *plugin_name, const void *plugin_addr,
334                       size_t plugin_addr_len, uint32_t session_id,
335                       const struct GNUNET_ATS_Information *atsi,
336                       uint32_t atsi_count)
337 {
338   struct ATS_Address *aa;
339   struct ATS_Address *old;
340   uint32_t i;
341
342   aa = create_address (peer,
343                        plugin_name,
344                        plugin_addr, plugin_addr_len,
345                        session_id);
346
347   aa->mlp_information = NULL;
348   aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
349   aa->ats_count = atsi_count;
350   memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
351
352 #if DEBUG_ATS
353   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' %u\n",
354               GNUNET_i2s (peer),
355               session_id);
356 #endif
357   /* Get existing address or address with session == 0 */
358   old = find_address (peer, aa);
359   if (old == NULL)
360   {
361     GNUNET_assert (GNUNET_OK ==
362                    GNUNET_CONTAINER_multihashmap_put (addresses,
363                                                       &peer->hashPubKey, aa,
364                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
365 #if DEBUG_ATS
366     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' %X\n",
367                 GNUNET_i2s (peer), aa);
368 #endif
369     old = aa;
370   }
371   else
372   {
373 #if DEBUG_ATS
374       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
375                 "Updated existing address for peer `%s' %p old session %u new session %u\n",
376                 GNUNET_i2s (peer), old,
377                 old->session_id, session_id);
378 #endif
379     GNUNET_free_non_null (old->ats);
380     old->session_id = session_id;
381     old->ats = NULL;
382     old->ats_count = 0;
383     old->ats = aa->ats;
384     old->ats_count = aa->ats_count;
385     GNUNET_free (aa->plugin);
386     GNUNET_free (aa);
387   }
388   for (i = 0; i < atsi_count; i++)
389     switch (ntohl (atsi[i].type))
390     {
391     case GNUNET_ATS_UTILIZATION_UP:
392       old->atsp_utilization_out.value__ = atsi[i].value;
393       break;
394     case GNUNET_ATS_UTILIZATION_DOWN:
395       old->atsp_utilization_in.value__ = atsi[i].value;
396       break;
397     case GNUNET_ATS_QUALITY_NET_DELAY:
398       old->atsp_latency.rel_value = ntohl (atsi[i].value);
399       break;
400     case GNUNET_ATS_QUALITY_NET_DISTANCE:
401       old->atsp_distance = ntohl (atsi[i].value);
402       break;
403     case GNUNET_ATS_COST_WAN:
404       old->atsp_cost_wan = ntohl (atsi[i].value);
405       break;
406     case GNUNET_ATS_COST_LAN:
407       old->atsp_cost_lan = ntohl (atsi[i].value);
408       break;
409     case GNUNET_ATS_COST_WLAN:
410       old->atsp_cost_wlan = ntohl (atsi[i].value);
411       break;
412     case GNUNET_ATS_NETWORK_TYPE:
413       old->atsp_network_type = ntohl (atsi[i].value);
414       break;
415
416     default:
417       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
418                   "Received unsupported ATS type %u\n", ntohl (atsi[i].type));
419       GNUNET_break (0);
420       break;
421     }
422 #if HAVE_LIBGLPK
423   if (ats_mode == MLP)
424     GAS_mlp_address_update (mlp, addresses, old);
425 #endif
426 }
427
428
429 /**
430  * Delete an address
431  *
432  * If session != 0, just the session is deleted, the address itself still exists
433  * If session == 0, remove full address
434  * If session == 0 and addrlen == 0, destroy inbound address
435  *
436  * @param cls unused
437  * @param key unused
438  * @param value the 'struct ATS_Address'
439  * @return GNUNET_OK (continue to iterate)
440  */
441 static int
442 destroy_by_session_id (void *cls, const GNUNET_HashCode * key, void *value)
443 {
444   const struct ATS_Address *info = cls;
445   struct ATS_Address *aa = value;
446
447   GNUNET_assert (0 ==
448                  memcmp (&aa->peer, &info->peer,
449                          sizeof (struct GNUNET_PeerIdentity)));
450   /* session == 0, remove full address  */
451   if ((info->session_id == 0) && (0 == strcmp (info->plugin, aa->plugin)) &&
452       (aa->addr_len == info->addr_len) &&
453       (0 == memcmp (info->addr, aa->addr, aa->addr_len)))
454   {
455 #if VERBOSE
456     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457                 "Deleting address for peer `%s': `%s' %u\n",
458                 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
459 #endif
460     if (GNUNET_YES == destroy_address (aa))
461       recalculate_assigned_bw ();
462     return GNUNET_OK;
463   }
464   /* session != 0, just remove session */
465   if (aa->session_id != info->session_id)
466     return GNUNET_OK;           /* irrelevant */
467   if (aa->session_id != 0)
468     GNUNET_break (0 == strcmp (info->plugin, aa->plugin));
469   /* session died */
470 #if VERBOSE
471   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472               "Deleting session for peer `%s': `%s' %u\n",
473               GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
474 #endif
475   aa->session_id = 0;
476
477   if (GNUNET_YES == aa->active)
478   {
479     aa->active = GNUNET_NO;
480     active_addr_count--;
481     recalculate_assigned_bw ();
482   }
483
484   /* session == 0 and addrlen == 0 : destroy address */
485   if (aa->addr_len == 0)
486   {
487 #if VERBOSE
488     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
489                 "Deleting session and address for peer `%s': `%s' %u\n",
490                 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
491 #endif
492     (void) destroy_address (aa);
493   }
494   else
495   {
496     /* session was set to 0, update address */
497 #if HAVE_LIBGLPK
498   if (ats_mode == MLP)
499     GAS_mlp_address_update (mlp, addresses, aa);
500 #endif
501   }
502
503   return GNUNET_OK;
504 }
505
506 void
507 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
508                        const char *plugin_name, const void *plugin_addr,
509                        size_t plugin_addr_len, uint32_t session_id)
510 {
511   struct ATS_Address *aa;
512
513   GNUNET_break (0 < strlen (plugin_name));
514   aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
515
516   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
517                                               &destroy_by_session_id, aa);
518
519   free_address (aa);
520 }
521
522
523 /**
524  * Find a "good" address to use for a peer.  If we already have an existing
525  * address, we stick to it.  Otherwise, we pick by lowest distance and then
526  * by lowest latency.
527  *
528  * @param cls the 'struct ATS_Address**' where we store the result
529  * @param key unused
530  * @param value another 'struct ATS_Address*' to consider using
531  * @return GNUNET_OK (continue to iterate)
532  */
533 static int
534 find_address_it (void *cls, const GNUNET_HashCode * key, void *value)
535 {
536   struct ATS_Address **ap = cls;
537   struct ATS_Address *aa = (struct ATS_Address *) value;
538   struct ATS_Address *ab = *ap;
539
540   if (NULL == ab)
541   {
542     *ap = aa;
543     return GNUNET_OK;
544   }
545   if ((ntohl (ab->assigned_bw_in.value__) == 0) &&
546       (ntohl (aa->assigned_bw_in.value__) > 0))
547   {
548     /* stick to existing connection */
549     *ap = aa;
550     return GNUNET_OK;
551   }
552   if (ab->atsp_distance > aa->atsp_distance)
553   {
554     /* user shorter distance */
555     *ap = aa;
556     return GNUNET_OK;
557   }
558   if (ab->atsp_latency.rel_value > aa->atsp_latency.rel_value)
559   {
560     /* user lower latency */
561     *ap = aa;
562     return GNUNET_OK;
563   }
564   /* don't care */
565   return GNUNET_OK;
566 }
567
568
569 void
570 GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer,
571                       const char *plugin_name, const void *plugin_addr,
572                       size_t plugin_addr_len, uint32_t session_id, int in_use)
573 {
574 #if DEBUG_ATS
575   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576               "Received `%s' message for peer `%s': %i\n", "ADDRESS_IN_USE",
577               GNUNET_i2s (peer), in_use);
578 #endif
579
580   struct ATS_Address *aa;
581   struct ATS_Address *old;
582
583
584   aa = create_address(peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
585   old = find_exact_address (peer, aa);
586   free_address (aa);
587
588   GNUNET_assert (old != NULL);
589   GNUNET_assert (old->used != in_use);
590   old->used = in_use;
591
592 #if HAVE_LIBGLPK
593   if (ats_mode == MLP)
594      GAS_mlp_address_update (mlp, addresses, old);
595 #endif
596 }
597
598
599 void request_address_mlp (const struct GNUNET_PeerIdentity *peer)
600 {
601   struct ATS_Address *aa;
602   aa = NULL;
603
604 #if HAVE_GLPK
605   /* Get preferred address from MLP */
606   struct ATS_PreferedAddress * paddr = NULL;
607   paddr = GAS_mlp_get_preferred_address (mlp, addresses, peer);
608   aa = paddr->address;
609   aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(paddr->bandwidth_out);
610   /* FIXME use bw in value */
611   paddr->bandwidth_in = paddr->bandwidth_out;
612   aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init (paddr->bandwidth_in);
613   GNUNET_free (paddr);
614 #endif
615
616   if (aa == NULL)
617   {
618     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
619                 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
620     return;
621   }
622   if (aa->active == GNUNET_NO)
623   {
624     aa->active = GNUNET_YES;
625     active_addr_count++;
626
627     send_bw_notification (aa);
628   }
629   else
630   {
631     /* just to be sure... */
632     GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
633                                                 aa->addr_len, aa->session_id,
634                                                 aa->ats, aa->ats_count,
635                                                 aa->assigned_bw_out,
636                                                 aa->assigned_bw_in);
637   }
638
639 }
640
641 void request_address_simple (const struct GNUNET_PeerIdentity *peer)
642 {
643   struct ATS_Address *aa;
644   aa = NULL;
645
646   /* Get address with: stick to current address, lower distance, lower latency */
647   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
648                                               &find_address_it, &aa);
649   if (aa == NULL)
650   {
651     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
652                 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
653     return;
654   }
655
656   if (aa->active == GNUNET_NO)
657   {
658     aa->active = GNUNET_YES;
659     active_addr_count++;
660     if (ats_mode == SIMPLE)
661     {
662       recalculate_assigned_bw ();
663     }
664   }
665   else
666   {
667     /* just to be sure... */
668     GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
669                                                 aa->addr_len, aa->session_id,
670                                                 aa->ats, aa->ats_count,
671                                                 aa->assigned_bw_out,
672                                                 aa->assigned_bw_in);
673   }
674 }
675
676
677 void
678 GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
679 {
680   if (ats_mode == SIMPLE)
681   {
682     request_address_simple (peer);
683   }
684   if (ats_mode == MLP)
685   {
686     request_address_mlp(peer);
687   }
688 }
689
690
691 // FIXME: this function should likely end up in the LP-subsystem and
692 // not with 'addresses' in the future...
693 void
694 GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
695                                  enum GNUNET_ATS_PreferenceKind kind,
696                                  float score)
697 {
698 #if HAVE_LIBGLPK
699   if (ats_mode == MLP)
700     GAS_mlp_address_change_preference (mlp, peer, kind, score);
701 #endif
702 }
703
704
705
706 /**
707  * Initialize address subsystem.
708  *
709  * @param cfg configuration to use
710  * @param stats the statistics handle to use
711  */
712 void
713 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
714                     const struct GNUNET_STATISTICS_Handle *stats)
715 {
716   int mode;
717
718   char *quota_wan_in_str;
719   char *quota_wan_out_str;
720
721   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", "WAN_QUOTA_IN", &quota_wan_in_str))
722   {
723     if (0 == strcmp(quota_wan_in_str, "unlimited") ||
724         (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_wan_in_str, &wan_quota_in)))
725       wan_quota_in = (UINT32_MAX) /10;
726
727     GNUNET_free (quota_wan_in_str);
728     quota_wan_in_str = NULL;
729   }
730   else
731   {
732     wan_quota_in = (UINT32_MAX) /10;
733   }
734
735   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", "WAN_QUOTA_OUT", &quota_wan_out_str))
736   {
737     if (0 == strcmp(quota_wan_out_str, "unlimited") ||
738         (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_wan_out_str, &wan_quota_out)))
739       wan_quota_out = (UINT32_MAX) /10;
740
741     GNUNET_free (quota_wan_out_str);
742     quota_wan_out_str = NULL;
743   }
744   else
745   {
746     wan_quota_out = (UINT32_MAX) /10;
747   }
748
749
750   mode = GNUNET_CONFIGURATION_get_value_yesno (cfg, "ats", "MLP");
751   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode %u", mode);
752   switch (mode)
753   {
754     /* MLP = YES */
755     case GNUNET_YES:
756 #if HAVE_LIBGLPK
757       ats_mode = MLP;
758       /* Init the MLP solver with default values */
759       mlp = GAS_mlp_init (cfg, stats, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS);
760       if (NULL == mlp)
761       {
762         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode was configured, but libglpk is not installed, switching to simple mode\n");
763         GNUNET_STATISTICS_update (GSA_stats, "MLP mode enabled", 0, GNUNET_NO);
764         break;
765       }
766       else
767       {
768         GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 1, GNUNET_NO);
769         break;
770       }
771 #else
772       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode was configured, but libglpk is not installed, switching to simple mode");
773       GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO);
774       ats_mode = SIMPLE;
775       break;
776 #endif
777     /* MLP = NO */
778     case GNUNET_NO:
779       GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO);
780       ats_mode = SIMPLE;
781       break;
782     /* No configuration value */
783     case GNUNET_SYSERR:
784       GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO);
785       ats_mode = SIMPLE;
786       break;
787     default:
788       break;
789   }
790   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started with %s mode\n", (SIMPLE == ats_mode) ? "SIMPLE" : "MLP");
791   addresses = GNUNET_CONTAINER_multihashmap_create (128);
792 }
793
794
795 /**
796  * Free memory of address.
797  *
798  * @param cls NULL
799  * @param key peer identity (unused)
800  * @param value the 'struct ATS_Address' to free
801  * @return GNUNET_OK (continue to iterate)
802  */
803 static int
804 free_address_it (void *cls, const GNUNET_HashCode * key, void *value)
805 {
806   struct ATS_Address *aa = value;
807
808   destroy_address (aa);
809   return GNUNET_OK;
810 }
811
812
813 void
814 GAS_addresses_destroy_all ()
815 {
816   if (addresses != NULL)
817     GNUNET_CONTAINER_multihashmap_iterate (addresses, &free_address_it, NULL);
818   GNUNET_assert (active_addr_count == 0);
819 }
820
821
822 /**
823  * Shutdown address subsystem.
824  */
825 void
826 GAS_addresses_done ()
827 {
828   GAS_addresses_destroy_all ();
829   GNUNET_CONTAINER_multihashmap_destroy (addresses);
830   addresses = NULL;
831 #if HAVE_LIBGLPK
832   if (ats_mode == MLP)
833   {
834     GAS_mlp_done (mlp);
835   }
836 #endif
837
838 }
839
840
841 /* end of gnunet-service-ats_addresses.c */