gnunet-daemon-experimentation_experiments.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2012,2013 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 experimentation/gnunet-daemon-experimentation_experiments.c
  19. * @brief experimentation daemon: experiment management
  20. * @author Christian Grothoff
  21. * @author Matthias Wachs
  22. */
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_core_service.h"
  26. #include "gnunet_statistics_service.h"
  27. #include "gnunet-daemon-experimentation.h"
  28. /**
  29. * Hashmap containing valid experiment issuers.
  30. */
  31. struct GNUNET_CONTAINER_MultiHashMap *valid_issuers;
  32. /**
  33. * Hashmap containing valid experiments
  34. */
  35. static struct GNUNET_CONTAINER_MultiHashMap *experiments;
  36. /**
  37. * Verify experiment signature
  38. *
  39. * @param i issuer
  40. * @param e experiment
  41. * @return #GNUNET_OK or #GNUNET_SYSERR
  42. */
  43. static int
  44. experiment_verify (struct Issuer *i, struct Experiment *e)
  45. {
  46. GNUNET_assert (NULL != i);
  47. GNUNET_assert (NULL != e);
  48. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  49. "Verification: to be implemented\n");
  50. return GNUNET_OK;
  51. }
  52. static int
  53. free_experiment (void *cls,
  54. const struct GNUNET_HashCode * key,
  55. void *value)
  56. {
  57. struct Experiment *e = value;
  58. GNUNET_break (0 == GNUNET_CONTAINER_multihashmap_remove (experiments, key, value));
  59. GNUNET_free_non_null (e->description);
  60. GNUNET_free_non_null (e->name);
  61. GNUNET_free (e);
  62. return GNUNET_OK;
  63. }
  64. /**
  65. * Free issuer element
  66. *
  67. * @param cls unused
  68. * @param key the key
  69. * @param value the issuer element to free
  70. * @return GNUNET_OK to continue
  71. */
  72. static int
  73. free_issuer (void *cls,
  74. const struct GNUNET_HashCode * key,
  75. void *value)
  76. {
  77. struct Issuer *i = value;
  78. GNUNET_break (0 == GNUNET_CONTAINER_multihashmap_remove (valid_issuers,
  79. key,
  80. i));
  81. GNUNET_free (i);
  82. return GNUNET_OK;
  83. }
  84. /**
  85. * Is peer a valid issuer
  86. *
  87. * @return #GNUNET_YES or #GNUNET_NO
  88. */
  89. int
  90. GED_experiments_issuer_accepted (const struct GNUNET_CRYPTO_EddsaPublicKey *issuer_id)
  91. {
  92. struct GNUNET_HashCode hash;
  93. GNUNET_CRYPTO_hash (issuer_id, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey), &hash);
  94. if (GNUNET_CONTAINER_multihashmap_contains (valid_issuers, &hash))
  95. return GNUNET_YES;
  96. return GNUNET_NO;
  97. }
  98. /**
  99. * Get the key under which the given experiment is stored in the
  100. * experiment map.
  101. */
  102. static void
  103. get_experiment_key (const struct GNUNET_CRYPTO_EddsaPublicKey *issuer,
  104. const char *name,
  105. const struct GNUNET_TIME_Absolute version,
  106. struct GNUNET_HashCode *key)
  107. {
  108. GNUNET_assert (GNUNET_YES ==
  109. GNUNET_CRYPTO_kdf (key, sizeof (struct GNUNET_HashCode),
  110. issuer, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
  111. name, strlen (name),
  112. &version, sizeof (version),
  113. NULL, 0));
  114. }
  115. /**
  116. * Find an experiment based on issuer name and version
  117. *
  118. * @param issuer the issuer
  119. * @param name experiment name
  120. * @param version experiment version
  121. * @return the experiment or NULL if not found
  122. */
  123. struct Experiment *
  124. GED_experiments_find (const struct GNUNET_CRYPTO_EddsaPublicKey *issuer,
  125. const char *name,
  126. const struct GNUNET_TIME_Absolute version)
  127. {
  128. struct GNUNET_HashCode hc;
  129. get_experiment_key (issuer,
  130. name,
  131. version,
  132. &hc);
  133. return GNUNET_CONTAINER_multihashmap_get (experiments,
  134. &hc);
  135. }
  136. struct GetCtx
  137. {
  138. struct Node *n;
  139. GNUNET_EXPERIMENTATION_experiments_get_cb get_cb;
  140. struct GNUNET_CRYPTO_EddsaPublicKey *issuer;
  141. };
  142. static int
  143. get_it (void *cls,
  144. const struct GNUNET_HashCode *key,
  145. void *value)
  146. {
  147. struct GetCtx *get_ctx = cls;
  148. struct Experiment *e = value;
  149. if (0 == memcmp (&e->issuer,
  150. get_ctx->issuer,
  151. sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
  152. get_ctx->get_cb (get_ctx->n, e);
  153. return GNUNET_OK;
  154. }
  155. void
  156. GED_experiments_get (struct Node *n,
  157. struct GNUNET_CRYPTO_EddsaPublicKey *issuer,
  158. GNUNET_EXPERIMENTATION_experiments_get_cb get_cb)
  159. {
  160. struct GetCtx get_ctx;
  161. GNUNET_assert (NULL != n);
  162. GNUNET_assert (NULL != experiments);
  163. GNUNET_assert (NULL != get_cb);
  164. get_ctx.n = n;
  165. get_ctx.get_cb = get_cb;
  166. get_ctx.issuer = issuer;
  167. GNUNET_CONTAINER_multihashmap_iterate (experiments,
  168. &get_it, &get_ctx);
  169. get_cb (n, NULL); // FIXME: ugly, end is easily signalled as we return: synchronous API!
  170. }
  171. /**
  172. * Add a new experiment
  173. */
  174. int
  175. GNUNET_EXPERIMENTATION_experiments_add (struct Issuer *i,
  176. const char *name,
  177. const struct GNUNET_CRYPTO_EddsaPublicKey *issuer_id,
  178. struct GNUNET_TIME_Absolute version,
  179. char *description,
  180. uint32_t required_capabilities,
  181. struct GNUNET_TIME_Absolute start,
  182. struct GNUNET_TIME_Relative frequency,
  183. struct GNUNET_TIME_Relative duration,
  184. struct GNUNET_TIME_Absolute stop)
  185. {
  186. struct Experiment *e;
  187. struct GNUNET_HashCode hc;
  188. e = GNUNET_new (struct Experiment);
  189. e->name = GNUNET_strdup (name);
  190. e->issuer = *issuer_id;
  191. e->version = version;
  192. if (NULL != description)
  193. e->description = GNUNET_strdup (description);
  194. e->required_capabilities = required_capabilities;
  195. e->start = start;
  196. e->frequency = frequency;
  197. e->duration = duration;
  198. e->stop = stop;
  199. /* verify experiment */
  200. if (GNUNET_SYSERR == experiment_verify (i, e))
  201. {
  202. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  203. _("Experiment `%s': Experiment signature is invalid\n"),
  204. name);
  205. GNUNET_free (e);
  206. GNUNET_free_non_null (e->name);
  207. GNUNET_free_non_null (e->description);
  208. return GNUNET_SYSERR;
  209. }
  210. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  211. _("Adding experiment `%s' running from `%s' to `%s' every %llu sec. for %llu sec. \n"),
  212. e->name,
  213. GNUNET_STRINGS_absolute_time_to_string (start),
  214. GNUNET_STRINGS_absolute_time_to_string (stop),
  215. (long long unsigned int) frequency.rel_value_us / 1000000LL,
  216. (long long unsigned int) duration.rel_value_us / 1000000LL);
  217. get_experiment_key (&e->issuer,
  218. name,
  219. version,
  220. &hc);
  221. GNUNET_CONTAINER_multihashmap_put (experiments,
  222. &hc,
  223. e,
  224. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  225. GNUNET_STATISTICS_set (GED_stats,
  226. "# experiments",
  227. GNUNET_CONTAINER_multihashmap_size (experiments), GNUNET_NO);
  228. return GNUNET_OK;
  229. }
  230. /**
  231. * Parse a configuration section containing experiments
  232. *
  233. * @param cls configuration handle
  234. * @param name section name
  235. */
  236. static void
  237. exp_file_iterator (void *cls,
  238. const char *name)
  239. {
  240. struct GNUNET_CONFIGURATION_Handle *exp = cls;
  241. struct Issuer *i;
  242. char *val;
  243. unsigned long long number;
  244. /* Experiment values */
  245. struct GNUNET_CRYPTO_EddsaPublicKey issuer;
  246. struct GNUNET_TIME_Absolute version;
  247. char *description;
  248. uint32_t required_capabilities;
  249. struct GNUNET_TIME_Absolute start ;
  250. struct GNUNET_TIME_Absolute stop;
  251. struct GNUNET_TIME_Relative frequency;
  252. struct GNUNET_TIME_Relative duration;
  253. struct GNUNET_HashCode phash;
  254. /* Mandatory fields */
  255. /* Issuer */
  256. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (exp, name, "ISSUER", &val))
  257. {
  258. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  259. _("Experiment `%s': Issuer missing\n"), name);
  260. return;
  261. }
  262. if (GNUNET_SYSERR ==
  263. GNUNET_CRYPTO_eddsa_public_key_from_string (val,
  264. strlen (val),
  265. &issuer))
  266. {
  267. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  268. _("Experiment `%s': Issuer invalid\n"), name);
  269. GNUNET_free (val);
  270. return;
  271. }
  272. GNUNET_CRYPTO_hash (&issuer, sizeof (issuer), &phash);
  273. if (NULL == (i = GNUNET_CONTAINER_multihashmap_get (valid_issuers, &phash)))
  274. {
  275. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  276. _("Experiment `%s': Issuer not accepted!\n"), name);
  277. GNUNET_free (val);
  278. return;
  279. }
  280. GNUNET_free (val);
  281. /* Version */
  282. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (exp, name, "VERSION", &number))
  283. {
  284. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  285. _("Experiment `%s': Version missing or invalid \n"), name);
  286. return;
  287. }
  288. version.abs_value_us = number; // FIXME: what is this supposed to be? Version != TIME!???
  289. /* Required capabilities */
  290. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (exp, name, "CAPABILITIES", &number))
  291. {
  292. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  293. _("Experiment `%s': Required capabilities missing \n"), name);
  294. return;
  295. }
  296. if (number > UINT32_MAX)
  297. {
  298. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  299. _("Experiment `%s': Required capabilities invalid \n"), name);
  300. return;
  301. }
  302. required_capabilities = number;
  303. /* Optional fields */
  304. /* Description */
  305. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (exp, name, "DESCRIPTION", &description))
  306. description = NULL;
  307. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (exp, name, "START", (long long unsigned int *) &start.abs_value_us))
  308. start = GNUNET_TIME_UNIT_ZERO_ABS;
  309. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (exp, name, "FREQUENCY", &frequency))
  310. frequency = EXP_DEFAULT_EXP_FREQ;
  311. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (exp, name, "DURATION", &duration))
  312. duration = EXP_DEFAULT_EXP_DUR;
  313. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (exp, name, "STOP", (long long unsigned int *)&stop.abs_value_us))
  314. stop = GNUNET_TIME_UNIT_FOREVER_ABS;
  315. GNUNET_EXPERIMENTATION_experiments_add (i, name, &issuer, version,
  316. description, required_capabilities,
  317. start, frequency, duration, stop);
  318. GNUNET_free_non_null (description);
  319. }
  320. /**
  321. * Load experiments from file
  322. *
  323. * @param file source file
  324. */
  325. static void
  326. load_file (const char * file)
  327. {
  328. struct GNUNET_CONFIGURATION_Handle *exp = GNUNET_CONFIGURATION_create();
  329. if (NULL == exp)
  330. return;
  331. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_parse (exp, file))
  332. {
  333. GNUNET_CONFIGURATION_destroy (exp);
  334. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  335. _("Failed to parse file `%s'\n"),
  336. file);
  337. return;
  338. }
  339. GNUNET_CONFIGURATION_iterate_sections (exp, &exp_file_iterator, exp);
  340. GNUNET_CONFIGURATION_destroy (exp);
  341. }
  342. /**
  343. * Start experiments management
  344. */
  345. int
  346. GED_experiments_start ()
  347. {
  348. struct Issuer *i;
  349. char *issuers;
  350. char *file;
  351. char *pos;
  352. struct GNUNET_CRYPTO_EddsaPublicKey issuer_ID;
  353. struct GNUNET_HashCode hash;
  354. /* Load valid issuer */
  355. if (GNUNET_SYSERR ==
  356. GNUNET_CONFIGURATION_get_value_string (GED_cfg,
  357. "EXPERIMENTATION",
  358. "ISSUERS",
  359. &issuers))
  360. {
  361. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  362. _("No valid experiment issuers configured! Set value to public keys of issuers! Exiting.\n"));
  363. GED_experiments_stop ();
  364. return GNUNET_SYSERR;
  365. }
  366. valid_issuers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
  367. for (pos = strtok (issuers, " "); pos != NULL; pos = strtok (NULL, " "))
  368. {
  369. if (GNUNET_SYSERR == GNUNET_CRYPTO_eddsa_public_key_from_string (pos,
  370. strlen (pos),
  371. &issuer_ID))
  372. {
  373. GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
  374. "EXPERIMENTATION",
  375. "ISSUERS",
  376. _("Invalid value for public key\n"));
  377. GED_experiments_stop ();
  378. GNUNET_free (issuers);
  379. return GNUNET_SYSERR;
  380. }
  381. i = GNUNET_new (struct Issuer);
  382. i->pubkey = issuer_ID;
  383. GNUNET_CRYPTO_hash( &issuer_ID, sizeof (issuer_ID), &hash);
  384. GNUNET_CONTAINER_multihashmap_put (valid_issuers,
  385. &hash,
  386. i,
  387. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  388. }
  389. GNUNET_free (issuers);
  390. if (0 == GNUNET_CONTAINER_multihashmap_size (valid_issuers))
  391. {
  392. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  393. _("No valid experiment issuers configured! Set value to public keys of issuers! Exiting.\n"));
  394. GED_experiments_stop ();
  395. return GNUNET_SYSERR;
  396. }
  397. GNUNET_STATISTICS_set (GED_stats,
  398. "# issuer",
  399. GNUNET_CONTAINER_multihashmap_size (valid_issuers),
  400. GNUNET_NO);
  401. experiments = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
  402. /* Load experiments from file */
  403. if (GNUNET_SYSERR ==
  404. GNUNET_CONFIGURATION_get_value_string (GED_cfg,
  405. "EXPERIMENTATION",
  406. "EXPERIMENTS",
  407. &file))
  408. return GNUNET_OK;
  409. if (GNUNET_YES != GNUNET_DISK_file_test (file))
  410. {
  411. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  412. _("Cannot read experiments file `%s'\n"), file);
  413. GNUNET_free (file);
  414. return GNUNET_OK;
  415. }
  416. load_file (file);
  417. GNUNET_free (file);
  418. return GNUNET_OK;
  419. }
  420. /**
  421. * Stop experiments management
  422. */
  423. void
  424. GED_experiments_stop ()
  425. {
  426. if (NULL != valid_issuers)
  427. {
  428. GNUNET_CONTAINER_multihashmap_iterate (valid_issuers, &free_issuer, NULL);
  429. GNUNET_CONTAINER_multihashmap_destroy (valid_issuers);
  430. }
  431. valid_issuers = NULL;
  432. if (NULL != experiments)
  433. {
  434. GNUNET_CONTAINER_multihashmap_iterate (experiments, &free_experiment, NULL);
  435. GNUNET_CONTAINER_multihashmap_destroy (experiments);
  436. }
  437. experiments = NULL;
  438. }
  439. /* end of gnunet-daemon-experimentation_experiments.c */