gnunet-service-ats_preferences.c 21 KB

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