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