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