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