gnunet-service-zonemaster-monitor.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012, 2013, 2014, 2017, 2018 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 zonemaster/gnunet-service-zonemaster-monitor.c
  18. * @brief monitor namestore changes and publish them immediately to GNUnet name system
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_dht_service.h"
  24. #include "gnunet_namestore_service.h"
  25. #include "gnunet_statistics_service.h"
  26. #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
  27. /**
  28. * How often should we (re)publish each record before
  29. * it expires?
  30. */
  31. #define PUBLISH_OPS_PER_EXPIRATION 4
  32. /**
  33. * How many pending DHT operations do we allow at most?
  34. */
  35. #define DHT_QUEUE_LIMIT 2000
  36. /**
  37. * How many events may the namestore give us before it has to wait
  38. * for us to keep up?
  39. */
  40. #define NAMESTORE_QUEUE_LIMIT 5
  41. /**
  42. * What replication level do we use for DHT PUT operations?
  43. */
  44. #define DHT_GNS_REPLICATION_LEVEL 5
  45. /**
  46. * Handle for DHT PUT activity triggered from the namestore monitor.
  47. */
  48. struct DhtPutActivity
  49. {
  50. /**
  51. * Kept in a DLL.
  52. */
  53. struct DhtPutActivity *next;
  54. /**
  55. * Kept in a DLL.
  56. */
  57. struct DhtPutActivity *prev;
  58. /**
  59. * Handle for the DHT PUT operation.
  60. */
  61. struct GNUNET_DHT_PutHandle *ph;
  62. /**
  63. * When was this PUT initiated?
  64. */
  65. struct GNUNET_TIME_Absolute start_date;
  66. };
  67. /**
  68. * Handle to the statistics service
  69. */
  70. static struct GNUNET_STATISTICS_Handle *statistics;
  71. /**
  72. * Our handle to the DHT
  73. */
  74. static struct GNUNET_DHT_Handle *dht_handle;
  75. /**
  76. * Our handle to the namestore service
  77. */
  78. static struct GNUNET_NAMESTORE_Handle *namestore_handle;
  79. /**
  80. * Handle to monitor namestore changes to instant propagation.
  81. */
  82. static struct GNUNET_NAMESTORE_ZoneMonitor *zmon;
  83. /**
  84. * Head of monitor activities; kept in a DLL.
  85. */
  86. static struct DhtPutActivity *ma_head;
  87. /**
  88. * Tail of monitor activities; kept in a DLL.
  89. */
  90. static struct DhtPutActivity *ma_tail;
  91. /**
  92. * Number of entries in the DHT queue #ma_head.
  93. */
  94. static unsigned int ma_queue_length;
  95. /**
  96. * Optimize block insertion by caching map of private keys to
  97. * public keys in memory?
  98. */
  99. static int cache_keys;
  100. /**
  101. * Task run during shutdown.
  102. *
  103. * @param cls unused
  104. * @param tc unused
  105. */
  106. static void
  107. shutdown_task (void *cls)
  108. {
  109. struct DhtPutActivity *ma;
  110. (void) cls;
  111. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  112. "Shutting down!\n");
  113. while (NULL != (ma = ma_head))
  114. {
  115. GNUNET_DHT_put_cancel (ma->ph);
  116. ma_queue_length--;
  117. GNUNET_CONTAINER_DLL_remove (ma_head,
  118. ma_tail,
  119. ma);
  120. GNUNET_free (ma);
  121. }
  122. if (NULL != statistics)
  123. {
  124. GNUNET_STATISTICS_destroy (statistics,
  125. GNUNET_NO);
  126. statistics = NULL;
  127. }
  128. if (NULL != zmon)
  129. {
  130. GNUNET_NAMESTORE_zone_monitor_stop (zmon);
  131. zmon = NULL;
  132. }
  133. if (NULL != namestore_handle)
  134. {
  135. GNUNET_NAMESTORE_disconnect (namestore_handle);
  136. namestore_handle = NULL;
  137. }
  138. if (NULL != dht_handle)
  139. {
  140. GNUNET_DHT_disconnect (dht_handle);
  141. dht_handle = NULL;
  142. }
  143. }
  144. /**
  145. * Continuation called from DHT once the PUT operation triggered
  146. * by a monitor is done.
  147. *
  148. * @param cls a `struct DhtPutActivity`
  149. */
  150. static void
  151. dht_put_monitor_continuation (void *cls)
  152. {
  153. struct DhtPutActivity *ma = cls;
  154. GNUNET_NAMESTORE_zone_monitor_next (zmon,
  155. 1);
  156. ma_queue_length--;
  157. GNUNET_CONTAINER_DLL_remove (ma_head,
  158. ma_tail,
  159. ma);
  160. GNUNET_free (ma);
  161. }
  162. /**
  163. * Convert namestore records from the internal format to that
  164. * suitable for publication (removes private records, converts
  165. * to absolute expiration time).
  166. *
  167. * @param rd input records
  168. * @param rd_count size of the @a rd and @a rd_public arrays
  169. * @param rd_public where to write the converted records
  170. * @return number of records written to @a rd_public
  171. */
  172. static unsigned int
  173. convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd,
  174. unsigned int rd_count,
  175. struct GNUNET_GNSRECORD_Data *rd_public)
  176. {
  177. struct GNUNET_TIME_Absolute now;
  178. unsigned int rd_public_count;
  179. rd_public_count = 0;
  180. now = GNUNET_TIME_absolute_get ();
  181. for (unsigned int i=0;i<rd_count;i++)
  182. {
  183. if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE))
  184. continue;
  185. if ( (0 == (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) &&
  186. (rd[i].expiration_time < now.abs_value_us) )
  187. continue; /* record already expired, skip it */
  188. rd_public[rd_public_count++] = rd[i];
  189. }
  190. return rd_public_count;
  191. }
  192. /**
  193. * Store GNS records in the DHT.
  194. *
  195. * @param key key of the zone
  196. * @param label label to store under
  197. * @param rd_public public record data
  198. * @param rd_public_count number of records in @a rd_public
  199. * @param ma handle for the PUT operation
  200. * @return DHT PUT handle, NULL on error
  201. */
  202. static struct GNUNET_DHT_PutHandle *
  203. perform_dht_put (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
  204. const char *label,
  205. const struct GNUNET_GNSRECORD_Data *rd_public,
  206. unsigned int rd_public_count,
  207. struct DhtPutActivity *ma)
  208. {
  209. struct GNUNET_GNSRECORD_Block *block;
  210. struct GNUNET_HashCode query;
  211. struct GNUNET_TIME_Absolute expire;
  212. size_t block_size;
  213. struct GNUNET_DHT_PutHandle *ret;
  214. expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count,
  215. rd_public);
  216. if (cache_keys)
  217. block = GNUNET_GNSRECORD_block_create2 (key,
  218. expire,
  219. label,
  220. rd_public,
  221. rd_public_count);
  222. else
  223. block = GNUNET_GNSRECORD_block_create (key,
  224. expire,
  225. label,
  226. rd_public,
  227. rd_public_count);
  228. if (NULL == block)
  229. {
  230. GNUNET_break (0);
  231. return NULL; /* whoops */
  232. }
  233. block_size = ntohl (block->purpose.size)
  234. + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
  235. + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
  236. GNUNET_GNSRECORD_query_from_private_key (key,
  237. label,
  238. &query);
  239. GNUNET_STATISTICS_update (statistics,
  240. "DHT put operations initiated",
  241. 1,
  242. GNUNET_NO);
  243. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  244. "Storing %u record(s) for label `%s' in DHT with expiration `%s' under key %s\n",
  245. rd_public_count,
  246. label,
  247. GNUNET_STRINGS_absolute_time_to_string (expire),
  248. GNUNET_h2s (&query));
  249. ret = GNUNET_DHT_put (dht_handle,
  250. &query,
  251. DHT_GNS_REPLICATION_LEVEL,
  252. GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
  253. GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
  254. block_size,
  255. block,
  256. expire,
  257. &dht_put_monitor_continuation,
  258. ma);
  259. GNUNET_free (block);
  260. return ret;
  261. }
  262. /**
  263. * Process a record that was stored in the namestore
  264. * (invoked by the monitor).
  265. *
  266. * @param cls closure, NULL
  267. * @param zone private key of the zone; NULL on disconnect
  268. * @param label label of the records; NULL on disconnect
  269. * @param rd_count number of entries in @a rd array, 0 if label was deleted
  270. * @param rd array of records with data to store
  271. */
  272. static void
  273. handle_monitor_event (void *cls,
  274. const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
  275. const char *label,
  276. unsigned int rd_count,
  277. const struct GNUNET_GNSRECORD_Data *rd)
  278. {
  279. struct GNUNET_GNSRECORD_Data rd_public[rd_count];
  280. unsigned int rd_public_count;
  281. struct DhtPutActivity *ma;
  282. (void) cls;
  283. GNUNET_STATISTICS_update (statistics,
  284. "Namestore monitor events received",
  285. 1,
  286. GNUNET_NO);
  287. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  288. "Received %u records for label `%s' via namestore monitor\n",
  289. rd_count,
  290. label);
  291. /* filter out records that are not public, and convert to
  292. absolute expiration time. */
  293. rd_public_count = convert_records_for_export (rd,
  294. rd_count,
  295. rd_public);
  296. if (0 == rd_public_count)
  297. {
  298. GNUNET_NAMESTORE_zone_monitor_next (zmon,
  299. 1);
  300. return; /* nothing to do */
  301. }
  302. ma = GNUNET_new (struct DhtPutActivity);
  303. ma->start_date = GNUNET_TIME_absolute_get ();
  304. ma->ph = perform_dht_put (zone,
  305. label,
  306. rd,
  307. rd_count,
  308. ma);
  309. if (NULL == ma->ph)
  310. {
  311. /* PUT failed, do not remember operation */
  312. GNUNET_free (ma);
  313. GNUNET_NAMESTORE_zone_monitor_next (zmon,
  314. 1);
  315. return;
  316. }
  317. GNUNET_CONTAINER_DLL_insert_tail (ma_head,
  318. ma_tail,
  319. ma);
  320. ma_queue_length++;
  321. if (ma_queue_length > DHT_QUEUE_LIMIT)
  322. {
  323. ma = ma_head;
  324. GNUNET_CONTAINER_DLL_remove (ma_head,
  325. ma_tail,
  326. ma);
  327. GNUNET_DHT_put_cancel (ma->ph);
  328. ma_queue_length--;
  329. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  330. "DHT PUT unconfirmed after %s, aborting PUT\n",
  331. GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (ma->start_date),
  332. GNUNET_YES));
  333. GNUNET_free (ma);
  334. }
  335. }
  336. /**
  337. * The zone monitor encountered an IPC error trying to to get in
  338. * sync. Restart from the beginning.
  339. *
  340. * @param cls NULL
  341. */
  342. static void
  343. handle_monitor_error (void *cls)
  344. {
  345. (void) cls;
  346. GNUNET_STATISTICS_update (statistics,
  347. "Namestore monitor errors encountered",
  348. 1,
  349. GNUNET_NO);
  350. }
  351. /**
  352. * Performe zonemaster duties: watch namestore, publish records.
  353. *
  354. * @param cls closure
  355. * @param server the initialized server
  356. * @param c configuration to use
  357. */
  358. static void
  359. run (void *cls,
  360. const struct GNUNET_CONFIGURATION_Handle *c,
  361. struct GNUNET_SERVICE_Handle *service)
  362. {
  363. unsigned long long max_parallel_bg_queries = 128;
  364. (void) cls;
  365. (void) service;
  366. namestore_handle = GNUNET_NAMESTORE_connect (c);
  367. if (NULL == namestore_handle)
  368. {
  369. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  370. _("Failed to connect to the namestore!\n"));
  371. GNUNET_SCHEDULER_shutdown ();
  372. return;
  373. }
  374. cache_keys = GNUNET_CONFIGURATION_get_value_yesno (c,
  375. "namestore",
  376. "CACHE_KEYS");
  377. if (GNUNET_OK ==
  378. GNUNET_CONFIGURATION_get_value_number (c,
  379. "zonemaster",
  380. "MAX_PARALLEL_BACKGROUND_QUERIES",
  381. &max_parallel_bg_queries))
  382. {
  383. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  384. "Number of allowed parallel background queries: %llu\n",
  385. max_parallel_bg_queries);
  386. }
  387. if (0 == max_parallel_bg_queries)
  388. max_parallel_bg_queries = 1;
  389. dht_handle = GNUNET_DHT_connect (c,
  390. (unsigned int) max_parallel_bg_queries);
  391. if (NULL == dht_handle)
  392. {
  393. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  394. _("Could not connect to DHT!\n"));
  395. GNUNET_SCHEDULER_add_now (&shutdown_task,
  396. NULL);
  397. return;
  398. }
  399. /* Schedule periodic put for our records. */
  400. statistics = GNUNET_STATISTICS_create ("zonemaster-mon",
  401. c);
  402. zmon = GNUNET_NAMESTORE_zone_monitor_start (c,
  403. NULL,
  404. GNUNET_NO,
  405. &handle_monitor_error,
  406. NULL,
  407. &handle_monitor_event,
  408. NULL,
  409. NULL /* sync_cb */,
  410. NULL);
  411. GNUNET_NAMESTORE_zone_monitor_next (zmon,
  412. NAMESTORE_QUEUE_LIMIT - 1);
  413. GNUNET_break (NULL != zmon);
  414. GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
  415. NULL);
  416. }
  417. /**
  418. * Define "main" method using service macro.
  419. */
  420. GNUNET_SERVICE_MAIN
  421. ("zonemaster-monitor",
  422. GNUNET_SERVICE_OPTION_NONE,
  423. &run,
  424. NULL,
  425. NULL,
  426. NULL,
  427. GNUNET_MQ_handler_end());
  428. /* end of gnunet-service-zonemaster-monitor.c */