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