docu
[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 #include "gnunet-service-ats_addresses_simplistic.h"
38
39 /**
40  * ATS addresses : ATS address management
41  *
42  * General
43  *
44  * This component manages the addresses known to ATS service and suggests
45  * addresses to transport service when it is interested in address suggestions
46  * for a peer.
47  *
48  * Address management and suggestions
49  *
50  * Transport service notifies ATS about changes to the addresses known to him.
51  * When transport learns a new address it tells ATS about it using
52  * GAS_address_add.
53  *
54  * Bandwidth assignment
55  *
56  * The addresses are used to perform resource allocation operations. ATS
57  * addresses takes care of instantiating the solver configured and notifies the
58  * respective solver about address changes and receives changes to the bandwidth
59  * assignment from the solver. The current bandwidth assignment is sent to
60  * transport.
61  *
62  *
63  * Address lifecycle:
64  *
65  * Adding addresses:
66  *
67  * - If you add a new address without a session, a new address will be added
68  * - If you add this address again now with a session a, the existing address
69  *   will be updated with this session
70  * - If you add this address again now with a session b, a new address object
71  *   with this session will be added
72
73  * Destroying addresses:
74  *
75  * - If you destroy an address without a session, the address itself and all
76  *   address instances with an session will be removed
77  * - If you destroy an address with a session, the session for this address
78  *   will be removed
79  *
80  * Conclusion
81  * Addresses without a session will be updated with a new session and if the
82  * the session is destroyed the session is removed and address itself still
83  * exists for suggestion
84  *
85  */
86
87
88 /**
89  * Available ressource assignment modes
90  */
91 enum ATS_Mode
92 {
93   /*
94    * Simplistic mode:
95    *
96    * Assign each peer an equal amount of bandwidth (bw)
97    *
98    * bw_per_peer = bw_total / #active addresses
99    */
100   MODE_SIMPLISTIC,
101
102   /*
103    * MLP mode:
104    *
105    * Solve ressource assignment as an optimization problem
106    * Uses an mixed integer programming solver
107    */
108   MODE_MLP
109 };
110
111 /**
112  * Pending Address suggestion requests
113  */
114 struct GAS_Addresses_Suggestion_Requests
115 {
116   /**
117    * Next in DLL
118    */
119   struct GAS_Addresses_Suggestion_Requests *next;
120
121   /**
122    * Previous in DLL
123    */
124   struct GAS_Addresses_Suggestion_Requests *prev;
125
126   /**
127    * Peer ID
128    */
129   struct GNUNET_PeerIdentity id;
130 };
131
132 /**
133  * Handle for ATS address component
134  */
135 struct GAS_Addresses_Handle
136 {
137   /**
138    *
139    */
140   struct GNUNET_STATISTICS_Handle *stat;
141
142   /**
143    * A multihashmap to store all addresses
144    */
145   struct GNUNET_CONTAINER_MultiHashMap *addresses;
146
147   /**
148    * Configure WAN quota in
149    */
150   unsigned long long wan_quota_in;
151
152   /**
153    * Configure WAN quota out
154    */
155   unsigned long long wan_quota_out;
156
157   /**
158    * Is ATS addresses running
159    */
160   int running;
161
162   /**
163    * Configured ATS solver
164    */
165   int ats_mode;
166
167   /**
168    *  Solver handle
169    */
170   void *solver;
171
172   /**
173    * Address suggestion requests DLL head
174    */
175   struct GAS_Addresses_Suggestion_Requests *r_head;
176
177   /**
178    * Address suggestion requests DLL tail
179    */
180   struct GAS_Addresses_Suggestion_Requests *r_tail;
181
182   /* Solver functions */
183
184   /**
185    * Initialize solver
186    */
187   GAS_solver_init s_init;
188
189   /**
190    * Add an address to the solver
191    */
192   GAS_solver_address_add s_add;
193
194   /**
195    * Update address in solver
196    */
197   GAS_solver_address_update s_update;
198
199   /**
200    * Get address from solver
201    */
202   GAS_solver_get_preferred_address s_get;
203
204   /**
205    * Delete address in solver
206    */
207   GAS_solver_address_delete s_del;
208
209   /**
210    * Change preference for quality in solver
211    */
212   GAS_solver_address_change_preference s_pref;
213
214   /**
215    * Shutdown solver
216    */
217   GAS_solver_done s_done;
218 };
219
220
221 static unsigned int
222 assemble_ats_information (const struct ATS_Address *aa,  struct GNUNET_ATS_Information **dest)
223 {
224   unsigned int ats_count = GNUNET_ATS_PropertyCount - 1;
225   struct GNUNET_ATS_Information *ats = GNUNET_malloc (ats_count * sizeof (struct GNUNET_ATS_Information));
226   (*dest) = ats;
227
228   ats[0].type = ntohl(GNUNET_ATS_UTILIZATION_UP);
229   ats[0].value = aa->atsp_utilization_out.value__;
230   ats[1].type = ntohl(GNUNET_ATS_UTILIZATION_DOWN);
231   ats[1].value = aa->atsp_utilization_in.value__;
232   ats[2].type = ntohl(GNUNET_ATS_NETWORK_TYPE);
233   ats[2].value = ntohl(aa->atsp_network_type);
234   ats[3].type = ntohl(GNUNET_ATS_QUALITY_NET_DELAY);
235   ats[3].value = ntohl(aa->atsp_latency.rel_value);
236   ats[4].type = ntohl(GNUNET_ATS_QUALITY_NET_DISTANCE);
237   ats[4].value = ntohl(aa->atsp_distance);
238   ats[5].type = ntohl(GNUNET_ATS_COST_WAN);
239   ats[5].value = ntohl (aa->atsp_cost_wan);
240   ats[6].type = ntohl(GNUNET_ATS_COST_LAN);
241   ats[6].value = ntohl (aa->atsp_cost_lan);
242   ats[7].type = ntohl(GNUNET_ATS_COST_WLAN);
243   ats[7].value = ntohl (aa->atsp_cost_wlan);
244   return ats_count;
245 }
246
247 static unsigned int
248 disassemble_ats_information (const struct GNUNET_ATS_Information *src,
249                              uint32_t ats_count,
250                              struct ATS_Address *dest)
251 {
252   int i;
253   int res = 0;
254   for (i = 0; i < ats_count; i++)
255     switch (ntohl (src[i].type))
256     {
257     case GNUNET_ATS_UTILIZATION_UP:
258       dest->atsp_utilization_out.value__ = src[i].value;
259       res ++;
260       break;
261     case GNUNET_ATS_UTILIZATION_DOWN:
262       dest->atsp_utilization_in.value__ = src[i].value;
263       res ++;
264       break;
265     case GNUNET_ATS_QUALITY_NET_DELAY:
266       dest->atsp_latency.rel_value = ntohl (src[i].value);
267       res ++;
268       break;
269     case GNUNET_ATS_QUALITY_NET_DISTANCE:
270       dest->atsp_distance = ntohl (src[i].value);
271       res ++;
272       break;
273     case GNUNET_ATS_COST_WAN:
274       dest->atsp_cost_wan = ntohl (src[i].value);
275       res ++;
276       break;
277     case GNUNET_ATS_COST_LAN:
278       dest->atsp_cost_lan = ntohl (src[i].value);
279       res ++;
280       break;
281     case GNUNET_ATS_COST_WLAN:
282       dest->atsp_cost_wlan = ntohl (src[i].value);
283       res ++;
284       break;
285     case GNUNET_ATS_NETWORK_TYPE:
286       dest->atsp_network_type = ntohl (src[i].value);
287       res ++;
288       break;
289     case GNUNET_ATS_ARRAY_TERMINATOR:
290       break;
291     default:
292       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
293                   "Received unsupported ATS type %u\n", ntohl (src[i].type));
294       GNUNET_break (0);
295       break;
296     }
297   return res;
298 }
299
300 /**
301  * Free the given address
302  * @param addr address to destroy
303  */
304 static void
305 free_address (struct ATS_Address *addr)
306 {
307   GNUNET_free (addr->plugin);
308   GNUNET_free (addr);
309 }
310
311 /**
312  * Create a ATS_address with the given information
313  * @param peer peer
314  * @param plugin_name plugin
315  * @param plugin_addr address
316  * @param plugin_addr_len address length
317  * @param session_id session
318  * @return the ATS_Address
319  */
320 static struct ATS_Address *
321 create_address (const struct GNUNET_PeerIdentity *peer,
322                 const char *plugin_name,
323                 const void *plugin_addr, size_t plugin_addr_len,
324                 uint32_t session_id)
325 {
326   struct ATS_Address *aa = NULL;
327
328   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
329   aa->peer = *peer;
330   aa->addr_len = plugin_addr_len;
331   aa->addr = &aa[1];
332   memcpy (&aa[1], plugin_addr, plugin_addr_len);
333   aa->plugin = GNUNET_strdup (plugin_name);
334   aa->session_id = session_id;
335   aa->active = GNUNET_NO;
336   aa->used = GNUNET_NO;
337   aa->solver_information = NULL;
338   aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init(0);
339   aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(0);
340   return aa;
341 }
342
343
344 /**
345  * Destroy the given address.
346  *
347  * @param handle the address handle
348  * @param addr address to destroy
349  * @return GNUNET_YES if bandwidth allocations should be recalcualted
350  */
351 static int
352 destroy_address (struct GAS_Addresses_Handle *handle, struct ATS_Address *addr)
353 {
354   int ret;
355
356   ret = GNUNET_NO;
357   GNUNET_assert (GNUNET_YES ==
358                  GNUNET_CONTAINER_multihashmap_remove (handle->addresses,
359                                                        &addr->peer.hashPubKey,
360                                                        addr));
361   free_address (addr);
362   return ret;
363 }
364
365
366 struct CompareAddressContext
367 {
368   const struct ATS_Address *search;
369
370   /* exact_address != NULL if address and session is equal */
371   struct ATS_Address *exact_address;
372   /* exact_address != NULL if address and session is 0 */
373   struct ATS_Address *base_address;
374 };
375
376
377 static int
378 compare_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
379 {
380   struct CompareAddressContext *cac = cls;
381   struct ATS_Address *aa = value;
382
383   /* Find an matching exact address:
384    *
385    * Compare by:
386    * aa->addr_len == cac->search->addr_len
387    * aa->plugin == cac->search->plugin
388    * aa->addr == cac->search->addr
389    * aa->session == cac->search->session
390    *
391    * return as exact address
392    */
393   if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
394   {
395       if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
396         cac->exact_address = aa;
397   }
398
399   /* Find an matching base address:
400    *
401    * Properties:
402    *
403    * aa->session_id == 0
404    *
405    * Compare by:
406    * aa->addr_len == cac->search->addr_len
407    * aa->plugin == cac->search->plugin
408    * aa->addr == cac->search->addr
409    *
410    * return as base address
411    */
412   if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
413   {
414       if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0))
415         cac->base_address = aa;
416   }
417
418   /* Find an matching exact address based on session:
419    *
420    * Properties:
421    *
422    * cac->search->addr_len == 0
423    *
424    * Compare by:
425    * aa->plugin == cac->search->plugin
426    * aa->session_id == cac->search->session_id
427    *
428    * return as exact address
429    */
430   if (0 == cac->search->addr_len)
431   {
432       if ((0 == strcmp (aa->plugin, cac->search->plugin)) && (aa->session_id == cac->search->session_id))
433         cac->exact_address = aa;
434   }
435
436   if (cac->exact_address == NULL)
437     return GNUNET_YES; /* Continue iteration to find exact address */
438   else
439     return GNUNET_NO; /* Stop iteration since we have an exact address */
440 }
441
442
443 /**
444  * Find an existing equivalent address record.
445  * Compares by peer identity and network address OR by session ID
446  * (one of the two must match).
447  *
448  * @param handle the address handle
449  * @param peer peer to lookup addresses for
450  * @param addr existing address record
451  * @return existing address record, NULL for none
452  */
453 struct ATS_Address *
454 find_equivalent_address (struct GAS_Addresses_Handle *handle,
455                          const struct GNUNET_PeerIdentity *peer,
456                          const struct ATS_Address *addr)
457 {
458   struct CompareAddressContext cac;
459
460   cac.exact_address = NULL;
461   cac.base_address = NULL;
462   cac.search = addr;
463   GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
464                                               &compare_address_it, &cac);
465
466   if (cac.exact_address == NULL)
467     return cac.base_address;
468   return cac.exact_address;
469 }
470
471
472 static struct ATS_Address *
473 lookup_address (struct GAS_Addresses_Handle *handle,
474                 const struct GNUNET_PeerIdentity *peer,
475                 const char *plugin_name,
476                 const void *plugin_addr,
477                 size_t plugin_addr_len,
478                 uint32_t session_id,
479                 const struct GNUNET_ATS_Information *atsi,
480                 uint32_t atsi_count)
481 {
482   struct ATS_Address *aa;
483   struct ATS_Address *ea;
484
485   aa = create_address (peer,
486                        plugin_name,
487                        plugin_addr, plugin_addr_len,
488                        session_id);
489
490   /* Get existing address or address with session == 0 */
491   ea = find_equivalent_address (handle, peer, aa);
492   free_address (aa);
493   if (ea == NULL)
494   {
495     return NULL;
496   }
497   else if (ea->session_id != session_id)
498   {
499     return NULL;
500   }
501   return ea;
502 }
503
504
505 void
506 GAS_addresses_add (struct GAS_Addresses_Handle *handle,
507                    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                    const struct GNUNET_ATS_Information *atsi,
511                    uint32_t atsi_count)
512 {
513   struct ATS_Address *aa;
514   struct ATS_Address *ea;
515   unsigned int ats_res;
516
517   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518               "Received `%s' for peer `%s'\n",
519               "ADDRESS ADD",
520               GNUNET_i2s (peer));
521
522   if (GNUNET_NO == handle->running)
523     return;
524
525   GNUNET_assert (NULL != handle->addresses);
526
527   aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
528                        session_id);
529   if (atsi_count != (ats_res = disassemble_ats_information(atsi, atsi_count, aa)))
530   {
531       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
532                 "While adding address: had %u ATS elements to add, could only add %u\n",
533                 atsi_count, ats_res);
534   }
535
536   /* Get existing address or address with session == 0 */
537   ea = find_equivalent_address (handle, peer, aa);
538   if (ea == NULL)
539   {
540     /* We have a new address */
541     GNUNET_assert (GNUNET_OK ==
542                    GNUNET_CONTAINER_multihashmap_put (handle->addresses,
543                                                       &peer->hashPubKey, aa,
544                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
545     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' session id %u, %p\n",
546                 GNUNET_i2s (peer), session_id, aa);
547     /* Tell solver about new address */
548     handle->s_add (handle->solver, handle->addresses, aa);
549     return;
550   }
551   GNUNET_free (aa->plugin);
552   GNUNET_free (aa);
553
554   if (ea->session_id != 0)
555   {
556       /* This address with the same session is already existing
557        * Should not happen */
558       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
559                 "Added already existing address for peer `%s' `%s' %p with new session %u\n",
560                 GNUNET_i2s (peer), plugin_name, session_id);
561       GNUNET_break (0);
562       return;
563   }
564
565   /* We have an address without an session, update this address */
566
567   /* Notify solver about update with atsi information and session */
568   handle->s_update (handle->solver, handle->addresses, ea, session_id, ea->used, atsi, atsi_count);
569
570   /* Do the update */
571   ea->session_id = session_id;
572   if (atsi_count != (ats_res = disassemble_ats_information(atsi, atsi_count, ea)))
573   {
574       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
575                   "While updating address: had %u ATS elements to add, could only add %u\n",
576                   atsi_count, ats_res);
577   }
578   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
579            "Updated existing address for peer `%s' %p with new session %u\n",
580            GNUNET_i2s (peer), ea, session_id);
581 }
582
583
584 void
585 GAS_addresses_update (struct GAS_Addresses_Handle *handle,
586                       const struct GNUNET_PeerIdentity *peer,
587                       const char *plugin_name, const void *plugin_addr,
588                       size_t plugin_addr_len, uint32_t session_id,
589                       const struct GNUNET_ATS_Information *atsi,
590                       uint32_t atsi_count)
591 {
592   struct ATS_Address *aa;
593   uint32_t ats_res;
594
595   if (GNUNET_NO == handle->running)
596     return;
597
598   GNUNET_assert (NULL != handle->addresses);
599
600   /* Get existing address */
601   aa = lookup_address (handle, peer, plugin_name, plugin_addr, plugin_addr_len,
602                        session_id, atsi, atsi_count);
603   if (aa == NULL)
604   {
605     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to update unknown address for peer `%s' `%s' session id %u\n",
606                 GNUNET_i2s (peer), plugin_name, session_id);
607     GNUNET_break (0);
608     return;
609   }
610
611   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
612                 "Received `%s' for peer `%s' address \n",
613                 "ADDRESS UPDATE",
614                 GNUNET_i2s (peer), aa);
615
616   /* Tell solver about update */
617   handle->s_update (handle->solver, handle->addresses, aa, session_id, aa->used, atsi, atsi_count);
618
619   /* Update address */
620   if (atsi_count != (ats_res = disassemble_ats_information (atsi, atsi_count, aa)))
621   {
622       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
623                 "While adding address: had %u ATS elements to add, could only add %u\n",
624                 atsi_count, ats_res);
625   }
626   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
627             "Updated %u ATS elements for address %p\n",
628             ats_res, aa);
629 }
630
631
632 struct DestroyContext
633 {
634   struct ATS_Address *aa;
635
636   struct GAS_Addresses_Handle *handle;
637
638   /**
639    * GNUNET_NO  : full address
640    * GNUNET_YES : just session
641    */
642   int result;
643 };
644
645
646 /**
647  * Delete an address
648  *
649  * If session != 0, just the session is deleted, the address itself still exists
650  * If session == 0, remove full address
651  * If session == 0 and addrlen == 0, destroy inbound address
652  *
653  * @param cls unused
654  * @param key unused
655  * @param value the 'struct ATS_Address'
656  * @return GNUNET_OK (continue to iterate)
657  */
658 static int
659 destroy_by_session_id (void *cls, const struct GNUNET_HashCode * key, void *value)
660 {
661   struct DestroyContext *dc = cls;
662   struct GAS_Addresses_Handle *handle = dc->handle;
663   const struct ATS_Address *des = dc->aa;
664   struct ATS_Address *aa = value;
665
666   GNUNET_assert (0 == memcmp (&aa->peer, &des->peer,
667                               sizeof (struct GNUNET_PeerIdentity)));
668
669
670   if (des->session_id == 0)
671   {
672     /* Session == 0, remove full address  */
673     if ((0 == strcmp (des->plugin, aa->plugin)) &&
674         (aa->addr_len == des->addr_len) &&
675         (0 == memcmp (des->addr, aa->addr, aa->addr_len)))
676     {
677
678       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
679                   "Deleting full address for peer `%s' session %u %p\n",
680                   GNUNET_i2s (&aa->peer), aa->session_id, aa);
681
682       /* Notify solver about deletion */
683       handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
684       destroy_address (handle, aa);
685       dc->result = GNUNET_NO;
686       return GNUNET_OK; /* Continue iteration */
687     }
688   }
689   else
690   {
691     /* Session != 0, just remove session */
692     if (aa->session_id != des->session_id)
693       return GNUNET_OK; /* irrelevant */
694
695     if ((aa->session_id != 0) &&
696         (0 != strcmp (des->plugin, aa->plugin)))
697     {
698         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699                     "Different plugins during removal: `%s' vs `%s' \n",
700                     des->plugin, aa->plugin);
701         GNUNET_break (0);
702         return GNUNET_OK;
703     }
704
705     if (aa->addr_len == 0)
706     {
707         /* Inbound connection died, delete full address */
708         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709                     "Deleting inbound address for peer `%s': `%s' session %u\n",
710                     GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
711
712         /* Notify solver about deletion */
713         handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
714         destroy_address (handle, aa);
715         dc->result = GNUNET_NO;
716         return GNUNET_OK; /* Continue iteration */
717     }
718     else
719     {
720         /* Session died */
721         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
722                     "Deleting session for peer `%s': `%s' %u\n",
723                     GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
724         /* Notify solver to delete session */
725         handle->s_del (handle->solver, handle->addresses, aa, GNUNET_YES);
726         aa->session_id = 0;
727         return GNUNET_OK;
728     }
729   }
730   return GNUNET_OK;
731 }
732
733 void
734 GAS_addresses_destroy (struct GAS_Addresses_Handle *handle,
735                        const struct GNUNET_PeerIdentity *peer,
736                        const char *plugin_name, const void *plugin_addr,
737                        size_t plugin_addr_len, uint32_t session_id)
738 {
739   struct ATS_Address *ea;
740   struct DestroyContext dc;
741
742   if (GNUNET_NO == handle->running)
743     return;
744
745   /* Get existing address */
746   ea = lookup_address (handle, peer, plugin_name, plugin_addr, plugin_addr_len,
747                        session_id, NULL, 0);
748
749   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
750               "Received `%s' for peer `%s' address %p session %u\n",
751               "ADDRESS DESTROY",
752               GNUNET_i2s (peer), ea, session_id);
753
754   if (ea == NULL)
755   {
756     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tried to destroy unknown address for peer `%s' `%s' session id %u\n",
757                 GNUNET_i2s (peer), plugin_name, session_id);
758     return;
759   }
760
761   GNUNET_break (0 < strlen (plugin_name));
762   dc.handle = handle;
763   dc.aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
764
765   GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
766                                               &destroy_by_session_id, &dc);
767   free_address (dc.aa);
768 }
769
770
771 int
772 GAS_addresses_in_use (struct GAS_Addresses_Handle *handle,
773                       const struct GNUNET_PeerIdentity *peer,
774                       const char *plugin_name, const void *plugin_addr,
775                       size_t plugin_addr_len, uint32_t session_id, int in_use)
776 {
777   struct ATS_Address *ea;
778
779   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
780                 "Received `%s' for peer `%s'\n",
781                 "ADDRESS IN USE",
782                 GNUNET_i2s (peer));
783
784   if (GNUNET_NO == handle->running)
785     return GNUNET_SYSERR;
786
787   ea = lookup_address (handle, peer, plugin_name,
788                         plugin_addr, plugin_addr_len,
789                         session_id, NULL, 0);
790   if (NULL == ea)
791   {
792     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
793                 "Trying to set unknown address `%s', %s %u %s \n",
794                 GNUNET_i2s (peer),
795                 plugin_name, session_id,
796                 (GNUNET_NO == in_use) ? "NO" : "YES");
797     GNUNET_break (0);
798     return GNUNET_SYSERR;
799   }
800   if (ea->used == in_use)
801   {
802     GNUNET_break (0);
803     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
804                 "Address in use called multiple times for peer `%s': %s -> %s \n",
805                 GNUNET_i2s (peer),
806                 (GNUNET_NO == ea->used) ? "NO" : "YES",
807                 (GNUNET_NO == in_use) ? "NO" : "YES");
808     return GNUNET_SYSERR;
809   }
810
811   /* Tell solver about update */
812   handle->s_update (handle->solver, handle->addresses, ea, session_id, in_use, NULL, 0);
813   ea->used = in_use;
814
815   return GNUNET_OK;
816 }
817
818
819 /**
820  * Cancel address suggestions for a peer
821  *
822  * @param handle the address handle
823  * @param peer the respective peer
824  */
825 void
826 GAS_addresses_request_address_cancel (struct GAS_Addresses_Handle *handle,
827                                       const struct GNUNET_PeerIdentity *peer)
828 {
829   struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
830
831   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
832               "Received request: `%s' for peer %s\n", "request_address_cancel", GNUNET_i2s (peer));
833
834   while (NULL != cur)
835   {
836       if (0 == memcmp (peer, &cur->id, sizeof (cur->id)))
837         break; /* found */
838       cur = cur->next;
839   }
840
841   if (NULL == cur)
842   {
843       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
844                   "No address requests pending for peer `%s', cannot remove!\n", GNUNET_i2s (peer));
845       return;
846   }
847   GAS_addresses_handle_backoff_reset (handle, peer);
848   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849               "Removed request pending for peer `%s\n", GNUNET_i2s (peer));
850   GNUNET_CONTAINER_DLL_remove (handle->r_head, handle->r_tail, cur);
851   GNUNET_free (cur);
852 }
853
854
855 /**
856  * Add an address suggestions for a peer
857  *
858  * @param handle the address handle
859  * @param peer the respective peer
860  */
861 void
862 GAS_addresses_request_address (struct GAS_Addresses_Handle *handle,
863                                const struct GNUNET_PeerIdentity *peer)
864 {
865   struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
866   struct ATS_Address *aa;
867   struct GNUNET_ATS_Information *ats;
868   unsigned int ats_count;
869
870   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
871               "Received `%s' for peer `%s'\n",
872               "REQUEST ADDRESS",
873               GNUNET_i2s (peer));
874
875   if (GNUNET_NO == handle->running)
876     return;
877   while (NULL != cur)
878   {
879       if (0 == memcmp (peer, &cur->id, sizeof (cur->id)))
880         break; /* already suggesting */
881       cur = cur->next;
882   }
883   if (NULL == cur)
884   {
885       cur = GNUNET_malloc (sizeof (struct GAS_Addresses_Suggestion_Requests));
886       cur->id = (*peer);
887       GNUNET_CONTAINER_DLL_insert (handle->r_head, handle->r_tail, cur);
888   }
889
890   /* Get prefered address from solver */
891   aa = (struct ATS_Address *) handle->s_get (handle->solver, handle->addresses, peer);
892   if (NULL == aa)
893   {
894     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
895                 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
896     return;
897   }
898
899   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
900               "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer));
901
902   ats_count = assemble_ats_information (aa, &ats);
903   GAS_scheduling_transmit_address_suggestion (peer,
904                                               aa->plugin,
905                                               aa->addr, aa->addr_len,
906                                               aa->session_id,
907                                               ats, ats_count,
908                                               aa->assigned_bw_out,
909                                               aa->assigned_bw_in);
910
911   aa->block_interval = GNUNET_TIME_relative_add (aa->block_interval, ATS_BLOCKING_DELTA);
912   aa->blocked_until = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), aa->block_interval);
913
914   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
915        "Address %p ready for suggestion, block interval now %llu \n",
916        aa, aa->block_interval);
917
918   GNUNET_free (ats);
919 }
920
921
922 static int
923 reset_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
924 {
925   struct ATS_Address *aa = value;
926
927   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
928               "Resetting interval for peer `%s' address %p from %llu to 0\n",
929               GNUNET_i2s (&aa->peer), aa, aa->block_interval);
930
931   aa->blocked_until = GNUNET_TIME_UNIT_ZERO_ABS;
932   aa->block_interval = GNUNET_TIME_UNIT_ZERO;
933   return GNUNET_OK;
934 }
935
936
937 void
938 GAS_addresses_handle_backoff_reset (struct GAS_Addresses_Handle *handle,
939                                     const struct GNUNET_PeerIdentity *peer)
940 {
941   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
942               "Received `%s' for peer `%s'\n",
943               "RESET BACKOFF",
944               GNUNET_i2s (peer));
945
946   GNUNET_break (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses,
947                                               &peer->hashPubKey,
948                                               &reset_address_it,
949                                               NULL));
950 }
951
952
953 void
954 GAS_addresses_change_preference (struct GAS_Addresses_Handle *handle,
955                                  void *client,
956                                  const struct GNUNET_PeerIdentity *peer,
957                                  enum GNUNET_ATS_PreferenceKind kind,
958                                  float score)
959 {
960   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
961               "Received `%s' for peer `%s' for client %p\n",
962               "CHANGE PREFERENCE",
963               GNUNET_i2s (peer), client);
964
965   if (GNUNET_NO == handle->running)
966     return;
967
968   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->addresses,
969                                                           &peer->hashPubKey))
970   {
971       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
972                   "Received `%s' for unknown peer `%s' from client %p\n",
973                   "CHANGE PREFERENCE",
974                   GNUNET_i2s (peer), client);
975       return;
976   }
977
978   /* Tell solver about update */
979   handle->s_pref (handle->solver, client, peer, kind, score);
980 }
981
982
983 /**
984  * Load quotas for networks from configuration
985  *
986  * @param cfg configuration handle
987  * @param out_dest where to write outbound quotas
988  * @param in_dest where to write inbound quotas
989  * @param dest_length length of inbound and outbound arrays
990  * @return number of networks loaded
991  */
992 static unsigned int
993 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
994 {
995   char *network_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
996   char * entry_in = NULL;
997   char * entry_out = NULL;
998   char * quota_out_str;
999   char * quota_in_str;
1000   int c;
1001   int res;
1002
1003   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
1004   {
1005     in_dest[c] = 0;
1006     out_dest[c] = 0;
1007     GNUNET_asprintf (&entry_out, "%s_QUOTA_OUT", network_str[c]);
1008     GNUNET_asprintf (&entry_in, "%s_QUOTA_IN", network_str[c]);
1009
1010     /* quota out */
1011     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, &quota_out_str))
1012     {
1013       res = GNUNET_NO;
1014       if (0 == strcmp(quota_out_str, BIG_M_STRING))
1015       {
1016         out_dest[c] = GNUNET_ATS_MaxBandwidth;
1017         res = GNUNET_YES;
1018       }
1019       if ((GNUNET_NO == res) && (GNUNET_OK == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &out_dest[c])))
1020         res = GNUNET_YES;
1021       if ((GNUNET_NO == res) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_out,  &out_dest[c])))
1022          res = GNUNET_YES;
1023
1024       if (GNUNET_NO == res)
1025       {
1026           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
1027               network_str[c], quota_out_str, GNUNET_ATS_DefaultBandwidth);
1028           out_dest[c] = GNUNET_ATS_DefaultBandwidth;
1029       }
1030       else
1031       {
1032           GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Outbound quota configure for network `%s' is %llu\n"),
1033               network_str[c], out_dest[c]);
1034       }
1035       GNUNET_free (quota_out_str);
1036     }
1037     else
1038     {
1039       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
1040           network_str[c], GNUNET_ATS_DefaultBandwidth);
1041       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
1042     }
1043
1044     /* quota in */
1045     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, &quota_in_str))
1046     {
1047       res = GNUNET_NO;
1048       if (0 == strcmp(quota_in_str, BIG_M_STRING))
1049       {
1050         in_dest[c] = GNUNET_ATS_MaxBandwidth;
1051         res = GNUNET_YES;
1052       }
1053       if ((GNUNET_NO == res) && (GNUNET_OK == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
1054         res = GNUNET_YES;
1055       if ((GNUNET_NO == res) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_in,  &in_dest[c])))
1056          res = GNUNET_YES;
1057
1058       if (GNUNET_NO == res)
1059       {
1060           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
1061               network_str[c], quota_in_str, GNUNET_ATS_DefaultBandwidth);
1062           in_dest[c] = GNUNET_ATS_DefaultBandwidth;
1063       }
1064       else
1065       {
1066           GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Inbound quota configured for network `%s' is %llu\n"),
1067               network_str[c], in_dest[c]);
1068       }
1069       GNUNET_free (quota_in_str);
1070     }
1071     else
1072     {
1073       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
1074           network_str[c], GNUNET_ATS_DefaultBandwidth);
1075       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
1076     }
1077     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded quota for network `%s' (in/out): %llu %llu\n", network_str[c], in_dest[c], out_dest[c]);
1078     GNUNET_free (entry_out);
1079     GNUNET_free (entry_in);
1080   }
1081   return GNUNET_ATS_NetworkTypeCount;
1082 }
1083
1084
1085 static void
1086 bandwidth_changed_cb (void *cls, struct ATS_Address *address)
1087 {
1088   struct GAS_Addresses_Handle *handle = cls;
1089   struct GAS_Addresses_Suggestion_Requests *cur;
1090
1091   GNUNET_assert (handle != NULL);
1092   GNUNET_assert (address != NULL);
1093
1094   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth assignment changed for peer %s \n", GNUNET_i2s(&address->peer));
1095   struct GNUNET_ATS_Information *ats;
1096   unsigned int ats_count;
1097
1098   cur = handle->r_head;
1099   while (NULL != cur)
1100   {
1101       if (0 == memcmp (&address->peer, &cur->id, sizeof (cur->id)))
1102         break; /* we have an address request pending*/
1103       cur = cur->next;
1104   }
1105   if (NULL == cur)
1106   {
1107       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108                   "Nobody is interested in peer `%s' :(\n",GNUNET_i2s (&address->peer));
1109       return;
1110   }
1111
1112   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1113               "Sending bandwidth update for peer `%s'\n",GNUNET_i2s (&address->peer));
1114
1115   ats_count = assemble_ats_information (address, &ats);
1116   GAS_scheduling_transmit_address_suggestion (&address->peer,
1117                                               address->plugin,
1118                                               address->addr, address->addr_len,
1119                                               address->session_id,
1120                                               ats, ats_count,
1121                                               address->assigned_bw_out,
1122                                               address->assigned_bw_in);
1123   GNUNET_free (ats);
1124 }
1125
1126
1127 /**
1128  * Initialize address subsystem.
1129  *
1130  * @param cfg configuration to use
1131  * @param stats the statistics handle to use
1132  */
1133 struct GAS_Addresses_Handle *
1134 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
1135                     const struct GNUNET_STATISTICS_Handle *stats)
1136 {
1137   struct GAS_Addresses_Handle *ah;
1138   int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1139   unsigned long long  quotas_in[GNUNET_ATS_NetworkTypeCount];
1140   unsigned long long  quotas_out[GNUNET_ATS_NetworkTypeCount];
1141   int quota_count;
1142   char *mode_str;
1143   int c;
1144
1145   ah = GNUNET_malloc (sizeof (struct GAS_Addresses_Handle));
1146   ah->running = GNUNET_NO;
1147
1148   ah->stat = (struct GNUNET_STATISTICS_Handle *) stats;
1149   /* Initialize the addresses database */
1150   ah->addresses = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
1151   GNUNET_assert (NULL != ah->addresses);
1152
1153   /* Figure out configured solution method */
1154   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
1155   {
1156       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "No ressource assignment method configured, using simplistic approch\n");
1157       ah->ats_mode = MODE_SIMPLISTIC;
1158   }
1159   else
1160   {
1161       for (c = 0; c < strlen (mode_str); c++)
1162         mode_str[c] = toupper (mode_str[c]);
1163       if (0 == strcmp (mode_str, "SIMPLISTIC"))
1164       {
1165           ah->ats_mode = MODE_SIMPLISTIC;
1166       }
1167       else if (0 == strcmp (mode_str, "MLP"))
1168       {
1169           ah->ats_mode = MODE_MLP;
1170 #if !HAVE_LIBGLPK
1171           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Assignment method `%s' configured, but GLPK is not availabe, please install \n", mode_str);
1172           ah->ats_mode = MODE_SIMPLISTIC;
1173 #endif
1174       }
1175       else
1176       {
1177           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid ressource assignment method `%s' configured, using simplistic approch\n", mode_str);
1178           ah->ats_mode = MODE_SIMPLISTIC;
1179       }
1180       GNUNET_free (mode_str);
1181   }
1182   /* Start configured solution method */
1183   switch (ah->ats_mode)
1184   {
1185     case MODE_MLP:
1186       /* Init the MLP solver with default values */
1187 #if HAVE_LIBGLPK
1188       ah->ats_mode = MODE_MLP;
1189       ah->s_init = &GAS_mlp_init;
1190       ah->s_add = &GAS_mlp_address_add;
1191       ah->s_update = &GAS_mlp_address_update;
1192       ah->s_get = &GAS_mlp_get_preferred_address;
1193       ah->s_pref = &GAS_mlp_address_change_preference;
1194       ah->s_del =  &GAS_mlp_address_delete;
1195       ah->s_done = &GAS_mlp_done;
1196 #else
1197       GNUNET_free (ah);
1198       return NULL;
1199 #endif
1200       break;
1201     case MODE_SIMPLISTIC:
1202       /* Init the simplistic solver with default values */
1203       ah->ats_mode = MODE_SIMPLISTIC;
1204       ah->s_init = &GAS_simplistic_init;
1205       ah->s_add = &GAS_simplistic_address_add;
1206       ah->s_update = &GAS_simplistic_address_update;
1207       ah->s_get = &GAS_simplistic_get_preferred_address;
1208       ah->s_pref = &GAS_simplistic_address_change_preference;
1209       ah->s_del  = &GAS_simplistic_address_delete;
1210       ah->s_done = &GAS_simplistic_done;
1211       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n", "SIMPLISTIC");
1212       break;
1213     default:
1214       return NULL;
1215       break;
1216   }
1217
1218   GNUNET_assert (NULL != ah->s_init);
1219   GNUNET_assert (NULL != ah->s_add);
1220   GNUNET_assert (NULL != ah->s_update);
1221   GNUNET_assert (NULL != ah->s_get);
1222   GNUNET_assert (NULL != ah->s_pref);
1223   GNUNET_assert (NULL != ah->s_del);
1224   GNUNET_assert (NULL != ah->s_done);
1225
1226   quota_count = load_quotas(cfg, quotas_in, quotas_out, GNUNET_ATS_NetworkTypeCount);
1227
1228   ah->solver = ah->s_init (cfg, stats, quotas, quotas_in, quotas_out, quota_count, &bandwidth_changed_cb, ah);
1229   if (NULL == ah->solver)
1230   {
1231     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to initialize solver!\n");
1232     GNUNET_free (ah);
1233     return NULL;
1234   }
1235
1236   /* up and running */
1237   ah->running = GNUNET_YES;
1238   return ah;
1239 }
1240
1241
1242 /**
1243  * Free memory of address.
1244  *
1245  * @param cls NULL
1246  * @param key peer identity (unused)
1247  * @param value the 'struct ATS_Address' to free
1248  * @return GNUNET_OK (continue to iterate)
1249  */
1250 static int
1251 free_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1252 {
1253   struct GAS_Addresses_Handle *handle = cls;
1254   struct ATS_Address *aa = value;
1255   handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
1256   destroy_address (handle, aa);
1257   return GNUNET_OK;
1258 }
1259
1260
1261 void
1262 GAS_addresses_destroy_all (struct GAS_Addresses_Handle *handle)
1263 {
1264   if (GNUNET_NO == handle->running)
1265     return;
1266
1267   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1268               "Received `%s'\n",
1269               "DESTROY ALL");
1270
1271   if (handle->addresses != NULL)
1272     GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &free_address_it, handle);
1273 }
1274
1275
1276 /**
1277  * Shutdown address subsystem.
1278  */
1279 void
1280 GAS_addresses_done (struct GAS_Addresses_Handle *handle)
1281 {
1282   struct GAS_Addresses_Suggestion_Requests *cur;
1283
1284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1285               "Shutting down addresses\n");
1286   GNUNET_assert (NULL != handle);
1287   GAS_addresses_destroy_all (handle);
1288   handle->running = GNUNET_NO;
1289   GNUNET_CONTAINER_multihashmap_destroy (handle->addresses);
1290   handle->addresses = NULL;
1291   while (NULL != (cur = handle->r_head))
1292   {
1293       GNUNET_CONTAINER_DLL_remove (handle->r_head, handle->r_tail, cur);
1294       GNUNET_free (cur);
1295   }
1296   handle->s_done (handle->solver);
1297   GNUNET_free (handle);
1298   /* Stop configured solution method */
1299
1300 }
1301
1302 struct PeerIteratorContext
1303 {
1304   GNUNET_ATS_Peer_Iterator it;
1305   void *it_cls;
1306   struct GNUNET_CONTAINER_MultiHashMap *peers_returned;
1307 };
1308
1309 static int
1310 peer_it (void *cls,
1311          const struct GNUNET_HashCode * key,
1312          void *value)
1313 {
1314   struct PeerIteratorContext *ip_ctx = cls;
1315   struct GNUNET_PeerIdentity tmp;
1316
1317   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(ip_ctx->peers_returned, key))
1318   {
1319       GNUNET_CONTAINER_multihashmap_put(ip_ctx->peers_returned, key, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1320       tmp.hashPubKey = (*key);
1321       ip_ctx->it (ip_ctx->it_cls, &tmp);
1322   }
1323
1324   return GNUNET_OK;
1325 }
1326
1327 /**
1328  * Return all peers currently known to ATS
1329  *
1330  * @param handle the address handle
1331  * @param p_it the iterator to call for every peer, callbach with id == NULL
1332  *        when done
1333  * @param p_it_cls the closure for the iterator
1334  */
1335 void
1336 GAS_addresses_iterate_peers (struct GAS_Addresses_Handle *handle, GNUNET_ATS_Peer_Iterator p_it, void *p_it_cls)
1337 {
1338   struct PeerIteratorContext ip_ctx;
1339   unsigned int size;
1340
1341   if (NULL == p_it)
1342       return;
1343   GNUNET_assert (NULL != handle->addresses);
1344
1345   size = GNUNET_CONTAINER_multihashmap_size(handle->addresses);
1346   if (0 != size)
1347   {
1348     ip_ctx.it = p_it;
1349     ip_ctx.it_cls = p_it_cls;
1350     ip_ctx.peers_returned = GNUNET_CONTAINER_multihashmap_create (size, GNUNET_NO);
1351     GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &peer_it, &ip_ctx);
1352     GNUNET_CONTAINER_multihashmap_destroy (ip_ctx.peers_returned);
1353   }
1354   p_it (p_it_cls, NULL);
1355 }
1356
1357 struct PeerInfoIteratorContext
1358 {
1359   GNUNET_ATS_PeerInfo_Iterator it;
1360   void *it_cls;
1361 };
1362
1363
1364 static int 
1365 peerinfo_it (void *cls,
1366              const struct GNUNET_HashCode * key,
1367              void *value)
1368 {
1369   struct PeerInfoIteratorContext *pi_ctx = cls;
1370   struct ATS_Address *addr = (struct ATS_Address *)  value;
1371   struct GNUNET_ATS_Information *ats;
1372   uint32_t ats_count;
1373
1374   if (NULL != pi_ctx->it)
1375   {
1376     ats_count = assemble_ats_information (addr, &ats);
1377
1378     pi_ctx->it (pi_ctx->it_cls,
1379                 &addr->peer,
1380                 addr->plugin,
1381                 addr->addr, addr->addr_len,
1382                 addr->active,
1383                 ats, ats_count,
1384                 addr->assigned_bw_out,
1385                 addr->assigned_bw_in);
1386     GNUNET_free (ats);
1387   }
1388   return GNUNET_YES;
1389 }
1390
1391
1392 /**
1393  * Return all peers currently known to ATS
1394  *
1395  * @param handle the address handle
1396  * @param peer the respective peer
1397  * @param pi_it the iterator to call for every peer
1398  * @param pi_it_cls the closure for the iterator
1399  */
1400 void
1401 GAS_addresses_get_peer_info (struct GAS_Addresses_Handle *handle,
1402                              const struct GNUNET_PeerIdentity *peer,
1403                              GNUNET_ATS_PeerInfo_Iterator pi_it,
1404                              void *pi_it_cls)
1405 {
1406   struct PeerInfoIteratorContext pi_ctx;
1407   struct GNUNET_BANDWIDTH_Value32NBO zero_bw;
1408   GNUNET_assert (NULL != peer);
1409   GNUNET_assert (NULL != handle->addresses);
1410   if (NULL == pi_it)
1411     return; /* does not make sense without callback */
1412
1413   zero_bw = GNUNET_BANDWIDTH_value_init (0);
1414   pi_ctx.it = pi_it;
1415   pi_ctx.it_cls = pi_it_cls;
1416
1417   GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey, &peerinfo_it, &pi_ctx);
1418
1419   if (NULL != pi_it)
1420     pi_it (pi_it_cls, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0, zero_bw, zero_bw);
1421
1422 }
1423
1424
1425 /* end of gnunet-service-ats_addresses.c */