f0b50b0eba89e7cccfb8a0280ab4f4c556c97c4d
[oweals/gnunet.git] / src / ats / gnunet-service-ats_preferences.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011-2015 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  * @file ats/gnunet-service-ats_preferences.c
22  * @brief ats service, interaction with 'performance' API
23  * @author Matthias Wachs
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet-service-ats.h"
28 #include "gnunet-service-ats_addresses.h"
29 #include "gnunet-service-ats_performance.h"
30 #include "gnunet-service-ats_plugins.h"
31 #include "gnunet-service-ats_preferences.h"
32 #include "gnunet-service-ats_reservations.h"
33 #include "ats.h"
34
35 #define LOG(kind,...) GNUNET_log_from (kind, "ats-preferencesx",__VA_ARGS__)
36
37 #define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
38 #define PREF_AGING_FACTOR 0.95
39 #define PREF_EPSILON 0.01
40
41
42 /**
43  * Relative preferences for a peer
44  */
45 struct PeerRelative
46 {
47   /**
48    * Relative preference values
49    */
50   double f_rel[GNUNET_ATS_PreferenceCount];
51
52   /**
53    * Peer id
54    */
55   struct GNUNET_PeerIdentity id;
56 };
57
58
59 /**
60  * FIXME
61  */
62 struct GAS_Addresses_Preference_Clients
63 {
64   /**
65    * Next in DLL
66    */
67   struct GAS_Addresses_Preference_Clients *next;
68
69   /**
70    * Previous in DLL
71    */
72   struct GAS_Addresses_Preference_Clients *prev;
73
74   /**
75    * Peer ID
76    */
77   void *client;
78 };
79
80
81 /**
82  * Preference requests DLL head
83  */
84 static struct GAS_Addresses_Preference_Clients *preference_clients_head;
85
86 /**
87  * Preference requests DLL head
88  */
89 static struct GAS_Addresses_Preference_Clients *preference_clients_tail;
90
91 /**
92  * Preferences clients
93  */
94 static int pref_clients;
95
96 /**
97  * Default values
98  */
99 static struct PeerRelative defvalues;
100
101
102
103 /**
104  * Preference client
105  */
106 struct PreferenceClient
107 {
108   /**
109    * Next in DLL
110    */
111   struct PreferenceClient *prev;
112
113   /**
114    * Next in DLL
115    */
116   struct PreferenceClient *next;
117
118   /**
119    * Client handle
120    */
121   void *client;
122
123   /**
124    * Array of sum of absolute preferences for this client
125    */
126   double f_abs_sum[GNUNET_ATS_PreferenceCount];
127
128   /**
129    * Array of sum of relative preferences for this client
130    */
131   double f_rel_sum[GNUNET_ATS_PreferenceCount];
132
133   /**
134    * Head of peer list
135    */
136   struct PreferencePeer *p_head;
137
138   /**
139    * Tail of peer list
140    */
141   struct PreferencePeer *p_tail;
142 };
143
144
145 /**
146  * Preference peer
147  */
148 struct PreferencePeer
149 {
150   /**
151    * Next in DLL
152    */
153   struct PreferencePeer *next;
154
155   /**
156    * Previous in DLL
157    */
158   struct PreferencePeer *prev;
159
160   /**
161    * Client
162    */
163   struct PreferenceClient *client;
164
165   /**
166    * Peer id
167    */
168   struct GNUNET_PeerIdentity id;
169
170   /**
171    * Absolute preference values for all preference types
172    */
173   double f_abs[GNUNET_ATS_PreferenceCount];
174
175   /**
176    * Relative preference values for all preference types
177    */
178   double f_rel[GNUNET_ATS_PreferenceCount];
179
180   /**
181    * Absolute point of time of next aging process
182    */
183   struct GNUNET_TIME_Absolute next_aging[GNUNET_ATS_PreferenceCount];
184 };
185
186
187 /**
188  * Hashmap to store peer information for preference normalization
189  */
190 static struct GNUNET_CONTAINER_MultiPeerMap *preference_peers;
191
192 /**
193  * Clients in DLL: head
194  */
195 static struct PreferenceClient *pc_head;
196
197 /**
198  * Clients in DLL: tail
199  */
200 static struct PreferenceClient *pc_tail;
201
202
203
204 static struct GNUNET_SCHEDULER_Task * aging_task;
205
206
207
208
209 static struct GAS_Addresses_Preference_Clients *
210 find_preference_client (void *client)
211 {
212   struct GAS_Addresses_Preference_Clients *cur;
213
214   for (cur = preference_clients_head; NULL != cur; cur = cur->next)
215     if (cur->client == client)
216       return cur;
217   return NULL;
218 }
219
220
221 /**
222  * Update a peer
223  *
224  * @param id peer id
225  * @param kind the kind
226  * @param rp the relative peer struct
227  * @return the new relative preference
228  */
229 static void
230 update_relative_values_for_peer (const struct GNUNET_PeerIdentity *id,
231                                  enum GNUNET_ATS_PreferenceKind kind,
232                                  struct PeerRelative *rp)
233 {
234   struct PreferenceClient *c_cur;
235   struct PreferencePeer *p_cur;
236   double f_rel_total;
237   double f_rel_sum;
238   double backup;
239   unsigned int peer_count;
240
241   f_rel_sum = 0.0;
242   f_rel_total = 0.0;
243   peer_count = 0;
244
245   /* For all clients */
246   for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
247   {
248     /* For peer entries with this id */
249     for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
250     {
251       f_rel_sum += p_cur->f_rel[kind];
252       if (0 == memcmp (id, &p_cur->id, sizeof(struct GNUNET_PeerIdentity)))
253       {
254         peer_count ++;
255         f_rel_total += p_cur->f_rel[kind];
256       }
257
258     }
259   }
260
261   LOG (GNUNET_ERROR_TYPE_DEBUG,
262       "%u clients have a total relative preference for peer `%s' `%s' of %.3f and for %s in total %.3f\n",
263       peer_count, GNUNET_i2s (id),
264       GNUNET_ATS_print_preference_type (kind),
265       f_rel_total,
266       GNUNET_ATS_print_preference_type (kind),
267       f_rel_sum);
268
269   /* Find entry for the peer containing relative values in the hashmap */
270   if (NULL != rp)
271   {
272     backup = rp->f_rel[kind];
273     if (f_rel_sum > 0)
274       rp->f_rel[kind] = f_rel_total / f_rel_sum;
275     else
276     {
277       /* No client had any preferences for this type and any peer */
278       rp->f_rel[kind] = DEFAULT_REL_PREFERENCE;
279     }
280     if (backup != rp->f_rel[kind])
281       GAS_normalized_preference_changed (&rp->id, kind, rp->f_rel[kind]);
282   }
283 }
284
285
286 static int
287 update_iterator (void *cls,
288                  const struct GNUNET_PeerIdentity *key,
289                  void *value)
290 {
291   enum GNUNET_ATS_PreferenceKind *kind = cls;
292   struct PeerRelative *pr = value;
293
294   update_relative_values_for_peer (key,
295                                    *kind,
296                                    pr);
297   return GNUNET_OK;
298 }
299
300
301
302 /**
303  * Recalculate preference for a specific ATS property
304  *
305  * @param c the preference client
306  * @param kind the preference kind
307  * @return the result
308  */
309 static void
310 recalculate_relative_preferences (struct PreferenceClient *c,
311                                   enum GNUNET_ATS_PreferenceKind kind)
312 {
313   struct PreferencePeer *p_cur;
314
315   /* For this client: sum of absolute preference values for this preference */
316   c->f_abs_sum[kind] = 0.0;
317   /* For this client: sum of relative preference values for this preference
318    *
319    * Note: this value should also be 1.0, but:
320    * if no preferences exist due to aging, this value can be 0.0
321    * and the client can be removed */
322   c->f_rel_sum[kind] = 0.0;
323
324   for (p_cur = c->p_head; NULL != p_cur; p_cur = p_cur->next)
325     c->f_abs_sum[kind] += p_cur->f_abs[kind];
326   LOG (GNUNET_ERROR_TYPE_DEBUG,
327       "Client %p has sum of total preferences for %s of %.3f\n",
328       c->client, GNUNET_ATS_print_preference_type (kind), c->f_abs_sum[kind]);
329
330   /* For all peers: calculate relative preference */
331   for (p_cur = c->p_head; NULL != p_cur; p_cur = p_cur->next)
332   {
333     /* Calculate relative preference for specific kind */
334
335     /* Every application has a preference for each peer between
336      * [0 .. 1] in relative values
337      * and [0 .. inf] in absolute values */
338     p_cur->f_rel[kind] =  p_cur->f_abs[kind] / c->f_abs_sum[kind];
339     c->f_rel_sum[kind] += p_cur->f_rel[kind];
340
341     LOG (GNUNET_ERROR_TYPE_DEBUG,
342         "Client %p has relative preference for %s for peer `%s' of %.3f\n",
343         c->client,
344         GNUNET_ATS_print_preference_type (kind),
345         GNUNET_i2s (&p_cur->id),
346         p_cur->f_rel[kind]);
347   }
348
349 }
350
351
352
353 static void
354 run_preference_update (struct PreferenceClient *c_cur,
355                        struct PreferencePeer *p_cur,
356                        enum GNUNET_ATS_PreferenceKind kind,
357                        float score_abs)
358 {
359   double old_value;
360
361   /* Update relative value */
362   old_value = p_cur->f_rel[kind];
363   recalculate_relative_preferences (c_cur, kind);
364   if (p_cur->f_rel[kind] == old_value)
365     return;
366
367   /* Relative preference value changed, recalculate for all peers */
368   GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
369                                          &update_iterator,
370                                          &kind);
371 }
372
373
374
375
376 /**
377  * Reduce absolute preferences since they got old
378  *
379  * @param cls the PreferencePeer
380  * @param tc context
381  */
382 static void
383 preference_aging (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
384 {
385   struct PreferencePeer *p;
386   struct PreferenceClient *cur_client;
387   int i;
388   int values_to_update;
389   double backup;
390
391   aging_task = NULL;
392   values_to_update = 0;
393   cur_client = NULL;
394
395   for (cur_client = pc_head; NULL != cur_client; cur_client = cur_client->next)
396   {
397     for (p = cur_client->p_head; NULL != p; p = p->next)
398     {
399       /* Aging absolute values: */
400       for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
401       {
402         if (0
403             == GNUNET_TIME_absolute_get_remaining (p->next_aging[i]).rel_value_us)
404         {
405           GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
406               "Aging preference for peer `%s'\n", GNUNET_i2s (&p->id));
407           backup = p->f_abs[i];
408           if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE)
409             p->f_abs[i] *= PREF_AGING_FACTOR;
410
411           if (p->f_abs[i] <= DEFAULT_ABS_PREFERENCE + PREF_EPSILON)
412             p->f_abs[i] = DEFAULT_ABS_PREFERENCE;
413
414           if ( (p->f_abs[i] != DEFAULT_ABS_PREFERENCE) &&
415                (backup != p->f_abs[i]) )
416           {
417             GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
418                 "Aged preference for peer `%s' from %.3f to %.3f\n",
419                 GNUNET_i2s (&p->id), backup, p->f_abs[i]);
420
421             run_preference_update(cur_client, p, i, p->f_abs[i]);
422
423             p->next_aging[i] = GNUNET_TIME_absolute_add (
424                 GNUNET_TIME_absolute_get (), PREF_AGING_INTERVAL);
425             values_to_update++;
426           }
427         }
428       }
429     }
430   }
431
432   if (values_to_update > 0)
433   {
434     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
435         "Rescheduling aging task due to %u elements to age\n",
436         values_to_update);
437     aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
438         &preference_aging, NULL );
439   }
440   else
441     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
442         "No values to age left, not rescheduling aging task\n");
443
444 }
445
446
447 /**
448  * Update the absolute preference value for a peer
449  * @param c the client
450  * @param p the peer
451  * @param kind the preference kind
452  * @param score_abs the absolute value
453  * @return the new relative preference value
454  */
455 static void
456 update_abs_preference (struct PreferenceClient *c,
457                        struct PreferencePeer *p,
458                        enum GNUNET_ATS_PreferenceKind kind,
459                        float score_abs)
460 {
461   double score = score_abs;
462
463   /* Update preference value according to type */
464   switch (kind)
465   {
466   case GNUNET_ATS_PREFERENCE_BANDWIDTH:
467   case GNUNET_ATS_PREFERENCE_LATENCY:
468     p->f_abs[kind] = score;
469     /* p->f_abs[kind] = (p->f_abs[kind] + score) / 2;  */
470     p->next_aging[kind] = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
471         PREF_AGING_INTERVAL);
472     break;
473   case GNUNET_ATS_PREFERENCE_END:
474     break;
475   default:
476     break;
477   }
478 }
479
480
481
482
483
484 /**
485  * A performance client disconnected
486  *
487  * @param client the client
488  */
489 void
490 GAS_preference_client_disconnect (struct GNUNET_SERVER_Client *client)
491 {
492   struct GAS_Addresses_Preference_Clients *pc;
493
494   if (NULL != (pc = find_preference_client (client)))
495   {
496     GNUNET_CONTAINER_DLL_remove (preference_clients_head,
497                                  preference_clients_tail,
498                                  pc);
499     GNUNET_free (pc);
500     GNUNET_assert (pref_clients > 0);
501     pref_clients --;
502     GNUNET_STATISTICS_set (GSA_stats,
503                            "# active performance clients",
504                            pref_clients,
505                            GNUNET_NO);
506   }
507 }
508
509
510 /**
511  * Change the preference for a peer
512  *
513  * @param client the client sending this request
514  * @param peer the peer id
515  * @param kind the preference kind to change
516  * @param score_abs the new preference score
517  */
518 static void
519 preference_change (void *client,
520                     const struct GNUNET_PeerIdentity *peer,
521                     enum GNUNET_ATS_PreferenceKind kind,
522                     float score_abs)
523 {
524   struct GAS_Addresses_Preference_Clients *pc;
525
526   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
527       "Received `%s' for peer `%s' for client %p\n", "CHANGE PREFERENCE",
528       GNUNET_i2s (peer), client);
529
530   if (GNUNET_NO ==
531       GNUNET_CONTAINER_multipeermap_contains (GSA_addresses,
532                                               peer))
533   {
534     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
535         "Received `%s' for unknown peer `%s' from client %p\n",
536         "CHANGE PREFERENCE", GNUNET_i2s (peer), client);
537     return;
538   }
539
540   if (NULL == find_preference_client (client))
541   {
542     pc = GNUNET_new (struct GAS_Addresses_Preference_Clients);
543     pc->client = client;
544     GNUNET_CONTAINER_DLL_insert (preference_clients_head,
545                                  preference_clients_tail,
546                                  pc);
547     pref_clients ++;
548     GNUNET_STATISTICS_set (GSA_stats,
549                            "# active performance clients",
550                            pref_clients,
551                            GNUNET_NO);
552   }
553   GAS_plugin_update_preferences (client, peer, kind, score_abs);
554 }
555
556
557 /**
558  * Handle 'preference change' messages from clients.
559  *
560  * @param cls unused, NULL
561  * @param client client that sent the request
562  * @param message the request message
563  */
564 void
565 GAS_handle_preference_change (void *cls,
566                               struct GNUNET_SERVER_Client *client,
567                               const struct GNUNET_MessageHeader *message)
568 {
569   const struct ChangePreferenceMessage *msg;
570   const struct PreferenceInformation *pi;
571   uint16_t msize;
572   uint32_t nump;
573   uint32_t i;
574
575   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576               "Received `%s' message\n",
577               "PREFERENCE_CHANGE");
578   msize = ntohs (message->size);
579   if (msize < sizeof (struct ChangePreferenceMessage))
580   {
581     GNUNET_break (0);
582     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
583     return;
584   }
585   msg = (const struct ChangePreferenceMessage *) message;
586   nump = ntohl (msg->num_preferences);
587   if (msize !=
588       sizeof (struct ChangePreferenceMessage) +
589       nump * sizeof (struct PreferenceInformation))
590   {
591     GNUNET_break (0);
592     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
593     return;
594   }
595   GNUNET_STATISTICS_update (GSA_stats,
596                             "# preference change requests processed",
597                             1, GNUNET_NO);
598   pi = (const struct PreferenceInformation *) &msg[1];
599   for (i = 0; i < nump; i++)
600     preference_change (client,
601                        &msg->peer,
602                        (enum GNUNET_ATS_PreferenceKind)
603                        ntohl (pi[i].preference_kind),
604                        pi[i].preference_value);
605   GNUNET_SERVER_receive_done (client, GNUNET_OK);
606 }
607
608
609 /**
610  * Initialize preferences subsystem.
611  */
612 void
613 GAS_preference_init ()
614 {
615   int i;
616
617   preference_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
618   for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
619     defvalues.f_rel[i] = DEFAULT_REL_PREFERENCE;
620 }
621
622
623 /**
624  * Free a peer
625  *
626  * @param cls unused
627  * @param key the key
628  * @param value RelativePeer
629  * @return #GNUNET_OK to continue
630  */
631 static int
632 free_peer (void *cls,
633            const struct GNUNET_PeerIdentity *key,
634            void *value)
635 {
636   struct PeerRelative *rp = value;
637
638   if (GNUNET_YES ==
639       GNUNET_CONTAINER_multipeermap_remove (preference_peers,
640                                             key,
641                                             value))
642     GNUNET_free (rp);
643   else
644     GNUNET_break (0);
645   return GNUNET_OK;
646 }
647
648
649 static void
650 free_client (struct PreferenceClient *pc)
651 {
652   struct PreferencePeer *next_p;
653   struct PreferencePeer *p;
654
655   next_p = pc->p_head;
656   while (NULL != (p = next_p))
657   {
658     next_p = p->next;
659     GNUNET_CONTAINER_DLL_remove(pc->p_head, pc->p_tail, p);
660     GNUNET_free(p);
661   }
662   GNUNET_free(pc);
663 }
664
665
666 /**
667  * Shutdown preferences subsystem.
668  */
669 void
670 GAS_preference_done ()
671 {
672   struct GAS_Addresses_Preference_Clients *pcur;
673   struct PreferenceClient *pc;
674   struct PreferenceClient *next_pc;
675
676   if (NULL != aging_task)
677   {
678     GNUNET_SCHEDULER_cancel (aging_task);
679     aging_task = NULL;
680   }
681   next_pc = pc_head;
682   while (NULL != (pc = next_pc))
683   {
684     next_pc = pc->next;
685     GNUNET_CONTAINER_DLL_remove(pc_head, pc_tail, pc);
686     free_client (pc);
687   }
688   GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
689                                          &free_peer,
690                                          NULL);
691   GNUNET_CONTAINER_multipeermap_destroy (preference_peers);
692
693   while (NULL != (pcur = preference_clients_head))
694   {
695     GNUNET_CONTAINER_DLL_remove (preference_clients_head,
696                                  preference_clients_tail,
697                                  pcur);
698     GNUNET_assert (pref_clients > 0);
699     pref_clients --;
700     GNUNET_STATISTICS_set (GSA_stats,
701                            "# active performance clients",
702                            pref_clients,
703                            GNUNET_NO);
704     GNUNET_free (pcur);
705   }
706 }
707
708
709 /**
710  * Normalize an updated preference value
711  *
712  * @param client the client with this preference
713  * @param peer the peer to change the preference for
714  * @param kind the kind to change the preference
715  * @param score_abs the normalized score
716  */
717 void
718 GAS_normalization_normalize_preference (void *client,
719                                         const struct GNUNET_PeerIdentity *peer,
720                                         enum GNUNET_ATS_PreferenceKind kind,
721                                         float score_abs)
722 {
723   struct PreferenceClient *c_cur;
724   struct PreferencePeer *p_cur;
725   struct PeerRelative *r_cur;
726   double old_value;
727   int i;
728
729   LOG (GNUNET_ERROR_TYPE_DEBUG,
730        "Client changes preference for peer `%s' for `%s' to %.2f\n",
731        GNUNET_i2s (peer),
732        GNUNET_ATS_print_preference_type (kind),
733        score_abs);
734
735   if (kind >= GNUNET_ATS_PreferenceCount)
736   {
737     GNUNET_break(0);
738     return;
739   }
740
741   /* Find preference client */
742   for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
743   {
744     if (client == c_cur->client)
745       break;
746   }
747   /* Not found: create new preference client */
748   if (NULL == c_cur)
749   {
750     c_cur = GNUNET_new (struct PreferenceClient);
751     c_cur->client = client;
752     for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
753     {
754       c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
755       c_cur->f_rel_sum[i] = DEFAULT_REL_PREFERENCE;
756     }
757
758     GNUNET_CONTAINER_DLL_insert(pc_head, pc_tail, c_cur);
759     LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding new client %p \n", c_cur);
760   }
761
762   /* Find entry for peer */
763   for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
764     if (0 == memcmp (&p_cur->id, peer, sizeof(p_cur->id)))
765       break;
766
767   /* Not found: create new peer entry */
768   if (NULL == p_cur)
769   {
770     p_cur = GNUNET_new (struct PreferencePeer);
771     p_cur->client = c_cur;
772     p_cur->id = (*peer);
773     for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
774     {
775       /* Default value per peer absolute preference for a preference: 0 */
776       p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
777       /* Default value per peer relative preference for a quality: 1.0 */
778       p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
779       p_cur->next_aging[i] = GNUNET_TIME_UNIT_FOREVER_ABS;
780     }
781     LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding new peer %p for client %p \n",
782         p_cur, c_cur);
783     GNUNET_CONTAINER_DLL_insert(c_cur->p_head, c_cur->p_tail, p_cur);
784   }
785
786   /* Create struct for peer */
787   if (NULL == GNUNET_CONTAINER_multipeermap_get (preference_peers, peer))
788   {
789     r_cur = GNUNET_new (struct PeerRelative);
790     r_cur->id = (*peer);
791     for (i = 0; i < GNUNET_ATS_PreferenceCount; i++)
792       r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
793     GNUNET_assert(
794         GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (preference_peers,
795             &r_cur->id, r_cur, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
796   }
797
798   /* Update absolute value */
799   old_value = p_cur->f_abs[kind];
800   update_abs_preference (c_cur, p_cur, kind, score_abs);
801   if (p_cur->f_abs[kind] == old_value)
802     return;
803
804   run_preference_update (c_cur, p_cur, kind, score_abs);
805
806   /* Start aging task */
807   if (NULL == aging_task)
808     aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
809                                                &preference_aging,
810                                                NULL);
811
812 }
813
814
815 /**
816  * Get the normalized preference values for a specific peer or
817  * the default values if
818  *
819  * @param cls ignored
820  * @param id the peer
821  * @return pointer to the values, can be indexed with GNUNET_ATS_PreferenceKind,
822  * default preferences if peer does not exist
823  */
824 const double *
825 GAS_normalization_get_preferences_by_peer (void *cls,
826                                            const struct GNUNET_PeerIdentity *id)
827 {
828   GNUNET_assert(NULL != preference_peers);
829   GNUNET_assert(NULL != id);
830
831   struct PeerRelative *rp;
832   if (NULL == (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers, id)))
833   {
834     return defvalues.f_rel;
835   }
836   return rp->f_rel;
837 }
838
839
840 /**
841  * Get the normalized preference values for a specific client and peer
842  *
843  * @param client client
844  * @param peer the peer
845  * @param pref the preference type
846  * @return the value
847  */
848 double
849 GAS_normalization_get_preferences_by_client (const void *client,
850                                              const struct GNUNET_PeerIdentity *peer,
851                                              enum GNUNET_ATS_PreferenceKind pref)
852 {
853   struct PreferenceClient *c_cur;
854   struct PreferencePeer *p_cur;
855
856   /* Find preference client */
857   for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
858   {
859     if (client == c_cur->client)
860       break;
861   }
862   if (NULL == c_cur)
863     return -1.0;
864
865   for (p_cur = c_cur->p_head; NULL != p_cur; p_cur = p_cur->next)
866   {
867     if (0 == memcmp (peer, &p_cur->id, sizeof (struct GNUNET_PeerIdentity)))
868       break;
869   }
870   if (NULL == p_cur)
871     return DEFAULT_REL_PREFERENCE; /* Not found, return default */
872
873   return p_cur->f_rel[pref];
874 }
875
876
877
878 /**
879  * A performance client disconnected
880  *
881  * @param client the client
882  */
883 void
884 GAS_normalization_preference_client_disconnect (void *client)
885 {
886   struct PreferenceClient *c_cur;
887   /* Find preference client */
888
889   for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
890   {
891     if (client == c_cur->client)
892       break;
893   }
894   if (NULL == c_cur)
895     return;
896
897   GNUNET_CONTAINER_DLL_remove(pc_head, pc_tail, c_cur);
898   free_client (c_cur);
899 }
900