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