gnunet-daemon-regexprofiler.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012, 2013 Christian Grothoff
  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 regex/gnunet-daemon-regexprofiler.c
  18. * @brief daemon that uses cadet to announce a regular expression. Used in
  19. * conjunction with gnunet-regex-profiler to announce regexes on several peers
  20. * without the need to explicitly connect to the cadet service running on the
  21. * peer from within the profiler.
  22. * @author Maximilian Szengel
  23. * @author Bartlomiej Polot
  24. */
  25. #include "platform.h"
  26. #include "gnunet_util_lib.h"
  27. #include "regex_internal_lib.h"
  28. #include "regex_test_lib.h"
  29. #include "gnunet_dht_service.h"
  30. #include "gnunet_statistics_service.h"
  31. /**
  32. * Return value from 'main'.
  33. */
  34. static int global_ret;
  35. /**
  36. * Configuration we use.
  37. */
  38. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  39. /**
  40. * Handle to the statistics service.
  41. */
  42. static struct GNUNET_STATISTICS_Handle *stats_handle;
  43. /**
  44. * Peer's dht handle.
  45. */
  46. static struct GNUNET_DHT_Handle *dht_handle;
  47. /**
  48. * Peer's regex announce handle.
  49. */
  50. static struct REGEX_INTERNAL_Announcement *announce_handle;
  51. /**
  52. * Periodically reannounce regex.
  53. */
  54. static struct GNUNET_SCHEDULER_Task *reannounce_task;
  55. /**
  56. * What's the maximum reannounce period.
  57. */
  58. static struct GNUNET_TIME_Relative reannounce_period_max;
  59. /**
  60. * Maximal path compression length for regex announcing.
  61. */
  62. static unsigned long long max_path_compression;
  63. /**
  64. * Name of the file containing policies that this peer should announce. One
  65. * policy per line.
  66. */
  67. static char *policy_filename;
  68. /**
  69. * Prefix to add before every regex we're announcing.
  70. */
  71. static char *regex_prefix;
  72. /**
  73. * Regex with prefix.
  74. */
  75. static char *rx_with_pfx;
  76. /**
  77. * How many put rounds should we do.
  78. */
  79. static unsigned int rounds = 3;
  80. /**
  81. * Private key for this peer.
  82. */
  83. static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
  84. /**
  85. * Task run during shutdown.
  86. *
  87. * @param cls unused
  88. */
  89. static void
  90. shutdown_task (void *cls)
  91. {
  92. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n");
  93. if (NULL != announce_handle)
  94. {
  95. REGEX_INTERNAL_announce_cancel (announce_handle);
  96. announce_handle = NULL;
  97. }
  98. if (NULL != reannounce_task)
  99. {
  100. GNUNET_free_nz (GNUNET_SCHEDULER_cancel (reannounce_task));
  101. reannounce_task = NULL;
  102. }
  103. if (NULL != dht_handle)
  104. {
  105. GNUNET_DHT_disconnect (dht_handle);
  106. dht_handle = NULL;
  107. }
  108. GNUNET_free (my_private_key);
  109. my_private_key = NULL;
  110. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  111. "Daemon for %s shutting down\n",
  112. policy_filename);
  113. }
  114. /**
  115. * Announce a previously announced regex re-using cached data.
  116. *
  117. * @param cls Closure (regex to announce if needed).
  118. */
  119. static void
  120. reannounce_regex (void *cls)
  121. {
  122. char *regex = cls;
  123. struct GNUNET_TIME_Relative random_delay;
  124. reannounce_task = NULL;
  125. if (0 == rounds--)
  126. {
  127. global_ret = 0;
  128. GNUNET_SCHEDULER_shutdown ();
  129. GNUNET_free (regex);
  130. return;
  131. }
  132. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Announcing regex: %s\n", regex);
  133. GNUNET_STATISTICS_update (stats_handle, "# regexes announced", 1, GNUNET_NO);
  134. if ((NULL == announce_handle) && (NULL != regex))
  135. {
  136. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  137. "First time, creating regex: %s\n",
  138. regex);
  139. announce_handle = REGEX_INTERNAL_announce (dht_handle,
  140. my_private_key,
  141. regex,
  142. (unsigned
  143. int) max_path_compression,
  144. stats_handle);
  145. }
  146. else
  147. {
  148. GNUNET_assert (NULL != announce_handle);
  149. REGEX_INTERNAL_reannounce (announce_handle);
  150. }
  151. random_delay =
  152. GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,
  153. GNUNET_CRYPTO_random_u32 (
  154. GNUNET_CRYPTO_QUALITY_WEAK,
  155. reannounce_period_max.rel_value_us));
  156. reannounce_task = GNUNET_SCHEDULER_add_delayed (random_delay,
  157. &reannounce_regex, cls);
  158. }
  159. /**
  160. * Announce the given regular expression using regex and the path compression
  161. * length read from config.
  162. *
  163. * @param regex regular expression to announce on this peer's cadet.
  164. */
  165. static void
  166. announce_regex (const char *regex)
  167. {
  168. char *copy;
  169. if ((NULL == regex) || (0 == strlen (regex)))
  170. {
  171. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot announce empty regex\n");
  172. return;
  173. }
  174. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  175. "Daemon for %s starting\n",
  176. policy_filename);
  177. GNUNET_assert (NULL == reannounce_task);
  178. copy = GNUNET_strdup (regex);
  179. reannounce_task = GNUNET_SCHEDULER_add_now (&reannounce_regex,
  180. (void *) copy);
  181. }
  182. /**
  183. * Scan through the policy_dir looking for the n-th filename.
  184. *
  185. * @param cls Closure (target number n).
  186. * @param filename complete filename (absolute path).
  187. * @return GNUNET_OK to continue to iterate,
  188. * GNUNET_NO to stop when found
  189. */
  190. static int
  191. scan (void *cls, const char *filename)
  192. {
  193. long n = (long) cls;
  194. static long c = 0;
  195. if (c == n)
  196. {
  197. policy_filename = GNUNET_strdup (filename);
  198. return GNUNET_NO;
  199. }
  200. c++;
  201. return GNUNET_OK;
  202. }
  203. /**
  204. * @brief Main function that will be run by the scheduler.
  205. *
  206. * @param cls closure
  207. * @param args remaining command-line arguments
  208. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  209. * @param cfg_ configuration
  210. */
  211. static void
  212. run (void *cls, char *const *args GNUNET_UNUSED,
  213. const char *cfgfile GNUNET_UNUSED,
  214. const struct GNUNET_CONFIGURATION_Handle *cfg_)
  215. {
  216. char *regex = NULL;
  217. char **components;
  218. char *policy_dir;
  219. long long unsigned int peer_id;
  220. cfg = cfg_;
  221. my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
  222. GNUNET_assert (NULL != my_private_key);
  223. if (GNUNET_OK !=
  224. GNUNET_CONFIGURATION_get_value_number (cfg, "REGEXPROFILER",
  225. "MAX_PATH_COMPRESSION",
  226. &max_path_compression))
  227. {
  228. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  229. _
  230. (
  231. "%s service is lacking key configuration settings (%s). Exiting.\n"),
  232. "regexprofiler", "max_path_compression");
  233. global_ret = GNUNET_SYSERR;
  234. GNUNET_SCHEDULER_shutdown ();
  235. return;
  236. }
  237. if (GNUNET_OK !=
  238. GNUNET_CONFIGURATION_get_value_string (cfg, "REGEXPROFILER",
  239. "POLICY_DIR", &policy_dir))
  240. {
  241. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "REGEXPROFILER",
  242. "POLICY_DIR");
  243. global_ret = GNUNET_SYSERR;
  244. GNUNET_SCHEDULER_shutdown ();
  245. return;
  246. }
  247. if (GNUNET_OK !=
  248. GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
  249. "PEERID", &peer_id))
  250. {
  251. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "TESTBED", "PEERID");
  252. global_ret = GNUNET_SYSERR;
  253. GNUNET_free (policy_dir);
  254. GNUNET_SCHEDULER_shutdown ();
  255. return;
  256. }
  257. if (GNUNET_OK !=
  258. GNUNET_CONFIGURATION_get_value_string (cfg, "REGEXPROFILER",
  259. "REGEX_PREFIX", &regex_prefix))
  260. {
  261. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "REGEXPROFILER",
  262. "REGEX_PREFIX");
  263. global_ret = GNUNET_SYSERR;
  264. GNUNET_free (policy_dir);
  265. GNUNET_SCHEDULER_shutdown ();
  266. return;
  267. }
  268. if (GNUNET_OK !=
  269. GNUNET_CONFIGURATION_get_value_time (cfg, "REGEXPROFILER",
  270. "REANNOUNCE_PERIOD_MAX",
  271. &reannounce_period_max))
  272. {
  273. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  274. "reannounce_period_max not given. Using 10 minutes.\n");
  275. reannounce_period_max =
  276. GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 10);
  277. }
  278. stats_handle = GNUNET_STATISTICS_create ("regexprofiler", cfg);
  279. dht_handle = GNUNET_DHT_connect (cfg, 1);
  280. if (NULL == dht_handle)
  281. {
  282. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  283. "Could not acquire dht handle. Exiting.\n");
  284. global_ret = GNUNET_SYSERR;
  285. GNUNET_free (policy_dir);
  286. GNUNET_SCHEDULER_shutdown ();
  287. return;
  288. }
  289. /* Read regexes from policy files */
  290. GNUNET_assert (-1 != GNUNET_DISK_directory_scan (policy_dir, &scan,
  291. (void *) (long) peer_id));
  292. if (NULL == (components = REGEX_TEST_read_from_file (policy_filename)))
  293. {
  294. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  295. "Policy file %s contains no policies. Exiting.\n",
  296. policy_filename);
  297. global_ret = GNUNET_SYSERR;
  298. GNUNET_free (policy_dir);
  299. GNUNET_SCHEDULER_shutdown ();
  300. return;
  301. }
  302. GNUNET_free (policy_dir);
  303. regex = REGEX_TEST_combine (components, 16);
  304. REGEX_TEST_free_from_file (components);
  305. /* Announcing regexes from policy_filename */
  306. GNUNET_asprintf (&rx_with_pfx,
  307. "%s(%s)(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)*",
  308. regex_prefix,
  309. regex);
  310. announce_regex (rx_with_pfx);
  311. GNUNET_free (regex);
  312. GNUNET_free (rx_with_pfx);
  313. /* Scheduled the task to clean up when shutdown is called */
  314. GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
  315. NULL);
  316. }
  317. /**
  318. * The main function of the regexprofiler service.
  319. *
  320. * @param argc number of arguments from the command line
  321. * @param argv command line arguments
  322. * @return 0 ok, 1 on error
  323. */
  324. int
  325. main (int argc, char *const *argv)
  326. {
  327. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  328. GNUNET_GETOPT_OPTION_END
  329. };
  330. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  331. return 2;
  332. return (GNUNET_OK ==
  333. GNUNET_PROGRAM_run (argc, argv, "regexprofiler",
  334. gettext_noop
  335. (
  336. "Daemon to announce regular expressions for the peer using cadet."),
  337. options, &run, NULL)) ? global_ret : 1;
  338. }
  339. #if defined(__linux__) && defined(__GLIBC__)
  340. #include <malloc.h>
  341. /**
  342. * MINIMIZE heap size (way below 128k) since this process doesn't need much.
  343. */
  344. void __attribute__ ((constructor))
  345. GNUNET_ARM_memory_init ()
  346. {
  347. mallopt (M_TRIM_THRESHOLD, 4 * 1024);
  348. mallopt (M_TOP_PAD, 1 * 1024);
  349. malloc_trim (0);
  350. }
  351. #endif
  352. /* end of gnunet-daemon-regexprofiler.c */