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