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