gnunet-service-zonemaster.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  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.c
  18. * @brief publish records from namestore to GNUnet name system
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_dnsparser_lib.h"
  24. #include "gnunet_dht_service.h"
  25. #include "gnunet_namestore_service.h"
  26. #include "gnunet_statistics_service.h"
  27. #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
  28. /**
  29. * How often should we (re)publish each record before
  30. * it expires?
  31. */
  32. #define PUBLISH_OPS_PER_EXPIRATION 4
  33. /**
  34. * How often do we measure the delta between desired zone
  35. * iteration speed and actual speed, and tell statistics
  36. * service about it?
  37. */
  38. #define DELTA_INTERVAL 100
  39. /**
  40. * How many records do we fetch in one shot from the namestore?
  41. */
  42. #define NS_BLOCK_SIZE 1000
  43. /**
  44. * How many pending DHT operations do we allow at most?
  45. */
  46. #define DHT_QUEUE_LIMIT 2000
  47. /**
  48. * How many events may the namestore give us before it has to wait
  49. * for us to keep up?
  50. */
  51. #define NAMESTORE_QUEUE_LIMIT 50
  52. /**
  53. * The initial interval in milliseconds btween puts in
  54. * a zone iteration
  55. */
  56. #define INITIAL_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS
  57. /**
  58. * The upper bound for the zone iteration interval
  59. * (per record).
  60. */
  61. #define MAXIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
  62. /**
  63. * The factor the current zone iteration interval is divided by for each
  64. * additional new record
  65. */
  66. #define LATE_ITERATION_SPEEDUP_FACTOR 2
  67. /**
  68. * What replication level do we use for DHT PUT operations?
  69. */
  70. #define DHT_GNS_REPLICATION_LEVEL 5
  71. /**
  72. * Handle for DHT PUT activity triggered from the namestore monitor.
  73. */
  74. struct DhtPutActivity
  75. {
  76. /**
  77. * Kept in a DLL.
  78. */
  79. struct DhtPutActivity *next;
  80. /**
  81. * Kept in a DLL.
  82. */
  83. struct DhtPutActivity *prev;
  84. /**
  85. * Handle for the DHT PUT operation.
  86. */
  87. struct GNUNET_DHT_PutHandle *ph;
  88. /**
  89. * When was this PUT initiated?
  90. */
  91. struct GNUNET_TIME_Absolute start_date;
  92. };
  93. /**
  94. * Handle to the statistics service
  95. */
  96. static struct GNUNET_STATISTICS_Handle *statistics;
  97. /**
  98. * Our handle to the DHT
  99. */
  100. static struct GNUNET_DHT_Handle *dht_handle;
  101. /**
  102. * Our handle to the namestore service
  103. */
  104. static struct GNUNET_NAMESTORE_Handle *namestore_handle;
  105. /**
  106. * Handle to iterate over our authoritative zone in namestore
  107. */
  108. static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
  109. /**
  110. * Head of iteration put activities; kept in a DLL.
  111. */
  112. static struct DhtPutActivity *it_head;
  113. /**
  114. * Tail of iteration put activities; kept in a DLL.
  115. */
  116. static struct DhtPutActivity *it_tail;
  117. /**
  118. * Number of entries in the DHT queue #it_head.
  119. */
  120. static unsigned int dht_queue_length;
  121. /**
  122. * Useful for zone update for DHT put
  123. */
  124. static unsigned long long num_public_records;
  125. /**
  126. * Last seen record count
  127. */
  128. static unsigned long long last_num_public_records;
  129. /**
  130. * Number of successful put operations performed in the current
  131. * measurement cycle (as measured in #check_zone_namestore_next()).
  132. */
  133. static unsigned long long put_cnt;
  134. /**
  135. * What is the frequency at which we currently would like
  136. * to perform DHT puts (per record)? Calculated in
  137. * update_velocity() from the #zone_publish_time_window()
  138. * and the total number of record sets we have (so far)
  139. * observed in the zone.
  140. */
  141. static struct GNUNET_TIME_Relative target_iteration_velocity_per_record;
  142. /**
  143. * Minimum relative expiration time of records seem during the current
  144. * zone iteration.
  145. */
  146. static struct GNUNET_TIME_Relative min_relative_record_time;
  147. /**
  148. * Minimum relative expiration time of records seem during the last
  149. * zone iteration.
  150. */
  151. static struct GNUNET_TIME_Relative last_min_relative_record_time;
  152. /**
  153. * Default time window for zone iteration
  154. */
  155. static struct GNUNET_TIME_Relative zone_publish_time_window_default;
  156. /**
  157. * Time window for zone iteration, adjusted based on relative record
  158. * expiration times in our zone.
  159. */
  160. static struct GNUNET_TIME_Relative zone_publish_time_window;
  161. /**
  162. * When did we last start measuring the #DELTA_INTERVAL successful
  163. * DHT puts? Used for velocity calculations.
  164. */
  165. static struct GNUNET_TIME_Absolute last_put_100;
  166. /**
  167. * By how much should we try to increase our per-record iteration speed
  168. * (over the desired speed calculated directly from the #put_interval)?
  169. * Basically this value corresponds to the per-record CPU time overhead
  170. * we have.
  171. */
  172. static struct GNUNET_TIME_Relative sub_delta;
  173. /**
  174. * zone publish task
  175. */
  176. static struct GNUNET_SCHEDULER_Task *zone_publish_task;
  177. /**
  178. * How many more values are left for the current query before we need
  179. * to explicitly ask the namestore for more?
  180. */
  181. static unsigned int ns_iteration_left;
  182. /**
  183. * #GNUNET_YES if zone has never been published before
  184. */
  185. static int first_zone_iteration;
  186. /**
  187. * Optimize block insertion by caching map of private keys to
  188. * public keys in memory?
  189. */
  190. static int cache_keys;
  191. /**
  192. * Task run during shutdown.
  193. *
  194. * @param cls unused
  195. * @param tc unused
  196. */
  197. static void
  198. shutdown_task (void *cls)
  199. {
  200. struct DhtPutActivity *ma;
  201. (void) cls;
  202. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  203. "Shutting down!\n");
  204. while (NULL != (ma = it_head))
  205. {
  206. GNUNET_DHT_put_cancel (ma->ph);
  207. dht_queue_length--;
  208. GNUNET_CONTAINER_DLL_remove (it_head,
  209. it_tail,
  210. ma);
  211. dht_queue_length--;
  212. GNUNET_free (ma);
  213. }
  214. if (NULL != statistics)
  215. {
  216. GNUNET_STATISTICS_destroy (statistics,
  217. GNUNET_NO);
  218. statistics = NULL;
  219. }
  220. if (NULL != zone_publish_task)
  221. {
  222. GNUNET_SCHEDULER_cancel (zone_publish_task);
  223. zone_publish_task = NULL;
  224. }
  225. if (NULL != namestore_iter)
  226. {
  227. GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
  228. namestore_iter = NULL;
  229. }
  230. if (NULL != namestore_handle)
  231. {
  232. GNUNET_NAMESTORE_disconnect (namestore_handle);
  233. namestore_handle = NULL;
  234. }
  235. if (NULL != dht_handle)
  236. {
  237. GNUNET_DHT_disconnect (dht_handle);
  238. dht_handle = NULL;
  239. }
  240. }
  241. /**
  242. * Method called periodically that triggers iteration over authoritative records
  243. *
  244. * @param cls NULL
  245. */
  246. static void
  247. publish_zone_namestore_next (void *cls)
  248. {
  249. (void) cls;
  250. zone_publish_task = NULL;
  251. GNUNET_assert (NULL != namestore_iter);
  252. GNUNET_assert (0 == ns_iteration_left);
  253. ns_iteration_left = NS_BLOCK_SIZE;
  254. GNUNET_NAMESTORE_zone_iterator_next (namestore_iter,
  255. NS_BLOCK_SIZE);
  256. }
  257. /**
  258. * Periodically iterate over our zone and store everything in dht
  259. *
  260. * @param cls NULL
  261. */
  262. static void
  263. publish_zone_dht_start (void *cls);
  264. /**
  265. * Calculate #target_iteration_velocity_per_record.
  266. */
  267. static void
  268. calculate_put_interval ()
  269. {
  270. if (0 == num_public_records)
  271. {
  272. /**
  273. * If no records are known (startup) or none present
  274. * we can safely set the interval to the value for a single
  275. * record
  276. */
  277. target_iteration_velocity_per_record = zone_publish_time_window;
  278. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
  279. "No records in namestore database.\n");
  280. }
  281. else
  282. {
  283. last_min_relative_record_time
  284. = GNUNET_TIME_relative_min (last_min_relative_record_time,
  285. min_relative_record_time);
  286. zone_publish_time_window
  287. = GNUNET_TIME_relative_min (GNUNET_TIME_relative_divide (last_min_relative_record_time,
  288. PUBLISH_OPS_PER_EXPIRATION),
  289. zone_publish_time_window_default);
  290. target_iteration_velocity_per_record
  291. = GNUNET_TIME_relative_divide (zone_publish_time_window,
  292. last_num_public_records);
  293. }
  294. target_iteration_velocity_per_record
  295. = GNUNET_TIME_relative_min (target_iteration_velocity_per_record,
  296. MAXIMUM_ZONE_ITERATION_INTERVAL);
  297. GNUNET_STATISTICS_set (statistics,
  298. "Minimum relative record expiration (in μs)",
  299. last_min_relative_record_time.rel_value_us,
  300. GNUNET_NO);
  301. GNUNET_STATISTICS_set (statistics,
  302. "Zone publication time window (in μs)",
  303. zone_publish_time_window.rel_value_us,
  304. GNUNET_NO);
  305. GNUNET_STATISTICS_set (statistics,
  306. "Target zone iteration velocity (μs)",
  307. target_iteration_velocity_per_record.rel_value_us,
  308. GNUNET_NO);
  309. }
  310. /**
  311. * Re-calculate our velocity and the desired velocity.
  312. * We have succeeded in making #DELTA_INTERVAL puts, so
  313. * now calculate the new desired delay between puts.
  314. *
  315. * @param cnt how many records were processed since the last call?
  316. */
  317. static void
  318. update_velocity (unsigned int cnt)
  319. {
  320. struct GNUNET_TIME_Relative delta;
  321. unsigned long long pct = 0;
  322. if (0 == cnt)
  323. return;
  324. /* How fast were we really? */
  325. delta = GNUNET_TIME_absolute_get_duration (last_put_100);
  326. delta.rel_value_us /= cnt;
  327. last_put_100 = GNUNET_TIME_absolute_get ();
  328. /* calculate expected frequency */
  329. if ( (num_public_records > last_num_public_records) &&
  330. (GNUNET_NO == first_zone_iteration) )
  331. {
  332. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  333. "Last record count was lower than current record count. Reducing interval.\n");
  334. last_num_public_records = num_public_records * LATE_ITERATION_SPEEDUP_FACTOR;
  335. calculate_put_interval ();
  336. }
  337. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  338. "Desired global zone iteration interval is %s/record!\n",
  339. GNUNET_STRINGS_relative_time_to_string (target_iteration_velocity_per_record,
  340. GNUNET_YES));
  341. /* Tell statistics actual vs. desired speed */
  342. GNUNET_STATISTICS_set (statistics,
  343. "Current zone iteration velocity (μs/record)",
  344. delta.rel_value_us,
  345. GNUNET_NO);
  346. /* update "sub_delta" based on difference, taking
  347. previous sub_delta into account! */
  348. if (target_iteration_velocity_per_record.rel_value_us > delta.rel_value_us)
  349. {
  350. /* We were too fast, reduce sub_delta! */
  351. struct GNUNET_TIME_Relative corr;
  352. corr = GNUNET_TIME_relative_subtract (target_iteration_velocity_per_record,
  353. delta);
  354. if (sub_delta.rel_value_us > delta.rel_value_us)
  355. {
  356. /* Reduce sub_delta by corr */
  357. sub_delta = GNUNET_TIME_relative_subtract (sub_delta,
  358. corr);
  359. }
  360. else
  361. {
  362. /* We're doing fine with waiting the full time, this
  363. should theoretically only happen if we run at
  364. infinite speed. */
  365. sub_delta = GNUNET_TIME_UNIT_ZERO;
  366. }
  367. }
  368. else if (target_iteration_velocity_per_record.rel_value_us < delta.rel_value_us)
  369. {
  370. /* We were too slow, increase sub_delta! */
  371. struct GNUNET_TIME_Relative corr;
  372. corr = GNUNET_TIME_relative_subtract (delta,
  373. target_iteration_velocity_per_record);
  374. sub_delta = GNUNET_TIME_relative_add (sub_delta,
  375. corr);
  376. if (sub_delta.rel_value_us > target_iteration_velocity_per_record.rel_value_us)
  377. {
  378. /* CPU overload detected, we cannot go at desired speed,
  379. as this would mean using a negative delay. */
  380. /* compute how much faster we would want to be for
  381. the desired velocity */
  382. if (0 == target_iteration_velocity_per_record.rel_value_us)
  383. pct = UINT64_MAX; /* desired speed is infinity ... */
  384. else
  385. pct = (sub_delta.rel_value_us -
  386. target_iteration_velocity_per_record.rel_value_us) * 100LLU
  387. / target_iteration_velocity_per_record.rel_value_us;
  388. sub_delta = target_iteration_velocity_per_record;
  389. }
  390. }
  391. GNUNET_STATISTICS_set (statistics,
  392. "# size of the DHT queue (it)",
  393. dht_queue_length,
  394. GNUNET_NO);
  395. GNUNET_STATISTICS_set (statistics,
  396. "% speed increase needed for target velocity",
  397. pct,
  398. GNUNET_NO);
  399. GNUNET_STATISTICS_set (statistics,
  400. "# records processed in current iteration",
  401. num_public_records,
  402. GNUNET_NO);
  403. }
  404. /**
  405. * Check if the current zone iteration needs to be continued
  406. * by calling #publish_zone_namestore_next(), and if so with what delay.
  407. */
  408. static void
  409. check_zone_namestore_next ()
  410. {
  411. struct GNUNET_TIME_Relative delay;
  412. if (0 != ns_iteration_left)
  413. return; /* current NAMESTORE iteration not yet done */
  414. update_velocity (put_cnt);
  415. put_cnt = 0;
  416. delay = GNUNET_TIME_relative_subtract (target_iteration_velocity_per_record,
  417. sub_delta);
  418. /* We delay *once* per #NS_BLOCK_SIZE, so we need to multiply the
  419. per-record delay calculated so far with the #NS_BLOCK_SIZE */
  420. GNUNET_STATISTICS_set (statistics,
  421. "Current artificial NAMESTORE delay (μs/record)",
  422. delay.rel_value_us,
  423. GNUNET_NO);
  424. delay = GNUNET_TIME_relative_multiply (delay,
  425. NS_BLOCK_SIZE);
  426. /* make sure we do not overshoot because of the #NS_BLOCK_SIZE factor */
  427. delay = GNUNET_TIME_relative_min (MAXIMUM_ZONE_ITERATION_INTERVAL,
  428. delay);
  429. /* no delays on first iteration */
  430. if (GNUNET_YES == first_zone_iteration)
  431. delay = GNUNET_TIME_UNIT_ZERO;
  432. GNUNET_assert (NULL == zone_publish_task);
  433. zone_publish_task = GNUNET_SCHEDULER_add_delayed (delay,
  434. &publish_zone_namestore_next,
  435. NULL);
  436. }
  437. /**
  438. * Continuation called from DHT once the PUT operation is done.
  439. *
  440. * @param cls a `struct DhtPutActivity`
  441. */
  442. static void
  443. dht_put_continuation (void *cls)
  444. {
  445. struct DhtPutActivity *ma = cls;
  446. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  447. "PUT complete\n");
  448. dht_queue_length--;
  449. GNUNET_CONTAINER_DLL_remove (it_head,
  450. it_tail,
  451. ma);
  452. GNUNET_free (ma);
  453. }
  454. /**
  455. * Convert namestore records from the internal format to that
  456. * suitable for publication (removes private records, converts
  457. * to absolute expiration time).
  458. *
  459. * @param rd input records
  460. * @param rd_count size of the @a rd and @a rd_public arrays
  461. * @param rd_public where to write the converted records
  462. * @return number of records written to @a rd_public
  463. */
  464. static unsigned int
  465. convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd,
  466. unsigned int rd_count,
  467. struct GNUNET_GNSRECORD_Data *rd_public)
  468. {
  469. struct GNUNET_TIME_Absolute now;
  470. unsigned int rd_public_count;
  471. rd_public_count = 0;
  472. now = GNUNET_TIME_absolute_get ();
  473. for (unsigned int i=0;i<rd_count;i++)
  474. {
  475. if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE))
  476. continue;
  477. if ( (0 == (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) &&
  478. (rd[i].expiration_time < now.abs_value_us) )
  479. continue; /* record already expired, skip it */
  480. if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
  481. {
  482. /* GNUNET_GNSRECORD_block_create will convert to absolute time;
  483. we just need to adjust our iteration frequency */
  484. min_relative_record_time.rel_value_us =
  485. GNUNET_MIN (rd[i].expiration_time,
  486. min_relative_record_time.rel_value_us);
  487. }
  488. rd_public[rd_public_count++] = rd[i];
  489. }
  490. return rd_public_count;
  491. }
  492. /**
  493. * Store GNS records in the DHT.
  494. *
  495. * @param key key of the zone
  496. * @param label label to store under
  497. * @param rd_public public record data
  498. * @param rd_public_count number of records in @a rd_public
  499. * @param ma handle for the put operation
  500. * @return DHT PUT handle, NULL on error
  501. */
  502. static struct GNUNET_DHT_PutHandle *
  503. perform_dht_put (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
  504. const char *label,
  505. const struct GNUNET_GNSRECORD_Data *rd_public,
  506. unsigned int rd_public_count,
  507. struct DhtPutActivity *ma)
  508. {
  509. struct GNUNET_GNSRECORD_Block *block;
  510. struct GNUNET_HashCode query;
  511. struct GNUNET_TIME_Absolute expire;
  512. size_t block_size;
  513. struct GNUNET_DHT_PutHandle *ret;
  514. expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count,
  515. rd_public);
  516. if (cache_keys)
  517. block = GNUNET_GNSRECORD_block_create2 (key,
  518. expire,
  519. label,
  520. rd_public,
  521. rd_public_count);
  522. else
  523. block = GNUNET_GNSRECORD_block_create (key,
  524. expire,
  525. label,
  526. rd_public,
  527. rd_public_count);
  528. if (NULL == block)
  529. {
  530. GNUNET_break (0);
  531. return NULL; /* whoops */
  532. }
  533. block_size = ntohl (block->purpose.size)
  534. + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
  535. + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
  536. GNUNET_GNSRECORD_query_from_private_key (key,
  537. label,
  538. &query);
  539. GNUNET_STATISTICS_update (statistics,
  540. "DHT put operations initiated",
  541. 1,
  542. GNUNET_NO);
  543. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  544. "Storing %u record(s) for label `%s' in DHT with expiration `%s' under key %s\n",
  545. rd_public_count,
  546. label,
  547. GNUNET_STRINGS_absolute_time_to_string (expire),
  548. GNUNET_h2s (&query));
  549. num_public_records++;
  550. ret = GNUNET_DHT_put (dht_handle,
  551. &query,
  552. DHT_GNS_REPLICATION_LEVEL,
  553. GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
  554. GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
  555. block_size,
  556. block,
  557. expire,
  558. &dht_put_continuation,
  559. ma);
  560. GNUNET_free (block);
  561. return ret;
  562. }
  563. /**
  564. * We encountered an error in our zone iteration.
  565. *
  566. * @param cls NULL
  567. */
  568. static void
  569. zone_iteration_error (void *cls)
  570. {
  571. (void) cls;
  572. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  573. "Got disconnected from namestore database, retrying.\n");
  574. namestore_iter = NULL;
  575. /* We end up here on error/disconnect/shutdown, so potentially
  576. while a zone publish task or a DHT put is still running; hence
  577. we need to cancel those. */
  578. if (NULL != zone_publish_task)
  579. {
  580. GNUNET_SCHEDULER_cancel (zone_publish_task);
  581. zone_publish_task = NULL;
  582. }
  583. zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
  584. NULL);
  585. }
  586. /**
  587. * Zone iteration is completed.
  588. *
  589. * @param cls NULL
  590. */
  591. static void
  592. zone_iteration_finished (void *cls)
  593. {
  594. (void) cls;
  595. /* we're done with one iteration, calculate when to do the next one */
  596. namestore_iter = NULL;
  597. last_num_public_records = num_public_records;
  598. first_zone_iteration = GNUNET_NO;
  599. last_min_relative_record_time = min_relative_record_time;
  600. calculate_put_interval ();
  601. /* reset for next iteration */
  602. min_relative_record_time
  603. = GNUNET_TIME_UNIT_FOREVER_REL;
  604. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  605. "Zone iteration finished. Adjusted zone iteration interval to %s\n",
  606. GNUNET_STRINGS_relative_time_to_string (target_iteration_velocity_per_record,
  607. GNUNET_YES));
  608. GNUNET_STATISTICS_set (statistics,
  609. "Target zone iteration velocity (μs)",
  610. target_iteration_velocity_per_record.rel_value_us,
  611. GNUNET_NO);
  612. GNUNET_STATISTICS_set (statistics,
  613. "Number of public records in DHT",
  614. last_num_public_records,
  615. GNUNET_NO);
  616. GNUNET_assert (NULL == zone_publish_task);
  617. if (0 == last_num_public_records)
  618. {
  619. zone_publish_task = GNUNET_SCHEDULER_add_delayed (target_iteration_velocity_per_record,
  620. &publish_zone_dht_start,
  621. NULL);
  622. }
  623. else
  624. {
  625. zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
  626. NULL);
  627. }
  628. }
  629. /**
  630. * Function used to put all records successively into the DHT.
  631. *
  632. * @param cls the closure (NULL)
  633. * @param key the private key of the authority (ours)
  634. * @param label the name of the records, NULL once the iteration is done
  635. * @param rd_count the number of records in @a rd
  636. * @param rd the record data
  637. */
  638. static void
  639. put_gns_record (void *cls,
  640. const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
  641. const char *label,
  642. unsigned int rd_count,
  643. const struct GNUNET_GNSRECORD_Data *rd)
  644. {
  645. struct GNUNET_GNSRECORD_Data rd_public[rd_count];
  646. unsigned int rd_public_count;
  647. struct DhtPutActivity *ma;
  648. (void) cls;
  649. ns_iteration_left--;
  650. rd_public_count = convert_records_for_export (rd,
  651. rd_count,
  652. rd_public);
  653. if (0 == rd_public_count)
  654. {
  655. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  656. "Record set empty, moving to next record set\n");
  657. check_zone_namestore_next ();
  658. return;
  659. }
  660. /* We got a set of records to publish */
  661. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  662. "Starting DHT PUT\n");
  663. ma = GNUNET_new (struct DhtPutActivity);
  664. ma->start_date = GNUNET_TIME_absolute_get ();
  665. ma->ph = perform_dht_put (key,
  666. label,
  667. rd_public,
  668. rd_public_count,
  669. ma);
  670. put_cnt++;
  671. if (0 == put_cnt % DELTA_INTERVAL)
  672. update_velocity (DELTA_INTERVAL);
  673. check_zone_namestore_next ();
  674. if (NULL == ma->ph)
  675. {
  676. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  677. "Could not perform DHT PUT, is the DHT running?\n");
  678. GNUNET_free (ma);
  679. return;
  680. }
  681. dht_queue_length++;
  682. GNUNET_CONTAINER_DLL_insert_tail (it_head,
  683. it_tail,
  684. ma);
  685. if (dht_queue_length > DHT_QUEUE_LIMIT)
  686. {
  687. ma = it_head;
  688. GNUNET_CONTAINER_DLL_remove (it_head,
  689. it_tail,
  690. ma);
  691. GNUNET_DHT_put_cancel (ma->ph);
  692. dht_queue_length--;
  693. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  694. "DHT PUT unconfirmed after %s, aborting PUT\n",
  695. GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (ma->start_date),
  696. GNUNET_YES));
  697. GNUNET_free (ma);
  698. }
  699. }
  700. /**
  701. * Periodically iterate over all zones and store everything in DHT
  702. *
  703. * @param cls NULL
  704. */
  705. static void
  706. publish_zone_dht_start (void *cls)
  707. {
  708. (void) cls;
  709. zone_publish_task = NULL;
  710. GNUNET_STATISTICS_update (statistics,
  711. "Full zone iterations launched",
  712. 1,
  713. GNUNET_NO);
  714. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  715. "Starting DHT zone update!\n");
  716. /* start counting again */
  717. num_public_records = 0;
  718. GNUNET_assert (NULL == namestore_iter);
  719. ns_iteration_left = 1;
  720. namestore_iter
  721. = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
  722. NULL, /* All zones */
  723. &zone_iteration_error,
  724. NULL,
  725. &put_gns_record,
  726. NULL,
  727. &zone_iteration_finished,
  728. NULL);
  729. GNUNET_assert (NULL != namestore_iter);
  730. }
  731. /**
  732. * Performe zonemaster duties: watch namestore, publish records.
  733. *
  734. * @param cls closure
  735. * @param server the initialized server
  736. * @param c configuration to use
  737. */
  738. static void
  739. run (void *cls,
  740. const struct GNUNET_CONFIGURATION_Handle *c,
  741. struct GNUNET_SERVICE_Handle *service)
  742. {
  743. unsigned long long max_parallel_bg_queries = 128;
  744. (void) cls;
  745. (void) service;
  746. last_put_100 = GNUNET_TIME_absolute_get (); /* first time! */
  747. min_relative_record_time
  748. = GNUNET_TIME_UNIT_FOREVER_REL;
  749. target_iteration_velocity_per_record = INITIAL_ZONE_ITERATION_INTERVAL;
  750. namestore_handle = GNUNET_NAMESTORE_connect (c);
  751. if (NULL == namestore_handle)
  752. {
  753. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  754. _("Failed to connect to the namestore!\n"));
  755. GNUNET_SCHEDULER_shutdown ();
  756. return;
  757. }
  758. cache_keys = GNUNET_CONFIGURATION_get_value_yesno (c,
  759. "namestore",
  760. "CACHE_KEYS");
  761. zone_publish_time_window_default = GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY;
  762. if (GNUNET_OK ==
  763. GNUNET_CONFIGURATION_get_value_time (c,
  764. "zonemaster",
  765. "ZONE_PUBLISH_TIME_WINDOW",
  766. &zone_publish_time_window_default))
  767. {
  768. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  769. "Time window for zone iteration: %s\n",
  770. GNUNET_STRINGS_relative_time_to_string (zone_publish_time_window,
  771. GNUNET_YES));
  772. }
  773. zone_publish_time_window = zone_publish_time_window_default;
  774. if (GNUNET_OK ==
  775. GNUNET_CONFIGURATION_get_value_number (c,
  776. "zonemaster",
  777. "MAX_PARALLEL_BACKGROUND_QUERIES",
  778. &max_parallel_bg_queries))
  779. {
  780. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  781. "Number of allowed parallel background queries: %llu\n",
  782. max_parallel_bg_queries);
  783. }
  784. if (0 == max_parallel_bg_queries)
  785. max_parallel_bg_queries = 1;
  786. dht_handle = GNUNET_DHT_connect (c,
  787. (unsigned int) max_parallel_bg_queries);
  788. if (NULL == dht_handle)
  789. {
  790. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  791. _("Could not connect to DHT!\n"));
  792. GNUNET_SCHEDULER_add_now (&shutdown_task,
  793. NULL);
  794. return;
  795. }
  796. /* Schedule periodic put for our records. */
  797. first_zone_iteration = GNUNET_YES;
  798. statistics = GNUNET_STATISTICS_create ("zonemaster",
  799. c);
  800. GNUNET_STATISTICS_set (statistics,
  801. "Target zone iteration velocity (μs)",
  802. target_iteration_velocity_per_record.rel_value_us,
  803. GNUNET_NO);
  804. zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
  805. NULL);
  806. GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
  807. NULL);
  808. }
  809. /**
  810. * Define "main" method using service macro.
  811. */
  812. GNUNET_SERVICE_MAIN
  813. ("zonemaster",
  814. GNUNET_SERVICE_OPTION_NONE,
  815. &run,
  816. NULL,
  817. NULL,
  818. NULL,
  819. GNUNET_MQ_handler_end());
  820. /* end of gnunet-service-zonemaster.c */