diff options
Diffstat (limited to 'src/ats/gnunet-service-ats_preferences.c')
-rw-r--r-- | src/ats/gnunet-service-ats_preferences.c | 771 |
1 files changed, 0 insertions, 771 deletions
diff --git a/src/ats/gnunet-service-ats_preferences.c b/src/ats/gnunet-service-ats_preferences.c deleted file mode 100644 index c2b2dc4c1..000000000 --- a/src/ats/gnunet-service-ats_preferences.c +++ /dev/null | |||
@@ -1,771 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2015 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file ats/gnunet-service-ats_preferences.c | ||
22 | * @brief manage preferences expressed by clients | ||
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-preferences", __VA_ARGS__) | ||
36 | |||
37 | /** | ||
38 | * How frequently do we age preference values? | ||
39 | */ | ||
40 | #define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply ( \ | ||
41 | GNUNET_TIME_UNIT_SECONDS, 10) | ||
42 | |||
43 | /** | ||
44 | * By which factor do we age preferences expressed during | ||
45 | * each #PREF_AGING_INTERVAL? | ||
46 | */ | ||
47 | #define PREF_AGING_FACTOR 0.95 | ||
48 | |||
49 | /** | ||
50 | * What is the lowest threshold up to which preference values | ||
51 | * are aged, and below which we consider them zero and thus | ||
52 | * no longer subject to aging? | ||
53 | */ | ||
54 | #define PREF_EPSILON 0.01 | ||
55 | |||
56 | |||
57 | /** | ||
58 | * Relative preferences for a peer. | ||
59 | */ | ||
60 | struct PeerRelative | ||
61 | { | ||
62 | /** | ||
63 | * Array of relative preference values, to be indexed by | ||
64 | * an `enum GNUNET_ATS_PreferenceKind`. | ||
65 | */ | ||
66 | double f_rel[GNUNET_ATS_PREFERENCE_END]; | ||
67 | |||
68 | /** | ||
69 | * Number of clients that are expressing a preference for | ||
70 | * this peer. When this counter reaches zero, this entry | ||
71 | * is freed. | ||
72 | */ | ||
73 | unsigned int num_clients; | ||
74 | }; | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Default values, returned as our preferences if we do not | ||
79 | * have any preferences expressed for a peer. | ||
80 | */ | ||
81 | static struct PeerRelative defvalues; | ||
82 | |||
83 | |||
84 | /** | ||
85 | * Preference information per peer and client. | ||
86 | */ | ||
87 | struct PreferencePeer | ||
88 | { | ||
89 | /** | ||
90 | * Next in DLL of preference entries for the same client. | ||
91 | */ | ||
92 | struct PreferencePeer *next; | ||
93 | |||
94 | /** | ||
95 | * Previous in DLL of preference entries for the same client. | ||
96 | */ | ||
97 | struct PreferencePeer *prev; | ||
98 | |||
99 | /** | ||
100 | * Absolute preference values for all preference types | ||
101 | * as expressed by this client for this peer. | ||
102 | */ | ||
103 | double f_abs[GNUNET_ATS_PREFERENCE_END]; | ||
104 | |||
105 | /** | ||
106 | * Relative preference values for all preference types, | ||
107 | * normalized in [0..1] based on how the respective | ||
108 | * client scored other peers. | ||
109 | */ | ||
110 | double f_rel[GNUNET_ATS_PREFERENCE_END]; | ||
111 | }; | ||
112 | |||
113 | |||
114 | /** | ||
115 | * Preference client, as in a client that expressed preferences | ||
116 | * for peers. This is the information we keep track of for each | ||
117 | * such client. | ||
118 | */ | ||
119 | struct PreferenceClient | ||
120 | { | ||
121 | /** | ||
122 | * Next in client list | ||
123 | */ | ||
124 | struct PreferenceClient *next; | ||
125 | |||
126 | /** | ||
127 | * Previous in client peer list | ||
128 | */ | ||
129 | struct PreferenceClient *prev; | ||
130 | |||
131 | /** | ||
132 | * Client handle | ||
133 | */ | ||
134 | struct GNUNET_SERVICE_Client *client; | ||
135 | |||
136 | /** | ||
137 | * Mapping peer identities to `struct PreferencePeer` entry | ||
138 | * for the respective peer. | ||
139 | */ | ||
140 | struct GNUNET_CONTAINER_MultiPeerMap *peer2pref; | ||
141 | |||
142 | /** | ||
143 | * Array of sums of absolute preferences for all | ||
144 | * peers as expressed by this client. | ||
145 | */ | ||
146 | double f_abs_sum[GNUNET_ATS_PREFERENCE_END]; | ||
147 | }; | ||
148 | |||
149 | |||
150 | /** | ||
151 | * Hashmap to store peer information for preference normalization. | ||
152 | * Maps the identity of a peer to a `struct PeerRelative` containing | ||
153 | * the current relative preference values for that peer. | ||
154 | */ | ||
155 | static struct GNUNET_CONTAINER_MultiPeerMap *preference_peers; | ||
156 | |||
157 | /** | ||
158 | * Clients in DLL: head | ||
159 | */ | ||
160 | static struct PreferenceClient *pc_head; | ||
161 | |||
162 | /** | ||
163 | * Clients in DLL: tail | ||
164 | */ | ||
165 | static struct PreferenceClient *pc_tail; | ||
166 | |||
167 | /** | ||
168 | * Handle for task we run periodically to age preferences over time. | ||
169 | */ | ||
170 | static struct GNUNET_SCHEDULER_Task *aging_task; | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Closure for #sum_relative_preferences(). | ||
175 | */ | ||
176 | struct SumContext | ||
177 | { | ||
178 | /** | ||
179 | * Where to accumulate the result. | ||
180 | */ | ||
181 | double f_rel_total; | ||
182 | |||
183 | /** | ||
184 | * Which kind of preference value are we adding up? | ||
185 | */ | ||
186 | enum GNUNET_ATS_PreferenceKind kind; | ||
187 | }; | ||
188 | |||
189 | |||
190 | /** | ||
191 | * Add the relative preference for the kind given to the | ||
192 | * closure. | ||
193 | * | ||
194 | * @param cls the `struct SumContext` with the kind and place | ||
195 | * to store the result | ||
196 | * @param peer ignored | ||
197 | * @param value the `struct PreferencePeer` for getting the rel pref. | ||
198 | * @return #GNUNET_OK | ||
199 | */ | ||
200 | static int | ||
201 | sum_relative_preferences (void *cls, | ||
202 | const struct GNUNET_PeerIdentity *peer, | ||
203 | void *value) | ||
204 | { | ||
205 | struct SumContext *sum_ctx = cls; | ||
206 | struct PreferencePeer *p_cur = value; | ||
207 | |||
208 | sum_ctx->f_rel_total += p_cur->f_rel[sum_ctx->kind]; | ||
209 | return GNUNET_OK; | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Update the total relative preference for a peer by summing | ||
215 | * up the relative preferences all clients have for this peer. | ||
216 | * | ||
217 | * @param id peer id of the peer for which we should do the update | ||
218 | * @param kind the kind of preference value to update | ||
219 | * @return the new relative preference | ||
220 | */ | ||
221 | static void | ||
222 | update_relative_values_for_peer (const struct GNUNET_PeerIdentity *id, | ||
223 | enum GNUNET_ATS_PreferenceKind kind) | ||
224 | { | ||
225 | struct PreferenceClient *c_cur; | ||
226 | struct SumContext sum_ctx; | ||
227 | struct PeerRelative *rp; | ||
228 | |||
229 | sum_ctx.f_rel_total = 0.0; | ||
230 | sum_ctx.kind = kind; | ||
231 | for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next) | ||
232 | GNUNET_CONTAINER_multipeermap_get_multiple (c_cur->peer2pref, | ||
233 | id, | ||
234 | &sum_relative_preferences, | ||
235 | &sum_ctx); | ||
236 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
237 | "Total relative preference for peer `%s' for `%s' is %.3f\n", | ||
238 | GNUNET_i2s (id), | ||
239 | GNUNET_ATS_print_preference_type (kind), | ||
240 | sum_ctx.f_rel_total); | ||
241 | rp = GNUNET_CONTAINER_multipeermap_get (preference_peers, | ||
242 | id); | ||
243 | GNUNET_assert (NULL != rp); | ||
244 | if (rp->f_rel[kind] != sum_ctx.f_rel_total) | ||
245 | { | ||
246 | rp->f_rel[kind] = sum_ctx.f_rel_total; | ||
247 | GAS_plugin_notify_preference_changed (id, | ||
248 | kind, | ||
249 | rp->f_rel[kind]); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | |||
254 | /** | ||
255 | * Free a peer's `struct PeerRelative`. | ||
256 | * | ||
257 | * @param cls unused | ||
258 | * @param key the key | ||
259 | * @param value the `struct PeerRelative` to free. | ||
260 | * @return #GNUNET_OK to continue | ||
261 | */ | ||
262 | static int | ||
263 | free_peer (void *cls, | ||
264 | const struct GNUNET_PeerIdentity *key, | ||
265 | void *value) | ||
266 | { | ||
267 | struct PeerRelative *rp = value; | ||
268 | |||
269 | GNUNET_assert (GNUNET_YES == | ||
270 | GNUNET_CONTAINER_multipeermap_remove (preference_peers, | ||
271 | key, | ||
272 | value)); | ||
273 | GNUNET_free (rp); | ||
274 | return GNUNET_OK; | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * Free `struct PreferencePeer` entry in map. | ||
280 | * | ||
281 | * @param cls the `struct PreferenceClient` with the map | ||
282 | * @param key the peer the entry is for | ||
283 | * @param value the `struct PreferencePeer` entry to free | ||
284 | * @return #GNUNET_OK (continue to iterate) | ||
285 | */ | ||
286 | static int | ||
287 | free_preference (void *cls, | ||
288 | const struct GNUNET_PeerIdentity *key, | ||
289 | void *value) | ||
290 | { | ||
291 | struct PreferenceClient *pc = cls; | ||
292 | struct PreferencePeer *p = value; | ||
293 | struct PeerRelative *pr; | ||
294 | |||
295 | GNUNET_assert (GNUNET_OK == | ||
296 | GNUNET_CONTAINER_multipeermap_remove (pc->peer2pref, | ||
297 | key, | ||
298 | p)); | ||
299 | GNUNET_free (p); | ||
300 | pr = GNUNET_CONTAINER_multipeermap_get (preference_peers, | ||
301 | key); | ||
302 | GNUNET_assert (NULL != pr); | ||
303 | GNUNET_assert (pr->num_clients > 0); | ||
304 | pr->num_clients--; | ||
305 | if (0 == pr->num_clients) | ||
306 | { | ||
307 | free_peer (NULL, | ||
308 | key, | ||
309 | pr); | ||
310 | } | ||
311 | return GNUNET_OK; | ||
312 | } | ||
313 | |||
314 | |||
315 | /** | ||
316 | * Closure for #age_values(). | ||
317 | */ | ||
318 | struct AgeContext | ||
319 | { | ||
320 | /** | ||
321 | * Counter of values remaining to update, incremented for each value | ||
322 | * changed (to a new non-zero value). | ||
323 | */ | ||
324 | unsigned int values_to_update; | ||
325 | |||
326 | /** | ||
327 | * Client we are currently aging values for. | ||
328 | */ | ||
329 | struct PreferenceClient *cur_client; | ||
330 | }; | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Age preference values of the given peer. | ||
335 | * | ||
336 | * @param cls a ` | ||
337 | * @param peer peer being aged | ||
338 | * @param value the `struct PreferencePeer` for the peer | ||
339 | * @return #GNUNET_OK (continue to iterate) | ||
340 | */ | ||
341 | static int | ||
342 | age_values (void *cls, | ||
343 | const struct GNUNET_PeerIdentity *peer, | ||
344 | void *value) | ||
345 | { | ||
346 | struct AgeContext *ac = cls; | ||
347 | struct PreferencePeer *p = value; | ||
348 | unsigned int i; | ||
349 | int dead; | ||
350 | |||
351 | dead = GNUNET_YES; | ||
352 | for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++) | ||
353 | { | ||
354 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
355 | "Aging preference for peer `%s'\n", | ||
356 | GNUNET_i2s (peer)); | ||
357 | if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE) | ||
358 | p->f_abs[i] *= PREF_AGING_FACTOR; | ||
359 | if (p->f_abs[i] <= DEFAULT_ABS_PREFERENCE + PREF_EPSILON) | ||
360 | { | ||
361 | p->f_abs[i] = DEFAULT_ABS_PREFERENCE; | ||
362 | p->f_rel[i] = DEFAULT_REL_PREFERENCE; | ||
363 | update_relative_values_for_peer (peer, | ||
364 | i); | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | ac->values_to_update++; | ||
369 | dead = GNUNET_NO; | ||
370 | } | ||
371 | } | ||
372 | if (GNUNET_YES == dead) | ||
373 | { | ||
374 | /* all preferences are zero, remove this entry */ | ||
375 | free_preference (ac->cur_client, | ||
376 | peer, | ||
377 | p); | ||
378 | } | ||
379 | return GNUNET_OK; | ||
380 | } | ||
381 | |||
382 | |||
383 | /** | ||
384 | * Reduce absolute preferences since they got old. | ||
385 | * | ||
386 | * @param cls unused | ||
387 | */ | ||
388 | static void | ||
389 | preference_aging (void *cls) | ||
390 | { | ||
391 | struct AgeContext ac; | ||
392 | |||
393 | aging_task = NULL; | ||
394 | GAS_plugin_solver_lock (); | ||
395 | ac.values_to_update = 0; | ||
396 | for (ac.cur_client = pc_head; NULL != ac.cur_client; ac.cur_client = | ||
397 | ac.cur_client->next) | ||
398 | GNUNET_CONTAINER_multipeermap_iterate (ac.cur_client->peer2pref, | ||
399 | &age_values, | ||
400 | &ac); | ||
401 | GAS_plugin_solver_unlock (); | ||
402 | if (ac.values_to_update > 0) | ||
403 | { | ||
404 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
405 | "Rescheduling aging task due to %u elements remaining to age\n", | ||
406 | ac.values_to_update); | ||
407 | if (NULL == aging_task) | ||
408 | aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL, | ||
409 | &preference_aging, | ||
410 | NULL); | ||
411 | } | ||
412 | else | ||
413 | { | ||
414 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
415 | "No values to age left, not rescheduling aging task\n"); | ||
416 | } | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
421 | * Closure for #update_rel_sum() and #update_abs_sum(). | ||
422 | */ | ||
423 | struct UpdateContext | ||
424 | { | ||
425 | /** | ||
426 | * Preference client with the sum of all absolute scores. | ||
427 | */ | ||
428 | struct PreferenceClient *pc; | ||
429 | |||
430 | /** | ||
431 | * Which kind are we updating? | ||
432 | */ | ||
433 | enum GNUNET_ATS_PreferenceKind kind; | ||
434 | }; | ||
435 | |||
436 | |||
437 | /** | ||
438 | * Compute updated absolute score for the client based on the | ||
439 | * current absolute scores for each peer. | ||
440 | * | ||
441 | * @param cls a `struct UpdateContext` | ||
442 | * @param peer peer being updated | ||
443 | * @param value the `struct PreferencePeer` for the peer | ||
444 | * @return #GNUNET_OK (continue to iterate) | ||
445 | */ | ||
446 | static int | ||
447 | update_abs_sum (void *cls, | ||
448 | const struct GNUNET_PeerIdentity *peer, | ||
449 | void *value) | ||
450 | { | ||
451 | struct UpdateContext *uc = cls; | ||
452 | struct PreferencePeer *p_cur = value; | ||
453 | |||
454 | uc->pc->f_abs_sum[uc->kind] += p_cur->f_abs[uc->kind]; | ||
455 | return GNUNET_OK; | ||
456 | } | ||
457 | |||
458 | |||
459 | /** | ||
460 | * Compute updated relative score for each peer based on the | ||
461 | * current absolute score given by this client. | ||
462 | * | ||
463 | * @param cls a `struct UpdateContext` | ||
464 | * @param peer peer being updated | ||
465 | * @param value the `struct PreferencePeer` for the peer (updated) | ||
466 | * @return #GNUNET_OK (continue to iterate) | ||
467 | */ | ||
468 | static int | ||
469 | update_rel_sum (void *cls, | ||
470 | const struct GNUNET_PeerIdentity *peer, | ||
471 | void *value) | ||
472 | { | ||
473 | struct UpdateContext *uc = cls; | ||
474 | struct PreferencePeer *p_cur = value; | ||
475 | |||
476 | p_cur->f_rel[uc->kind] = p_cur->f_abs[uc->kind] / uc->pc->f_abs_sum[uc->kind]; | ||
477 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
478 | "Client has relative preference for %s for peer `%s' of %.3f\n", | ||
479 | GNUNET_ATS_print_preference_type (uc->kind), | ||
480 | GNUNET_i2s (peer), | ||
481 | p_cur->f_rel[uc->kind]); | ||
482 | return GNUNET_OK; | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * Recalculate preference for a specific ATS property | ||
488 | * | ||
489 | * @param c the preference client | ||
490 | * @param kind the preference kind | ||
491 | * @return the result | ||
492 | */ | ||
493 | static void | ||
494 | recalculate_relative_preferences (struct PreferenceClient *c, | ||
495 | enum GNUNET_ATS_PreferenceKind kind) | ||
496 | { | ||
497 | struct UpdateContext uc; | ||
498 | |||
499 | /* For this client: sum of absolute preference values for this preference */ | ||
500 | uc.kind = kind; | ||
501 | uc.pc = c; | ||
502 | c->f_abs_sum[kind] = 0.0; | ||
503 | |||
504 | /* For all peers: calculate sum of absolute preferences */ | ||
505 | GNUNET_CONTAINER_multipeermap_iterate (c->peer2pref, | ||
506 | &update_abs_sum, | ||
507 | &uc); | ||
508 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
509 | "Client has sum of total preferences for %s of %.3f\n", | ||
510 | GNUNET_ATS_print_preference_type (kind), | ||
511 | c->f_abs_sum[kind]); | ||
512 | |||
513 | /* For all peers: calculate relative preference */ | ||
514 | GNUNET_CONTAINER_multipeermap_iterate (c->peer2pref, | ||
515 | &update_rel_sum, | ||
516 | &uc); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * The relative preferences of one of the clients have | ||
522 | * changed, update the global preferences for the given | ||
523 | * peer and notify the plugin. | ||
524 | * | ||
525 | * @param cls the kind of preference to calculate the | ||
526 | * new global relative preference values for | ||
527 | * @param key the peer to update relative preference values for | ||
528 | * @param value a `struct PeerRelative`, unused | ||
529 | */ | ||
530 | static int | ||
531 | update_iterator (void *cls, | ||
532 | const struct GNUNET_PeerIdentity *key, | ||
533 | void *value) | ||
534 | { | ||
535 | enum GNUNET_ATS_PreferenceKind *kind = cls; | ||
536 | |||
537 | update_relative_values_for_peer (key, | ||
538 | *kind); | ||
539 | return GNUNET_OK; | ||
540 | } | ||
541 | |||
542 | |||
543 | /** | ||
544 | * Update the absolute preference and calculate the | ||
545 | * new relative preference value. | ||
546 | * | ||
547 | * @param client the client with this preference | ||
548 | * @param peer the peer to change the preference for | ||
549 | * @param kind the kind to change the preference | ||
550 | * @param score_abs the normalized score | ||
551 | */ | ||
552 | static void | ||
553 | update_preference (struct GNUNET_SERVICE_Client *client, | ||
554 | const struct GNUNET_PeerIdentity *peer, | ||
555 | enum GNUNET_ATS_PreferenceKind kind, | ||
556 | float score_abs) | ||
557 | { | ||
558 | struct PreferenceClient *c_cur; | ||
559 | struct PreferencePeer *p_cur; | ||
560 | struct PeerRelative *r_cur; | ||
561 | unsigned int i; | ||
562 | |||
563 | if (kind >= GNUNET_ATS_PREFERENCE_END) | ||
564 | { | ||
565 | GNUNET_break (0); | ||
566 | return; | ||
567 | } | ||
568 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
569 | "Client changes preference for peer `%s' for `%s' to %.2f\n", | ||
570 | GNUNET_i2s (peer), | ||
571 | GNUNET_ATS_print_preference_type (kind), | ||
572 | score_abs); | ||
573 | |||
574 | /* Find preference client */ | ||
575 | for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next) | ||
576 | if (client == c_cur->client) | ||
577 | break; | ||
578 | /* Not found: create new preference client */ | ||
579 | if (NULL == c_cur) | ||
580 | { | ||
581 | c_cur = GNUNET_new (struct PreferenceClient); | ||
582 | c_cur->client = client; | ||
583 | c_cur->peer2pref = GNUNET_CONTAINER_multipeermap_create (16, | ||
584 | GNUNET_NO); | ||
585 | for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++) | ||
586 | c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE; | ||
587 | GNUNET_CONTAINER_DLL_insert (pc_head, | ||
588 | pc_tail, | ||
589 | c_cur); | ||
590 | } | ||
591 | |||
592 | /* check global peer entry exists */ | ||
593 | if (NULL == | ||
594 | (r_cur = GNUNET_CONTAINER_multipeermap_get (preference_peers, | ||
595 | peer))) | ||
596 | { | ||
597 | /* Create struct for peer */ | ||
598 | r_cur = GNUNET_new (struct PeerRelative); | ||
599 | for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++) | ||
600 | r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE; | ||
601 | GNUNET_assert (GNUNET_OK == | ||
602 | GNUNET_CONTAINER_multipeermap_put (preference_peers, | ||
603 | peer, | ||
604 | r_cur, | ||
605 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
606 | } | ||
607 | |||
608 | /* Find entry for peer */ | ||
609 | p_cur = GNUNET_CONTAINER_multipeermap_get (c_cur->peer2pref, | ||
610 | peer); | ||
611 | if (NULL == p_cur) | ||
612 | { | ||
613 | /* Not found: create new peer entry */ | ||
614 | p_cur = GNUNET_new (struct PreferencePeer); | ||
615 | for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++) | ||
616 | { | ||
617 | /* Default value per peer absolute preference for a preference*/ | ||
618 | p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE; | ||
619 | /* Default value per peer relative preference for a quality */ | ||
620 | p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE; | ||
621 | } | ||
622 | GNUNET_assert (GNUNET_YES == | ||
623 | GNUNET_CONTAINER_multipeermap_put (c_cur->peer2pref, | ||
624 | peer, | ||
625 | p_cur, | ||
626 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
627 | r_cur->num_clients++; | ||
628 | } | ||
629 | |||
630 | p_cur->f_abs[kind] += score_abs; | ||
631 | recalculate_relative_preferences (c_cur, kind); | ||
632 | GNUNET_CONTAINER_multipeermap_iterate (preference_peers, | ||
633 | &update_iterator, | ||
634 | &kind); | ||
635 | |||
636 | if (NULL == aging_task) | ||
637 | aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL, | ||
638 | &preference_aging, | ||
639 | NULL); | ||
640 | } | ||
641 | |||
642 | |||
643 | /** | ||
644 | * Handle 'preference change' messages from clients. | ||
645 | * | ||
646 | * @param client the client that sent the request | ||
647 | * @param msg the request message | ||
648 | */ | ||
649 | void | ||
650 | GAS_handle_preference_change (struct GNUNET_SERVICE_Client *client, | ||
651 | const struct ChangePreferenceMessage *msg) | ||
652 | { | ||
653 | const struct PreferenceInformation *pi; | ||
654 | uint32_t nump; | ||
655 | |||
656 | nump = ntohl (msg->num_preferences); | ||
657 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
658 | "Received PREFERENCE_CHANGE message for peer `%s'\n", | ||
659 | GNUNET_i2s (&msg->peer)); | ||
660 | GNUNET_STATISTICS_update (GSA_stats, | ||
661 | "# preference change requests processed", | ||
662 | 1, | ||
663 | GNUNET_NO); | ||
664 | pi = (const struct PreferenceInformation *) &msg[1]; | ||
665 | GAS_plugin_solver_lock (); | ||
666 | for (uint32_t i = 0; i < nump; i++) | ||
667 | update_preference (client, | ||
668 | &msg->peer, | ||
669 | (enum GNUNET_ATS_PreferenceKind) ntohl ( | ||
670 | pi[i].preference_kind), | ||
671 | pi[i].preference_value); | ||
672 | GAS_plugin_solver_unlock (); | ||
673 | } | ||
674 | |||
675 | |||
676 | /** | ||
677 | * Initialize preferences subsystem. | ||
678 | */ | ||
679 | void | ||
680 | GAS_preference_init () | ||
681 | { | ||
682 | unsigned int i; | ||
683 | |||
684 | preference_peers = GNUNET_CONTAINER_multipeermap_create (16, | ||
685 | GNUNET_NO); | ||
686 | for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++) | ||
687 | defvalues.f_rel[i] = DEFAULT_REL_PREFERENCE; | ||
688 | } | ||
689 | |||
690 | |||
691 | /** | ||
692 | * Shutdown preferences subsystem. | ||
693 | */ | ||
694 | void | ||
695 | GAS_preference_done () | ||
696 | { | ||
697 | struct PreferenceClient *pc; | ||
698 | struct PreferenceClient *next_pc; | ||
699 | |||
700 | if (NULL != aging_task) | ||
701 | { | ||
702 | GNUNET_SCHEDULER_cancel (aging_task); | ||
703 | aging_task = NULL; | ||
704 | } | ||
705 | next_pc = pc_head; | ||
706 | while (NULL != (pc = next_pc)) | ||
707 | { | ||
708 | next_pc = pc->next; | ||
709 | GNUNET_CONTAINER_DLL_remove (pc_head, | ||
710 | pc_tail, | ||
711 | pc); | ||
712 | GNUNET_CONTAINER_multipeermap_iterate (pc->peer2pref, | ||
713 | &free_preference, | ||
714 | pc); | ||
715 | GNUNET_CONTAINER_multipeermap_destroy (pc->peer2pref); | ||
716 | GNUNET_free (pc); | ||
717 | } | ||
718 | GNUNET_CONTAINER_multipeermap_iterate (preference_peers, | ||
719 | &free_peer, | ||
720 | NULL); | ||
721 | GNUNET_CONTAINER_multipeermap_destroy (preference_peers); | ||
722 | } | ||
723 | |||
724 | |||
725 | /** | ||
726 | * Get the normalized preference values for a specific peer or | ||
727 | * the default values if | ||
728 | * | ||
729 | * @param cls ignored | ||
730 | * @param id the peer | ||
731 | * @return pointer to the values, can be indexed with GNUNET_ATS_PreferenceKind, | ||
732 | * default preferences if peer does not exist | ||
733 | */ | ||
734 | const double * | ||
735 | GAS_preference_get_by_peer (void *cls, | ||
736 | const struct GNUNET_PeerIdentity *id) | ||
737 | { | ||
738 | struct PeerRelative *rp; | ||
739 | |||
740 | if (NULL == | ||
741 | (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers, | ||
742 | id))) | ||
743 | { | ||
744 | return defvalues.f_rel; | ||
745 | } | ||
746 | return rp->f_rel; | ||
747 | } | ||
748 | |||
749 | |||
750 | void | ||
751 | GAS_preference_client_disconnect (struct GNUNET_SERVICE_Client *client) | ||
752 | { | ||
753 | struct PreferenceClient *c_cur; | ||
754 | |||
755 | for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next) | ||
756 | if (client == c_cur->client) | ||
757 | break; | ||
758 | if (NULL == c_cur) | ||
759 | return; | ||
760 | GNUNET_CONTAINER_DLL_remove (pc_head, | ||
761 | pc_tail, | ||
762 | c_cur); | ||
763 | GNUNET_CONTAINER_multipeermap_iterate (c_cur->peer2pref, | ||
764 | &free_preference, | ||
765 | c_cur); | ||
766 | GNUNET_CONTAINER_multipeermap_destroy (c_cur->peer2pref); | ||
767 | GNUNET_free (c_cur); | ||
768 | } | ||
769 | |||
770 | |||
771 | /* end of gnunet-service-ats_preferences.c */ | ||