fix assertion: address has to be removed from peermap before notifying solver
[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_ats_plugin.h"
30 #include "gnunet-service-ats.h"
31 #include "gnunet-service-ats_addresses.h"
32 #include "gnunet-service-ats_normalization.h"
33 #include "gnunet-service-ats_performance.h"
34 #include "gnunet-service-ats_scheduling.h"
35 #include "gnunet-service-ats_reservations.h"
36
37 #if 0
38 #if HAVE_LIBGLPK
39 #include "gnunet-service-ats-solver_mlp.h"
40 #endif
41 #include "gnunet-service-ats-solver_proportional.h"
42 #include "gnunet-service-ats-solver_ril.h"
43 #endif
44
45 /**
46  * NOTE: Do not change this documentation. This documentation is based on
47  * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
48  * use build_txt.sh to generate plaintext output
49  *
50  *   1 ATS addresses : ATS address management
51  *
52  *    This ATS addresses ("addresses") component manages the addresses known to
53  *    ATS service and suggests addresses to transport service when it is
54  *    interested in address suggestion for a peer. ATS addresses also
55  *    instantiates the bandwidth assignment mechanism (solver), notifies it
56  *    about changes to addresses and forwards changes to bandwidth assignments
57  *    to transport, depending if transport is interested in this change.
58  *
59  *     1.1 Input data
60  *
61  *       1.1.1 Addresses
62  *
63  *    Addresses are added by specifying peer ID, plugin, address, address length
64  *    and session, if available. ATS information can be specified if available.
65  *
66  *       1.1.2 Networks
67  *
68  *    ATS specifies a fix set of networks an address can belong to. For each
69  *    network an inbound and outbound quota will be specified. The available
70  *    networks and addtional helper varaibles are defined in
71  *    gnunet_ats_service.h. At the moment 5 networks are defined:
72  *      * GNUNET_ATS_NET_UNSPECIFIED
73  *      * GNUNET_ATS_NET_LOOPBACK
74  *      * GNUNET_ATS_NET_LAN
75  *      * GNUNET_ATS_NET_WAN
76  *      * GNUNET_ATS_NET_WLAN
77  *
78  *    The total number of networks defined is stored in
79  *    GNUNET_ATS_NetworkTypeCount GNUNET_ATS_NetworkType can be used array
80  *    initializer for an int array, while GNUNET_ATS_NetworkType is an
81  *    initializer for a char array containing a string description of all
82  *    networks
83  *
84  *       1.1.3 Quotas
85  *
86  *    An inbound and outbound quota for each of the networks mentioned in 1.1.2
87  *    is loaded from ats configuration during initialization. This quota defines
88  *    to total amount of inbound and outbound traffic allowed for a specific
89  *    network. The configuration values used are in section ats:
90  *      * "NETWORK"_QUOTA_IN = <value>
91  *      * "NETWORK"_QUOTA_IN = <value>
92  *
93  *    You can specify quotas by setting the <value> to a:
94  *      * unrestricted: unlimited
95  *      * number of bytes: e.g. 10240
96  *      * fancy value: e.g. 64 Kib
97  *
98  *    unlimited is defined as GNUNET_ATS_MaxBandwidthString and equivalent to
99  *    the value GNUNET_ATS_MaxBandwidth Important predefined values for quotas
100  *    are:
101  *      * GNUNET_ATS_DefaultBandwidth: 65536
102  *      * GNUNET_ATS_MaxBandwidth: UINT32_MAX
103  *      * GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT: 1024
104  *
105  *    Details of loading quotas and default values will be described on
106  *
107  *       1.1.4 Preference values
108  *
109  *     1.2 Data structures used
110  *
111  *    Addresse uses struct ATS_Address for each address. The structs are stored
112  *    in a linked list and provides a pointer void *solver_information for the
113  *    solver to store address specific information. It provides the int values
114  *    active which is set to GNUNET_YES if the address is select for transport
115  *    use and used, representing that transport service is actively using this
116  *    address. Address information are stored in peer, addr, addr_len, plugin.
117  *
118  *     1.3 Initialization
119  *
120  *    During initialization a hashmap to store addresses is created. The quotas
121  *    for all networks defined for ATS are loaded from configuration. For each
122  *    network first the logic will check if the string
123  *    GNUNET_ATS_MaxBandwidthString is configured, if not it will try to convert
124  *    the configured value as a fancy size and if this fails it will try to use
125  *    it as a value_number. If no configuration value is found it will assign
126  *    GNUNET_ATS_DefaultBandwidth. The most important step is to load the
127  *    configured solver using configuration "[ats]:MODE". Current solvers are
128  *    MODE_PROPORTIONAL, MODE_MLP. Interaction is done using a solver API
129  *
130  *     1.4 Solver API
131  *
132  *    Solver functions:
133  *      * s_init: init the solver with required information
134  *      * s_add: add a new address
135  *      * s_update: update ATS values or session for an address
136  *      * s_get: get prefered address for a peer
137  *      * s_del: delete an address
138  *      * s_pref: change preference value for a peer
139  *      * s_done: shutdown solver
140  *
141  *    Callbacks: addresses provides a bandwidth_changed_cb callback to the
142  *    solver which is called when bandwidth assigned to peer has changed
143  *
144  *     1.5 Shutdown
145  *
146  *    During shutdown all addresses are freed and the solver told to shutdown
147  *
148  *     1.6 Addresses and sessions
149  *
150  *    Addresses consist of the address itself and a numerical session. When a
151  *    new address without a session is added it has no session, so it gets
152  *    session 0 assigned. When an address with a session is added and an address
153  *    object with session 0 is found, this object is updated with the session
154  *    otherwise a new address object with this session assigned is created.
155  *
156  *       1.6.1 Terminology
157  *
158  *    Addresses a1,a2 with session s1, s2 are "exact" if:
159  *    (a1 == a2)&&(s1 == s2)
160  *    Addresses a1,a2 with session s1, s2 are "equivalent" if:
161  *    (a1 == a2)&&((s1 == s2)||(s1 == 0)||(s2 == 0)
162  *
163  *     1.7 Address management
164  *
165  *    Transport service notifies ATS about changes to the addresses known to
166  *    him.
167  *
168  *       1.7.1 Adding an address
169  *
170  *    When transport learns a new address it tells ATS and ATS is telling
171  *    addresses about it using GAS_address_add. If not known to addresses it
172  *    creates a new address object and calls solver's s_add. ATS information are
173  *    deserialized and solver is notified about the session and ATS information
174  *    using s_update.
175  *
176  *       1.7.2 Updating an address
177  *
178  *    Addresses does an lookup up for the existing address with the given
179  *    session. If disassembles included ATS information and notifies the solver
180  *    using s_update about the update.
181  *
182  *       1.7.3 Deleting an address
183  *
184  *    Addresses does an lookup for the exact address and session and if removes
185  *    this address. If session != 0 the session is set to 0 and the address is
186  *    kept. If session == 0, the addresses is removed.
187  *
188  *       1.7.4 Requesting an address suggestion
189  *
190  *    The address client issues a request address message to be notified about
191  *    address suggestions for a specific peer. Addresses asks the solver with
192  *    s_get. If no address is available, it will not send a response, otherwise
193  *    it will respond with the choosen address.
194  *
195  *       1.7.5 Address suggestions
196  *
197  *    Addresses will notify the client automatically on any bandwidth_changed_cb
198  *    by the solver if a address suggestion request is pending. If no address is
199  *    available it will not respond at all If the client is not interested
200  *    anymore, it has to cancel the address suggestion request.
201  *
202  *       1.7.6 Suggestions blocks and reset
203  *
204  *    After suggesting an address it is blocked for ATS_BLOCKING_DELTA sec. to
205  *    prevent the client from being thrashed. If the client requires immediately
206  *    it can reset this block using GAS_addresses_handle_backoff_reset.
207  *
208  *       1.7.7 Marking address in use
209  *
210  *    The client can notify addresses that it successfully uses an address and
211  *    wants this address to be kept by calling GSA_address_in_use. Adresses will
212  *    mark the address as used an notify the solver about the use.
213  *
214  *       1.7.8 Address lifecycle
215  *
216  *      * (add address)
217  *      * (updated address) || (address in use)
218  *      * (delete address)
219  *
220  *     1.8 Bandwidth assignment
221  *
222  *    The addresses are used to perform resource allocation operations. ATS
223  *    addresses takes care of instantiating the solver configured and notifies
224  *    the respective solver about address changes and receives changes to the
225  *    bandwidth assignment from the solver. The current bandwidth assignment is
226  *    sent to transport. The specific solvers will be described in the specific
227  *    section.
228  *
229  *     1.9 Changing peer preferences
230  *
231  *    The bandwidth assigned to a peer can be influenced by setting a preference
232  *    for a peer. The prefernce will be given to to the solver with s_pref which
233  *    has to take care of the preference value
234
235  */
236
237
238 /**
239  * Pending Address suggestion requests
240  */
241 struct GAS_Addresses_Suggestion_Requests
242 {
243   /**
244    * Next in DLL
245    */
246   struct GAS_Addresses_Suggestion_Requests *next;
247
248   /**
249    * Previous in DLL
250    */
251   struct GAS_Addresses_Suggestion_Requests *prev;
252
253   /**
254    * Peer ID
255    */
256   struct GNUNET_PeerIdentity id;
257 };
258
259 /**
260  * Handle for ATS address component
261  */
262 struct GAS_Addresses_Handle
263 {
264   /**
265    *
266    */
267   struct GNUNET_STATISTICS_Handle *stat;
268
269   /**
270    * A multihashmap to store all addresses
271    */
272   struct GNUNET_CONTAINER_MultiPeerMap *addresses;
273
274   /**
275    * Configure WAN quota in
276    */
277   unsigned long long wan_quota_in;
278
279   /**
280    * Configure WAN quota out
281    */
282   unsigned long long wan_quota_out;
283
284   /**
285    * Is ATS addresses running
286    */
287   int running;
288
289   /**
290    * Configured ATS solver
291    */
292   int ats_mode;
293
294   /**
295    *  Solver handle
296    */
297   void *solver;
298
299   /**
300    * Address suggestion requests DLL head
301    */
302   struct GAS_Addresses_Suggestion_Requests *r_head;
303
304   /**
305    * Address suggestion requests DLL tail
306    */
307   struct GAS_Addresses_Suggestion_Requests *r_tail;
308
309   /* Solver functions */
310   struct GNUNET_ATS_PluginEnvironment env;
311
312   char *plugin;
313 };
314
315 /**
316  * Disassemble ATS information and update performance information in address
317  *
318  * Updates existing information and adds new information
319  *
320  * @param dest destination address
321  * @param update source ATS information
322  * @param update_count number of ATS information
323  * @param delta_dest ats performance information which were updated
324  *                              including previous value
325  * @param delta_count number of ATS information in the delta
326  * @return GNUNET_YES if address was address updated, GNUNET_NO otherwise
327  */
328 static unsigned int
329 disassemble_ats_information (struct ATS_Address *dest,
330     const struct GNUNET_ATS_Information *update, uint32_t update_count,
331     struct GNUNET_ATS_Information **delta_dest, uint32_t *delta_count)
332 {
333
334   int c1;
335   int c2;
336   int found;
337   int change;
338
339   struct GNUNET_ATS_Information add_atsi[update_count];
340   struct GNUNET_ATS_Information delta_atsi[update_count];
341   struct GNUNET_ATS_Information *tmp_atsi;
342   uint32_t add_atsi_count;
343   uint32_t delta_atsi_count;
344
345   change = GNUNET_NO;
346   add_atsi_count = 0;
347   delta_atsi_count = 0;
348
349   if (0 == update_count)
350     return GNUNET_NO;
351
352   if (NULL == dest->atsi)
353   {
354     /* Create performance information */
355     dest->atsi =
356         GNUNET_malloc (update_count * sizeof (struct GNUNET_ATS_Information));
357     dest->atsi_count = update_count;
358     memcpy (dest->atsi, update,
359         update_count * sizeof(struct GNUNET_ATS_Information));
360     (*delta_dest) =
361         GNUNET_malloc (update_count * sizeof (struct GNUNET_ATS_Information));
362     for (c1 = 0; c1 < update_count; c1++)
363     {
364       (*delta_dest)[c1].type = update[c1].type;
365       (*delta_dest)[c1].value = htonl (GNUNET_ATS_VALUE_UNDEFINED);
366     }
367     (*delta_count) = update_count;
368     return GNUNET_YES;
369   }
370
371   for (c1 = 0; c1 < update_count; c1++)
372   {
373     /* Update existing performance information */
374     found = GNUNET_NO;
375     for (c2 = 0; c2 < dest->atsi_count; c2++)
376     {
377       if (update[c1].type == dest->atsi[c2].type)
378       {
379         if (update[c1].value != dest->atsi[c2].value)
380         {
381           /* Save previous value in delta */
382           delta_atsi[delta_atsi_count] = dest->atsi[c2];
383           delta_atsi_count++;
384           /* Set new value */
385           dest->atsi[c2].value = update[c1].value;
386           change = GNUNET_YES;
387         }
388         found = GNUNET_YES;
389         break;
390       }
391     }
392     if (GNUNET_NO == found)
393     {
394       add_atsi[add_atsi_count] = update[c1];
395       add_atsi_count++;
396       delta_atsi[delta_atsi_count].type = update[c1].type;
397       delta_atsi[delta_atsi_count].value = htonl (GNUNET_ATS_VALUE_UNDEFINED);
398       delta_atsi_count++;
399     }
400   }
401
402   if (add_atsi_count > 0)
403   {
404     /* Extend ats performance information */
405
406     tmp_atsi = GNUNET_malloc ((dest->atsi_count + add_atsi_count) *
407         (sizeof (struct GNUNET_ATS_Information)));
408     memcpy (tmp_atsi, dest->atsi,
409         dest->atsi_count * sizeof(struct GNUNET_ATS_Information));
410     memcpy (&tmp_atsi[dest->atsi_count], add_atsi,
411         add_atsi_count * sizeof(struct GNUNET_ATS_Information));
412     GNUNET_free(dest->atsi);
413     dest->atsi = tmp_atsi;
414     dest->atsi_count = dest->atsi_count + add_atsi_count;
415     change = GNUNET_YES;
416   }
417
418   if (delta_atsi_count > 0)
419   {
420     /* Copy delta */
421     (*delta_dest) =
422         GNUNET_malloc (delta_atsi_count * sizeof (struct GNUNET_ATS_Information));
423     memcpy ((*delta_dest), delta_atsi,
424         delta_atsi_count * sizeof(struct GNUNET_ATS_Information));
425     (*delta_count) = delta_atsi_count;
426   }
427
428   return change;
429 }
430
431 /**
432  * Free the given address
433  *
434  * @param addr address to destroy
435  */
436 static void
437 free_address (struct ATS_Address *addr)
438 {
439   GNUNET_free(addr->plugin);
440   GNUNET_free_non_null(addr->atsi);
441   GNUNET_free(addr);
442 }
443
444 /**
445  * Create a ATS_address with the given information
446  *
447  * @param peer peer
448  * @param plugin_name plugin
449  * @param plugin_addr address
450  * @param plugin_addr_len address length
451  * @param session_id session
452  * @return the ATS_Address
453  */
454 static struct ATS_Address *
455 create_address (const struct GNUNET_PeerIdentity *peer, const char *plugin_name,
456     const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id)
457 {
458   struct ATS_Address *aa = NULL;
459   int c1;
460   int c2;
461
462   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
463   aa->peer = *peer;
464   aa->addr_len = plugin_addr_len;
465   aa->addr = &aa[1];
466   memcpy (&aa[1], plugin_addr, plugin_addr_len);
467   aa->plugin = GNUNET_strdup (plugin_name);
468   aa->session_id = session_id;
469   aa->active = GNUNET_NO;
470   aa->used = GNUNET_NO;
471   aa->solver_information = NULL;
472   aa->atsi = NULL;
473   aa->atsi_count = 0;
474   aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0);
475   aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0);
476
477   for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1++)
478   {
479     aa->atsin[c1].avg_queue_index = 0;
480     for (c2 = 0; c2 < GAS_normalization_queue_length; c2++)
481       aa->atsin[c1].atsi_abs[c2] = GNUNET_ATS_VALUE_UNDEFINED;
482   }
483
484   return aa;
485 }
486
487 struct CompareAddressContext
488 {
489   const struct ATS_Address *search;
490
491   /* exact_address != NULL if address and session is equal */
492   struct ATS_Address *exact_address;
493   /* exact_address != NULL if address and session is 0 */
494   struct ATS_Address *base_address;
495 };
496
497
498 /**
499  * Comapre addresses
500  *
501  * @param cls a CompareAddressContext containin the source address
502  * @param key peer id
503  * @param value the address to compare with
504  * @return #GNUNET_YES to continue, #GNUNET_NO if address is founce
505  */
506 static int
507 compare_address_it (void *cls,
508                     const struct GNUNET_PeerIdentity *key,
509                     void *value)
510 {
511   struct CompareAddressContext *cac = cls;
512   struct ATS_Address *aa = value;
513
514   /* Find an matching exact address:
515    *
516    * Compare by:
517    * aa->addr_len == cac->search->addr_len
518    * aa->plugin == cac->search->plugin
519    * aa->addr == cac->search->addr
520    * aa->session == cac->search->session
521    *
522    * return as exact address
523    */
524   if ((aa->addr_len == cac->search->addr_len)
525       && (0 == strcmp (aa->plugin, cac->search->plugin)))
526   {
527     if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len))
528         && (aa->session_id == cac->search->session_id))
529       cac->exact_address = aa;
530   }
531
532   /* Find an matching base address:
533    *
534    * Properties:
535    *
536    * aa->session_id == 0
537    *
538    * Compare by:
539    * aa->addr_len == cac->search->addr_len
540    * aa->plugin == cac->search->plugin
541    * aa->addr == cac->search->addr
542    *
543    * return as base address
544    */
545   if ((aa->addr_len == cac->search->addr_len)
546       && (0 == strcmp (aa->plugin, cac->search->plugin)))
547   {
548     if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len))
549         && (aa->session_id == 0))
550       cac->base_address = aa;
551   }
552
553   /* Find an matching exact address based on session:
554    *
555    * Properties:
556    *
557    * cac->search->addr_len == 0
558    *
559    * Compare by:
560    * aa->plugin == cac->search->plugin
561    * aa->session_id == cac->search->session_id
562    *
563    * return as exact address
564    */
565   if (0 == cac->search->addr_len)
566   {
567     if ((0 == strcmp (aa->plugin, cac->search->plugin))
568         && (aa->session_id == cac->search->session_id))
569       cac->exact_address = aa;
570   }
571
572   if (cac->exact_address == NULL )
573     return GNUNET_YES; /* Continue iteration to find exact address */
574   else
575     return GNUNET_NO; /* Stop iteration since we have an exact address */
576 }
577
578 /**
579  * Find an existing equivalent address record.
580  * Compares by peer identity and network address OR by session ID
581  * (one of the two must match).
582  *
583  * @param handle the address handle
584  * @param peer peer to lookup addresses for
585  * @param addr existing address record
586  * @return existing address record, NULL for none
587  */
588 struct ATS_Address *
589 find_equivalent_address (struct GAS_Addresses_Handle *handle,
590     const struct GNUNET_PeerIdentity *peer, const struct ATS_Address *addr)
591 {
592   struct CompareAddressContext cac;
593
594   cac.exact_address = NULL;
595   cac.base_address = NULL;
596   cac.search = addr;
597   GNUNET_CONTAINER_multipeermap_get_multiple (handle->addresses,
598                                               peer,
599                                               &compare_address_it, &cac);
600
601   if (cac.exact_address == NULL)
602     return cac.base_address;
603   return cac.exact_address;
604 }
605
606
607 /**
608  * Find the exact address
609  *
610  * @param handle the address handle to use
611  * @param peer peer
612  * @param plugin_name transport plugin name
613  * @param plugin_addr plugin address
614  * @param plugin_addr_len length of the plugin address
615  * @param session_id session id, can be 0
616  * @return an ATS_address or NULL
617  */
618
619 static struct ATS_Address *
620 find_exact_address (struct GAS_Addresses_Handle *handle,
621     const struct GNUNET_PeerIdentity *peer, const char *plugin_name,
622     const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id)
623 {
624   struct ATS_Address *aa;
625   struct ATS_Address *ea;
626
627   aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
628       session_id);
629
630   /* Get existing address or address with session == 0 */
631   ea = find_equivalent_address (handle, peer, aa);
632   free_address (aa);
633   if (ea == NULL )
634     return NULL ;
635   else if (ea->session_id != session_id)
636     return NULL ;
637   return ea;
638 }
639
640 /**
641  * Extract an ATS performance info from an address
642  *
643  * @param address the address
644  * @param type the type to extract in HBO
645  * @return the value in HBO or GNUNET_ATS_VALUE_UNDEFINED in HBO if value does not exist
646  */
647 static int
648 get_performance_info (struct ATS_Address *address, uint32_t type)
649 {
650   int c1;
651   GNUNET_assert(NULL != address);
652
653   if ((NULL == address->atsi) || (0 == address->atsi_count))
654     return GNUNET_ATS_VALUE_UNDEFINED;
655
656   for (c1 = 0; c1 < address->atsi_count; c1++)
657   {
658     if (ntohl (address->atsi[c1].type) == type)
659       return ntohl (address->atsi[c1].value);
660   }
661   return GNUNET_ATS_VALUE_UNDEFINED;
662 }
663
664 /**
665  * Add a new address for a peer.
666  *
667  * @param handle the address handle to use
668  * @param peer peer
669  * @param plugin_name transport plugin name
670  * @param plugin_addr plugin address
671  * @param plugin_addr_len length of the plugin address
672  * @param session_id session id, can be 0
673  * @param atsi performance information for this address
674  * @param atsi_count number of performance information contained
675  */
676 void
677 GAS_addresses_add (struct GAS_Addresses_Handle *handle,
678     const struct GNUNET_PeerIdentity *peer, const char *plugin_name,
679     const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id,
680     const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count)
681 {
682   struct ATS_Address *new_address;
683   struct ATS_Address *existing_address;
684   struct GNUNET_ATS_Information *atsi_delta;
685   uint32_t atsi_delta_count;
686   uint32_t addr_net;
687   uint32_t previous_session;
688   int c1;
689
690   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s'\n",
691       "ADDRESS ADD", GNUNET_i2s (peer));
692
693   if (GNUNET_NO == handle->running)
694     return;
695
696   GNUNET_assert(NULL != handle->addresses);
697
698   new_address = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
699       session_id);
700   atsi_delta = NULL;
701   disassemble_ats_information (new_address, atsi, atsi_count, &atsi_delta,
702       &atsi_delta_count);
703   GNUNET_free_non_null(atsi_delta);
704   addr_net = get_performance_info (new_address, GNUNET_ATS_NETWORK_TYPE);
705   if (GNUNET_ATS_VALUE_UNDEFINED == addr_net)
706     addr_net = GNUNET_ATS_NET_UNSPECIFIED;
707
708   /* Get existing address or address with session == 0 */
709   existing_address = find_equivalent_address (handle, peer, new_address);
710   if (existing_address == NULL )
711   {
712     /* Add a new address */
713     GNUNET_assert(
714         GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (handle->addresses,
715                                                         peer,
716                                                         new_address,
717                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
718
719     GNUNET_STATISTICS_set (handle->stat, "# addresses",
720         GNUNET_CONTAINER_multipeermap_size (handle->addresses), GNUNET_NO);
721
722     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
723         "Adding new address %p for peer `%s', length %u, session id %u, %s\n",
724         new_address, GNUNET_i2s (peer), plugin_addr_len, session_id,
725         GNUNET_ATS_print_network_type (addr_net));
726
727     /* Tell solver about new address */
728     handle->env.sf.s_add (handle->solver, new_address, addr_net);
729
730     handle->env.sf.s_bulk_start (handle->solver);
731     GAS_normalization_normalize_property (handle->addresses, new_address, atsi,
732         atsi_count);
733     handle->env.sf.s_bulk_stop (handle->solver);
734
735     /* Notify performance clients about new address */
736     GAS_performance_notify_all_clients (&new_address->peer, new_address->plugin,
737         new_address->addr, new_address->addr_len, new_address->session_id,
738         new_address->atsi, new_address->atsi_count,
739         new_address->assigned_bw_out, new_address->assigned_bw_in);
740     return;
741   }
742
743   /* We have an existing address we can use, clean up new */
744   GNUNET_free(new_address->plugin);
745   GNUNET_free_non_null(new_address->atsi);
746   GNUNET_free(new_address);
747   new_address = NULL;
748
749   if (0 != existing_address->session_id)
750   {
751     /* Should not happen */
752     GNUNET_break(0);
753     return;
754   }
755
756   addr_net = get_performance_info (existing_address, GNUNET_ATS_NETWORK_TYPE);
757   if (GNUNET_ATS_VALUE_UNDEFINED == addr_net)
758     addr_net = GNUNET_ATS_NET_UNSPECIFIED;
759
760   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
761       "Found existing address for peer `%s' %p with new session %u in network %s\n",
762       GNUNET_i2s (peer), existing_address, session_id,
763       GNUNET_ATS_print_network_type (addr_net));
764   /* We have an address without an session, update this address */
765   atsi_delta = NULL;
766   atsi_delta_count = 0;
767   if (GNUNET_YES
768       == disassemble_ats_information (existing_address, atsi, atsi_count,
769           &atsi_delta, &atsi_delta_count))
770   {
771     /* Notify performance clients about properties */
772     GAS_performance_notify_all_clients (&existing_address->peer,
773         existing_address->plugin, existing_address->addr,
774         existing_address->addr_len, existing_address->session_id,
775         existing_address->atsi, existing_address->atsi_count,
776         existing_address->assigned_bw_out, existing_address->assigned_bw_in);
777
778     for (c1 = 0; c1 < atsi_delta_count; c1++)
779     {
780       if ((GNUNET_ATS_NETWORK_TYPE == ntohl (atsi_delta[c1].type))
781           && (addr_net != ntohl (atsi_delta[c1].value)))
782       {
783         /* Network type changed */
784         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
785             "Address for peer `%s' %p changed from network %s to %s\n",
786             GNUNET_i2s (peer), existing_address,
787             GNUNET_ATS_print_network_type (addr_net),
788             GNUNET_ATS_print_network_type (ntohl (atsi_delta[c1].value)));
789         handle->env.sf.s_address_update_network (handle->solver, existing_address,
790             ntohl (atsi_delta[c1].value),
791             get_performance_info (existing_address, GNUNET_ATS_NETWORK_TYPE));
792         addr_net = get_performance_info (existing_address,
793             GNUNET_ATS_NETWORK_TYPE);
794       }
795     }
796     /* Notify solver about update with atsi information and session */
797     handle->env.sf.s_bulk_start (handle->solver);
798     GAS_normalization_normalize_property (handle->addresses, existing_address,
799         atsi, atsi_count);
800     handle->env.sf.s_bulk_stop (handle->solver);
801   }
802   GNUNET_free_non_null(atsi_delta);
803
804   /* Notify solver about new session */
805   if (existing_address->session_id == session_id)
806     return; /* possible, can both be 0 since address is revalidated */
807
808   previous_session = existing_address->session_id;
809   existing_address->session_id = session_id;
810   handle->env.sf.s_address_update_session (handle->solver, existing_address,
811       previous_session, session_id);
812
813   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
814       "Updated existing address for peer `%s' %p length %u with new session %u in network %s\n",
815       GNUNET_i2s (peer), existing_address, existing_address->addr_len,
816       session_id, GNUNET_ATS_print_network_type (addr_net));
817 }
818
819 /**
820  * Update an address with a session or performance information for a peer.
821  *
822  * If an address was added without a session it will be updated with the
823  * session
824  *
825  * @param handle the address handle to use
826  * @param peer peer
827  * @param plugin_name transport plugin name
828  * @param plugin_addr plugin address
829  * @param plugin_addr_len length of the plugin address
830  * @param session_id session id, can be 0
831  * @param atsi performance information for this address
832  * @param atsi_count number of performance information contained
833  */
834 void
835 GAS_addresses_update (struct GAS_Addresses_Handle *handle,
836     const struct GNUNET_PeerIdentity *peer, const char *plugin_name,
837     const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id,
838     const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count)
839 {
840   struct ATS_Address *aa;
841   struct GNUNET_ATS_Information *atsi_delta;
842   uint32_t atsi_delta_count;
843   uint32_t prev_session;
844   int c1;
845
846   if (GNUNET_NO == handle->running)
847     return;
848
849   GNUNET_assert(NULL != handle->addresses);
850
851   /* Get existing address */
852   aa = find_exact_address (handle, peer, plugin_name, plugin_addr,
853       plugin_addr_len, session_id);
854   if (aa == NULL )
855   {
856     /* GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to update unknown address for peer `%s' `%s' session id %u\n", */
857     /*             GNUNET_i2s (peer), plugin_name, session_id); */
858     /* GNUNET_break (0); */
859     return;
860   }
861
862   if (NULL == aa->solver_information)
863   {
864     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
865         "Tried to update unknown address for peer `%s' `%s' session id %u\n",
866         GNUNET_i2s (peer), plugin_name, session_id);
867     return;
868   }
869
870   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s' address \n",
871       "ADDRESS UPDATE", GNUNET_i2s (peer), aa);
872
873   /* Update address */
874   if (session_id != aa->session_id)
875   {
876     /* Session changed */
877     prev_session = aa->session_id;
878     aa->session_id = session_id;
879     handle->env.sf.s_address_update_session (handle->solver, aa, prev_session,
880         aa->session_id);
881   }
882
883   atsi_delta = NULL;
884   atsi_delta_count = 0;
885   if (GNUNET_YES
886       == disassemble_ats_information (aa, atsi, atsi_count, &atsi_delta,
887           &atsi_delta_count))
888   {
889     /* ATS properties changed */
890     for (c1 = 0; c1 < atsi_delta_count; c1++)
891     {
892       if (GNUNET_ATS_NETWORK_TYPE == ntohl (atsi_delta[c1].type))
893       {
894         /* Network type changed */
895         handle->env.sf.s_address_update_network (handle->solver, aa,
896             ntohl (atsi_delta[c1].value),
897             get_performance_info (aa, GNUNET_ATS_NETWORK_TYPE));
898       }
899     }
900
901     /* Notify performance clients about updated address */
902     GAS_performance_notify_all_clients (&aa->peer, aa->plugin, aa->addr,
903         aa->addr_len, aa->session_id, aa->atsi, aa->atsi_count,
904         aa->assigned_bw_out, aa->assigned_bw_in);
905
906     handle->env.sf.s_bulk_start (handle->solver);
907     GAS_normalization_normalize_property (handle->addresses, aa, atsi,
908         atsi_count);
909     handle->env.sf.s_bulk_stop (handle->solver);
910   }
911   GNUNET_free_non_null(atsi_delta);
912 }
913
914 struct DestroyContext
915 {
916   struct ATS_Address *aa;
917
918   struct GAS_Addresses_Handle *handle;
919
920   /**
921    * GNUNET_NO  : full address
922    * GNUNET_YES : just session
923    */
924   int result;
925 };
926
927 /**
928  * Delete an address
929  *
930  * If session != 0, just the session is deleted, the address itself still exists
931  * If session == 0, remove full address
932  * If session == 0 and addrlen == 0, destroy inbound address
933  *
934  * @param cls unused
935  * @param key unused
936  * @param value the 'struct ATS_Address'
937  * @return GNUNET_OK (continue to iterate)
938  */
939 static int
940 destroy_by_session_id (void *cls,
941                        const struct GNUNET_PeerIdentity *key,
942                        void *value)
943 {
944   struct DestroyContext *dc = cls;
945   struct GAS_Addresses_Handle *handle = dc->handle;
946   const struct ATS_Address *des = dc->aa;
947   struct ATS_Address *aa = value;
948
949   GNUNET_assert(
950       0 == memcmp (&aa->peer, &des->peer, sizeof(struct GNUNET_PeerIdentity)));
951
952   if (des->session_id == 0)
953   {
954     /* Session == 0, remove full address  */
955     if ((0 == strcmp (des->plugin, aa->plugin))
956         && (aa->addr_len == des->addr_len)
957         && (0 == memcmp (des->addr, aa->addr, aa->addr_len)))
958     {
959
960       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
961           "Deleting full address for peer `%s' session %u %p\n",
962           GNUNET_i2s (&aa->peer), aa->session_id, aa);
963
964       /* Notify solver about deletion */
965       GNUNET_assert(
966           GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (handle->addresses,
967                                                               &aa->peer,
968                                                               aa));
969       handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
970       free_address (aa);
971       dc->result = GNUNET_NO;
972       return GNUNET_OK; /* Continue iteration */
973     }
974   }
975   else
976   {
977     /* Session != 0, just remove session */
978     if (aa->session_id != des->session_id)
979       return GNUNET_OK; /* irrelevant */
980
981     if ((aa->session_id != 0) && (0 != strcmp (des->plugin, aa->plugin)))
982     {
983       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
984           "Different plugins during removal: `%s' vs `%s' \n", des->plugin,
985           aa->plugin);
986       GNUNET_break(0);
987       return GNUNET_OK;
988     }
989
990     if (aa->addr_len == 0)
991     {
992       /* Inbound connection died, delete full address */
993       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
994           "Deleting inbound address for peer `%s': `%s' session %u\n",
995           GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
996
997       /* Notify solver about deletion */
998       GNUNET_assert(
999           GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (handle->addresses,
1000                                                               &aa->peer, aa));
1001       handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
1002       free_address (aa);
1003       dc->result = GNUNET_NO;
1004       return GNUNET_OK; /* Continue iteration */
1005     }
1006     else
1007     {
1008       /* Session died */
1009       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1010           "Deleting session for peer `%s': `%s' %u\n", GNUNET_i2s (&aa->peer),
1011           aa->plugin, aa->session_id);
1012       /* Notify solver to delete session */
1013       handle->env.sf.s_del (handle->solver, aa, GNUNET_YES);
1014       aa->session_id = 0;
1015       aa->active = GNUNET_NO;
1016       return GNUNET_OK;
1017     }
1018   }
1019   return GNUNET_OK;
1020 }
1021
1022
1023 /**
1024  * Remove an address or just a session for a peer.
1025  *
1026  * @param handle the address handle to use
1027  * @param peer peer
1028  * @param plugin_name transport plugin name
1029  * @param plugin_addr plugin address
1030  * @param plugin_addr_len length of the plugin address
1031  * @param session_id session id, can be 0
1032  */
1033 void
1034 GAS_addresses_destroy (struct GAS_Addresses_Handle *handle,
1035     const struct GNUNET_PeerIdentity *peer, const char *plugin_name,
1036     const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id)
1037 {
1038   struct ATS_Address *ea;
1039   struct DestroyContext dc;
1040   if (GNUNET_NO == handle->running)
1041     return;
1042
1043   /* Get existing address */
1044   ea = find_exact_address (handle, peer, plugin_name, plugin_addr,
1045       plugin_addr_len, session_id);
1046   if (ea == NULL )
1047   {
1048     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1049         "Tried to destroy unknown address for peer `%s' `%s' session id %u\n",
1050         GNUNET_i2s (peer), plugin_name, session_id);
1051     return;
1052   }
1053
1054   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1055       "Received `%s' for peer `%s' address %p session %u\n", "ADDRESS DESTROY",
1056       GNUNET_i2s (peer), ea, session_id);
1057
1058   GNUNET_break(0 < strlen (plugin_name));
1059   dc.handle = handle;
1060   dc.aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
1061       session_id);
1062
1063   GNUNET_CONTAINER_multipeermap_get_multiple (handle->addresses,
1064                                               peer,
1065                                               &destroy_by_session_id, &dc);
1066   GNUNET_STATISTICS_set (handle->stat, "# addresses",
1067       GNUNET_CONTAINER_multipeermap_size (handle->addresses), GNUNET_NO);
1068   free_address (dc.aa);
1069 }
1070
1071 /**
1072  * Notification about active use of an address.
1073  * in_use == GNUNET_YES:
1074  *      This address is used to maintain an active connection with a peer.
1075  * in_use == GNUNET_NO:
1076  *      This address is no longer used to maintain an active connection with a peer.
1077  *
1078  * Note: can only be called with in_use == GNUNET_NO if called with GNUNET_YES
1079  * before
1080  *
1081  * @param handle the address handle to use
1082  * @param peer peer
1083  * @param plugin_name transport plugin name
1084  * @param plugin_addr plugin address
1085  * @param plugin_addr_len length of the plugin address
1086  * @param session_id session id, can be 0
1087  * @param in_use GNUNET_YES if GNUNET_NO
1088  * @return GNUNET_SYSERR on failure (address unknown ...)
1089  */
1090 int
1091 GAS_addresses_in_use (struct GAS_Addresses_Handle *handle,
1092     const struct GNUNET_PeerIdentity *peer, const char *plugin_name,
1093     const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id,
1094     int in_use)
1095 {
1096   struct ATS_Address *ea;
1097   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s'\n",
1098       "ADDRESS IN USE", GNUNET_i2s (peer));
1099
1100   if (GNUNET_NO == handle->running)
1101     return GNUNET_SYSERR;
1102
1103   ea = find_exact_address (handle, peer, plugin_name, plugin_addr,
1104       plugin_addr_len, session_id);
1105   if (NULL == ea)
1106   {
1107     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1108         "Trying to set unknown address `%s' `%s' `%u' to %s \n",
1109         GNUNET_i2s (peer), plugin_name, session_id,
1110         (GNUNET_NO == in_use) ? "NO" : "YES");
1111     GNUNET_break(0);
1112     return GNUNET_SYSERR;
1113   }
1114   if (ea->used == in_use)
1115   {
1116     GNUNET_break(0);
1117     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1118         "Address in use called multiple times for peer `%s': %s -> %s \n",
1119         GNUNET_i2s (peer), (GNUNET_NO == ea->used) ? "NO" : "YES",
1120         (GNUNET_NO == in_use) ? "NO" : "YES");
1121     return GNUNET_SYSERR;
1122   }
1123
1124   /* Tell solver about update */
1125   ea->used = in_use;
1126   handle->env.sf.s_address_update_inuse (handle->solver, ea, ea->used);
1127   return GNUNET_OK;
1128 }
1129
1130 /**
1131  * Cancel address suggestions for a peer
1132  *
1133  * @param handle the address handle
1134  * @param peer the peer id
1135  */
1136 void
1137 GAS_addresses_request_address_cancel (struct GAS_Addresses_Handle *handle,
1138     const struct GNUNET_PeerIdentity *peer)
1139 {
1140   struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
1141
1142   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received request: `%s' for peer %s\n",
1143       "request_address_cancel", GNUNET_i2s (peer));
1144
1145   while (NULL != cur)
1146   {
1147     if (0 == memcmp (peer, &cur->id, sizeof(cur->id)))
1148       break; /* found */
1149     cur = cur->next;
1150   }
1151
1152   if (NULL == cur)
1153   {
1154     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1155         "No address requests pending for peer `%s', cannot remove!\n",
1156         GNUNET_i2s (peer));
1157     return;
1158   }
1159   handle->env.sf.s_get_stop (handle->solver, peer);
1160   GAS_addresses_handle_backoff_reset (handle, peer);
1161   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Removed request pending for peer `%s\n",
1162       GNUNET_i2s (peer));
1163   GNUNET_CONTAINER_DLL_remove(handle->r_head, handle->r_tail, cur);
1164   GNUNET_free(cur);
1165 }
1166
1167
1168 /**
1169  * Request address suggestions for a peer
1170  *
1171  * @param handle the address handle
1172  * @param peer the peer id
1173  */
1174 void
1175 GAS_addresses_request_address (struct GAS_Addresses_Handle *handle,
1176     const struct GNUNET_PeerIdentity *peer)
1177 {
1178   struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
1179   struct ATS_Address *aa;
1180
1181   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Received `%s' for peer `%s'\n",
1182       "REQUEST ADDRESS", GNUNET_i2s (peer));
1183
1184   if (GNUNET_NO == handle->running)
1185     return;
1186   while (NULL != cur)
1187   {
1188     if (0 == memcmp (peer, &cur->id, sizeof(cur->id)))
1189       break; /* already suggesting */
1190     cur = cur->next;
1191   }
1192   if (NULL == cur)
1193   {
1194     cur = GNUNET_malloc (sizeof (struct GAS_Addresses_Suggestion_Requests));
1195     cur->id = (*peer);
1196     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1197         "Adding new address suggestion request for `%s'\n",
1198          GNUNET_i2s (peer));
1199     GNUNET_CONTAINER_DLL_insert(handle->r_head, handle->r_tail, cur);
1200   }
1201
1202   /*
1203    * Debuging information about addresses
1204    *
1205    * GNUNET_CONTAINER_multihashmap_get_multiple(handle->addresses,
1206    *  &peer->hashPubKey, &addrinfo_it, (void *) peer);
1207    */
1208
1209   /* Get prefered address from solver */
1210   aa = (struct ATS_Address *) handle->env.sf.s_get (handle->solver, peer);
1211   if (NULL == aa)
1212   {
1213     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Cannot suggest address for peer `%s'\n",
1214         GNUNET_i2s (peer));
1215     return;
1216   }
1217
1218   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Suggesting address %p for peer `%s'\n",
1219       aa, GNUNET_i2s (peer));
1220
1221   GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
1222       aa->addr_len, aa->session_id, aa->atsi, aa->atsi_count,
1223       aa->assigned_bw_out, aa->assigned_bw_in);
1224
1225   aa->block_interval = GNUNET_TIME_relative_add (aa->block_interval,
1226       ATS_BLOCKING_DELTA);
1227   aa->blocked_until = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
1228       aa->block_interval);
1229
1230   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1231       "Address %p ready for suggestion, block interval now %llu \n", aa,
1232       aa->block_interval);
1233 }
1234
1235 /**
1236  * Iterator to reset address blocking
1237  *
1238  * @param cls not used
1239  * @param key the peer
1240  * @param value the address to reset
1241  * @return #GNUNET_OK to continue
1242  */
1243 static int
1244 reset_address_it (void *cls,
1245                   const struct GNUNET_PeerIdentity *key,
1246                   void *value)
1247 {
1248   struct ATS_Address *aa = value;
1249
1250   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1251              "Resetting interval for peer `%s' address %p from %llu to 0\n",
1252              GNUNET_i2s (&aa->peer),
1253              aa,
1254              aa->block_interval);
1255   aa->blocked_until = GNUNET_TIME_UNIT_ZERO_ABS;
1256   aa->block_interval = GNUNET_TIME_UNIT_ZERO;
1257   return GNUNET_OK;
1258 }
1259
1260
1261 /**
1262  * Reset suggestion backoff for a peer
1263  *
1264  * Suggesting addresses is blocked for ATS_BLOCKING_DELTA. Blocking can be
1265  * reset using this function
1266  *
1267  * @param handle the address handle
1268  * @param peer the peer id
1269  */
1270 void
1271 GAS_addresses_handle_backoff_reset (struct GAS_Addresses_Handle *handle,
1272     const struct GNUNET_PeerIdentity *peer)
1273 {
1274   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s'\n",
1275       "RESET BACKOFF", GNUNET_i2s (peer));
1276
1277   GNUNET_break(
1278       GNUNET_SYSERR != GNUNET_CONTAINER_multipeermap_get_multiple (handle->addresses,
1279                                                                    peer,
1280                                                                    &reset_address_it, NULL));
1281 }
1282
1283
1284 /**
1285  * The preference changed for a peer
1286  *
1287  * @param cls the address handle
1288  * @param peer the peer
1289  * @param kind the ATS kind
1290  * @param pref_rel the new relative preference value
1291  */
1292 static void
1293 normalized_preference_changed_cb (void *cls,
1294     const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind kind,
1295     double pref_rel)
1296 {
1297   GNUNET_assert(NULL != cls);
1298   struct GAS_Addresses_Handle *handle = cls;
1299
1300   /* Tell solver about update */
1301   handle->env.sf.s_pref (handle->solver, peer, kind, pref_rel);
1302 }
1303
1304 /**
1305  * The relative value for a property changed
1306  *
1307  * @param cls the address handle
1308  * @param address the peer
1309  * @param type the ATS type
1310  * @param prop_rel the new relative preference value
1311  */
1312 static void
1313 normalized_property_changed_cb (void *cls, struct ATS_Address *address,
1314     uint32_t type, double prop_rel)
1315 {
1316   struct GAS_Addresses_Handle *ah = (struct GAS_Addresses_Handle *) cls;
1317   GNUNET_assert(NULL != ah);
1318
1319   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1320       "Normalized property %s for peer `%s' changed to %.3f \n",
1321       GNUNET_ATS_print_property_type (type), GNUNET_i2s (&address->peer),
1322       prop_rel);
1323
1324   ah->env.sf.s_address_update_property (ah->solver, address, type, 0, prop_rel);
1325 }
1326
1327 /**
1328  * Function allowing the solver to obtain normalized preference
1329  * values from solver
1330  *
1331  * @param cls unused
1332  * @param id the peer to return the normalized properties for
1333  * @return array of double values with |GNUNET_ATS_PreferenceCount| elements
1334  */
1335 const double *
1336 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
1337 {
1338   return GAS_normalization_get_preferences (id);
1339 }
1340
1341 /**
1342  * Function allowing the solver to obtain normalized property
1343  * values for an address from solver
1344  *
1345  * @param cls unused
1346  * @param address the address
1347  * @return array of double values with |GNUNET_ATS_QualityPropertiesCount| elements
1348  */
1349 const double *
1350 get_property_cb (void *cls, const struct ATS_Address *address)
1351 {
1352   return GAS_normalization_get_properties ((struct ATS_Address *) address);
1353 }
1354
1355 /**
1356  * Change the preference for a peer
1357  *
1358  * @param handle the address handle
1359  * @param client the client sending this request
1360  * @param peer the peer id
1361  * @param kind the preference kind to change
1362  * @param score_abs the new preference score
1363  */
1364 void
1365 GAS_addresses_change_preference (struct GAS_Addresses_Handle *handle,
1366     void *client, const struct GNUNET_PeerIdentity *peer,
1367     enum GNUNET_ATS_PreferenceKind kind, float score_abs)
1368 {
1369   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1370       "Received `%s' for peer `%s' for client %p\n", "CHANGE PREFERENCE",
1371       GNUNET_i2s (peer), client);
1372
1373   if (GNUNET_NO == handle->running)
1374     return;
1375
1376   if (GNUNET_NO ==
1377       GNUNET_CONTAINER_multipeermap_contains (handle->addresses,
1378                                               peer))
1379   {
1380     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1381         "Received `%s' for unknown peer `%s' from client %p\n",
1382         "CHANGE PREFERENCE", GNUNET_i2s (peer), client);
1383     return;
1384   }
1385
1386   handle->env.sf.s_bulk_start (handle->solver);
1387   /* Tell normalization about change, normalization will call callback if preference changed */
1388   GAS_normalization_normalize_preference (client, peer, kind, score_abs);
1389   handle->env.sf.s_bulk_stop (handle->solver);
1390 }
1391
1392 /**
1393  * Change the preference for a peer
1394  *
1395  * @param handle the address handle
1396  * @param application the client sending this request
1397  * @param peer the peer id
1398  * @param scope the time interval for this feedback: [now - scope .. now]
1399  * @param kind the preference kind to change
1400  * @param score_abs the new preference score
1401  */
1402 void
1403 GAS_addresses_preference_feedback (struct GAS_Addresses_Handle *handle,
1404     void *application, const struct GNUNET_PeerIdentity *peer,
1405     const struct GNUNET_TIME_Relative scope,
1406     enum GNUNET_ATS_PreferenceKind kind, float score_abs)
1407 {
1408   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1409       "Received `%s' for peer `%s' for client %p\n", "PREFERENCE FEEDBACK",
1410       GNUNET_i2s (peer), application);
1411
1412   if (GNUNET_NO == handle->running)
1413     return;
1414
1415   if (GNUNET_NO ==
1416       GNUNET_CONTAINER_multipeermap_contains (handle->addresses,
1417                                               peer))
1418   {
1419     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1420         "Received `%s' for unknown peer `%s' from client %p\n",
1421         "PREFERENCE FEEDBACK", GNUNET_i2s (peer), application);
1422     return;
1423   }
1424
1425   handle->env.sf.s_feedback (handle->solver, application, peer, scope, kind,
1426       score_abs);
1427 }
1428
1429 /**
1430  * Load quotas for networks from configuration
1431  *
1432  * @param cfg configuration handle
1433  * @param out_dest where to write outbound quotas
1434  * @param in_dest where to write inbound quotas
1435  * @param dest_length length of inbound and outbound arrays
1436  * @return number of networks loaded
1437  */
1438 static unsigned int
1439 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
1440     unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
1441 {
1442   char *network_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
1443   char * entry_in = NULL;
1444   char * entry_out = NULL;
1445   char * quota_out_str;
1446   char * quota_in_str;
1447   int c;
1448   int res;
1449
1450   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
1451   {
1452     in_dest[c] = 0;
1453     out_dest[c] = 0;
1454     GNUNET_asprintf (&entry_out, "%s_QUOTA_OUT", network_str[c]);
1455     GNUNET_asprintf (&entry_in, "%s_QUOTA_IN", network_str[c]);
1456
1457     /* quota out */
1458     if (GNUNET_OK
1459         == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_out,
1460             &quota_out_str))
1461     {
1462       res = GNUNET_NO;
1463       if (0 == strcmp (quota_out_str, GNUNET_ATS_MaxBandwidthString))
1464       {
1465         out_dest[c] = GNUNET_ATS_MaxBandwidth;
1466         res = GNUNET_YES;
1467       }
1468       if ((GNUNET_NO == res)
1469           && (GNUNET_OK
1470               == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str,
1471                   &out_dest[c])))
1472         res = GNUNET_YES;
1473       if ((GNUNET_NO == res)
1474           && (GNUNET_OK
1475               == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_out,
1476                   &out_dest[c])))
1477         res = GNUNET_YES;
1478
1479       if (GNUNET_NO == res)
1480       {
1481         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1482             _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
1483             network_str[c], quota_out_str, GNUNET_ATS_DefaultBandwidth);
1484         out_dest[c] = GNUNET_ATS_DefaultBandwidth;
1485       }
1486       else
1487       {
1488         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1489             _("Outbound quota configure for network `%s' is %llu\n"),
1490             network_str[c], out_dest[c]);
1491       }
1492       GNUNET_free(quota_out_str);
1493     }
1494     else
1495     {
1496       GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1497           _("No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
1498           network_str[c], GNUNET_ATS_DefaultBandwidth);
1499       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
1500     }
1501
1502     /* quota in */
1503     if (GNUNET_OK
1504         == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_in,
1505             &quota_in_str))
1506     {
1507       res = GNUNET_NO;
1508       if (0 == strcmp (quota_in_str, GNUNET_ATS_MaxBandwidthString))
1509       {
1510         in_dest[c] = GNUNET_ATS_MaxBandwidth;
1511         res = GNUNET_YES;
1512       }
1513       if ((GNUNET_NO == res)
1514           && (GNUNET_OK
1515               == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
1516         res = GNUNET_YES;
1517       if ((GNUNET_NO == res)
1518           && (GNUNET_OK
1519               == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_in,
1520                   &in_dest[c])))
1521         res = GNUNET_YES;
1522
1523       if (GNUNET_NO == res)
1524       {
1525         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1526             _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
1527             network_str[c], quota_in_str, GNUNET_ATS_DefaultBandwidth);
1528         in_dest[c] = GNUNET_ATS_DefaultBandwidth;
1529       }
1530       else
1531       {
1532         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1533             _("Inbound quota configured for network `%s' is %llu\n"),
1534             network_str[c], in_dest[c]);
1535       }
1536       GNUNET_free(quota_in_str);
1537     }
1538     else
1539     {
1540       GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1541           _("No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
1542           network_str[c], GNUNET_ATS_DefaultBandwidth);
1543       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
1544     }
1545     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1546         "Loaded quota for network `%s' (in/out): %llu %llu\n", network_str[c],
1547         in_dest[c], out_dest[c]);
1548     GNUNET_free(entry_out);
1549     GNUNET_free(entry_in);
1550   }
1551   return GNUNET_ATS_NetworkTypeCount;
1552 }
1553
1554 /**
1555  * Callback for solver to notify about assignment changes
1556  *
1557  * @param cls the GAS_Addresses_Handle
1558  * @param address the address with changes
1559  */
1560 static void
1561 bandwidth_changed_cb (void *cls, struct ATS_Address *address)
1562 {
1563   struct GAS_Addresses_Handle *handle = cls;
1564   struct GAS_Addresses_Suggestion_Requests *cur;
1565
1566   GNUNET_assert(handle != NULL);
1567   GNUNET_assert(address != NULL);
1568
1569   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1570       "Bandwidth assignment changed for peer %s \n",
1571       GNUNET_i2s (&address->peer));
1572
1573   /* Notify performance clients about changes to address */
1574   GAS_performance_notify_all_clients (&address->peer, address->plugin,
1575       address->addr, address->addr_len, address->session_id, address->atsi,
1576       address->atsi_count, address->assigned_bw_out, address->assigned_bw_in);
1577   cur = handle->r_head;
1578   while (NULL != cur)
1579   {
1580     if (0 == memcmp (&address->peer, &cur->id, sizeof(cur->id)))
1581       break; /* we have an address request pending*/
1582     cur = cur->next;
1583   }
1584   if (NULL == cur)
1585   {
1586     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Nobody is interested in peer `%s' :(\n",
1587         GNUNET_i2s (&address->peer));
1588     return;
1589   }
1590
1591   if ((0 == ntohl (address->assigned_bw_in.value__))
1592       && (0 == ntohl (address->assigned_bw_out.value__)))
1593   {
1594     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1595         "Telling transport to disconnect peer `%s'\n",
1596         GNUNET_i2s (&address->peer));
1597   }
1598   else
1599   {
1600     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1601         "Sending bandwidth update for peer `%s': %llu %llu\n",
1602         GNUNET_i2s (&address->peer), address->assigned_bw_out,
1603         address->assigned_bw_out);
1604   }
1605
1606   /* *Notify scheduling clients about suggestion */
1607   GAS_scheduling_transmit_address_suggestion (&address->peer, address->plugin,
1608       address->addr, address->addr_len, address->session_id, address->atsi,
1609       address->atsi_count, address->assigned_bw_out, address->assigned_bw_in);
1610 }
1611
1612 /**
1613  * Initialize address subsystem. The addresses subsystem manages the addresses
1614  * known and current performance information. It has a solver component
1615  * responsible for the resource allocation. It tells the solver about changes
1616  * and receives updates when the solver changes the resource allocation.
1617  *
1618  * @param cfg configuration to use
1619  * @param stats the statistics handle to use
1620  * @return an address handle
1621  */
1622 struct GAS_Addresses_Handle *
1623 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
1624     const struct GNUNET_STATISTICS_Handle *stats)
1625 {
1626   struct GAS_Addresses_Handle *ah;
1627   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
1628   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
1629   char *mode_str;
1630   char *plugin_short;
1631   int c;
1632
1633   ah = GNUNET_malloc (sizeof (struct GAS_Addresses_Handle));
1634   ah->running = GNUNET_NO;
1635
1636   ah->stat = (struct GNUNET_STATISTICS_Handle *) stats;
1637   /* Initialize the addresses database */
1638   ah->addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1639   GNUNET_assert(NULL != ah->addresses);
1640
1641   /* Figure out configured solution method */
1642   if (GNUNET_SYSERR
1643       == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
1644   {
1645     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1646         "No resource assignment method configured, using proportional approach\n");
1647     ah->ats_mode = MODE_PROPORTIONAL;
1648   }
1649   else
1650   {
1651     for (c = 0; c < strlen (mode_str); c++)
1652       mode_str[c] = toupper (mode_str[c]);
1653     if (0 == strcmp (mode_str, "PROPORTIONAL"))
1654     {
1655       ah->ats_mode = MODE_PROPORTIONAL;
1656       plugin_short = "proportional";
1657     }
1658     else if (0 == strcmp (mode_str, "MLP"))
1659     {
1660       ah->ats_mode = MODE_MLP;
1661       plugin_short = "mlp";
1662 #if !HAVE_LIBGLPK
1663       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1664           "Assignment method `%s' configured, but GLPK is not available, please install \n",
1665           mode_str);
1666       ah->ats_mode = MODE_PROPORTIONAL;
1667       plugin_short = "proportional";
1668 #endif
1669     }
1670     else if (0 == strcmp (mode_str, "RIL"))
1671     {
1672       ah->ats_mode = MODE_RIL;
1673       plugin_short = "ril";
1674     }
1675     else
1676     {
1677       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1678           "Invalid resource assignment method `%s' configured, using proportional approach\n",
1679           mode_str);
1680       ah->ats_mode = MODE_PROPORTIONAL;
1681       plugin_short = "proportional";
1682     }
1683     GNUNET_free(mode_str);
1684   }
1685
1686   load_quotas (cfg, quotas_in, quotas_out, GNUNET_ATS_NetworkTypeCount);
1687   ah->env.bandwidth_changed_cb = &bandwidth_changed_cb;
1688   ah->env.bw_changed_cb_cls = ah;
1689   ah->env.get_preferences = &get_preferences_cb;
1690   ah->env.get_preference_cls = ah;
1691   ah->env.get_property = &get_property_cb;
1692   ah->env.get_property_cls = ah;
1693   ah->env.cfg = cfg;
1694   ah->env.stats = stats;
1695   ah->env.addresses = ah->addresses;
1696
1697   ah->env.network_count = GNUNET_ATS_NetworkTypeCount;
1698   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1699   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1700   {
1701     ah->env.networks[c] = networks[c];
1702     ah->env.out_quota[c] = quotas_out[c];
1703     ah->env.in_quota[c] = quotas_in[c];
1704   }
1705
1706   GNUNET_asprintf (&ah->plugin, "libgnunet_plugin_ats_%s", plugin_short);
1707   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s '`%s'\n"), plugin_short, ah->plugin);
1708   if  (NULL == (ah->solver = GNUNET_PLUGIN_load (ah->plugin, &ah->env)))
1709   {
1710     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), ah->plugin);
1711     return NULL;
1712   }
1713
1714   GNUNET_assert (NULL != ah->env.sf.s_add);
1715   GNUNET_assert (NULL != ah->env.sf.s_address_update_inuse);
1716   GNUNET_assert (NULL != ah->env.sf.s_address_update_property);
1717   GNUNET_assert (NULL != ah->env.sf.s_address_update_session);
1718   GNUNET_assert (NULL != ah->env.sf.s_address_update_network);
1719   GNUNET_assert (NULL != ah->env.sf.s_get);
1720   GNUNET_assert (NULL != ah->env.sf.s_get_stop);
1721   GNUNET_assert (NULL != ah->env.sf.s_pref);
1722   GNUNET_assert (NULL != ah->env.sf.s_feedback);
1723   GNUNET_assert (NULL != ah->env.sf.s_del);
1724   GNUNET_assert (NULL != ah->env.sf.s_bulk_start);
1725   GNUNET_assert (NULL != ah->env.sf.s_bulk_stop);
1726
1727
1728   GAS_normalization_start (&normalized_preference_changed_cb, ah,
1729       &normalized_property_changed_cb, ah);
1730
1731   if (NULL == ah->solver)
1732   {
1733     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver!\n"));
1734     GNUNET_free(ah);
1735     return NULL ;
1736   }
1737   /* up and running */
1738   ah->running = GNUNET_YES;
1739
1740   GNUNET_STATISTICS_set (ah->stat, "# addresses",
1741       GNUNET_CONTAINER_multipeermap_size (ah->addresses), GNUNET_NO);
1742
1743   return ah;
1744 }
1745
1746 /**
1747  * Destroy all addresses iterator
1748  *
1749  * @param cls NULL
1750  * @param key peer identity (unused)
1751  * @param value the 'struct ATS_Address' to free
1752  * @return #GNUNET_OK (continue to iterate)
1753  */
1754 static int
1755 destroy_all_address_it (void *cls,
1756                         const struct GNUNET_PeerIdentity *key,
1757                         void *value)
1758 {
1759   struct GAS_Addresses_Handle *handle = cls;
1760   struct ATS_Address *aa = value;
1761
1762   /* Remove */
1763   GNUNET_assert(GNUNET_YES ==
1764                 GNUNET_CONTAINER_multipeermap_remove (handle->addresses, key, value));
1765   /* Notify */
1766   handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
1767   /* Destroy */
1768   free_address (aa);
1769
1770   return GNUNET_OK;
1771 }
1772
1773
1774 /**
1775  * Remove all addresses
1776  *
1777  * @param handle the address handle to use
1778  */
1779 void
1780 GAS_addresses_destroy_all (struct GAS_Addresses_Handle *handle)
1781 {
1782   if (GNUNET_NO == handle->running)
1783     return;
1784
1785   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Destroying all addresses\n");
1786   handle->env.sf.s_bulk_start (handle->solver);
1787   if (handle->addresses != NULL )
1788     GNUNET_CONTAINER_multipeermap_iterate (handle->addresses,
1789                                            &destroy_all_address_it,
1790                                            handle);
1791   handle->env.sf.s_bulk_start (handle->solver);
1792 }
1793
1794
1795 /**
1796  * Shutdown address subsystem.
1797  *
1798  * @param handle the address handle to shutdown
1799  */
1800 void
1801 GAS_addresses_done (struct GAS_Addresses_Handle *handle)
1802 {
1803   struct GAS_Addresses_Suggestion_Requests *cur;
1804
1805   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Shutting down addresses\n");
1806   GNUNET_assert(NULL != handle);
1807   GAS_addresses_destroy_all (handle);
1808   handle->running = GNUNET_NO;
1809   GNUNET_CONTAINER_multipeermap_destroy (handle->addresses);
1810   handle->addresses = NULL;
1811   while (NULL != (cur = handle->r_head))
1812   {
1813     GNUNET_CONTAINER_DLL_remove(handle->r_head, handle->r_tail, cur);
1814     GNUNET_free(cur);
1815   }
1816
1817   GNUNET_PLUGIN_unload (handle->plugin, handle->solver);
1818   GNUNET_free (handle->plugin);
1819   GNUNET_free(handle);
1820   /* Stop configured solution method */
1821   GAS_normalization_stop ();
1822 }
1823
1824
1825 struct PeerIteratorContext
1826 {
1827   GNUNET_ATS_Peer_Iterator it;
1828   void *it_cls;
1829   struct GNUNET_CONTAINER_MultiPeerMap *peers_returned;
1830 };
1831
1832
1833 /**
1834  * Iterator to iterate over all peers
1835  *
1836  * @param cls a PeerIteratorContext
1837  * @param key the peer id
1838  * @param value the ATS_address
1839  * @return #GNUNET_OK to continue
1840  */
1841 static int
1842 peer_it (void *cls,
1843          const struct GNUNET_PeerIdentity *key,
1844          void *value)
1845 {
1846   struct PeerIteratorContext *ip_ctx = cls;
1847
1848   if (GNUNET_NO ==
1849       GNUNET_CONTAINER_multipeermap_contains (ip_ctx->peers_returned, key))
1850   {
1851     GNUNET_CONTAINER_multipeermap_put (ip_ctx->peers_returned, key, NULL,
1852                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1853     ip_ctx->it (ip_ctx->it_cls, key);
1854   }
1855
1856   return GNUNET_OK;
1857 }
1858
1859 /**
1860  * Return information all peers currently known to ATS
1861  *
1862  * @param handle the address handle to use
1863  * @param p_it the iterator to call for every peer
1864  * @param p_it_cls the closure for the iterator
1865  */
1866 void
1867 GAS_addresses_iterate_peers (struct GAS_Addresses_Handle *handle,
1868     GNUNET_ATS_Peer_Iterator p_it, void *p_it_cls)
1869 {
1870   struct PeerIteratorContext ip_ctx;
1871   unsigned int size;
1872
1873   if (NULL == p_it)
1874     return;
1875   GNUNET_assert(NULL != handle->addresses);
1876
1877   size = GNUNET_CONTAINER_multipeermap_size (handle->addresses);
1878   if (0 != size)
1879   {
1880     ip_ctx.it = p_it;
1881     ip_ctx.it_cls = p_it_cls;
1882     ip_ctx.peers_returned = GNUNET_CONTAINER_multipeermap_create (size,
1883                                                                   GNUNET_NO);
1884     GNUNET_CONTAINER_multipeermap_iterate (handle->addresses,
1885                                            &peer_it,
1886                                            &ip_ctx);
1887     GNUNET_CONTAINER_multipeermap_destroy (ip_ctx.peers_returned);
1888   }
1889   p_it (p_it_cls, NULL );
1890 }
1891
1892 struct PeerInfoIteratorContext
1893 {
1894   GNUNET_ATS_PeerInfo_Iterator it;
1895   void *it_cls;
1896 };
1897
1898
1899 /**
1900  * Iterator to iterate over a peer's addresses
1901  *
1902  * @param cls a `struct PeerInfoIteratorContext`
1903  * @param key the peer id
1904  * @param value the `struct ATS_address`
1905  * @return #GNUNET_OK to continue
1906  */
1907 static int
1908 peerinfo_it (void *cls,
1909              const struct GNUNET_PeerIdentity *key,
1910              void *value)
1911 {
1912   struct PeerInfoIteratorContext *pi_ctx = cls;
1913   struct ATS_Address *addr = value;
1914
1915   if (NULL != pi_ctx->it)
1916   {
1917     pi_ctx->it (pi_ctx->it_cls, &addr->peer, addr->plugin, addr->addr,
1918         addr->addr_len, addr->active, addr->atsi, addr->atsi_count,
1919         addr->assigned_bw_out, addr->assigned_bw_in);
1920   }
1921   return GNUNET_YES;
1922 }
1923
1924
1925 /**
1926  * Return information all peers currently known to ATS
1927  *
1928  * @param handle the address handle to use
1929  * @param peer the respective peer
1930  * @param pi_it the iterator to call for every peer
1931  * @param pi_it_cls the closure for the iterator
1932  */
1933 void
1934 GAS_addresses_get_peer_info (struct GAS_Addresses_Handle *handle,
1935     const struct GNUNET_PeerIdentity *peer, GNUNET_ATS_PeerInfo_Iterator pi_it,
1936     void *pi_it_cls)
1937 {
1938   struct PeerInfoIteratorContext pi_ctx;
1939   struct GNUNET_BANDWIDTH_Value32NBO zero_bw;
1940
1941   GNUNET_assert(NULL != peer);
1942   GNUNET_assert(NULL != handle->addresses);
1943   if (NULL == pi_it)
1944     return; /* does not make sense without callback */
1945
1946   zero_bw = GNUNET_BANDWIDTH_value_init (0);
1947   pi_ctx.it = pi_it;
1948   pi_ctx.it_cls = pi_it_cls;
1949
1950   GNUNET_CONTAINER_multipeermap_get_multiple (handle->addresses,
1951                                               peer,
1952                                               &peerinfo_it, &pi_ctx);
1953
1954   if (NULL != pi_it)
1955     pi_it (pi_it_cls, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0, zero_bw,
1956         zero_bw);
1957
1958 }
1959
1960 /* end of gnunet-service-ats_addresses.c */