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