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