gnunet-service-ats_preferences.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011-2015 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. 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. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file ats/gnunet-service-ats_preferences.c
  19. * @brief manage preferences expressed by clients
  20. * @author Matthias Wachs
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet-service-ats.h"
  25. #include "gnunet-service-ats_addresses.h"
  26. #include "gnunet-service-ats_performance.h"
  27. #include "gnunet-service-ats_plugins.h"
  28. #include "gnunet-service-ats_preferences.h"
  29. #include "gnunet-service-ats_reservations.h"
  30. #include "ats.h"
  31. #define LOG(kind,...) GNUNET_log_from (kind, "ats-preferences",__VA_ARGS__)
  32. /**
  33. * How frequently do we age preference values?
  34. */
  35. #define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply (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_SERVER_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. * @param rp the relative peer struct where we store the global result
  183. * @return the new relative preference
  184. */
  185. static void
  186. update_relative_values_for_peer (const struct GNUNET_PeerIdentity *id,
  187. enum GNUNET_ATS_PreferenceKind kind)
  188. {
  189. struct PreferenceClient *c_cur;
  190. struct SumContext sum_ctx;
  191. struct PeerRelative *rp;
  192. sum_ctx.f_rel_total = 0.0;
  193. sum_ctx.kind = kind;
  194. for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
  195. GNUNET_CONTAINER_multipeermap_get_multiple (c_cur->peer2pref,
  196. id,
  197. &sum_relative_preferences,
  198. &sum_ctx);
  199. LOG (GNUNET_ERROR_TYPE_DEBUG,
  200. "Total relative preference for peer `%s' for `%s' is %.3f\n",
  201. GNUNET_i2s (id),
  202. GNUNET_ATS_print_preference_type (kind),
  203. sum_ctx.f_rel_total);
  204. rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
  205. id);
  206. GNUNET_assert (NULL != rp);
  207. if (rp->f_rel[kind] != sum_ctx.f_rel_total)
  208. {
  209. rp->f_rel[kind] = sum_ctx.f_rel_total;
  210. GAS_plugin_notify_preference_changed (id,
  211. kind,
  212. rp->f_rel[kind]);
  213. }
  214. }
  215. /**
  216. * Free a peer's `struct PeerRelative`.
  217. *
  218. * @param cls unused
  219. * @param key the key
  220. * @param value the `struct PeerRelative` to free.
  221. * @return #GNUNET_OK to continue
  222. */
  223. static int
  224. free_peer (void *cls,
  225. const struct GNUNET_PeerIdentity *key,
  226. void *value)
  227. {
  228. struct PeerRelative *rp = value;
  229. GNUNET_assert (GNUNET_YES ==
  230. GNUNET_CONTAINER_multipeermap_remove (preference_peers,
  231. key,
  232. value));
  233. GNUNET_free (rp);
  234. return GNUNET_OK;
  235. }
  236. /**
  237. * Free `struct PreferencePeer` entry in map.
  238. *
  239. * @param cls the `struct PreferenceClient` with the map
  240. * @param key the peer the entry is for
  241. * @param value the `struct PreferencePeer` entry to free
  242. * @return #GNUNET_OK (continue to iterate)
  243. */
  244. static int
  245. free_preference (void *cls,
  246. const struct GNUNET_PeerIdentity *key,
  247. void *value)
  248. {
  249. struct PreferenceClient *pc = cls;
  250. struct PreferencePeer *p = value;
  251. struct PeerRelative *pr;
  252. GNUNET_assert (GNUNET_OK ==
  253. GNUNET_CONTAINER_multipeermap_remove (pc->peer2pref,
  254. key,
  255. p));
  256. GNUNET_free (p);
  257. pr = GNUNET_CONTAINER_multipeermap_get (preference_peers,
  258. key);
  259. GNUNET_assert (NULL != pr);
  260. GNUNET_assert (pr->num_clients > 0);
  261. pr->num_clients--;
  262. if (0 == pr->num_clients)
  263. {
  264. free_peer (NULL,
  265. key,
  266. pr);
  267. }
  268. return GNUNET_OK;
  269. }
  270. /**
  271. * Closure for #age_values().
  272. */
  273. struct AgeContext
  274. {
  275. /**
  276. * Counter of values remaining to update, incremented for each value
  277. * changed (to a new non-zero value).
  278. */
  279. unsigned int values_to_update;
  280. /**
  281. * Client we are currently aging values for.
  282. */
  283. struct PreferenceClient *cur_client;
  284. };
  285. /**
  286. * Age preference values of the given peer.
  287. *
  288. * @param cls a `
  289. * @param peer peer being aged
  290. * @param value the `struct PreferencePeer` for the peer
  291. * @return #GNUNET_OK (continue to iterate)
  292. */
  293. static int
  294. age_values (void *cls,
  295. const struct GNUNET_PeerIdentity *peer,
  296. void *value)
  297. {
  298. struct AgeContext *ac = cls;
  299. struct PreferencePeer *p = value;
  300. unsigned int i;
  301. int dead;
  302. dead = GNUNET_YES;
  303. for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
  304. {
  305. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  306. "Aging preference for peer `%s'\n",
  307. GNUNET_i2s (peer));
  308. if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE)
  309. p->f_abs[i] *= PREF_AGING_FACTOR;
  310. if (p->f_abs[i] <= DEFAULT_ABS_PREFERENCE + PREF_EPSILON)
  311. {
  312. p->f_abs[i] = DEFAULT_ABS_PREFERENCE;
  313. p->f_rel[i] = DEFAULT_REL_PREFERENCE;
  314. update_relative_values_for_peer (peer,
  315. i);
  316. }
  317. else
  318. {
  319. ac->values_to_update++;
  320. dead = GNUNET_NO;
  321. }
  322. }
  323. if (GNUNET_YES == dead)
  324. {
  325. /* all preferences are zero, remove this entry */
  326. free_preference (ac->cur_client,
  327. peer,
  328. p);
  329. }
  330. return GNUNET_OK;
  331. }
  332. /**
  333. * Reduce absolute preferences since they got old.
  334. *
  335. * @param cls unused
  336. * @param tc context
  337. */
  338. static void
  339. preference_aging (void *cls,
  340. const struct GNUNET_SCHEDULER_TaskContext *tc)
  341. {
  342. struct AgeContext ac;
  343. aging_task = NULL;
  344. ac.values_to_update = 0;
  345. for (ac.cur_client = pc_head; NULL != ac.cur_client; ac.cur_client = ac.cur_client->next)
  346. GNUNET_CONTAINER_multipeermap_iterate (ac.cur_client->peer2pref,
  347. &age_values,
  348. &ac);
  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. aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
  355. &preference_aging,
  356. NULL);
  357. }
  358. else
  359. {
  360. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  361. "No values to age left, not rescheduling aging task\n");
  362. }
  363. }
  364. /**
  365. * Closure for #update_rel_sum() and #update_abs_sum().
  366. */
  367. struct UpdateContext
  368. {
  369. /**
  370. * Preference client with the sum of all absolute scores.
  371. */
  372. struct PreferenceClient *pc;
  373. /**
  374. * Which kind are we updating?
  375. */
  376. enum GNUNET_ATS_PreferenceKind kind;
  377. };
  378. /**
  379. * Compute updated absolute score for the client based on the
  380. * current absolute scores for each peer.
  381. *
  382. * @param cls a `struct UpdateContext`
  383. * @param peer peer being updated
  384. * @param value the `struct PreferencePeer` for the peer
  385. * @return #GNUNET_OK (continue to iterate)
  386. */
  387. static int
  388. update_abs_sum (void *cls,
  389. const struct GNUNET_PeerIdentity *peer,
  390. void *value)
  391. {
  392. struct UpdateContext *uc = cls;
  393. struct PreferencePeer *p_cur = value;
  394. uc->pc->f_abs_sum[uc->kind] += p_cur->f_abs[uc->kind];
  395. return GNUNET_OK;
  396. }
  397. /**
  398. * Compute updated relative score for each peer based on the
  399. * current absolute score given by this client.
  400. *
  401. * @param cls a `struct UpdateContext`
  402. * @param peer peer being updated
  403. * @param value the `struct PreferencePeer` for the peer (updated)
  404. * @return #GNUNET_OK (continue to iterate)
  405. */
  406. static int
  407. update_rel_sum (void *cls,
  408. const struct GNUNET_PeerIdentity *peer,
  409. void *value)
  410. {
  411. struct UpdateContext *uc = cls;
  412. struct PreferencePeer *p_cur = value;
  413. p_cur->f_rel[uc->kind] = p_cur->f_abs[uc->kind] / uc->pc->f_abs_sum[uc->kind];
  414. LOG (GNUNET_ERROR_TYPE_DEBUG,
  415. "Client has relative preference for %s for peer `%s' of %.3f\n",
  416. GNUNET_ATS_print_preference_type (uc->kind),
  417. GNUNET_i2s (peer),
  418. p_cur->f_rel[uc->kind]);
  419. return GNUNET_OK;
  420. }
  421. /**
  422. * Recalculate preference for a specific ATS property
  423. *
  424. * @param c the preference client
  425. * @param kind the preference kind
  426. * @return the result
  427. */
  428. static void
  429. recalculate_relative_preferences (struct PreferenceClient *c,
  430. enum GNUNET_ATS_PreferenceKind kind)
  431. {
  432. struct UpdateContext uc;
  433. /* For this client: sum of absolute preference values for this preference */
  434. uc.kind = kind;
  435. uc.pc = c;
  436. c->f_abs_sum[kind] = 0.0;
  437. /* For all peers: calculate sum of absolute preferences */
  438. GNUNET_CONTAINER_multipeermap_iterate (c->peer2pref,
  439. &update_abs_sum,
  440. &uc);
  441. LOG (GNUNET_ERROR_TYPE_DEBUG,
  442. "Client has sum of total preferences for %s of %.3f\n",
  443. GNUNET_ATS_print_preference_type (kind),
  444. c->f_abs_sum[kind]);
  445. /* For all peers: calculate relative preference */
  446. GNUNET_CONTAINER_multipeermap_iterate (c->peer2pref,
  447. &update_rel_sum,
  448. &uc);
  449. }
  450. /**
  451. * The relative preferences of one of the clients have
  452. * changed, update the global preferences for the given
  453. * peer and notify the plugin.
  454. *
  455. * @param value the kind of preference to calculate the
  456. * new global relative preference values for
  457. * @param key the peer to update relative preference values for
  458. * @param value a `struct PeerRelative`, unused
  459. */
  460. static int
  461. update_iterator (void *cls,
  462. const struct GNUNET_PeerIdentity *key,
  463. void *value)
  464. {
  465. enum GNUNET_ATS_PreferenceKind *kind = cls;
  466. update_relative_values_for_peer (key,
  467. *kind);
  468. return GNUNET_OK;
  469. }
  470. /**
  471. * Update the absolute preference and calculate the
  472. * new relative preference value.
  473. *
  474. * @param client the client with this preference
  475. * @param peer the peer to change the preference for
  476. * @param kind the kind to change the preference
  477. * @param score_abs the normalized score
  478. */
  479. static void
  480. update_preference (struct GNUNET_SERVER_Client *client,
  481. const struct GNUNET_PeerIdentity *peer,
  482. enum GNUNET_ATS_PreferenceKind kind,
  483. float score_abs)
  484. {
  485. struct PreferenceClient *c_cur;
  486. struct PreferencePeer *p_cur;
  487. struct PeerRelative *r_cur;
  488. unsigned int i;
  489. if (kind >= GNUNET_ATS_PREFERENCE_END)
  490. {
  491. GNUNET_break(0);
  492. return;
  493. }
  494. LOG (GNUNET_ERROR_TYPE_DEBUG,
  495. "Client changes preference for peer `%s' for `%s' to %.2f\n",
  496. GNUNET_i2s (peer),
  497. GNUNET_ATS_print_preference_type (kind),
  498. score_abs);
  499. /* Find preference client */
  500. for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
  501. if (client == c_cur->client)
  502. break;
  503. /* Not found: create new preference client */
  504. if (NULL == c_cur)
  505. {
  506. c_cur = GNUNET_new (struct PreferenceClient);
  507. c_cur->peer2pref = GNUNET_CONTAINER_multipeermap_create (16,
  508. GNUNET_NO);
  509. for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
  510. c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
  511. GNUNET_CONTAINER_DLL_insert (pc_head,
  512. pc_tail,
  513. c_cur);
  514. }
  515. /* check global peer entry exists */
  516. if (NULL ==
  517. (r_cur = GNUNET_CONTAINER_multipeermap_get (preference_peers,
  518. peer)))
  519. {
  520. /* Create struct for peer */
  521. r_cur = GNUNET_new (struct PeerRelative);
  522. for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
  523. r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
  524. GNUNET_assert (GNUNET_OK ==
  525. GNUNET_CONTAINER_multipeermap_put (preference_peers,
  526. peer,
  527. r_cur,
  528. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  529. }
  530. /* Find entry for peer */
  531. p_cur = GNUNET_CONTAINER_multipeermap_get (c_cur->peer2pref,
  532. peer);
  533. if (NULL == p_cur)
  534. {
  535. /* Not found: create new peer entry */
  536. p_cur = GNUNET_new (struct PreferencePeer);
  537. for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
  538. {
  539. /* Default value per peer absolute preference for a preference*/
  540. p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
  541. /* Default value per peer relative preference for a quality */
  542. p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
  543. }
  544. GNUNET_assert (GNUNET_YES ==
  545. GNUNET_CONTAINER_multipeermap_put (c_cur->peer2pref,
  546. peer,
  547. p_cur,
  548. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  549. r_cur->num_clients++;
  550. }
  551. p_cur->f_abs[kind] += score_abs;
  552. recalculate_relative_preferences (c_cur, kind);
  553. GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
  554. &update_iterator,
  555. &kind);
  556. if (NULL == aging_task)
  557. aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
  558. &preference_aging,
  559. NULL);
  560. }
  561. /**
  562. * Handle 'preference change' messages from clients.
  563. *
  564. * @param cls unused, NULL
  565. * @param client client that sent the request
  566. * @param message the request message
  567. */
  568. void
  569. GAS_handle_preference_change (void *cls,
  570. struct GNUNET_SERVER_Client *client,
  571. const struct GNUNET_MessageHeader *message)
  572. {
  573. const struct ChangePreferenceMessage *msg;
  574. const struct PreferenceInformation *pi;
  575. uint16_t msize;
  576. uint32_t nump;
  577. uint32_t i;
  578. msize = ntohs (message->size);
  579. if (msize < sizeof (struct ChangePreferenceMessage))
  580. {
  581. GNUNET_break (0);
  582. GNUNET_SERVER_receive_done (client,
  583. GNUNET_SYSERR);
  584. return;
  585. }
  586. msg = (const struct ChangePreferenceMessage *) message;
  587. nump = ntohl (msg->num_preferences);
  588. if ( (msize !=
  589. sizeof (struct ChangePreferenceMessage) +
  590. nump * sizeof (struct PreferenceInformation)) ||
  591. (UINT16_MAX / sizeof (struct PreferenceInformation) < nump) )
  592. {
  593. GNUNET_break (0);
  594. GNUNET_SERVER_receive_done (client,
  595. GNUNET_SYSERR);
  596. return;
  597. }
  598. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  599. "Received PREFERENCE_CHANGE message for peer `%s'\n",
  600. GNUNET_i2s (&msg->peer));
  601. GNUNET_STATISTICS_update (GSA_stats,
  602. "# preference change requests processed",
  603. 1,
  604. GNUNET_NO);
  605. pi = (const struct PreferenceInformation *) &msg[1];
  606. GAS_plugin_solver_lock ();
  607. for (i = 0; i < nump; i++)
  608. update_preference (client,
  609. &msg->peer,
  610. (enum GNUNET_ATS_PreferenceKind) ntohl (pi[i].preference_kind),
  611. pi[i].preference_value);
  612. GAS_plugin_solver_unlock ();
  613. GNUNET_SERVER_receive_done (client,
  614. GNUNET_OK);
  615. }
  616. /**
  617. * Initialize preferences subsystem.
  618. */
  619. void
  620. GAS_preference_init ()
  621. {
  622. unsigned int i;
  623. preference_peers = GNUNET_CONTAINER_multipeermap_create (16,
  624. GNUNET_NO);
  625. for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
  626. defvalues.f_rel[i] = DEFAULT_REL_PREFERENCE;
  627. }
  628. /**
  629. * Shutdown preferences subsystem.
  630. */
  631. void
  632. GAS_preference_done ()
  633. {
  634. struct PreferenceClient *pc;
  635. struct PreferenceClient *next_pc;
  636. if (NULL != aging_task)
  637. {
  638. GNUNET_SCHEDULER_cancel (aging_task);
  639. aging_task = NULL;
  640. }
  641. next_pc = pc_head;
  642. while (NULL != (pc = next_pc))
  643. {
  644. next_pc = pc->next;
  645. GNUNET_CONTAINER_DLL_remove (pc_head,
  646. pc_tail,
  647. pc);
  648. GNUNET_CONTAINER_multipeermap_iterate (pc->peer2pref,
  649. &free_preference,
  650. pc);
  651. GNUNET_CONTAINER_multipeermap_destroy (pc->peer2pref);
  652. GNUNET_free (pc);
  653. }
  654. GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
  655. &free_peer,
  656. NULL);
  657. GNUNET_CONTAINER_multipeermap_destroy (preference_peers);
  658. }
  659. /**
  660. * Get the normalized preference values for a specific peer or
  661. * the default values if
  662. *
  663. * @param cls ignored
  664. * @param id the peer
  665. * @return pointer to the values, can be indexed with GNUNET_ATS_PreferenceKind,
  666. * default preferences if peer does not exist
  667. */
  668. const double *
  669. GAS_preference_get_by_peer (void *cls,
  670. const struct GNUNET_PeerIdentity *id)
  671. {
  672. struct PeerRelative *rp;
  673. if (NULL ==
  674. (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
  675. id)))
  676. {
  677. return defvalues.f_rel;
  678. }
  679. return rp->f_rel;
  680. }
  681. /**
  682. * A performance client disconnected
  683. *
  684. * @param client the client
  685. */
  686. void
  687. GAS_preference_client_disconnect (struct GNUNET_SERVER_Client *client)
  688. {
  689. struct PreferenceClient *c_cur;
  690. for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
  691. if (client == c_cur->client)
  692. break;
  693. if (NULL == c_cur)
  694. return;
  695. GNUNET_CONTAINER_DLL_remove (pc_head,
  696. pc_tail,
  697. c_cur);
  698. GNUNET_CONTAINER_multipeermap_iterate (c_cur->peer2pref,
  699. &free_preference,
  700. c_cur);
  701. GNUNET_CONTAINER_multipeermap_destroy (c_cur->peer2pref);
  702. GNUNET_free (c_cur);
  703. }
  704. /* end of gnunet-service-ats_preferences.c */