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