docu
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses_simplistic.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_simplistic.h
23  * @brief ats simplistic ressource assignment
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet_statistics_service.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "ats-simplistic",__VA_ARGS__)
33
34 /**
35  *
36  * NOTE: Do not change this documentation. This documentation is based on
37  * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
38  * use build_txt.sh to generate plaintext output
39  *
40  * ATS addresses : simplistic solver
41  *
42  *    The simplistic solver ("simplistic") distributes the available bandwidth
43  *    fair over all the addresses influenced by the preference values. For each
44  *    available network type an in- and outbound quota is configured and the
45  *    bandwidth available in these networks is distributed over the addresses.
46  *    The solver first assigns every addresses the minimum amount of bandwidth
47  *    GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT and then distributes the remaining
48  *    bandwidth available according to the preference values. For each peer only
49  *    a single address gets bandwidth assigned and only one address marked as
50  *    active.
51  *    The most important functionality for the solver is implemented in:
52  *      * find_address_it
53  *        is an hashmap iterator returning the prefered address for an peer
54  *      * update_quota_per_network
55  *        distributes available bandwidth for a network over active addresses
56  *
57  *    Changes to addresses automatically have an impact on the the bandwidth
58  *    assigned to other addresses in the same network since the solver
59  *    distributes the remaining bandwidth over the addresses in the network.
60  *    When changes to the addresses occur, the solver first performs the
61  *    changes, like adding or deleting addresses, and then updates bandwidth
62  *    assignment for the affected network. Bandwidth assignment is only
63  *    recalculated on demand when an address is requested by a client for a peer
64  *    or when the addresses available have changed or an address changed the
65  *    network it is located in. When the bandwidth assignment has changed the
66  *    callback is called with the new bandwidth assignments. The bandwidth
67  *    distribution for a network is recalculated due to:
68  *      * address suggestion requests
69  *      * address deletions
70  *      * address switching networks during address update
71  *      * preference changes
72  *
73  *     3.1 Data structures used
74  *
75  *    For each ATS network (e.g. WAN, LAN, loopback) a struct Network is used to
76  *    specify network related information as total adresses and active addresses
77  *    in this network and the configured in- and outbound quota. Each network
78  *    also contains a list of addresses added to the solver located in this
79  *    network. The simplistic solver uses the addresses' solver_information
80  *    field to store the simplistic network it belongs to for each address.
81  *
82  *     3.2 Initializing
83  *
84  *    When the simplistic solver is initialized the solver creates a new solver
85  *    handle and initializes the network structures with the quotas passed from
86  *    addresses and returns the handle solver.
87  *
88  *     3.3 Adding an address
89  *
90  *    When a new address is added to the solver using s_add, a lookup for the
91  *    network for this address is done and the address is enqueued in in the
92  *    linked list of the network.
93  *
94  *     3.4 Updating an address
95  *
96  *    The main purpose of address updates is to update the ATS information for
97  *    addresse selection. Important for the simplistic solver is when an address
98  *    switches network it is located in. This is common because addresses added
99  *    by transport's validation mechanism are commonly located in
100  *    GNUNET_ATS_NET_UNSPECIFIED. Addresses in validation are located in this
101  *    network type and only if a connection is successful on return of payload
102  *    data transport switches to the real network the address is located in.
103  *    When an address changes networks it is first of all removed from the old
104  *    network using the solver API function GAS_simplistic_address_delete and
105  *    the network in the address struct is updated. A lookup for the respective
106  *    new simplistic network is done and stored in the addresse's
107  *    solver_information field. Next the address is re-added to the solver using
108  *    the solver API function GAS_simplistic_address_add. If the address was
109  *    marked as in active, the solver checks if bandwidth is available in the
110  *    network and if yes sets the address to active and updates the bandwidth
111  *    distribution in this network. If no bandwidth is available it sets the
112  *    bandwidth for this address to 0 and tries to suggest an alternative
113  *    address. If an alternative address was found, addresses' callback is
114  *    called for this address.
115  *
116  *     3.5 Deleting an address
117  *
118  *    When an address is removed from the solver, it removes the respective
119  *    address from the network and if the address was marked as active, it
120  *    updates the bandwidth distribution for this network.
121  *
122  *     3.6 Requesting addresses
123  *
124  *    When an address is requested for a peer the solver performs a lookup for
125  *    the peer entry in addresses address hashmap and selects the best address.
126  *    The selection of the most suitable address is done in the find_address_it
127  *    hashmap iterator described in detail in section 3.7. If no address is
128  *    returned, no address can be suggested at the moment. If the address
129  *    returned is marked as active, the solver can return this address. If the
130  *    address is not marked as active, the solver checks if another address
131  *    belongign to this peer is marked as active and marks the address as
132  *    inactive, updates the bandwidth for this address to 0, call the bandwidth
133  *    changed callback for this address due to the change and updates quota
134  *    assignment for the addresse's network. the now in-active address is
135  *    belonging to. The solver marks the new address as active and updates the
136  *    bandwidth assignment for this network.
137  *
138  *     3.7 Choosing addresses
139  *
140  *    Choosing the best possible address for suggestion is done by iterating
141  *    over all addresses of a peer stored in addresses' hashmap and using the
142  *    hashmap iterator find_address_it to select the best available address.
143  *    Several checks are done when an address is selected. First if this address
144  *    is currently blocked by addresses from being suggested. An address is
145  *    blocked for the duration of ATS_BLOCKING_DELTA when it is suggested to
146  *    transport. Next it is checked if at least
147  *    GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT bytes bandwidth is available in the
148  *    addresse's network, because suggesting an address without bandwidth does
149  *    not make sense. This also ensures that all active addresses in this
150  *    network get at least the minimum amount of bandwidth assigned. In the next
151  *    step the solver ensures that for tcp connections inbound connections are
152  *    prefered over outbound connections. In the next stet the solver ensures
153  *    that connections are prefered in the following order:
154  *      * connections are already established and have bandwidth assigned
155  *      * connections with a shorter distance
156  *      * connectes have a shorter latency
157  *
158  *     3.8 Changing preferences
159  *
160  *     3.9 Shutdown
161  *
162  *    During shutdown all network entries and aging processes are destroyed and
163  *    freed.
164  *
165  *
166  * OLD DOCUMENTATION
167  *
168  * This solver ssigns in and outbound bandwidth equally for all addresses in
169  * specific network type (WAN, LAN) based on configured in and outbound quota
170  * for this network.
171  *
172  * The solver is notified by addresses about changes to the addresses and
173  * recalculates the bandwith assigned if required. The solver notifies addresses
174  * by calling the GAS_bandwidth_changed_cb callback.
175  *
176  * - Initialization
177  *
178  *
179  *
180  *
181  * For each peer only a single is selected and marked as "active" in the address
182  * struct.
183  *
184  * E.g.:
185  *
186  * You have the networks WAN and LAN and quotas
187  * WAN_TOTAL_IN, WAN_TOTAL_OUT
188  * LAN_TOTAL_IN, LAN_TOTAL_OUT
189  *
190  * If you have x addresses in the network segment LAN, the quotas are
191  * QUOTA_PER_ADDRESS = LAN_TOTAL_OUT / x
192  *
193  * Quotas are automatically recalculated and reported back when addresses are
194  * - requested
195  *
196  */
197
198 #define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
199 #define PREF_AGING_FACTOR 0.95
200
201 #define DEFAULT_PREFERENCE 1.0
202 #define MIN_UPDATE_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
203
204 /**
205  * A handle for the simplistic solver
206  */
207 struct GAS_SIMPLISTIC_Handle
208 {
209   /**
210    * Statistics handle
211    */
212
213   struct GNUNET_STATISTICS_Handle *stats;
214
215   /**
216    * Total number of addresses for solver
217    */
218   unsigned int total_addresses;
219
220   /**
221    * Number of active addresses for solver
222    */
223   unsigned int active_addresses;
224
225   /**
226    * Networks array
227    */
228   struct Network *network_entries;
229
230   /**
231    * Number of networks
232    */
233   unsigned int networks;
234
235   /**
236    * Callback
237    */
238   GAS_bandwidth_changed_cb bw_changed;
239
240   /**
241    * Callback cls
242    */
243   void *bw_changed_cls;
244
245   struct GNUNET_CONTAINER_MultiHashMap *prefs;
246
247   struct PreferenceClient *pc_head;
248   struct PreferenceClient *pc_tail;
249 };
250
251 struct Network
252 {
253   /**
254    * ATS network type
255    */
256   unsigned int type;
257
258   /**
259    * Network description
260    */
261   char *desc;
262
263   /**
264    * Total inbound quota
265    *
266    */
267   unsigned long long total_quota_in;
268
269   /**
270    * Total outbound quota
271    *
272    */
273   unsigned long long total_quota_out;
274
275   /**
276    * Number of active addresses for this network
277    */
278   unsigned int active_addresses;
279
280   /**
281    * Number of total addresses for this network
282    */
283   unsigned int total_addresses;
284
285   /**
286    * String for statistics total addresses
287    */
288   char *stat_total;
289
290   /**
291    * String for statistics active addresses
292    */
293   char *stat_active;
294
295   struct AddressWrapper *head;
296   struct AddressWrapper *tail;
297 };
298
299 struct AddressWrapper
300 {
301   struct AddressWrapper *next;
302   struct AddressWrapper *prev;
303
304   struct ATS_Address *addr;
305 };
306
307
308 struct PreferenceClient
309 {
310   struct PreferenceClient *prev;
311   struct PreferenceClient *next;
312   void *client;
313
314   double f_total[GNUNET_ATS_PreferenceCount];
315
316   struct PreferencePeer *p_head;
317   struct PreferencePeer *p_tail;
318 };
319
320
321 struct PreferencePeer
322 {
323   struct PreferencePeer *next;
324   struct PreferencePeer *prev;
325   struct PreferenceClient *client;
326   struct GAS_SIMPLISTIC_Handle *s;
327   struct GNUNET_PeerIdentity id;
328
329   double f[GNUNET_ATS_PreferenceCount];
330   double f_rel[GNUNET_ATS_PreferenceCount];
331   double f_rel_total;
332
333   GNUNET_SCHEDULER_TaskIdentifier aging_task;
334 };
335
336 /**
337  * Get the prefered address for a specific peer
338  *
339  * @param solver the solver handle
340  * @param addresses the address hashmap containing all addresses
341  * @param peer the identity of the peer
342  */
343 const struct ATS_Address *
344 GAS_simplistic_get_preferred_address (void *solver,
345                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
346                                const struct GNUNET_PeerIdentity *peer);
347
348 /**
349  * Init the simplistic problem solving component
350  *
351  * Quotas:
352  * network[i] contains the network type as type GNUNET_ATS_NetworkType[i]
353  * out_quota[i] contains outbound quota for network type i
354  * in_quota[i] contains inbound quota for network type i
355  *
356  * Example
357  * network = {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK, GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN}
358  * network[2]   == GNUNET_ATS_NET_LAN
359  * out_quota[2] == 65353
360  * in_quota[2]  == 65353
361  *
362  * @param cfg configuration handle
363  * @param stats the GNUNET_STATISTICS handle
364  * @param network array of GNUNET_ATS_NetworkType with length dest_length
365  * @param out_quota array of outbound quotas
366  * @param in_quota array of outbound quota
367  * @param dest_length array length for quota arrays
368  * @param bw_changed_cb callback for changed bandwidth amounts
369  * @param bw_changed_cb_cls cls for callback
370  * @return handle for the solver on success, NULL on fail
371  */
372 void *
373 GAS_simplistic_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
374                      const struct GNUNET_STATISTICS_Handle *stats,
375                      int *network,
376                      unsigned long long *out_quota,
377                      unsigned long long *in_quota,
378                      int dest_length,
379                      GAS_bandwidth_changed_cb bw_changed_cb,
380                      void *bw_changed_cb_cls)
381 {
382   int c;
383   struct GAS_SIMPLISTIC_Handle *s = GNUNET_malloc (sizeof (struct GAS_SIMPLISTIC_Handle));
384   struct Network * cur;
385   char * net_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
386
387
388   s->stats = (struct GNUNET_STATISTICS_Handle *) stats;
389   s->bw_changed = bw_changed_cb;
390   s->bw_changed_cls = bw_changed_cb_cls;
391   s->networks = dest_length;
392   s->network_entries = GNUNET_malloc (dest_length * sizeof (struct Network));
393   s->active_addresses = 0;
394   s->total_addresses = 0;
395   s->prefs = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
396
397   for (c = 0; c < dest_length; c++)
398   {
399       cur = &s->network_entries[c];
400       cur->total_addresses = 0;
401       cur->active_addresses = 0;
402       cur->type = network[c];
403       cur->total_quota_in = in_quota[c];
404       cur->total_quota_out = out_quota[c];
405       cur->desc = net_str[c];
406       GNUNET_asprintf (&cur->stat_total, "# ATS addresses %s total", cur->desc);
407       GNUNET_asprintf (&cur->stat_active, "# ATS active addresses %s total", cur->desc);
408   }
409   return s;
410 }
411
412 static int
413 free_pref (void *cls,
414            const struct GNUNET_HashCode * key,
415            void *value)
416 {
417   float *v = value;
418   GNUNET_free (v);
419   return GNUNET_OK;
420 }
421
422 /**
423  * Shutdown the simplistic problem solving component
424  *
425  * @param solver the respective handle to shutdown
426  */
427 void
428 GAS_simplistic_done (void *solver)
429 {
430   struct GAS_SIMPLISTIC_Handle *s = solver;
431   struct PreferenceClient *pc;
432   struct PreferenceClient *next_pc;
433   struct PreferencePeer *p;
434   struct PreferencePeer *next_p;
435   struct AddressWrapper *cur;
436   struct AddressWrapper *next;
437   int c;
438   GNUNET_assert (s != NULL);
439
440   for (c = 0; c < s->networks; c++)
441   {
442       if (s->network_entries[c].total_addresses > 0)
443       {
444         LOG (GNUNET_ERROR_TYPE_ERROR,
445                     "Had %u addresses for network `%s' not deleted during shutdown\n",
446                     s->network_entries[c].total_addresses,
447                     s->network_entries[c].desc);
448         GNUNET_break (0);
449       }
450
451       if (s->network_entries[c].active_addresses > 0)
452       {
453         LOG (GNUNET_ERROR_TYPE_ERROR,
454                     "Had %u active addresses for network `%s' not deleted during shutdown\n",
455                     s->network_entries[c].active_addresses,
456                     s->network_entries[c].desc);
457         GNUNET_break (0);
458       }
459
460       next = s->network_entries[c].head;
461       while (NULL != (cur = next))
462       {
463           next = cur->next;
464           GNUNET_CONTAINER_DLL_remove (s->network_entries[c].head,
465                                        s->network_entries[c].tail,
466                                        cur);
467           GNUNET_free (cur);
468       }
469       GNUNET_free (s->network_entries[c].stat_total);
470       GNUNET_free (s->network_entries[c].stat_active);
471   }
472   if (s->total_addresses > 0)
473   {
474     LOG (GNUNET_ERROR_TYPE_ERROR,
475                 "Had %u addresses not deleted during shutdown\n",
476                 s->total_addresses);
477     GNUNET_break (0);
478   }
479   if (s->active_addresses > 0)
480   {
481     LOG (GNUNET_ERROR_TYPE_ERROR,
482                 "Had %u active addresses not deleted during shutdown\n",
483                 s->active_addresses);
484     GNUNET_break (0);
485   }
486   GNUNET_free (s->network_entries);
487
488   next_pc = s->pc_head;
489   while (NULL != (pc = next_pc))
490   {
491       next_pc = pc->next;
492       GNUNET_CONTAINER_DLL_remove (s->pc_head, s->pc_tail, pc);
493       next_p = pc->p_head;
494       while (NULL != (p = next_p))
495       {
496           next_p = p->next;
497           if (GNUNET_SCHEDULER_NO_TASK != p->aging_task)
498           {
499                 GNUNET_SCHEDULER_cancel(p->aging_task);
500                 p->aging_task = GNUNET_SCHEDULER_NO_TASK;
501           }
502           GNUNET_CONTAINER_DLL_remove (pc->p_head, pc->p_tail, p);
503           GNUNET_free (p);
504       }
505       GNUNET_free (pc);
506   }
507
508   GNUNET_CONTAINER_multihashmap_iterate (s->prefs, &free_pref, NULL);
509   GNUNET_CONTAINER_multihashmap_destroy (s->prefs);
510   GNUNET_free (s);
511 }
512
513
514 /**
515  * Test if bandwidth is available in this network
516  *
517  * @param net the network type to update
518  * @return GNUNET_YES or GNUNET_NO
519  */
520
521 static int
522 bw_available_in_network (struct Network *net)
523 {
524   unsigned int na = net->active_addresses + 1;
525   uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
526   if (((net->total_quota_in / na) > min_bw) &&
527       ((net->total_quota_out / na) > min_bw))
528   {    
529     LOG (GNUNET_ERROR_TYPE_DEBUG,
530          "Enough bandwidth available for %u active addresses in network `%s'\n",
531          na,
532          net->desc);
533                                                                       
534     return GNUNET_YES;
535   }
536     LOG (GNUNET_ERROR_TYPE_DEBUG,
537          "Not enough bandwidth available for %u active addresses in network `%s'\n",
538          na,
539          net->desc);  
540   return GNUNET_NO;
541 }
542
543
544 /**
545  * Update the quotas for a network type
546  *
547  * @param s the solver handle
548  * @param net the network type to update
549  * @param address_except address excluded from notifcation, since we suggest
550  * this address
551  */
552 static void
553 update_quota_per_network (struct GAS_SIMPLISTIC_Handle *s,
554                           struct Network *net,
555                           struct ATS_Address *address_except)
556 {
557   unsigned long long remaining_quota_in = 0;
558   unsigned long long quota_out_used = 0;
559
560   unsigned long long remaining_quota_out = 0;
561   unsigned long long quota_in_used = 0;
562   uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
563   double total_prefs; /* Important: has to be double not float due to precision */
564   double cur_pref; /* Important: has to be double not float due to precision */
565   double *t = NULL; /* Important: has to be double not float due to precision */
566
567   unsigned long long assigned_quota_in = 0;
568   unsigned long long assigned_quota_out = 0;
569   struct AddressWrapper *cur;
570
571   LOG (GNUNET_ERROR_TYPE_DEBUG,
572               "Recalculate quota for network type `%s' for %u addresses (in/out): %llu/%llu \n",
573               net->desc, net->active_addresses, net->total_quota_in, net->total_quota_in);
574
575   if (net->active_addresses == 0)
576     return; /* no addresses to update */
577
578   /* Idea
579    * Assign every peer in network minimum Bandwidth
580    * Distribute bandwidth left according to preference
581    */
582
583   if ((net->active_addresses * min_bw) > net->total_quota_in)
584   {
585     GNUNET_break (0);
586     return;
587   }
588   if ((net->active_addresses * min_bw) > net->total_quota_out)
589   {
590     GNUNET_break (0);
591     return;
592   }
593
594   remaining_quota_in = net->total_quota_in - (net->active_addresses * min_bw);
595   remaining_quota_out = net->total_quota_out - (net->active_addresses * min_bw);
596   LOG (GNUNET_ERROR_TYPE_DEBUG, "Remaining bandwidth : (in/out): %llu/%llu \n",
597               remaining_quota_in, remaining_quota_out);
598   total_prefs = 0.0;
599   for (cur = net->head; NULL != cur; cur = cur->next)
600   {
601       if (GNUNET_YES == cur->addr->active)
602       {
603         t = GNUNET_CONTAINER_multihashmap_get (s->prefs, &cur->addr->peer.hashPubKey);
604         if (NULL == t)
605                 total_prefs += DEFAULT_PREFERENCE;
606         else
607          {
608                         total_prefs += (*t);
609          }
610       }
611   }
612   for (cur = net->head; NULL != cur; cur = cur->next)
613   {
614      if (GNUNET_YES == cur->addr->active)
615      {
616        cur_pref = 0.0;
617        t = GNUNET_CONTAINER_multihashmap_get (s->prefs, &cur->addr->peer.hashPubKey);
618        if (NULL == t)
619          cur_pref = DEFAULT_PREFERENCE;
620        else
621          cur_pref = (*t);
622        assigned_quota_in = min_bw + ((cur_pref / total_prefs) * remaining_quota_in);
623        assigned_quota_out = min_bw + ((cur_pref / total_prefs) * remaining_quota_out);
624
625        LOG (GNUNET_ERROR_TYPE_DEBUG,
626                    "New quota for peer `%s' with preference (cur/total) %.3f/%.3f (in/out): %llu / %llu\n",
627                    GNUNET_i2s (&cur->addr->peer),
628                    cur_pref, total_prefs,
629                    assigned_quota_in, assigned_quota_out);
630      }
631      else
632      {
633        assigned_quota_in = 0;
634        assigned_quota_out = 0;
635      }
636
637      quota_in_used += assigned_quota_in;
638      quota_out_used += assigned_quota_out;
639      /* Prevent overflow due to rounding errors */
640      if (assigned_quota_in > UINT32_MAX)
641        assigned_quota_in = UINT32_MAX;
642      if (assigned_quota_out > UINT32_MAX)
643        assigned_quota_out = UINT32_MAX;
644
645      /* Compare to current bandwidth assigned */
646      if ((assigned_quota_in != ntohl(cur->addr->assigned_bw_in.value__)) ||
647          (assigned_quota_out != ntohl(cur->addr->assigned_bw_out.value__)))
648      {
649        cur->addr->assigned_bw_in.value__ = htonl (assigned_quota_in);
650        cur->addr->assigned_bw_out.value__ = htonl (assigned_quota_out);
651        /* Notify on change */
652        if ((GNUNET_YES == cur->addr->active) && (cur->addr != address_except))
653          s->bw_changed (s->bw_changed_cls, cur->addr);
654      }
655
656   }
657   LOG (GNUNET_ERROR_TYPE_DEBUG,
658                           "Total bandwidth assigned is (in/out): %llu /%llu\n",
659                           quota_in_used,
660                           quota_out_used);
661   if (quota_out_used > net->total_quota_out + 1) /* +1 is required due to rounding errors */
662   {
663       LOG (GNUNET_ERROR_TYPE_ERROR,
664                             "Total outbound bandwidth assigned is larger than allowed (used/allowed) for %u active addresses: %llu / %llu\n",
665                             net->active_addresses,
666                             quota_out_used,
667                             net->total_quota_out);
668   }
669   if (quota_in_used > net->total_quota_in + 1) /* +1 is required due to rounding errors */
670   {
671       LOG (GNUNET_ERROR_TYPE_ERROR,
672                             "Total inbound bandwidth assigned is larger than allowed (used/allowed) for %u active addresses: %llu / %llu\n",
673                             net->active_addresses,
674                             quota_in_used,
675                             net->total_quota_in);
676   }
677 }
678
679 static void
680 update_all_networks (struct GAS_SIMPLISTIC_Handle *s)
681 {
682         int i;
683         for (i = 0; i < s->networks; i++)
684                 update_quota_per_network (s, &s->network_entries[i], NULL);
685
686 }
687
688 static void
689 addresse_increment (struct GAS_SIMPLISTIC_Handle *s,
690                                 struct Network *net,
691                                 int total,
692                                 int active)
693 {
694   if (GNUNET_YES == total)
695   {
696       s->total_addresses ++;
697       net->total_addresses ++;
698       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", 1, GNUNET_NO);
699       GNUNET_STATISTICS_update (s->stats, net->stat_total, 1, GNUNET_NO);
700   }
701   if (GNUNET_YES == active)
702   {
703     net->active_addresses ++;
704     s->active_addresses ++;
705     GNUNET_STATISTICS_update (s->stats, "# ATS active addresses total", 1, GNUNET_NO);
706     GNUNET_STATISTICS_update (s->stats, net->stat_active, 1, GNUNET_NO);
707   }
708
709 }
710
711 static int
712 addresse_decrement (struct GAS_SIMPLISTIC_Handle *s,
713                     struct Network *net,
714                     int total,
715                     int active)
716 {
717   int res = GNUNET_OK;
718   if (GNUNET_YES == total)
719   {
720     if (s->total_addresses < 1)
721     {
722       GNUNET_break (0);
723       res = GNUNET_SYSERR;
724     }
725     else
726     {
727       s->total_addresses --;
728       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1, GNUNET_NO);
729     }
730     if (net->total_addresses < 1)
731     {
732       GNUNET_break (0);
733       res = GNUNET_SYSERR;
734     }
735     else
736     {
737       net->total_addresses --;
738       GNUNET_STATISTICS_update (s->stats, net->stat_total, -1, GNUNET_NO);
739     }
740   }
741
742   if (GNUNET_YES == active)
743   {
744     if (net->active_addresses < 1)
745     {
746       GNUNET_break (0);
747       res = GNUNET_SYSERR;
748     }
749     else
750     {
751       net->active_addresses --;
752       GNUNET_STATISTICS_update (s->stats, net->stat_active, -1, GNUNET_NO);
753     }
754     if (s->active_addresses < 1)
755     {
756       GNUNET_break (0);
757       res = GNUNET_SYSERR;
758     }
759     else
760     {
761       s->active_addresses --;
762       GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1, GNUNET_NO);
763     }
764   }
765   return res;
766 }
767
768
769 /**
770  * Add a single address to the solve
771  *
772  * @param solver the solver Handle
773  * @param addresses the address hashmap containing all addresses
774  * @param address the address to add
775  */
776 void
777 GAS_simplistic_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
778 {
779   struct GAS_SIMPLISTIC_Handle *s = solver;
780   struct Network *net = NULL;
781   struct AddressWrapper *aw = NULL;
782
783   GNUNET_assert (NULL != s);
784   int c;
785   for (c = 0; c < s->networks; c++)
786   {
787       net = &s->network_entries[c];
788       if (address->atsp_network_type == net->type)
789           break;
790   }
791   if (NULL == net)
792   {
793     GNUNET_break (0);
794     return;
795   }
796
797   aw = GNUNET_malloc (sizeof (struct AddressWrapper));
798   aw->addr = address;
799   GNUNET_CONTAINER_DLL_insert (net->head, net->tail, aw);
800   addresse_increment (s, net, GNUNET_YES, GNUNET_NO);
801   aw->addr->solver_information = net;
802
803
804   LOG (GNUNET_ERROR_TYPE_DEBUG, "After adding address now total %u and active %u addresses in network `%s'\n",
805       net->total_addresses,
806       net->active_addresses,
807       net->desc);
808 }
809
810 /**
811  * Remove an address from the solver
812  *
813  * @param solver the solver handle
814  * @param addresses the address hashmap containing all addresses
815  * @param address the address to remove
816  * @param session_only delete only session not whole address
817  */
818 void
819 GAS_simplistic_address_delete (void *solver,
820     struct GNUNET_CONTAINER_MultiHashMap * addresses,
821     struct ATS_Address *address, int session_only)
822 {
823   struct GAS_SIMPLISTIC_Handle *s = solver;
824   struct Network *net;
825   struct AddressWrapper *aw;
826
827   /* Remove an adress completely, we have to:
828    * - Remove from specific network
829    * - Decrease number of total addresses
830    * - If active:
831    *   - decrease number of active addreses
832    *   - update quotas
833    */
834
835   net = (struct Network *) address->solver_information;
836
837   if (GNUNET_NO == session_only)
838   {
839     LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting %s address %p for peer `%s' from network `%s' (total: %u/ active: %u)\n",
840         (GNUNET_NO == address->active) ? "inactive" : "active",
841         address, GNUNET_i2s (&address->peer),
842         net->desc, net->total_addresses, net->active_addresses);
843
844     /* Remove address */
845     addresse_decrement (s, net, GNUNET_YES, GNUNET_NO);
846     for (aw = net->head; NULL != aw; aw = aw->next)
847     {
848         if (aw->addr == address)
849           break;
850     }
851     if (NULL == aw )
852     {
853         GNUNET_break (0);
854         return;
855     }
856     GNUNET_CONTAINER_DLL_remove (net->head, net->tail, aw);
857     GNUNET_free (aw);
858   }
859   else
860   {
861       /* Remove session only: remove if active and update */
862       LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting %s session %p for peer `%s' from network `%s' (total: %u/ active: %u)\n",
863           (GNUNET_NO == address->active) ? "inactive" : "active",
864           address, GNUNET_i2s (&address->peer),
865           net->desc, net->total_addresses, net->active_addresses);
866   }
867
868   if (GNUNET_YES == address->active)
869   {
870       /* Address was active, remove from network and update quotas*/
871       address->active = GNUNET_NO;
872       if (GNUNET_SYSERR == addresse_decrement (s, net, GNUNET_NO, GNUNET_YES))
873         GNUNET_break (0);
874       update_quota_per_network (s, net, NULL);
875   }
876   LOG (GNUNET_ERROR_TYPE_DEBUG, "After deleting address now total %u and active %u addresses in network `%s'\n",
877       net->total_addresses,
878       net->active_addresses,
879       net->desc);
880
881 }
882
883 static struct Network *
884 find_network (struct GAS_SIMPLISTIC_Handle *s, uint32_t type)
885 {
886   int c;
887   for (c = 0 ; c < s->networks; c++)
888   {
889       if (s->network_entries[c].type == type)
890         return &s->network_entries[c];
891   }
892   return NULL;
893 }
894
895 /**
896  * Updates a single address in the solve
897  *
898  * @param solver the solver Handle
899  * @param addresses the address hashmap containing all addresses
900  * @param address the update address
901  * @param session the new session (if changed otherwise current)
902  * @param in_use the new address in use state (if changed otherwise current)
903  * @param atsi the latest ATS information
904  * @param atsi_count the atsi count
905  */
906 void
907 GAS_simplistic_address_update (void *solver,
908                               struct GNUNET_CONTAINER_MultiHashMap *addresses,
909                               struct ATS_Address *address,
910                               uint32_t session,
911                               int in_use,
912                               const struct GNUNET_ATS_Information *atsi,
913                               uint32_t atsi_count)
914 {
915   struct ATS_Address *new;
916   struct GAS_SIMPLISTIC_Handle *s = (struct GAS_SIMPLISTIC_Handle *) solver;
917   int i;
918   uint32_t value;
919   uint32_t type;
920   int save_active = GNUNET_NO;
921   struct Network *new_net = NULL;
922   for (i = 0; i < atsi_count; i++)
923   {
924     type = ntohl (atsi[i].type);
925     value = ntohl (atsi[i].value);
926     switch (type)
927     {
928     case GNUNET_ATS_UTILIZATION_UP:
929       //if (address->atsp_utilization_out.value__ != atsi[i].value)
930
931       break;
932     case GNUNET_ATS_UTILIZATION_DOWN:
933       //if (address->atsp_utilization_in.value__ != atsi[i].value)
934
935       break;
936     case GNUNET_ATS_QUALITY_NET_DELAY:
937       //if (address->atsp_latency.rel_value != value)
938
939       break;
940     case GNUNET_ATS_QUALITY_NET_DISTANCE:
941       //if (address->atsp_distance != value)
942
943       break;
944     case GNUNET_ATS_COST_WAN:
945       //if (address->atsp_cost_wan != value)
946
947       break;
948     case GNUNET_ATS_COST_LAN:
949       //if (address->atsp_cost_lan != value)
950
951       break;
952     case GNUNET_ATS_COST_WLAN:
953       //if (address->atsp_cost_wlan != value)
954
955       break;
956     case GNUNET_ATS_NETWORK_TYPE:
957       if (address->atsp_network_type != value)
958       {
959
960         LOG (GNUNET_ERROR_TYPE_DEBUG, "Network type changed, moving %s address from `%s' to `%s'\n",
961             (GNUNET_YES == address->active) ? "active" : "inactive",
962             GNUNET_ATS_print_network_type(address->atsp_network_type),
963             GNUNET_ATS_print_network_type(value));
964
965         save_active = address->active;
966         /* remove from old network */
967         GAS_simplistic_address_delete (solver, addresses, address, GNUNET_NO);
968
969         /* set new network type */
970         address->atsp_network_type = value;
971         new_net = find_network (solver, value);
972         address->solver_information = new_net;
973         if (address->solver_information == NULL)
974         {
975             GNUNET_break (0);
976             address->atsp_network_type = GNUNET_ATS_NET_UNSPECIFIED;
977             return;
978         }
979
980         /* Add to new network and update*/
981         GAS_simplistic_address_add (solver, addresses, address);
982         if (GNUNET_YES == save_active)
983         {
984           /* check if bandwidth available in new network */
985           if (GNUNET_YES == (bw_available_in_network (new_net)))
986           {
987               /* Suggest updated address */
988               address->active = GNUNET_YES;
989               addresse_increment (s, new_net, GNUNET_NO, GNUNET_YES);
990               update_quota_per_network (solver, new_net, NULL);
991           }
992           else
993           {
994             LOG (GNUNET_ERROR_TYPE_DEBUG, "Not enough bandwidth in new network, suggesting alternative address ..\n");
995
996             /* Set old address to zero bw */
997             address->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0);
998             address->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0);
999             s->bw_changed  (s->bw_changed_cls, address);
1000
1001             /* Find new address to suggest since no bandwidth in network*/
1002             new = (struct ATS_Address *) GAS_simplistic_get_preferred_address (s, addresses, &address->peer);
1003             if (NULL != new)
1004             {
1005                 /* Have an alternative address to suggest */
1006                 s->bw_changed  (s->bw_changed_cls, new);
1007             }
1008
1009           }
1010         }
1011       }
1012       break;
1013     case GNUNET_ATS_ARRAY_TERMINATOR:
1014       break;
1015     default:
1016       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1017                   "Received unsupported ATS type %u\n", type);
1018       GNUNET_break (0);
1019       break;
1020
1021     }
1022
1023   }
1024   if (address->session_id != session)
1025   {
1026       LOG (GNUNET_ERROR_TYPE_DEBUG,
1027                   "Session changed from %u to %u\n", address->session_id, session);
1028       address->session_id = session;
1029   }
1030   if (address->used != in_use)
1031   {
1032       LOG (GNUNET_ERROR_TYPE_DEBUG,
1033                   "Usage changed from %u to %u\n", address->used, in_use);
1034       address->used = in_use;
1035   }
1036
1037 }
1038
1039
1040
1041 /**
1042  * Find a "good" address to use for a peer.  If we already have an existing
1043  * address, we stick to it.  Otherwise, we pick by lowest distance and then
1044  * by lowest latency.
1045  *
1046  * @param cls the 'struct ATS_Address**' where we store the result
1047  * @param key unused
1048  * @param value another 'struct ATS_Address*' to consider using
1049  * @return GNUNET_OK (continue to iterate)
1050  */
1051 static int
1052 find_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1053 {
1054   struct ATS_Address **previous_p = cls;
1055   struct ATS_Address *current = (struct ATS_Address *) value;
1056   struct ATS_Address *previous = *previous_p;
1057   struct GNUNET_TIME_Absolute now;
1058   struct Network *net = (struct Network *) current->solver_information;
1059
1060   now = GNUNET_TIME_absolute_get();
1061
1062   if (current->blocked_until.abs_value == GNUNET_TIME_absolute_max (now, current->blocked_until).abs_value)
1063   {
1064     /* This address is blocked for suggestion */
1065     LOG (GNUNET_ERROR_TYPE_DEBUG,
1066                 "Address %p blocked for suggestion for %llu ms \n",
1067                 current,
1068                 GNUNET_TIME_absolute_get_difference(now, current->blocked_until).rel_value);
1069     return GNUNET_OK;
1070   }
1071
1072   if (GNUNET_NO == bw_available_in_network (net))
1073     return GNUNET_OK; /* There's no bandwidth available in this network */
1074
1075   if (NULL != previous)
1076   {
1077     if ((0 == strcmp (previous->plugin, "tcp")) &&
1078         (0 == strcmp (current->plugin, "tcp")))
1079     {
1080       if ((0 != previous->addr_len) &&
1081           (0 == current->addr_len))
1082       {
1083         /* saved address was an outbound address, but we have an inbound address */
1084         *previous_p = current;
1085         return GNUNET_OK;
1086       }
1087       if (0 == previous->addr_len)
1088       {
1089         /* saved address was an inbound address, so do not overwrite */
1090         return GNUNET_OK;
1091       }
1092     }
1093   }
1094
1095   if (NULL == previous)
1096   {
1097     *previous_p = current;
1098     return GNUNET_OK;
1099   }
1100   if ((ntohl (previous->assigned_bw_in.value__) == 0) &&
1101       (ntohl (current->assigned_bw_in.value__) > 0))
1102   {
1103     /* stick to existing connection */
1104     *previous_p = current;
1105     return GNUNET_OK;
1106   }
1107   if (previous->atsp_distance > current->atsp_distance)
1108   {
1109     /* user shorter distance */
1110     *previous_p = current;
1111     return GNUNET_OK;
1112   }
1113   if (previous->atsp_latency.rel_value > current->atsp_latency.rel_value)
1114   {
1115     /* user lower latency */
1116     *previous_p = current;
1117     return GNUNET_OK;
1118   }
1119   /* don't care */
1120   return GNUNET_OK;
1121 }
1122
1123 static int
1124 find_active_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1125 {
1126   struct ATS_Address * dest = (struct ATS_Address *) (*(struct ATS_Address **)cls);
1127   struct ATS_Address * aa = (struct ATS_Address *) value;
1128
1129   if (GNUNET_YES == aa->active)
1130   {
1131       if (dest != NULL)
1132       {
1133           /* should never happen */
1134           LOG (GNUNET_ERROR_TYPE_ERROR, "Multiple active addresses for peer `%s'\n", GNUNET_i2s (&aa->peer));
1135           GNUNET_break (0);
1136           return GNUNET_NO;
1137       }
1138       dest = aa;
1139   }
1140   return GNUNET_OK;
1141 }
1142
1143 static struct ATS_Address *
1144 find_active_address (void *solver,
1145                      struct GNUNET_CONTAINER_MultiHashMap * addresses,
1146                      const struct GNUNET_PeerIdentity *peer)
1147 {
1148   struct ATS_Address * dest = NULL;
1149
1150   GNUNET_CONTAINER_multihashmap_get_multiple(addresses,
1151        &peer->hashPubKey,
1152        &find_active_address_it, &dest);
1153   return dest;
1154 }
1155
1156 /**
1157  * Get the prefered address for a specific peer
1158  *
1159  * @param solver the solver handle
1160  * @param addresses the address hashmap containing all addresses
1161  * @param peer the identity of the peer
1162  */
1163 const struct ATS_Address *
1164 GAS_simplistic_get_preferred_address (void *solver,
1165                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
1166                                const struct GNUNET_PeerIdentity *peer)
1167 {
1168   struct GAS_SIMPLISTIC_Handle *s = solver;
1169   struct Network *net_prev;
1170   struct Network *net_cur;
1171   struct ATS_Address *cur;
1172   struct ATS_Address *prev;
1173
1174   GNUNET_assert (s != NULL);
1175   cur = NULL;
1176   /* Get address with: stick to current address, lower distance, lower latency */
1177   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
1178                                               &find_address_it, &cur);
1179   if (NULL == cur)
1180   {
1181     LOG (GNUNET_ERROR_TYPE_DEBUG, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
1182     return NULL;
1183   }
1184
1185   LOG (GNUNET_ERROR_TYPE_DEBUG, "Suggesting %s address %p for peer `%s'\n",
1186       (GNUNET_NO == cur->active) ? "inactive" : "active",
1187       cur, GNUNET_i2s (peer));
1188   net_cur = (struct Network *) cur->solver_information;
1189   if (GNUNET_YES == cur->active)
1190   {
1191       /* This address was selected previously, so no need to update quotas */
1192       return cur;
1193   }
1194
1195   /* This address was not active, so we have to:
1196    *
1197    * - mark previous active address as not active
1198    * - update quota for previous address network
1199    * - update quota for this address network
1200    */
1201
1202   prev = find_active_address (s, addresses, peer);
1203   if (NULL != prev)
1204   {
1205       net_prev = (struct Network *) prev->solver_information;
1206       prev->active = GNUNET_NO; /* No active any longer */
1207       prev->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0); /* no bw assigned */
1208       prev->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0); /* no bw assigned */
1209       s->bw_changed (s->bw_changed_cls, prev); /* notify about bw change, REQUIRED? */
1210       if (GNUNET_SYSERR == addresse_decrement (s, net_prev, GNUNET_NO, GNUNET_YES))
1211         GNUNET_break (0);
1212       update_quota_per_network (s, net_prev, NULL);
1213   }
1214
1215   if (GNUNET_NO == (bw_available_in_network (cur->solver_information)))
1216   {
1217     GNUNET_break (0); /* This should never happen*/
1218     return NULL;
1219   }
1220
1221   cur->active = GNUNET_YES;
1222   addresse_increment(s, net_cur, GNUNET_NO, GNUNET_YES);
1223   update_quota_per_network (s, net_cur, cur);
1224
1225   return cur;
1226 }
1227
1228
1229 /**
1230  * Stop notifying about address and bandwidth changes for this peer
1231  *
1232  * @param solver the MLP handle
1233  * @param addresses address hashmap
1234  * @param peer the peer
1235  */
1236 void
1237 GAS_simplistic_stop_get_preferred_address (void *solver,
1238                                      struct GNUNET_CONTAINER_MultiHashMap *addresses,
1239                                      const struct GNUNET_PeerIdentity *peer)
1240 {
1241         return;
1242 }
1243
1244 static void
1245 recalculate_preferences (struct PreferencePeer *p)
1246 {
1247         struct GAS_SIMPLISTIC_Handle *s = p->s;
1248         struct PreferencePeer *p_cur;
1249         struct PreferenceClient *c_cur = p->client;
1250         double p_rel_global;
1251   double *dest;
1252   int kind;
1253   int rkind;
1254   int clients;
1255
1256   /**
1257    * Idea:
1258    *
1259    * We have:
1260    * Set of clients c
1261    * Set of peers p_i in P
1262    * Set of preference kinds k
1263    * A preference value f_k_p_i with an unknown range
1264    *
1265    * We get:
1266    * A client specific relative preference f_p_i_rel [1..2] for all peers
1267    *
1268    * For every client c
1269    * {
1270    *   For every preference kind k:
1271    *   {
1272    *     We remember for the preference f_p_i for each peer p_i.
1273    *     We have a default preference value f_p_i = 0
1274    *     We have a sum of all preferences f_t = sum (f_p_i)
1275    *     So we can calculate a relative preference value fr_p_i:
1276    *
1277    *     f_k_p_i_ *  / f_t
1278    *     f_k_p_i_rel = [1..2], default 1.0
1279    *    }
1280    *    f_p_i_rel = sum (f_k_p_i_rel) / count(k)
1281    * }
1282    *
1283    **/
1284
1285   /* For this client: for all preferences, except TERMINATOR */
1286   for (kind = GNUNET_ATS_PREFERENCE_END + 1 ; kind < GNUNET_ATS_PreferenceCount; kind ++)
1287   {
1288           /* Recalcalculate total preference for this quality kind over all peers*/
1289           c_cur->f_total[kind] = 0;
1290           for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
1291                 c_cur->f_total[kind] += p_cur->f[kind];
1292
1293           LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p has total preference for %s of %.3f\n",
1294                         c_cur->client,
1295               GNUNET_ATS_print_preference_type (kind),
1296               c_cur->f_total[kind]);
1297
1298           /* Recalcalculate relative preference for all peers */
1299           for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
1300           {
1301             /* Calculate relative preference for specific kind */
1302                 if (0.0 == c_cur->f_total[kind])
1303                 {
1304                                 /* No one has preference, so set default preference */
1305                                 p_cur->f_rel[kind] = DEFAULT_PREFERENCE;
1306                 }
1307                 else
1308                 {
1309                                 p_cur->f_rel[kind] = (c_cur->f_total[kind] + p_cur->f[kind]) / c_cur->f_total[kind];
1310                 }
1311             LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p: peer `%s' has relative preference for %s of %.3f\n",
1312                         c_cur->client,
1313                 GNUNET_i2s (&p_cur->id),
1314                 GNUNET_ATS_print_preference_type (kind),
1315                 p_cur->f_rel[kind]);
1316
1317             /* Calculate peer relative preference */
1318             /* Start with kind = 1 to exclude terminator */
1319             p_cur->f_rel_total = 0;
1320             for (rkind = GNUNET_ATS_PREFERENCE_END + 1; rkind < GNUNET_ATS_PreferenceCount; rkind ++)
1321             {
1322                 p_cur->f_rel_total += p_cur->f_rel[rkind];
1323             }
1324             p_cur->f_rel_total /=  (GNUNET_ATS_PreferenceCount - 1.0); /* -1 due to terminator */
1325             LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p: peer `%s' has total relative preference of %.3f\n",
1326                         c_cur->client,
1327                 GNUNET_i2s (&p_cur->id),
1328                 p_cur->f_rel_total);
1329           }
1330   }
1331
1332   /* Calculcate global total relative peer preference over all clients */
1333   p_rel_global = 0.0;
1334   clients = 0;
1335   for (c_cur = s->pc_head; NULL != c_cur; c_cur = c_cur->next)
1336   {
1337       for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
1338           if (0 == memcmp (&p_cur->id, &p->id, sizeof (p_cur->id)))
1339               break;
1340       if (NULL != p_cur)
1341       {
1342           clients++;
1343           p_rel_global += p_cur->f_rel_total;
1344       }
1345   }
1346   p_rel_global /= clients;
1347   LOG (GNUNET_ERROR_TYPE_DEBUG, "Global preference value for peer `%s': %.3f\n",
1348       GNUNET_i2s (&p->id), p_rel_global);
1349
1350   /* Update global map */
1351   if (NULL != (dest = GNUNET_CONTAINER_multihashmap_get(s->prefs, &p->id.hashPubKey)))
1352       (*dest) = p_rel_global;
1353   else
1354   {
1355       dest = GNUNET_malloc (sizeof (double));
1356       (*dest) = p_rel_global;
1357       GNUNET_CONTAINER_multihashmap_put(s->prefs,
1358           &p->id.hashPubKey,
1359           dest,
1360           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1361   }
1362 }
1363
1364 static void
1365 update_preference (struct PreferencePeer *p,
1366                                                                          enum GNUNET_ATS_PreferenceKind kind,
1367                                                          float score_f)
1368 {
1369         double score = score_f;
1370
1371   /* Update preference value according to type */
1372   switch (kind) {
1373     case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1374     case GNUNET_ATS_PREFERENCE_LATENCY:
1375       p->f[kind] = (p->f[kind] + score) / 2;
1376       break;
1377     case GNUNET_ATS_PREFERENCE_END:
1378       break;
1379     default:
1380       break;
1381   }
1382   recalculate_preferences(p);
1383   update_all_networks (p->s);
1384 }
1385
1386
1387 static void
1388 preference_aging (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1389 {
1390         int i;
1391         double *t = NULL;
1392         double backup;
1393         struct PreferencePeer *p = cls;
1394         GNUNET_assert (NULL != p);
1395
1396
1397         p->aging_task = GNUNET_SCHEDULER_NO_TASK;
1398
1399   LOG (GNUNET_ERROR_TYPE_DEBUG, "Aging preferences for peer `%s'\n",
1400                 GNUNET_i2s (&p->id));
1401
1402   /* Issue for aging :
1403    *
1404    * Not for every peer preference values are set by default, so reducing the
1405    * absolute preference value does not help for aging because it does not have
1406    * influence on the relative values.
1407    *
1408    * So we have to reduce the relative value to have an immediate impact on
1409    * quota calculation. In addition we cannot call recalculate_preferences here
1410    * but instead reduce the absolute value to have an aging impact on future
1411    * calls to change_preference where recalculate_preferences is called
1412    *
1413    */
1414   /* Aging absolute values: */
1415   for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
1416   {
1417                 if (p->f[i] > 1.0)
1418                 {
1419                         backup = p->f[i];
1420                         p->f[i] *= PREF_AGING_FACTOR;
1421                         LOG (GNUNET_ERROR_TYPE_DEBUG, "Aged preference for peer `%s' from %.3f to %.3f\n",
1422                         GNUNET_i2s (&p->id), backup, p->f[i]);
1423                 }
1424   }
1425   /* Updating relative value */
1426   t = GNUNET_CONTAINER_multihashmap_get (p->s->prefs, &p->id.hashPubKey);
1427   if (NULL == t)
1428   {
1429         GNUNET_break (0);
1430   }
1431   else
1432   {
1433                 if ((*t) > 1.0)
1434                         (*t) = (*t) * PREF_AGING_FACTOR;
1435                 else
1436                         (*t) = 1.0;
1437                 update_all_networks (p->s);
1438   }
1439   p->aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
1440                 &preference_aging, p);
1441 }
1442
1443
1444 /**
1445  * Changes the preferences for a peer in the problem
1446  *
1447  * @param solver the solver handle
1448  * @param client the client with this preference
1449  * @param peer the peer to change the preference for
1450  * @param kind the kind to change the preference
1451  * @param score the score
1452  */
1453 void
1454 GAS_simplistic_address_change_preference (void *solver,
1455                                    void *client,
1456                                    const struct GNUNET_PeerIdentity *peer,
1457                                    enum GNUNET_ATS_PreferenceKind kind,
1458                                    float score)
1459 {
1460   static struct GNUNET_TIME_Absolute next_update;
1461   struct GAS_SIMPLISTIC_Handle *s = solver;
1462   struct PreferenceClient *c_cur;
1463   struct PreferencePeer *p_cur;
1464   int i;
1465
1466   GNUNET_assert (NULL != solver);
1467   GNUNET_assert (NULL != client);
1468   GNUNET_assert (NULL != peer);
1469
1470   LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p changes preference for peer `%s' %s %f\n",
1471                                 client,
1472                                 GNUNET_i2s (peer),
1473                                 GNUNET_ATS_print_preference_type (kind),
1474                                 score);
1475
1476   if (kind >= GNUNET_ATS_PreferenceCount)
1477   {
1478       GNUNET_break (0);
1479       return;
1480   }
1481
1482   /* Find preference client */
1483   for (c_cur = s->pc_head; NULL != c_cur; c_cur = c_cur->next)
1484   {
1485       if (client == c_cur->client)
1486         break;
1487   }
1488   /* Not found: create new preference client */
1489   if (NULL == c_cur)
1490   {
1491     c_cur = GNUNET_malloc (sizeof (struct PreferenceClient));
1492     c_cur->client = client;
1493     GNUNET_CONTAINER_DLL_insert (s->pc_head, s->pc_tail, c_cur);
1494   }
1495
1496   /* Find entry for peer */
1497   for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
1498     if (0 == memcmp (&p_cur->id, peer, sizeof (p_cur->id)))
1499         break;
1500
1501   /* Not found: create new peer entry */
1502   if (NULL == p_cur)
1503   {
1504       p_cur = GNUNET_malloc (sizeof (struct PreferencePeer));
1505       p_cur->s = s;
1506       p_cur->client = c_cur;
1507       p_cur->id = (*peer);
1508       for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
1509       {
1510         /* Default value per peer absolut preference for a quality:
1511          * No value set, so absolute preference 0 */
1512         p_cur->f[i] = 0.0;
1513         /* Default value per peer relative preference for a quality: 1.0 */
1514         p_cur->f_rel[i] = DEFAULT_PREFERENCE;
1515       }
1516       p_cur->aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL, &preference_aging, p_cur);
1517       GNUNET_CONTAINER_DLL_insert (c_cur->p_head, c_cur->p_tail, p_cur);
1518   }
1519
1520   update_preference (p_cur, kind, score);
1521
1522   /* FIXME: We should update quotas if UPDATE_INTERVAL is reached */
1523   if (GNUNET_TIME_absolute_get().abs_value > next_update.abs_value)
1524   {
1525       /* update quotas*/
1526       next_update = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
1527                                               MIN_UPDATE_INTERVAL);
1528   }
1529 }
1530
1531 /* end of gnunet-service-ats_addresses_simplistic.c */