fixing dv plugin
[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  * Handle for ATS address component
275  */
276 struct GAS_Addresses_Handle
277 {
278   /**
279    *
280    */
281   struct GNUNET_STATISTICS_Handle *stat;
282
283   /**
284    * A multihashmap to store all addresses
285    */
286   struct GNUNET_CONTAINER_MultiPeerMap *addresses;
287
288   /**
289    * Is ATS addresses running
290    */
291   int running;
292
293   /**
294    * Preferences clients
295    */
296   int pref_clients;
297
298   /**
299    * Configured ATS solver
300    */
301   int ats_mode;
302
303   /**
304    *  Solver handle
305    */
306   void *solver;
307
308   /**
309    * Address suggestion requests DLL head
310    */
311   struct GAS_Addresses_Suggestion_Requests *pending_requests_head;
312
313   /**
314    * Address suggestion requests DLL tail
315    */
316   struct GAS_Addresses_Suggestion_Requests *pending_requests_tail;
317
318   /**
319    * Address suggestion requests DLL head
320    */
321   struct GAS_Addresses_Preference_Clients *preference_clients_head;
322
323   /**
324    * Address suggestion requests DLL head
325    */
326   struct GAS_Addresses_Preference_Clients *preference_clients_tail;
327
328   /**
329    * Solver functions
330    */
331   struct GNUNET_ATS_PluginEnvironment env;
332
333   /**
334    * Solver plugin name as string
335    */
336   char *plugin;
337 };
338
339 /**
340  * Disassemble ATS information and update performance information in address
341  *
342  * Updates existing information and adds new information
343  *
344  * @param dest destination address
345  * @param update source ATS information
346  * @param update_count number of ATS information
347  * @param delta_dest ats performance information which were updated
348  *                              including previous value
349  * @param delta_count number of ATS information in the delta
350  * @return GNUNET_YES if address was address updated, GNUNET_NO otherwise
351  */
352 static unsigned int
353 disassemble_ats_information (struct ATS_Address *dest,
354     const struct GNUNET_ATS_Information *update, uint32_t update_count,
355     struct GNUNET_ATS_Information **delta_dest, uint32_t *delta_count)
356 {
357
358   int c1;
359   int c2;
360   int found;
361   int change;
362
363   struct GNUNET_ATS_Information add_atsi[update_count];
364   struct GNUNET_ATS_Information delta_atsi[update_count];
365   struct GNUNET_ATS_Information *tmp_atsi;
366   uint32_t add_atsi_count;
367   uint32_t delta_atsi_count;
368
369   change = GNUNET_NO;
370   add_atsi_count = 0;
371   delta_atsi_count = 0;
372
373   if (0 == update_count)
374     return GNUNET_NO;
375
376   if (NULL == dest->atsi)
377   {
378     /* Create performance information */
379     dest->atsi =
380         GNUNET_malloc (update_count * sizeof (struct GNUNET_ATS_Information));
381     dest->atsi_count = update_count;
382     memcpy (dest->atsi, update,
383         update_count * sizeof(struct GNUNET_ATS_Information));
384     (*delta_dest) =
385         GNUNET_malloc (update_count * sizeof (struct GNUNET_ATS_Information));
386     for (c1 = 0; c1 < update_count; c1++)
387     {
388       (*delta_dest)[c1].type = update[c1].type;
389       (*delta_dest)[c1].value = htonl (GNUNET_ATS_VALUE_UNDEFINED);
390     }
391     (*delta_count) = update_count;
392     return GNUNET_YES;
393   }
394
395   for (c1 = 0; c1 < update_count; c1++)
396   {
397     /* Update existing performance information */
398     found = GNUNET_NO;
399     for (c2 = 0; c2 < dest->atsi_count; c2++)
400     {
401       if (update[c1].type == dest->atsi[c2].type)
402       {
403         if (update[c1].value != dest->atsi[c2].value)
404         {
405           /* Save previous value in delta */
406           delta_atsi[delta_atsi_count] = dest->atsi[c2];
407           delta_atsi_count++;
408           /* Set new value */
409           dest->atsi[c2].value = update[c1].value;
410           change = GNUNET_YES;
411         }
412         found = GNUNET_YES;
413         break;
414       }
415     }
416     if (GNUNET_NO == found)
417     {
418       add_atsi[add_atsi_count] = update[c1];
419       add_atsi_count++;
420       delta_atsi[delta_atsi_count].type = update[c1].type;
421       delta_atsi[delta_atsi_count].value = htonl (GNUNET_ATS_VALUE_UNDEFINED);
422       delta_atsi_count++;
423     }
424   }
425
426   if (add_atsi_count > 0)
427   {
428     /* Extend ats performance information */
429
430     tmp_atsi = GNUNET_malloc ((dest->atsi_count + add_atsi_count) *
431         (sizeof (struct GNUNET_ATS_Information)));
432     memcpy (tmp_atsi, dest->atsi,
433         dest->atsi_count * sizeof(struct GNUNET_ATS_Information));
434     memcpy (&tmp_atsi[dest->atsi_count], add_atsi,
435         add_atsi_count * sizeof(struct GNUNET_ATS_Information));
436     GNUNET_free(dest->atsi);
437     dest->atsi = tmp_atsi;
438     dest->atsi_count = dest->atsi_count + add_atsi_count;
439     change = GNUNET_YES;
440   }
441
442   if (delta_atsi_count > 0)
443   {
444     /* Copy delta */
445     (*delta_dest) =
446         GNUNET_malloc (delta_atsi_count * sizeof (struct GNUNET_ATS_Information));
447     memcpy ((*delta_dest), delta_atsi,
448         delta_atsi_count * sizeof(struct GNUNET_ATS_Information));
449     (*delta_count) = delta_atsi_count;
450   }
451
452   return change;
453 }
454
455 /**
456  * Free the given address
457  *
458  * @param addr address to destroy
459  */
460 static void
461 free_address (struct ATS_Address *addr)
462 {
463   GNUNET_free(addr->plugin);
464   GNUNET_free_non_null(addr->atsi);
465   GNUNET_free(addr);
466 }
467
468 /**
469  * Create a ATS_address with the given information
470  *
471  * @param peer peer
472  * @param plugin_name plugin
473  * @param plugin_addr address
474  * @param plugin_addr_len address length
475  * @param session_id session
476  * @return the ATS_Address
477  */
478 static struct ATS_Address *
479 create_address (const struct GNUNET_PeerIdentity *peer,
480     const char *plugin_name,
481     const void *plugin_addr,
482     size_t plugin_addr_len,
483     uint32_t local_address_info,
484     uint32_t session_id)
485 {
486   struct ATS_Address *aa = NULL;
487   int c1;
488   int c2;
489
490   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
491   aa->peer = *peer;
492   aa->addr_len = plugin_addr_len;
493   aa->addr = &aa[1];
494   memcpy (&aa[1], plugin_addr, plugin_addr_len);
495   aa->plugin = GNUNET_strdup (plugin_name);
496   aa->session_id = session_id;
497   aa->local_address_info = local_address_info;
498   aa->active = GNUNET_NO;
499   aa->used = GNUNET_NO;
500   aa->solver_information = NULL;
501   aa->atsi = NULL;
502   aa->atsi_count = 0;
503   aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0);
504   aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0);
505
506   for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1++)
507   {
508     aa->atsin[c1].avg_queue_index = 0;
509     for (c2 = 0; c2 < GAS_normalization_queue_length; c2++)
510       aa->atsin[c1].atsi_abs[c2] = GNUNET_ATS_VALUE_UNDEFINED;
511   }
512
513   return aa;
514 }
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  * Find an existing equivalent address record.
609  * Compares by peer identity and network address OR by session ID
610  * (one of the two must match).
611  *
612  * @param handle the address handle
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 (struct GAS_Addresses_Handle *handle,
619     const struct GNUNET_PeerIdentity *peer, 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 (handle->addresses,
627                                               peer,
628                                               &compare_address_it, &cac);
629
630   if (cac.exact_address == NULL)
631     return cac.base_address;
632   return cac.exact_address;
633 }
634
635
636 /**
637  * Find the exact address
638  *
639  * @param handle the address handle to use
640  * @param peer peer
641  * @param plugin_name transport plugin name
642  * @param plugin_addr plugin address
643  * @param plugin_addr_len length of the plugin address
644  * @param session_id session id, can be 0
645  * @return an ATS_address or NULL
646  */
647
648 static struct ATS_Address *
649 find_exact_address (struct GAS_Addresses_Handle *handle,
650     const struct GNUNET_PeerIdentity *peer,
651     const char *plugin_name,
652     const void *plugin_addr,
653     size_t plugin_addr_len,
654     uint32_t local_address_info,
655     uint32_t session_id)
656 {
657   struct ATS_Address *aa;
658   struct ATS_Address *ea;
659
660   aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
661       local_address_info, session_id);
662
663   /* Get existing address or address with session == 0 */
664   ea = find_equivalent_address (handle, peer, aa);
665   free_address (aa);
666   if (ea == NULL )
667     return NULL ;
668   else if (ea->session_id != session_id)
669     return NULL ;
670   return ea;
671 }
672
673 /**
674  * Function allowing the solver to obtain normalized preference
675  * values from solver
676  *
677  * @param cls unused
678  * @param id the peer to return the normalized properties for
679  * @return array of double values with |GNUNET_ATS_PreferenceCount| elements
680  */
681 const double *
682 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
683 {
684   return GAS_normalization_get_preferences_by_peer (id);
685 }
686
687 /**
688  * Function allowing the solver to obtain normalized property
689  * values for an address from solver
690  *
691  * @param cls unused
692  * @param address the address
693  * @return array of double values with |GNUNET_ATS_QualityPropertiesCount| elements
694  */
695 const double *
696 get_property_cb (void *cls, const struct ATS_Address *address)
697 {
698   return GAS_normalization_get_properties ((struct ATS_Address *) address);
699 }
700
701 /**
702  * Extract an ATS performance info from an address
703  *
704  * @param address the address
705  * @param type the type to extract in HBO
706  * @return the value in HBO or GNUNET_ATS_VALUE_UNDEFINED in HBO if value does not exist
707  */
708 static int
709 get_performance_info (struct ATS_Address *address, uint32_t type)
710 {
711   int c1;
712   GNUNET_assert(NULL != address);
713
714   if ((NULL == address->atsi) || (0 == address->atsi_count))
715     return GNUNET_ATS_VALUE_UNDEFINED;
716
717   for (c1 = 0; c1 < address->atsi_count; c1++)
718   {
719     if (ntohl (address->atsi[c1].type) == type)
720       return ntohl (address->atsi[c1].value);
721   }
722   return GNUNET_ATS_VALUE_UNDEFINED;
723 }
724
725 /**
726  * Add a new address for a peer.
727  *
728  * @param handle the address handle to use
729  * @param peer peer
730  * @param plugin_name transport plugin name
731  * @param plugin_addr plugin address
732  * @param plugin_addr_len length of the plugin address
733  * @param session_id session id, can be 0
734  * @param atsi performance information for this address
735  * @param atsi_count number of performance information contained
736  */
737 void
738 GAS_addresses_add (struct GAS_Addresses_Handle *handle,
739     const struct GNUNET_PeerIdentity *peer,
740     const char *plugin_name,
741     const void *plugin_addr,
742     size_t plugin_addr_len,
743     uint32_t local_address_info,
744     uint32_t session_id,
745     const struct GNUNET_ATS_Information *atsi,
746     uint32_t atsi_count)
747 {
748   struct ATS_Address *new_address;
749   struct ATS_Address *existing_address;
750   struct GNUNET_ATS_Information *atsi_delta;
751   uint32_t atsi_delta_count;
752   uint32_t addr_net;
753   uint32_t previous_session;
754   int c1;
755
756   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s'\n",
757       "ADDRESS ADD", GNUNET_i2s (peer));
758
759   if (GNUNET_NO == handle->running)
760     return;
761
762   GNUNET_assert(NULL != handle->addresses);
763
764   new_address = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
765       local_address_info, session_id);
766   atsi_delta = NULL;
767   disassemble_ats_information (new_address, atsi, atsi_count, &atsi_delta,
768       &atsi_delta_count);
769   GNUNET_free_non_null(atsi_delta);
770   addr_net = get_performance_info (new_address, GNUNET_ATS_NETWORK_TYPE);
771   if (GNUNET_ATS_VALUE_UNDEFINED == addr_net)
772     addr_net = GNUNET_ATS_NET_UNSPECIFIED;
773
774   /* Get existing address or address with session == 0 */
775   existing_address = find_equivalent_address (handle, peer, new_address);
776   if (existing_address == NULL )
777   {
778     /* Add a new address */
779     new_address->t_added = GNUNET_TIME_absolute_get();
780     new_address->t_last_activity = GNUNET_TIME_absolute_get();
781     GNUNET_assert(
782         GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (handle->addresses,
783                                                         peer,
784                                                         new_address,
785                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
786
787     GNUNET_STATISTICS_set (handle->stat, "# addresses",
788         GNUNET_CONTAINER_multipeermap_size (handle->addresses), GNUNET_NO);
789
790     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
791         "Adding new address %p for peer `%s', length %u, session id %u, %s\n",
792         new_address,
793         GNUNET_i2s (peer),
794         plugin_addr_len, session_id,
795         GNUNET_ATS_print_network_type (addr_net));
796
797     /* Tell solver about new address */
798     handle->env.sf.s_add (handle->solver, new_address, addr_net);
799
800     handle->env.sf.s_bulk_start (handle->solver);
801     GAS_normalization_normalize_property (handle->addresses, new_address, atsi,
802         atsi_count);
803     handle->env.sf.s_bulk_stop (handle->solver);
804
805     /* Notify performance clients about new address */
806     GAS_performance_notify_all_clients (&new_address->peer, new_address->plugin,
807         new_address->addr, new_address->addr_len, new_address->session_id,
808         new_address->atsi, new_address->atsi_count,
809         new_address->assigned_bw_out, new_address->assigned_bw_in);
810     return;
811   }
812
813   /* We have an existing address we can use, clean up new */
814   GNUNET_free(new_address->plugin);
815   GNUNET_free_non_null(new_address->atsi);
816   GNUNET_free(new_address);
817   new_address = NULL;
818
819   if (0 != existing_address->session_id)
820   {
821     /* Should not happen */
822     GNUNET_break(0);
823     return;
824   }
825
826   addr_net = get_performance_info (existing_address, GNUNET_ATS_NETWORK_TYPE);
827   if (GNUNET_ATS_VALUE_UNDEFINED == addr_net)
828     addr_net = GNUNET_ATS_NET_UNSPECIFIED;
829
830   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
831       "Found existing address for peer `%s' %p with new session %u in network %s\n",
832       GNUNET_i2s (peer), existing_address, session_id,
833       GNUNET_ATS_print_network_type (addr_net));
834   /* We have an address without an session, update this address */
835   existing_address->t_added = GNUNET_TIME_absolute_get();
836   existing_address->t_last_activity = GNUNET_TIME_absolute_get();
837   atsi_delta = NULL;
838   atsi_delta_count = 0;
839   if (GNUNET_YES
840       == disassemble_ats_information (existing_address, atsi, atsi_count,
841           &atsi_delta, &atsi_delta_count))
842   {
843     /* Notify performance clients about properties */
844     GAS_performance_notify_all_clients (&existing_address->peer,
845         existing_address->plugin, existing_address->addr,
846         existing_address->addr_len, existing_address->session_id,
847         existing_address->atsi, existing_address->atsi_count,
848         existing_address->assigned_bw_out, existing_address->assigned_bw_in);
849
850     for (c1 = 0; c1 < atsi_delta_count; c1++)
851     {
852       if ((GNUNET_ATS_NETWORK_TYPE == ntohl (atsi_delta[c1].type))
853           && (addr_net != ntohl (atsi_delta[c1].value)))
854       {
855         /* Network type changed */
856         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
857             "Address for peer `%s' %p changed from network %s to %s\n",
858             GNUNET_i2s (peer), existing_address,
859             GNUNET_ATS_print_network_type (addr_net),
860             GNUNET_ATS_print_network_type (ntohl (atsi_delta[c1].value)));
861         handle->env.sf.s_address_update_network (handle->solver, existing_address,
862             ntohl (atsi_delta[c1].value),
863             get_performance_info (existing_address, GNUNET_ATS_NETWORK_TYPE));
864         addr_net = get_performance_info (existing_address,
865             GNUNET_ATS_NETWORK_TYPE);
866       }
867     }
868     /* Notify solver about update with atsi information and session */
869     handle->env.sf.s_bulk_start (handle->solver);
870     GAS_normalization_normalize_property (handle->addresses, existing_address,
871         atsi, atsi_count);
872     handle->env.sf.s_bulk_stop (handle->solver);
873   }
874   GNUNET_free_non_null(atsi_delta);
875
876   /* Notify solver about new session */
877   if (existing_address->session_id == session_id)
878     return; /* possible, can both be 0 since address is revalidated */
879
880   previous_session = existing_address->session_id;
881   existing_address->session_id = session_id;
882   handle->env.sf.s_address_update_session (handle->solver, existing_address,
883       previous_session, session_id);
884
885   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
886       "Updated existing address for peer `%s' %p length %u with new session %u in network %s\n",
887       GNUNET_i2s (peer), existing_address, existing_address->addr_len,
888       session_id, GNUNET_ATS_print_network_type (addr_net));
889 }
890
891 /**
892  * Update an address with a session or performance information for a peer.
893  *
894  * If an address was added without a session it will be updated with the
895  * session
896  *
897  * @param handle the address handle to use
898  * @param peer peer
899  * @param plugin_name transport plugin name
900  * @param plugin_addr plugin address
901  * @param plugin_addr_len length of the plugin address
902  * @param session_id session id, can be 0
903  * @param atsi performance information for this address
904  * @param atsi_count number of performance information contained
905  */
906 void
907 GAS_addresses_update (struct GAS_Addresses_Handle *handle,
908     const struct GNUNET_PeerIdentity *peer,
909     const char *plugin_name,
910     const void *plugin_addr,
911     size_t plugin_addr_len,
912     uint32_t local_address_info,
913     uint32_t session_id,
914     const struct GNUNET_ATS_Information *atsi,
915     uint32_t atsi_count)
916 {
917   struct ATS_Address *aa;
918   struct GNUNET_ATS_Information *atsi_delta;
919   uint32_t atsi_delta_count;
920   uint32_t prev_session;
921   int c1;
922
923   if (GNUNET_NO == handle->running)
924     return;
925
926   GNUNET_assert(NULL != handle->addresses);
927
928   /* Get existing address */
929   aa = find_exact_address (handle, peer, plugin_name, plugin_addr,
930       plugin_addr_len, local_address_info, session_id);
931   if (aa == NULL )
932     return;
933   if (NULL == aa->solver_information)
934     return;
935
936   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s' address \n",
937       "ADDRESS UPDATE", GNUNET_i2s (peer), aa);
938
939   /* Update address */
940   aa->t_last_activity = GNUNET_TIME_absolute_get();
941   if (session_id != aa->session_id)
942   {
943     /* Session changed */
944     prev_session = aa->session_id;
945     aa->session_id = session_id;
946     handle->env.sf.s_address_update_session (handle->solver, aa, prev_session,
947         aa->session_id);
948   }
949
950   atsi_delta = NULL;
951   atsi_delta_count = 0;
952   if (GNUNET_YES
953       == disassemble_ats_information (aa, atsi, atsi_count, &atsi_delta,
954           &atsi_delta_count))
955   {
956     /* ATS properties changed */
957     for (c1 = 0; c1 < atsi_delta_count; c1++)
958     {
959       if (GNUNET_ATS_NETWORK_TYPE == ntohl (atsi_delta[c1].type))
960       {
961         /* Network type changed */
962         handle->env.sf.s_address_update_network (handle->solver, aa,
963             ntohl (atsi_delta[c1].value),
964             get_performance_info (aa, GNUNET_ATS_NETWORK_TYPE));
965       }
966     }
967
968     /* Notify performance clients about updated address */
969     GAS_performance_notify_all_clients (&aa->peer, aa->plugin, aa->addr,
970         aa->addr_len, aa->session_id, aa->atsi, aa->atsi_count,
971         aa->assigned_bw_out, aa->assigned_bw_in);
972
973     handle->env.sf.s_bulk_start (handle->solver);
974     GAS_normalization_normalize_property (handle->addresses, aa, atsi,
975         atsi_count);
976     handle->env.sf.s_bulk_stop (handle->solver);
977   }
978   GNUNET_free_non_null(atsi_delta);
979 }
980
981 struct DestroyContext
982 {
983   struct ATS_Address *aa;
984
985   struct GAS_Addresses_Handle *handle;
986
987   /**
988    * GNUNET_NO  : full address
989    * GNUNET_YES : just session
990    */
991   int result;
992 };
993
994 /**
995  * Delete an address
996  *
997  * If session != 0, just the session is deleted, the address itself still exists
998  * If session == 0, remove full address
999  * If session == 0 and addrlen == 0, destroy inbound address
1000  *
1001  * @param cls unused
1002  * @param key unused
1003  * @param value the 'struct ATS_Address'
1004  * @return GNUNET_OK (continue to iterate)
1005  */
1006 static int
1007 destroy_by_session_id (void *cls,
1008                        const struct GNUNET_PeerIdentity *key,
1009                        void *value)
1010 {
1011   struct DestroyContext *dc = cls;
1012   struct GAS_Addresses_Handle *handle = dc->handle;
1013   const struct ATS_Address *des = dc->aa;
1014   struct ATS_Address *aa = value;
1015
1016   GNUNET_assert(
1017       0 == memcmp (&aa->peer, &des->peer, sizeof(struct GNUNET_PeerIdentity)));
1018
1019   if (des->session_id == 0)
1020   {
1021     /* Session == 0, remove full address  */
1022     if ((0 == strcmp (des->plugin, aa->plugin))
1023         && (aa->addr_len == des->addr_len)
1024         && (0 == memcmp (des->addr, aa->addr, aa->addr_len)))
1025     {
1026
1027       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1028           "Deleting full address for peer `%s' session %u %p\n",
1029           GNUNET_i2s (&aa->peer), aa->session_id, aa);
1030
1031       /* Notify solver about deletion */
1032       GNUNET_assert(
1033           GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (handle->addresses,
1034                                                               &aa->peer,
1035                                                               aa));
1036       handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
1037       free_address (aa);
1038       dc->result = GNUNET_NO;
1039       return GNUNET_OK; /* Continue iteration */
1040     }
1041   }
1042   else
1043   {
1044     /* Session != 0, just remove session */
1045     if (aa->session_id != des->session_id)
1046       return GNUNET_OK; /* irrelevant */
1047
1048     if ((aa->session_id != 0) && (0 != strcmp (des->plugin, aa->plugin)))
1049     {
1050       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1051           "Different plugins during removal: `%s' vs `%s' \n", des->plugin,
1052           aa->plugin);
1053       GNUNET_break(0);
1054       return GNUNET_OK;
1055     }
1056
1057     if (aa->addr_len == 0)
1058     {
1059       /* Inbound connection died, delete full address */
1060       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1061           "Deleting inbound address for peer `%s': `%s' session %u\n",
1062           GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
1063
1064       /* Notify solver about deletion */
1065       GNUNET_assert(
1066           GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (handle->addresses,
1067                                                               &aa->peer, aa));
1068       handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
1069       free_address (aa);
1070       dc->result = GNUNET_NO;
1071       return GNUNET_OK; /* Continue iteration */
1072     }
1073     else
1074     {
1075       /* Session died */
1076       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1077           "Deleting session for peer `%s': `%s' %u\n", GNUNET_i2s (&aa->peer),
1078           aa->plugin, aa->session_id);
1079       /* Notify solver to delete session */
1080       handle->env.sf.s_del (handle->solver, aa, GNUNET_YES);
1081       aa->session_id = 0;
1082       aa->active = GNUNET_NO;
1083       return GNUNET_OK;
1084     }
1085   }
1086   return GNUNET_OK;
1087 }
1088
1089
1090 /**
1091  * Remove an address or just a session for a peer.
1092  *
1093  * @param handle the address handle to use
1094  * @param peer peer
1095  * @param plugin_name transport plugin name
1096  * @param plugin_addr plugin address
1097  * @param plugin_addr_len length of the plugin address
1098  * @param session_id session id, can be 0
1099  */
1100 void
1101 GAS_addresses_destroy (struct GAS_Addresses_Handle *handle,
1102     const struct GNUNET_PeerIdentity *peer,
1103     const char *plugin_name,
1104     const void *plugin_addr,
1105     size_t plugin_addr_len,
1106     uint32_t local_address_info,
1107     uint32_t session_id)
1108 {
1109   struct ATS_Address *ea;
1110   struct DestroyContext dc;
1111   if (GNUNET_NO == handle->running)
1112     return;
1113
1114   /* Get existing address */
1115   ea = find_exact_address (handle, peer, plugin_name, plugin_addr,
1116       plugin_addr_len, local_address_info, session_id);
1117   if (ea == NULL )
1118   {
1119     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1120         "Tried to destroy unknown address for peer `%s' `%s' session id %u\n",
1121         GNUNET_i2s (peer), plugin_name, session_id);
1122     return;
1123   }
1124
1125   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1126       "Received `%s' for peer `%s' address %p session %u\n", "ADDRESS DESTROY",
1127       GNUNET_i2s (peer), ea, session_id);
1128
1129   GNUNET_break(0 < strlen (plugin_name));
1130   dc.handle = handle;
1131   dc.aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
1132       local_address_info, session_id);
1133
1134   GNUNET_CONTAINER_multipeermap_get_multiple (handle->addresses,
1135                                               peer,
1136                                               &destroy_by_session_id, &dc);
1137   GNUNET_STATISTICS_set (handle->stat, "# addresses",
1138       GNUNET_CONTAINER_multipeermap_size (handle->addresses), GNUNET_NO);
1139   free_address (dc.aa);
1140 }
1141
1142 /**
1143  * Notification about active use of an address.
1144  * in_use == GNUNET_YES:
1145  *      This address is used to maintain an active connection with a peer.
1146  * in_use == GNUNET_NO:
1147  *      This address is no longer used to maintain an active connection with a peer.
1148  *
1149  * Note: can only be called with in_use == GNUNET_NO if called with GNUNET_YES
1150  * before
1151  *
1152  * @param handle the address handle to use
1153  * @param peer peer
1154  * @param plugin_name transport plugin name
1155  * @param plugin_addr plugin address
1156  * @param plugin_addr_len length of the plugin address
1157  * @param session_id session id, can be 0
1158  * @param in_use GNUNET_YES if GNUNET_NO
1159  * @return GNUNET_SYSERR on failure (address unknown ...)
1160  */
1161 int
1162 GAS_addresses_in_use (struct GAS_Addresses_Handle *handle,
1163     const struct GNUNET_PeerIdentity *peer, const char *plugin_name,
1164     const void *plugin_addr, size_t plugin_addr_len,
1165     uint32_t local_address_info,
1166     uint32_t session_id,
1167     int in_use)
1168 {
1169   struct ATS_Address *ea;
1170   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s'\n",
1171       "ADDRESS IN USE", GNUNET_i2s (peer));
1172
1173   if (GNUNET_NO == handle->running)
1174     return GNUNET_SYSERR;
1175
1176   ea = find_exact_address (handle, peer, plugin_name, plugin_addr,
1177       plugin_addr_len, local_address_info, session_id);
1178   if (NULL == ea)
1179   {
1180     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1181         "Trying to set unknown address `%s' `%s' `%u' to %s \n",
1182         GNUNET_i2s (peer), plugin_name, session_id,
1183         (GNUNET_NO == in_use) ? "NO" : "YES");
1184     GNUNET_break(0);
1185     return GNUNET_SYSERR;
1186   }
1187   if (ea->used == in_use)
1188   {
1189     GNUNET_break(0);
1190     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1191         "Address in use called multiple times for peer `%s': %s -> %s \n",
1192         GNUNET_i2s (peer), (GNUNET_NO == ea->used) ? "NO" : "YES",
1193         (GNUNET_NO == in_use) ? "NO" : "YES");
1194     return GNUNET_SYSERR;
1195   }
1196
1197   /* Tell solver about update */
1198   ea->used = in_use;
1199   ea->t_last_activity = GNUNET_TIME_absolute_get();
1200   handle->env.sf.s_address_update_inuse (handle->solver, ea, ea->used);
1201   return GNUNET_OK;
1202 }
1203
1204 /**
1205  * Cancel address suggestions for a peer
1206  *
1207  * @param handle the address handle
1208  * @param peer the peer id
1209  */
1210 void
1211 GAS_addresses_request_address_cancel (struct GAS_Addresses_Handle *handle,
1212     const struct GNUNET_PeerIdentity *peer)
1213 {
1214   struct GAS_Addresses_Suggestion_Requests *cur = handle->pending_requests_head;
1215
1216   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received request: `%s' for peer %s\n",
1217       "request_address_cancel", GNUNET_i2s (peer));
1218
1219   while (NULL != cur)
1220   {
1221     if (0 == memcmp (peer, &cur->id, sizeof(cur->id)))
1222       break; /* found */
1223     cur = cur->next;
1224   }
1225
1226   if (NULL == cur)
1227   {
1228     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1229         "No address requests pending for peer `%s', cannot remove!\n",
1230         GNUNET_i2s (peer));
1231     return;
1232   }
1233   handle->env.sf.s_get_stop (handle->solver, peer);
1234   GAS_addresses_handle_backoff_reset (handle, peer);
1235   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Removed request pending for peer `%s\n",
1236       GNUNET_i2s (peer));
1237   GNUNET_CONTAINER_DLL_remove(handle->pending_requests_head, handle->pending_requests_tail, cur);
1238   GNUNET_free(cur);
1239 }
1240
1241
1242 /**
1243  * Request address suggestions for a peer
1244  *
1245  * @param handle the address handle
1246  * @param peer the peer id
1247  */
1248 void
1249 GAS_addresses_request_address (struct GAS_Addresses_Handle *handle,
1250     const struct GNUNET_PeerIdentity *peer)
1251 {
1252   struct GAS_Addresses_Suggestion_Requests *cur = handle->pending_requests_head;
1253   struct ATS_Address *aa;
1254
1255   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s'\n",
1256       "REQUEST ADDRESS", GNUNET_i2s (peer));
1257
1258   if (GNUNET_NO == handle->running)
1259     return;
1260   while (NULL != cur)
1261   {
1262     if (0 == memcmp (peer, &cur->id, sizeof(cur->id)))
1263       break; /* already suggesting */
1264     cur = cur->next;
1265   }
1266   if (NULL == cur)
1267   {
1268     cur = GNUNET_new (struct GAS_Addresses_Suggestion_Requests);
1269     cur->id = (*peer);
1270     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1271         "Adding new address suggestion request for `%s'\n",
1272          GNUNET_i2s (peer));
1273     GNUNET_CONTAINER_DLL_insert(handle->pending_requests_head, handle->pending_requests_tail, cur);
1274   }
1275
1276   /* Get prefered address from solver */
1277   aa = (struct ATS_Address *) handle->env.sf.s_get (handle->solver, peer);
1278   if (NULL == aa)
1279   {
1280     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Cannot suggest address for peer `%s'\n",
1281         GNUNET_i2s (peer));
1282     return;
1283   }
1284
1285   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Suggesting address %p for peer `%s'\n",
1286       aa, GNUNET_i2s (peer));
1287
1288   GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
1289       aa->addr_len, aa->local_address_info, aa->session_id,
1290       aa->atsi, aa->atsi_count,
1291       aa->assigned_bw_out, aa->assigned_bw_in);
1292
1293   aa->block_interval = GNUNET_TIME_relative_add (aa->block_interval,
1294       ATS_BLOCKING_DELTA);
1295   aa->blocked_until = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
1296       aa->block_interval);
1297
1298   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1299       "Address %p ready for suggestion, block interval now %llu \n", aa,
1300       aa->block_interval);
1301 }
1302
1303 /**
1304  * Iterator to reset address blocking
1305  *
1306  * @param cls not used
1307  * @param key the peer
1308  * @param value the address to reset
1309  * @return #GNUNET_OK to continue
1310  */
1311 static int
1312 reset_address_it (void *cls,
1313                   const struct GNUNET_PeerIdentity *key,
1314                   void *value)
1315 {
1316   struct ATS_Address *aa = value;
1317
1318   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1319              "Resetting interval for peer `%s' address %p from %llu to 0\n",
1320              GNUNET_i2s (&aa->peer),
1321              aa,
1322              aa->block_interval);
1323   aa->blocked_until = GNUNET_TIME_UNIT_ZERO_ABS;
1324   aa->block_interval = GNUNET_TIME_UNIT_ZERO;
1325   return GNUNET_OK;
1326 }
1327
1328
1329 /**
1330  * Reset suggestion backoff for a peer
1331  *
1332  * Suggesting addresses is blocked for ATS_BLOCKING_DELTA. Blocking can be
1333  * reset using this function
1334  *
1335  * @param handle the address handle
1336  * @param peer the peer id
1337  */
1338 void
1339 GAS_addresses_handle_backoff_reset (struct GAS_Addresses_Handle *handle,
1340     const struct GNUNET_PeerIdentity *peer)
1341 {
1342   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received `%s' for peer `%s'\n",
1343       "RESET BACKOFF", GNUNET_i2s (peer));
1344
1345   GNUNET_break(
1346       GNUNET_SYSERR != GNUNET_CONTAINER_multipeermap_get_multiple (handle->addresses,
1347                                                                    peer,
1348                                                                    &reset_address_it, NULL));
1349 }
1350
1351
1352 static int
1353 eval_count_active_it (void *cls,
1354                       const struct GNUNET_PeerIdentity *id,
1355                       void *obj)
1356 {
1357   int *request_fulfilled = cls;
1358   struct ATS_Address *addr = obj;
1359
1360   if (GNUNET_YES == addr->active)
1361     (*request_fulfilled) = GNUNET_YES;
1362
1363   if (*request_fulfilled == GNUNET_YES)
1364     return GNUNET_NO;
1365   else
1366     return GNUNET_YES;
1367 }
1368
1369
1370 /**
1371  * Summary context
1372  */
1373 struct SummaryContext
1374 {
1375   /**
1376    * Sum of the utilized inbound bandwidth per network
1377    */
1378   unsigned long long bandwidth_in_assigned[GNUNET_ATS_NetworkTypeCount];
1379
1380   /**
1381    * Sum of the utilized outbound bandwidth per network
1382    */
1383   unsigned long long bandwidth_out_assigned[GNUNET_ATS_NetworkTypeCount];
1384
1385   /**
1386    * Sum addresses within a network
1387    */
1388   unsigned int addresses_in_network[GNUNET_ATS_NetworkTypeCount];
1389 };
1390
1391
1392 static int
1393 eval_sum_bw_used (void *cls, const struct GNUNET_PeerIdentity *id, void *obj)
1394 {
1395   struct SummaryContext *ctx = cls;
1396   struct ATS_Address *addr = obj;
1397   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1398   int net;
1399   int c;
1400
1401   if (GNUNET_YES == addr->active)
1402   {
1403     net = get_performance_info (addr, GNUNET_ATS_NETWORK_TYPE);
1404     for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1405     {
1406       if (net == networks[c])
1407       {
1408         ctx->addresses_in_network[c] ++;
1409         ctx->bandwidth_in_assigned[c] += ntohl (addr->assigned_bw_in.value__);
1410         ctx->bandwidth_out_assigned[c] += ntohl (addr->assigned_bw_out.value__);
1411       }
1412     }
1413     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1414                 "Active address in  %s with (in/out) %u/%u Bps\n",
1415                 GNUNET_ATS_print_network_type (net),
1416                 (unsigned int) ntohl (addr->assigned_bw_in.value__),
1417                 (unsigned int) ntohl (addr->assigned_bw_out.value__));
1418   }
1419   return GNUNET_OK;
1420 }
1421
1422
1423 /**
1424  * Summary context
1425  */
1426 struct RelativityContext
1427 {
1428
1429   struct GAS_Addresses_Handle *ah;
1430 };
1431
1432
1433 static int
1434 find_active_address (void *cls, const struct GNUNET_PeerIdentity *id, void *obj)
1435 {
1436   struct ATS_Address **res = cls;
1437   struct ATS_Address *addr = obj;
1438
1439   if (GNUNET_YES == addr->active)
1440     (*res) = addr;
1441
1442   if (NULL != (*res))
1443     return GNUNET_NO;
1444   else
1445     return GNUNET_YES;
1446 }
1447
1448 /**
1449  * Evaluate current bandwidth assignment
1450  *
1451  * @param ah address handle
1452  */
1453 void
1454 GAS_addresses_evaluate_assignment (struct GAS_Addresses_Handle *ah)
1455 {
1456   struct GAS_Addresses_Suggestion_Requests *cur;
1457   struct GAS_Addresses_Preference_Clients *pcur;
1458   int c;
1459
1460   float quality_requests_fulfilled = 0.0;
1461   float quality_bandwidth_utilization[GNUNET_ATS_NetworkTypeCount];
1462   float quality_bandwidth_utilization_total = 0.0;
1463   float quality_application_requirements = 0.0;
1464   float guq = 0.0;
1465
1466   int include_requests;
1467   int include_utilization;
1468   int include_requirements;
1469
1470   /* Variable related to requests */
1471   unsigned int requests_pending;
1472   unsigned int requests_fulfilled;
1473   unsigned int request_active;
1474
1475   /* Variable related to utilization */
1476   struct SummaryContext sum;
1477   struct ATS_Address *active_address;
1478   int network_count;
1479
1480   /* Variables for preferences */
1481   int prefs[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceType;
1482   double pref_val;
1483   double prop_val;
1484   const double *norm_values;
1485   double prefs_fulfill[GNUNET_ATS_PreferenceCount];
1486   int prefs_clients[GNUNET_ATS_PreferenceCount];
1487   int rels;
1488
1489   GNUNET_assert (NULL != ah);
1490   GNUNET_assert (NULL != ah->addresses);
1491
1492   requests_pending = 0;
1493   requests_fulfilled = 0;
1494   /* 1) How many requests could be fulfilled? */
1495   for (cur = ah->pending_requests_head; NULL != cur; cur = cur->next)
1496   {
1497     request_active = GNUNET_NO;
1498     GNUNET_CONTAINER_multipeermap_get_multiple (ah->addresses,
1499         &cur->id, &eval_count_active_it, &request_active);
1500     if (GNUNET_YES == request_active)
1501       requests_fulfilled ++;
1502     requests_pending ++;
1503     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': %u pending requests, %s\n",
1504         GNUNET_i2s (&cur->id),
1505         requests_pending,
1506         (GNUNET_YES == request_active) ? "active adress" : "no active address");
1507
1508   }
1509   if (requests_pending > 0)
1510   {
1511     quality_requests_fulfilled = (float) requests_fulfilled / requests_pending;
1512     include_requests = GNUNET_YES;
1513   }
1514   else
1515   {
1516     quality_requests_fulfilled = 0.0;
1517     include_requests = GNUNET_NO;
1518   }
1519   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u pending requests, %u requests fullfilled\n",
1520       requests_pending, requests_fulfilled);
1521
1522   /* 2) How well is bandwidth utilized? */
1523   network_count = 0;
1524   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1525   {
1526     quality_bandwidth_utilization[c] = 0.0;
1527     sum.addresses_in_network[c] = 0;
1528     sum.bandwidth_in_assigned[c] = 0;
1529     sum.bandwidth_out_assigned[c] = 0;
1530   }
1531   GNUNET_CONTAINER_multipeermap_iterate(ah->addresses,
1532       &eval_sum_bw_used, &sum);
1533   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1534   {
1535     quality_bandwidth_utilization[c] = (((float)sum.bandwidth_out_assigned[c] / ah->env.out_quota[c]) +
1536         ((float)sum.bandwidth_in_assigned[c] / ah->env.in_quota[c])) / 2;
1537
1538     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Utilization for network `%s': %f\n",
1539          GNUNET_ATS_print_network_type(ah->env.networks[c]),
1540          quality_bandwidth_utilization[c]);
1541     if (sum.addresses_in_network[c] > 0)
1542     {
1543       quality_bandwidth_utilization_total += quality_bandwidth_utilization[c];
1544       network_count ++;
1545     }
1546   }
1547   if (0 < network_count)
1548   {
1549     quality_bandwidth_utilization_total /= network_count;
1550     include_utilization = GNUNET_YES;
1551   }
1552   else
1553   {
1554     quality_bandwidth_utilization_total = 0.0;
1555     include_utilization = GNUNET_NO;
1556   }
1557
1558   /* 3) How well does selection match application requirements */
1559   if (0 == ah->pref_clients)
1560   {
1561     include_requirements = 0;
1562   }
1563   else
1564   {
1565     for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
1566     {
1567       prefs_fulfill[c] = 0.0;
1568       prefs_clients[c] = 0;
1569     }
1570
1571     for (cur = ah->pending_requests_head; NULL != cur; cur = cur->next)
1572     {
1573       active_address = NULL;
1574       GNUNET_CONTAINER_multipeermap_get_multiple (ah->addresses,
1575           &cur->id, &find_active_address, &active_address);
1576
1577       for (pcur = ah->preference_clients_head; NULL != pcur; pcur = pcur->next)
1578       {
1579         for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
1580         {
1581           if (prefs[c] == GNUNET_ATS_PREFERENCE_END)
1582             continue;
1583           pref_val = GAS_normalization_get_preferences_by_client (pcur->client, &cur->id, prefs[c]);
1584           if (-1.0 == pref_val)
1585           {
1586             GNUNET_break (0);
1587             continue;
1588           }
1589
1590           if (DEFAULT_REL_PREFERENCE == pref_val)
1591           {
1592             /* Default preference value */
1593             continue;
1594           }
1595
1596           if (NULL != active_address)
1597           {
1598             norm_values = GAS_normalization_get_properties (active_address);
1599             prop_val = norm_values[c];
1600             if ((norm_values[c] <= 1.0) || (norm_values[c] >= 2.0))
1601                 prop_val = DEFAULT_REL_QUALITY;
1602           }
1603           else
1604           {
1605             prop_val = DEFAULT_REL_QUALITY;
1606           }
1607
1608           /* We now have preference values [1..2] and properties [1..2] */
1609
1610           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u Client %p, Peer %s Property %s: pref: %.3f prop %.3f \n",
1611               c,
1612               pcur->client,
1613               GNUNET_i2s (&cur->id),
1614               GNUNET_ATS_print_preference_type(prefs[c]),
1615               pref_val,
1616               prop_val);
1617
1618           prefs_fulfill[c] += (pref_val * prop_val) / 2;
1619           prefs_clients[c] ++;
1620         }
1621       }
1622     }
1623     rels = 0;
1624     for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
1625     {
1626       if (0 < prefs_clients[c])
1627       {
1628         prefs_fulfill[c] /= prefs_clients[c];
1629         rels ++;
1630         quality_application_requirements += prefs_fulfill[c];
1631       }
1632     }
1633     if (rels > 0)
1634       quality_application_requirements /= rels;
1635     else
1636       quality_application_requirements = 0.0;
1637
1638     include_requirements = 1;
1639   }
1640   /* GUQ */
1641
1642   if (include_requests + include_utilization + include_requirements > 0)
1643     guq = (quality_requests_fulfilled + quality_bandwidth_utilization_total + quality_application_requirements) /
1644       (include_requests + include_utilization + include_requirements);
1645   else
1646     guq = 0.0;
1647
1648   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1649       "Requests fulfilled %.3f bandwidth utilized %.3f application preferences met %.3f => %.3f\n",
1650       quality_requests_fulfilled,
1651       quality_bandwidth_utilization_total,
1652       quality_application_requirements,
1653       guq);
1654 }
1655
1656 /**
1657  * Solver information callback
1658  *
1659  * @param cls the closure
1660  * @param op the operation
1661  * @param stat operation status
1662  * @param add additional information
1663  */
1664
1665 static void
1666 solver_info_cb (void *cls,
1667     enum GAS_Solver_Operation op,
1668     enum GAS_Solver_Status stat,
1669     enum GAS_Solver_Additional_Information add)
1670 {
1671   char *add_info;
1672
1673   switch (add) {
1674     case GAS_INFO_NONE:
1675       add_info = "GAS_INFO_NONE";
1676       break;
1677     case GAS_INFO_FULL:
1678       add_info = "GAS_INFO_MLP_FULL";
1679       break;
1680     case GAS_INFO_UPDATED:
1681       add_info = "GAS_INFO_MLP_UPDATED";
1682       break;
1683     case GAS_INFO_PROP_ALL:
1684       add_info = "GAS_INFO_PROP_ALL";
1685       break;
1686     case GAS_INFO_PROP_SINGLE:
1687       add_info = "GAS_INFO_PROP_SINGLE";
1688       break;
1689     default:
1690       add_info = "INVALID";
1691       break;
1692   }
1693   switch (op)
1694   {
1695     case GAS_OP_SOLVE_START:
1696       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1697           "Solver notifies `%s' with result `%s' `%s'\n", "GAS_OP_SOLVE_START",
1698           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
1699       return;
1700     case GAS_OP_SOLVE_STOP:
1701       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1702           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
1703           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
1704       return;
1705
1706     case GAS_OP_SOLVE_SETUP_START:
1707       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1708           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
1709           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
1710       return;
1711
1712     case GAS_OP_SOLVE_SETUP_STOP:
1713       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1714           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
1715           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
1716       return;
1717
1718     case GAS_OP_SOLVE_MLP_LP_START:
1719       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1720           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
1721           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
1722       return;
1723     case GAS_OP_SOLVE_MLP_LP_STOP:
1724       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1725           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
1726           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
1727       return;
1728
1729     case GAS_OP_SOLVE_MLP_MLP_START:
1730       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1731           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
1732           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
1733       return;
1734     case GAS_OP_SOLVE_MLP_MLP_STOP:
1735       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1736           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
1737           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
1738       return;
1739     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
1740       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1741           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
1742           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
1743       return;
1744     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
1745       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1746           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
1747           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
1748       GAS_addresses_evaluate_assignment (cls);
1749       return;
1750     default:
1751       break;
1752     }
1753 }
1754
1755
1756 /**
1757  * The preference changed for a peer
1758  *
1759  * @param cls the address handle
1760  * @param peer the peer
1761  * @param kind the ATS kind
1762  * @param pref_rel the new relative preference value
1763  */
1764 static void
1765 normalized_preference_changed_cb (void *cls,
1766     const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind kind,
1767     double pref_rel)
1768 {
1769   GNUNET_assert(NULL != cls);
1770   struct GAS_Addresses_Handle *handle = cls;
1771
1772   /* Tell solver about update */
1773   handle->env.sf.s_pref (handle->solver, peer, kind, pref_rel);
1774 }
1775
1776 /**
1777  * The relative value for a property changed
1778  *
1779  * @param cls the address handle
1780  * @param address the peer
1781  * @param type the ATS type
1782  * @param prop_rel the new relative preference value
1783  */
1784 static void
1785 normalized_property_changed_cb (void *cls, struct ATS_Address *address,
1786     uint32_t type, double prop_rel)
1787 {
1788   struct GAS_Addresses_Handle *ah = (struct GAS_Addresses_Handle *) cls;
1789   GNUNET_assert(NULL != ah);
1790
1791   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1792       "Normalized property %s for peer `%s' changed to %.3f \n",
1793       GNUNET_ATS_print_property_type (type), GNUNET_i2s (&address->peer),
1794       prop_rel);
1795
1796   ah->env.sf.s_address_update_property (ah->solver, address, type, 0, prop_rel);
1797 }
1798
1799 static struct GAS_Addresses_Preference_Clients *
1800 find_preference_client (struct GAS_Addresses_Handle *handle, void *client)
1801 {
1802   struct GAS_Addresses_Preference_Clients *cur;
1803
1804   for (cur = handle->preference_clients_head; NULL != cur; cur = cur->next)
1805   {
1806     if (cur->client == client)
1807       return cur;
1808   }
1809   return NULL;
1810 }
1811
1812 /**
1813  * A performance client disconnected
1814  *
1815  * @param handle address handle
1816  * @param client the client
1817  */
1818
1819 void
1820 GAS_addresses_preference_client_disconnect (struct GAS_Addresses_Handle *handle,
1821     void *client)
1822 {
1823   struct GAS_Addresses_Preference_Clients * pc;
1824   if (NULL != (pc = find_preference_client (handle, client)))
1825   {
1826     GNUNET_CONTAINER_DLL_remove (handle->preference_clients_head,
1827         handle->preference_clients_tail, pc);
1828     GNUNET_free (pc);
1829     GNUNET_assert (handle->pref_clients > 0);
1830     handle->pref_clients --;
1831     GNUNET_STATISTICS_set (handle->stat, "# active performance clients", handle->pref_clients, GNUNET_NO);
1832   }
1833   GAS_normalization_preference_client_disconnect (client);
1834 }
1835
1836 /**
1837  * Change the preference for a peer
1838  *
1839  * @param handle the address handle
1840  * @param client the client sending this request
1841  * @param peer the peer id
1842  * @param kind the preference kind to change
1843  * @param score_abs the new preference score
1844  */
1845 void
1846 GAS_addresses_preference_change (struct GAS_Addresses_Handle *handle,
1847     void *client, const struct GNUNET_PeerIdentity *peer,
1848     enum GNUNET_ATS_PreferenceKind kind, float score_abs)
1849 {
1850   struct GAS_Addresses_Preference_Clients * pc;
1851   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1852       "Received `%s' for peer `%s' for client %p\n", "CHANGE PREFERENCE",
1853       GNUNET_i2s (peer), client);
1854
1855   if (GNUNET_NO == handle->running)
1856     return;
1857
1858   if (GNUNET_NO ==
1859       GNUNET_CONTAINER_multipeermap_contains (handle->addresses,
1860                                               peer))
1861   {
1862     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1863         "Received `%s' for unknown peer `%s' from client %p\n",
1864         "CHANGE PREFERENCE", GNUNET_i2s (peer), client);
1865     return;
1866   }
1867
1868   if (NULL == find_preference_client (handle, client))
1869   {
1870     pc = GNUNET_new (struct GAS_Addresses_Preference_Clients);
1871     pc->client = client;
1872     GNUNET_CONTAINER_DLL_insert (handle->preference_clients_head,
1873         handle->preference_clients_tail, pc);
1874     handle->pref_clients ++;
1875     GNUNET_STATISTICS_set (handle->stat, "# active performance clients", handle->pref_clients, GNUNET_NO);
1876   }
1877
1878   handle->env.sf.s_bulk_start (handle->solver);
1879   /* Tell normalization about change, normalization will call callback if preference changed */
1880   GAS_normalization_normalize_preference (client, peer, kind, score_abs);
1881   handle->env.sf.s_bulk_stop (handle->solver);
1882 }
1883
1884 /**
1885  * Change the preference for a peer
1886  *
1887  * @param handle the address handle
1888  * @param application the client sending this request
1889  * @param peer the peer id
1890  * @param scope the time interval for this feedback: [now - scope .. now]
1891  * @param kind the preference kind to change
1892  * @param score_abs the new preference score
1893  */
1894 void
1895 GAS_addresses_preference_feedback (struct GAS_Addresses_Handle *handle,
1896     void *application, const struct GNUNET_PeerIdentity *peer,
1897     const struct GNUNET_TIME_Relative scope,
1898     enum GNUNET_ATS_PreferenceKind kind, float score_abs)
1899 {
1900   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1901       "Received `%s' for peer `%s' for client %p\n", "PREFERENCE FEEDBACK",
1902       GNUNET_i2s (peer), application);
1903
1904   if (GNUNET_NO == handle->running)
1905     return;
1906
1907   if (GNUNET_NO ==
1908       GNUNET_CONTAINER_multipeermap_contains (handle->addresses,
1909                                               peer))
1910   {
1911     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1912         "Received `%s' for unknown peer `%s' from client %p\n",
1913         "PREFERENCE FEEDBACK", GNUNET_i2s (peer), application);
1914     return;
1915   }
1916
1917   handle->env.sf.s_feedback (handle->solver, application, peer, scope, kind,
1918       score_abs);
1919 }
1920
1921 /**
1922  * Load quotas for networks from configuration
1923  *
1924  * @param cfg configuration handle
1925  * @param out_dest where to write outbound quotas
1926  * @param in_dest where to write inbound quotas
1927  * @param dest_length length of inbound and outbound arrays
1928  * @return number of networks loaded
1929  */
1930 static unsigned int
1931 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
1932     unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
1933 {
1934   char *network_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
1935   char * entry_in = NULL;
1936   char * entry_out = NULL;
1937   char * quota_out_str;
1938   char * quota_in_str;
1939   int c;
1940   int res;
1941
1942   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
1943   {
1944     in_dest[c] = 0;
1945     out_dest[c] = 0;
1946     GNUNET_asprintf (&entry_out, "%s_QUOTA_OUT", network_str[c]);
1947     GNUNET_asprintf (&entry_in, "%s_QUOTA_IN", network_str[c]);
1948
1949     /* quota out */
1950     if (GNUNET_OK
1951         == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_out,
1952             &quota_out_str))
1953     {
1954       res = GNUNET_NO;
1955       if (0 == strcmp (quota_out_str, GNUNET_ATS_MaxBandwidthString))
1956       {
1957         out_dest[c] = GNUNET_ATS_MaxBandwidth;
1958         res = GNUNET_YES;
1959       }
1960       if ((GNUNET_NO == res)
1961           && (GNUNET_OK
1962               == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str,
1963                   &out_dest[c])))
1964         res = GNUNET_YES;
1965       if ((GNUNET_NO == res)
1966           && (GNUNET_OK
1967               == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_out,
1968                   &out_dest[c])))
1969         res = GNUNET_YES;
1970
1971       if (GNUNET_NO == res)
1972       {
1973         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1974             _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
1975             network_str[c], quota_out_str, GNUNET_ATS_DefaultBandwidth);
1976         out_dest[c] = GNUNET_ATS_DefaultBandwidth;
1977       }
1978       else
1979       {
1980         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1981             _("Outbound quota configure for network `%s' is %llu\n"),
1982             network_str[c], out_dest[c]);
1983       }
1984       GNUNET_free(quota_out_str);
1985     }
1986     else
1987     {
1988       GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1989           _("No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
1990           network_str[c], GNUNET_ATS_DefaultBandwidth);
1991       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
1992     }
1993
1994     /* quota in */
1995     if (GNUNET_OK
1996         == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_in,
1997             &quota_in_str))
1998     {
1999       res = GNUNET_NO;
2000       if (0 == strcmp (quota_in_str, GNUNET_ATS_MaxBandwidthString))
2001       {
2002         in_dest[c] = GNUNET_ATS_MaxBandwidth;
2003         res = GNUNET_YES;
2004       }
2005       if ((GNUNET_NO == res)
2006           && (GNUNET_OK
2007               == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
2008         res = GNUNET_YES;
2009       if ((GNUNET_NO == res)
2010           && (GNUNET_OK
2011               == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_in,
2012                   &in_dest[c])))
2013         res = GNUNET_YES;
2014
2015       if (GNUNET_NO == res)
2016       {
2017         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2018             _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
2019             network_str[c], quota_in_str, GNUNET_ATS_DefaultBandwidth);
2020         in_dest[c] = GNUNET_ATS_DefaultBandwidth;
2021       }
2022       else
2023       {
2024         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2025             _("Inbound quota configured for network `%s' is %llu\n"),
2026             network_str[c], in_dest[c]);
2027       }
2028       GNUNET_free(quota_in_str);
2029     }
2030     else
2031     {
2032       GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
2033           _("No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
2034           network_str[c], GNUNET_ATS_DefaultBandwidth);
2035       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
2036     }
2037     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2038         "Loaded quota for network `%s' (in/out): %llu %llu\n", network_str[c],
2039         in_dest[c], out_dest[c]);
2040     GNUNET_free(entry_out);
2041     GNUNET_free(entry_in);
2042   }
2043   return GNUNET_ATS_NetworkTypeCount;
2044 }
2045
2046 /**
2047  * Callback for solver to notify about assignment changes
2048  *
2049  * @param cls the GAS_Addresses_Handle
2050  * @param address the address with changes
2051  */
2052 static void
2053 bandwidth_changed_cb (void *cls, struct ATS_Address *address)
2054 {
2055   struct GAS_Addresses_Handle *handle = cls;
2056   struct GAS_Addresses_Suggestion_Requests *cur;
2057
2058   GNUNET_assert(handle != NULL);
2059   GNUNET_assert(address != NULL);
2060
2061   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2062       "Bandwidth assignment changed for peer %s \n",
2063       GNUNET_i2s (&address->peer));
2064
2065   /* Notify performance clients about changes to address */
2066   GAS_performance_notify_all_clients (&address->peer, address->plugin,
2067       address->addr, address->addr_len, address->session_id, address->atsi,
2068       address->atsi_count, address->assigned_bw_out, address->assigned_bw_in);
2069   cur = handle->pending_requests_head;
2070   while (NULL != cur)
2071   {
2072     if (0 == memcmp (&address->peer, &cur->id, sizeof(cur->id)))
2073       break; /* we have an address request pending*/
2074     cur = cur->next;
2075   }
2076   if (NULL == cur)
2077   {
2078     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2079                "Nobody is interested in peer `%s' :(\n",
2080                GNUNET_i2s (&address->peer));
2081     return;
2082   }
2083
2084   if ((0 == ntohl (address->assigned_bw_in.value__))
2085       && (0 == ntohl (address->assigned_bw_out.value__)))
2086   {
2087     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2088                "Telling transport to disconnect peer `%s'\n",
2089                 GNUNET_i2s (&address->peer));
2090   }
2091   else
2092   {
2093     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2094                "Sending bandwidth update for peer `%s': %u %u\n",
2095                GNUNET_i2s (&address->peer),
2096                (unsigned int) ntohl (address->assigned_bw_out.value__),
2097                (unsigned int) ntohl (address->assigned_bw_out.value__));
2098   }
2099
2100   /* *Notify scheduling clients about suggestion */
2101   GAS_scheduling_transmit_address_suggestion (&address->peer, address->plugin,
2102       address->addr, address->addr_len, address->local_address_info,
2103       address->session_id, address->atsi,
2104       address->atsi_count, address->assigned_bw_out, address->assigned_bw_in);
2105 }
2106
2107
2108 /**
2109  * Initialize address subsystem. The addresses subsystem manages the addresses
2110  * known and current performance information. It has a solver component
2111  * responsible for the resource allocation. It tells the solver about changes
2112  * and receives updates when the solver changes the resource allocation.
2113  *
2114  * @param cfg configuration to use
2115  * @param stats the statistics handle to use
2116  * @return an address handle
2117  */
2118 struct GAS_Addresses_Handle *
2119 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
2120     const struct GNUNET_STATISTICS_Handle *stats)
2121 {
2122   struct GAS_Addresses_Handle *ah;
2123   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
2124   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
2125   char *mode_str;
2126   char *plugin_short;
2127   int c;
2128
2129   ah = GNUNET_new (struct GAS_Addresses_Handle);
2130   ah->running = GNUNET_NO;
2131
2132   ah->stat = (struct GNUNET_STATISTICS_Handle *) stats;
2133   /* Initialize the addresses database */
2134   ah->addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
2135   ah->pref_clients = 0;
2136   GNUNET_assert(NULL != ah->addresses);
2137
2138   /* Figure out configured solution method */
2139   if (GNUNET_SYSERR
2140       == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
2141   {
2142     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
2143         "No resource assignment method configured, using proportional approach\n");
2144     ah->ats_mode = MODE_PROPORTIONAL;
2145   }
2146   else
2147   {
2148     for (c = 0; c < strlen (mode_str); c++)
2149       mode_str[c] = toupper (mode_str[c]);
2150     if (0 == strcmp (mode_str, "PROPORTIONAL"))
2151       ah->ats_mode = MODE_PROPORTIONAL;
2152     else if (0 == strcmp (mode_str, "MLP"))
2153     {
2154       ah->ats_mode = MODE_MLP;
2155 #if !HAVE_LIBGLPK
2156       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2157           "Assignment method `%s' configured, but GLPK is not available, please install \n",
2158           mode_str);
2159       ah->ats_mode = MODE_PROPORTIONAL;
2160 #endif
2161     }
2162     else if (0 == strcmp (mode_str, "RIL"))
2163       ah->ats_mode = MODE_RIL;
2164     else
2165     {
2166       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2167           "Invalid resource assignment method `%s' configured, using proportional approach\n",
2168           mode_str);
2169       ah->ats_mode = MODE_PROPORTIONAL;
2170     }
2171     GNUNET_free(mode_str);
2172   }
2173
2174   load_quotas (cfg, quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount);
2175   ah->env.info_cb = &solver_info_cb;
2176   ah->env.info_cb_cls = ah;
2177   ah->env.bandwidth_changed_cb = &bandwidth_changed_cb;
2178   ah->env.bw_changed_cb_cls = ah;
2179   ah->env.get_preferences = &get_preferences_cb;
2180   ah->env.get_preference_cls = ah;
2181   ah->env.get_property = &get_property_cb;
2182   ah->env.get_property_cls = ah;
2183   ah->env.cfg = cfg;
2184   ah->env.stats = stats;
2185   ah->env.addresses = ah->addresses;
2186
2187   ah->env.network_count = GNUNET_ATS_NetworkTypeCount;
2188   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
2189   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
2190   {
2191     ah->env.networks[c] = networks[c];
2192     ah->env.out_quota[c] = quotas_out[c];
2193     ah->env.in_quota[c] = quotas_in[c];
2194   }
2195
2196   switch (ah->ats_mode) {
2197     case MODE_PROPORTIONAL:
2198       plugin_short = "proportional";
2199       break;
2200     case MODE_MLP:
2201       plugin_short = "mlp";
2202       break;
2203     case MODE_RIL:
2204       plugin_short = "ril";
2205       break;
2206     default:
2207       plugin_short = NULL;
2208       break;
2209   }
2210   GNUNET_asprintf (&ah->plugin, "libgnunet_plugin_ats_%s", plugin_short);
2211   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s '`%s'\n"), plugin_short, ah->plugin);
2212   if  (NULL == (ah->solver = GNUNET_PLUGIN_load (ah->plugin, &ah->env)))
2213   {
2214     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), ah->plugin);
2215     return NULL;
2216   }
2217
2218   GNUNET_assert (NULL != ah->env.sf.s_add);
2219   GNUNET_assert (NULL != ah->env.sf.s_address_update_inuse);
2220   GNUNET_assert (NULL != ah->env.sf.s_address_update_property);
2221   GNUNET_assert (NULL != ah->env.sf.s_address_update_session);
2222   GNUNET_assert (NULL != ah->env.sf.s_address_update_network);
2223   GNUNET_assert (NULL != ah->env.sf.s_get);
2224   GNUNET_assert (NULL != ah->env.sf.s_get_stop);
2225   GNUNET_assert (NULL != ah->env.sf.s_pref);
2226   GNUNET_assert (NULL != ah->env.sf.s_feedback);
2227   GNUNET_assert (NULL != ah->env.sf.s_del);
2228   GNUNET_assert (NULL != ah->env.sf.s_bulk_start);
2229   GNUNET_assert (NULL != ah->env.sf.s_bulk_stop);
2230
2231
2232   GAS_normalization_start (&normalized_preference_changed_cb, ah,
2233       &normalized_property_changed_cb, ah);
2234
2235   if (NULL == ah->solver)
2236   {
2237     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver!\n"));
2238     GNUNET_free(ah);
2239     return NULL ;
2240   }
2241   /* up and running */
2242   ah->running = GNUNET_YES;
2243
2244   GNUNET_STATISTICS_set (ah->stat, "# addresses",
2245       GNUNET_CONTAINER_multipeermap_size (ah->addresses), GNUNET_NO);
2246
2247   return ah;
2248 }
2249
2250 /**
2251  * Destroy all addresses iterator
2252  *
2253  * @param cls NULL
2254  * @param key peer identity (unused)
2255  * @param value the 'struct ATS_Address' to free
2256  * @return #GNUNET_OK (continue to iterate)
2257  */
2258 static int
2259 destroy_all_address_it (void *cls,
2260                         const struct GNUNET_PeerIdentity *key,
2261                         void *value)
2262 {
2263   struct GAS_Addresses_Handle *handle = cls;
2264   struct ATS_Address *aa = value;
2265
2266   /* Remove */
2267   GNUNET_assert(GNUNET_YES ==
2268                 GNUNET_CONTAINER_multipeermap_remove (handle->addresses, key, value));
2269   /* Notify */
2270   handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
2271   /* Destroy */
2272   free_address (aa);
2273
2274   return GNUNET_OK;
2275 }
2276
2277
2278 /**
2279  * Remove all addresses
2280  *
2281  * @param handle the address handle to use
2282  */
2283 void
2284 GAS_addresses_destroy_all (struct GAS_Addresses_Handle *handle)
2285 {
2286   if (GNUNET_NO == handle->running)
2287     return;
2288
2289   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Destroying all addresses\n");
2290   handle->env.sf.s_bulk_start (handle->solver);
2291   if (handle->addresses != NULL )
2292     GNUNET_CONTAINER_multipeermap_iterate (handle->addresses,
2293                                            &destroy_all_address_it,
2294                                            handle);
2295   handle->env.sf.s_bulk_start (handle->solver);
2296 }
2297
2298
2299 /**
2300  * Shutdown address subsystem.
2301  *
2302  * @param handle the address handle to shutdown
2303  */
2304 void
2305 GAS_addresses_done (struct GAS_Addresses_Handle *handle)
2306 {
2307   struct GAS_Addresses_Suggestion_Requests *cur;
2308   struct GAS_Addresses_Preference_Clients *pcur;
2309
2310   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Shutting down addresses\n");
2311   GNUNET_assert(NULL != handle);
2312   GAS_addresses_destroy_all (handle);
2313   handle->running = GNUNET_NO;
2314   GNUNET_CONTAINER_multipeermap_destroy (handle->addresses);
2315   handle->addresses = NULL;
2316   while (NULL != (cur = handle->pending_requests_head))
2317   {
2318     GNUNET_CONTAINER_DLL_remove(handle->pending_requests_head, handle->pending_requests_tail, cur);
2319     GNUNET_free(cur);
2320   }
2321
2322   while (NULL != (pcur = handle->preference_clients_head))
2323   {
2324     GNUNET_CONTAINER_DLL_remove (handle->preference_clients_head,
2325         handle->preference_clients_tail, pcur);
2326     GNUNET_assert (handle->pref_clients > 0);
2327     handle->pref_clients --;
2328     GNUNET_STATISTICS_set (handle->stat, "# active performance clients", handle->pref_clients, GNUNET_NO);
2329     GNUNET_free (pcur);
2330   }
2331
2332   GNUNET_PLUGIN_unload (handle->plugin, handle->solver);
2333   GNUNET_free (handle->plugin);
2334   GNUNET_free(handle);
2335   /* Stop configured solution method */
2336   GAS_normalization_stop ();
2337 }
2338
2339
2340 struct PeerIteratorContext
2341 {
2342   GNUNET_ATS_Peer_Iterator it;
2343   void *it_cls;
2344   struct GNUNET_CONTAINER_MultiPeerMap *peers_returned;
2345 };
2346
2347
2348 /**
2349  * Iterator to iterate over all peers
2350  *
2351  * @param cls a PeerIteratorContext
2352  * @param key the peer id
2353  * @param value the ATS_address
2354  * @return #GNUNET_OK to continue
2355  */
2356 static int
2357 peer_it (void *cls,
2358          const struct GNUNET_PeerIdentity *key,
2359          void *value)
2360 {
2361   struct PeerIteratorContext *ip_ctx = cls;
2362
2363   if (GNUNET_NO ==
2364       GNUNET_CONTAINER_multipeermap_contains (ip_ctx->peers_returned, key))
2365   {
2366     GNUNET_CONTAINER_multipeermap_put (ip_ctx->peers_returned, key, NULL,
2367                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
2368     ip_ctx->it (ip_ctx->it_cls, key);
2369   }
2370
2371   return GNUNET_OK;
2372 }
2373
2374 /**
2375  * Return information all peers currently known to ATS
2376  *
2377  * @param handle the address handle to use
2378  * @param p_it the iterator to call for every peer
2379  * @param p_it_cls the closure for the iterator
2380  */
2381 void
2382 GAS_addresses_iterate_peers (struct GAS_Addresses_Handle *handle,
2383     GNUNET_ATS_Peer_Iterator p_it, void *p_it_cls)
2384 {
2385   struct PeerIteratorContext ip_ctx;
2386   unsigned int size;
2387
2388   if (NULL == p_it)
2389     return;
2390   GNUNET_assert(NULL != handle->addresses);
2391
2392   size = GNUNET_CONTAINER_multipeermap_size (handle->addresses);
2393   if (0 != size)
2394   {
2395     ip_ctx.it = p_it;
2396     ip_ctx.it_cls = p_it_cls;
2397     ip_ctx.peers_returned = GNUNET_CONTAINER_multipeermap_create (size,
2398                                                                   GNUNET_NO);
2399     GNUNET_CONTAINER_multipeermap_iterate (handle->addresses,
2400                                            &peer_it,
2401                                            &ip_ctx);
2402     GNUNET_CONTAINER_multipeermap_destroy (ip_ctx.peers_returned);
2403   }
2404   p_it (p_it_cls, NULL );
2405 }
2406
2407 struct PeerInfoIteratorContext
2408 {
2409   GNUNET_ATS_PeerInfo_Iterator it;
2410   void *it_cls;
2411 };
2412
2413
2414 /**
2415  * Iterator to iterate over a peer's addresses
2416  *
2417  * @param cls a `struct PeerInfoIteratorContext`
2418  * @param key the peer id
2419  * @param value the `struct ATS_address`
2420  * @return #GNUNET_OK to continue
2421  */
2422 static int
2423 peerinfo_it (void *cls,
2424              const struct GNUNET_PeerIdentity *key,
2425              void *value)
2426 {
2427   struct PeerInfoIteratorContext *pi_ctx = cls;
2428   struct ATS_Address *addr = value;
2429
2430   if (NULL != pi_ctx->it)
2431   {
2432     pi_ctx->it (pi_ctx->it_cls, &addr->peer, addr->plugin, addr->addr,
2433         addr->addr_len, addr->active, addr->atsi, addr->atsi_count,
2434         addr->assigned_bw_out, addr->assigned_bw_in);
2435   }
2436   return GNUNET_YES;
2437 }
2438
2439
2440 /**
2441  * Return information all peers currently known to ATS
2442  *
2443  * @param handle the address handle to use
2444  * @param peer the respective peer
2445  * @param pi_it the iterator to call for every peer
2446  * @param pi_it_cls the closure for the iterator
2447  */
2448 void
2449 GAS_addresses_get_peer_info (struct GAS_Addresses_Handle *handle,
2450     const struct GNUNET_PeerIdentity *peer, GNUNET_ATS_PeerInfo_Iterator pi_it,
2451     void *pi_it_cls)
2452 {
2453   struct PeerInfoIteratorContext pi_ctx;
2454   struct GNUNET_BANDWIDTH_Value32NBO zero_bw;
2455
2456   GNUNET_assert(NULL != peer);
2457   GNUNET_assert(NULL != handle->addresses);
2458   if (NULL == pi_it)
2459     return; /* does not make sense without callback */
2460
2461   zero_bw = GNUNET_BANDWIDTH_value_init (0);
2462   pi_ctx.it = pi_it;
2463   pi_ctx.it_cls = pi_it_cls;
2464
2465   GNUNET_CONTAINER_multipeermap_get_multiple (handle->addresses,
2466                                               peer,
2467                                               &peerinfo_it, &pi_ctx);
2468
2469   if (NULL != pi_it)
2470     pi_it (pi_it_cls, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0, zero_bw,
2471         zero_bw);
2472
2473 }
2474
2475 /* end of gnunet-service-ats_addresses.c */