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