gnunet-service-ats_preferences.c 21 KB

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