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