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.c773
1 files changed, 773 insertions, 0 deletions
diff --git a/src/zonemaster/gnunet-service-zonemaster.c b/src/zonemaster/gnunet-service-zonemaster.c
new file mode 100644
index 000000000..d61eb723f
--- /dev/null
+++ b/src/zonemaster/gnunet-service-zonemaster.c
@@ -0,0 +1,773 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
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#include "gnunet_namestore_plugin.h"
33#include "gnunet_signatures.h"
34
35
36#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
37
38
39
40/**
41 * The initial interval in milliseconds btween puts in
42 * a zone iteration
43 */
44#define INITIAL_PUT_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS
45
46/**
47 * The lower bound for the zone iteration interval
48 */
49#define MINIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_SECONDS
50
51/**
52 * The upper bound for the zone iteration interval
53 */
54#define MAXIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
55
56/**
57 * The default put interval for the zone iteration. In case
58 * no option is found
59 */
60#define DEFAULT_ZONE_PUBLISH_TIME_WINDOW GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
61
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/**
69 * How long until a DHT PUT attempt should time out?
70 */
71#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
72
73/**
74 * What replication level do we use for DHT PUT operations?
75 */
76#define DHT_GNS_REPLICATION_LEVEL 5
77
78
79/**
80 * Handle for DHT PUT activity triggered from the namestore monitor.
81 */
82struct MonitorActivity
83{
84 /**
85 * Kept in a DLL.
86 */
87 struct MonitorActivity *next;
88
89 /**
90 * Kept in a DLL.
91 */
92 struct MonitorActivity *prev;
93
94 /**
95 * Handle for the DHT PUT operation.
96 */
97 struct GNUNET_DHT_PutHandle *ph;
98};
99
100
101/**
102 * Handle to the statistics service
103 */
104static struct GNUNET_STATISTICS_Handle *statistics;
105
106/**
107 * Our handle to the DHT
108 */
109static struct GNUNET_DHT_Handle *dht_handle;
110
111/**
112 * Active DHT put operation (or NULL)
113 */
114static struct GNUNET_DHT_PutHandle *active_put;
115
116/**
117 * Our handle to the namestore service
118 */
119static struct GNUNET_NAMESTORE_Handle *namestore_handle;
120
121/**
122 * Handle to iterate over our authoritative zone in namestore
123 */
124static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
125
126/**
127 * Handle to monitor namestore changes to instant propagation.
128 */
129static struct GNUNET_NAMESTORE_ZoneMonitor *zmon;
130
131/**
132 * Head of monitor activities; kept in a DLL.
133 */
134static struct MonitorActivity *ma_head;
135
136/**
137 * Tail of monitor activities; kept in a DLL.
138 */
139static struct MonitorActivity *ma_tail;
140
141/**
142 * Useful for zone update for DHT put
143 */
144static unsigned long long num_public_records;
145
146/**
147 * Last seen record count
148 */
149static unsigned long long last_num_public_records;
150
151/**
152 * Minimum relative expiration time of records seem during the current
153 * zone iteration.
154 */
155static struct GNUNET_TIME_Relative min_relative_record_time;
156
157/**
158 * Zone iteration PUT interval.
159 */
160static struct GNUNET_TIME_Relative put_interval;
161
162/**
163 * Default time window for zone iteration
164 */
165static struct GNUNET_TIME_Relative zone_publish_time_window_default;
166
167/**
168 * Time window for zone iteration, adjusted based on relative record
169 * expiration times in our zone.
170 */
171static struct GNUNET_TIME_Relative zone_publish_time_window;
172
173/**
174 * zone publish task
175 */
176static struct GNUNET_SCHEDULER_Task *zone_publish_task;
177
178/**
179 * #GNUNET_YES if zone has never been published before
180 */
181static int first_zone_iteration;
182
183/**
184 * Task run during shutdown.
185 *
186 * @param cls unused
187 * @param tc unused
188 */
189static void
190shutdown_task (void *cls)
191{
192 struct MonitorActivity *ma;
193
194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
195 "Shutting down!\n");
196 while (NULL != (ma = ma_head))
197 {
198 GNUNET_DHT_put_cancel (ma->ph);
199 GNUNET_CONTAINER_DLL_remove (ma_head,
200 ma_tail,
201 ma);
202 GNUNET_free (ma);
203 }
204 if (NULL != statistics)
205 {
206 GNUNET_STATISTICS_destroy (statistics,
207 GNUNET_NO);
208 statistics = NULL;
209 }
210 if (NULL != zone_publish_task)
211 {
212 GNUNET_SCHEDULER_cancel (zone_publish_task);
213 zone_publish_task = NULL;
214 }
215 if (NULL != namestore_iter)
216 {
217 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
218 namestore_iter = NULL;
219 }
220 if (NULL != zmon)
221 {
222 GNUNET_NAMESTORE_zone_monitor_stop (zmon);
223 zmon = NULL;
224 }
225 if (NULL != namestore_handle)
226 {
227 GNUNET_NAMESTORE_disconnect (namestore_handle);
228 namestore_handle = NULL;
229 }
230 if (NULL != active_put)
231 {
232 GNUNET_DHT_put_cancel (active_put);
233 active_put = NULL;
234 }
235 if (NULL != dht_handle)
236 {
237 GNUNET_DHT_disconnect (dht_handle);
238 dht_handle = NULL;
239 }
240}
241
242
243/**
244 * Method called periodically that triggers iteration over authoritative records
245 *
246 * @param cls closure
247 */
248static void
249publish_zone_dht_next (void *cls)
250{
251 zone_publish_task = NULL;
252 GNUNET_assert (NULL != namestore_iter);
253 GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
254}
255
256
257/**
258 * Periodically iterate over our zone and store everything in dht
259 *
260 * @param cls NULL
261 */
262static void
263publish_zone_dht_start (void *cls);
264
265
266/**
267 * Continuation called from DHT once the PUT operation is done.
268 *
269 * @param cls closure, NULL if called from regular iteration,
270 * `struct MonitorActivity` if called from #handle_monitor_event.
271 * @param success #GNUNET_OK on success
272 */
273static void
274dht_put_continuation (void *cls,
275 int success)
276{
277 struct MonitorActivity *ma = cls;
278 struct GNUNET_TIME_Relative next_put_interval;
279
280 num_public_records++;
281 if (NULL == ma)
282 {
283 active_put = NULL;
284 if ( (num_public_records > last_num_public_records) &&
285 (GNUNET_NO == first_zone_iteration) )
286 {
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Last record count was lower than current record count. Reducing interval.\n");
289 put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
290 num_public_records);
291 next_put_interval = GNUNET_TIME_relative_divide (put_interval,
292 LATE_ITERATION_SPEEDUP_FACTOR);
293 }
294 else
295 next_put_interval = put_interval;
296 next_put_interval = GNUNET_TIME_relative_min (next_put_interval,
297 MAXIMUM_ZONE_ITERATION_INTERVAL);
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299 "PUT complete, next PUT in %s!\n",
300 GNUNET_STRINGS_relative_time_to_string (next_put_interval,
301 GNUNET_YES));
302
303 GNUNET_STATISTICS_set (statistics,
304 "Current zone iteration interval (ms)",
305 next_put_interval.rel_value_us / 1000LL,
306 GNUNET_NO);
307 GNUNET_assert (NULL == zone_publish_task);
308 zone_publish_task = GNUNET_SCHEDULER_add_delayed (next_put_interval,
309 &publish_zone_dht_next,
310 NULL);
311 }
312 else
313 {
314 GNUNET_CONTAINER_DLL_remove (ma_head,
315 ma_tail,
316 ma);
317 GNUNET_free (ma);
318 }
319}
320
321
322/**
323 * Convert namestore records from the internal format to that
324 * suitable for publication (removes private records, converts
325 * to absolute expiration time).
326 *
327 * @param rd input records
328 * @param rd_count size of the @a rd and @a rd_public arrays
329 * @param rd_public where to write the converted records
330 * @return number of records written to @a rd_public
331 */
332static unsigned int
333convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd,
334 unsigned int rd_count,
335 struct GNUNET_GNSRECORD_Data *rd_public)
336{
337 struct GNUNET_TIME_Absolute now;
338 unsigned int rd_public_count;
339 unsigned int i;
340
341 rd_public_count = 0;
342 now = GNUNET_TIME_absolute_get ();
343 for (i=0;i<rd_count;i++)
344 if (0 == (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE))
345 {
346 rd_public[rd_public_count] = rd[i];
347 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
348 {
349 /* GNUNET_GNSRECORD_block_create will convert to absolute time;
350 we just need to adjust our iteration frequency */
351 min_relative_record_time.rel_value_us =
352 GNUNET_MIN (rd_public[rd_public_count].expiration_time,
353 min_relative_record_time.rel_value_us);
354 }
355 else if (rd_public[rd_public_count].expiration_time < now.abs_value_us)
356 {
357 /* record already expired, skip it */
358 continue;
359 }
360 rd_public_count++;
361 }
362 return rd_public_count;
363}
364
365
366/**
367 * Store GNS records in the DHT.
368 *
369 * @param key key of the zone
370 * @param label label to store under
371 * @param rd_public public record data
372 * @param rd_public_count number of records in @a rd_public
373 * @param pc_arg closure argument to pass to the #dht_put_continuation
374 * @return DHT PUT handle, NULL on error
375 */
376static struct GNUNET_DHT_PutHandle *
377perform_dht_put (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
378 const char *label,
379 const struct GNUNET_GNSRECORD_Data *rd_public,
380 unsigned int rd_public_count,
381 void *pc_arg)
382{
383 struct GNUNET_GNSRECORD_Block *block;
384 struct GNUNET_HashCode query;
385 struct GNUNET_TIME_Absolute expire;
386 size_t block_size;
387 struct GNUNET_DHT_PutHandle *ret;
388
389 expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count,
390 rd_public);
391 block = GNUNET_GNSRECORD_block_create (key,
392 expire,
393 label,
394 rd_public,
395 rd_public_count);
396 if (NULL == block)
397 return NULL; /* whoops */
398 block_size = ntohl (block->purpose.size)
399 + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
400 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
401 GNUNET_GNSRECORD_query_from_private_key (key,
402 label,
403 &query);
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
405 "Storing %u record(s) for label `%s' in DHT with expiration `%s' under key %s\n",
406 rd_public_count,
407 label,
408 GNUNET_STRINGS_absolute_time_to_string (expire),
409 GNUNET_h2s (&query));
410 ret = GNUNET_DHT_put (dht_handle,
411 &query,
412 DHT_GNS_REPLICATION_LEVEL,
413 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
414 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
415 block_size,
416 block,
417 expire,
418 &dht_put_continuation,
419 pc_arg);
420 GNUNET_free (block);
421 return ret;
422}
423
424
425/**
426 * We encountered an error in our zone iteration.
427 */
428static void
429zone_iteration_error (void *cls)
430{
431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432 "Got disconnected from namestore database, retrying.\n");
433 namestore_iter = NULL;
434 /* We end up here on error/disconnect/shutdown, so potentially
435 while a zone publish task or a DHT put is still running; hence
436 we need to cancel those. */
437 if (NULL != zone_publish_task)
438 {
439 GNUNET_SCHEDULER_cancel (zone_publish_task);
440 zone_publish_task = NULL;
441 }
442 if (NULL != active_put)
443 {
444 GNUNET_DHT_put_cancel (active_put);
445 active_put = NULL;
446 }
447 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
448 NULL);
449}
450
451
452/**
453 * Zone iteration is completed.
454 */
455static void
456zone_iteration_finished (void *cls)
457{
458 /* we're done with one iteration, calculate when to do the next one */
459 namestore_iter = NULL;
460 last_num_public_records = num_public_records;
461 first_zone_iteration = GNUNET_NO;
462 if (0 == num_public_records)
463 {
464 /**
465 * If no records are known (startup) or none present
466 * we can safely set the interval to the value for a single
467 * record
468 */
469 put_interval = zone_publish_time_window;
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
471 "No records in namestore database.\n");
472 }
473 else
474 {
475 /* If records are present, next publication is based on the minimum
476 * relative expiration time of the records published divided by 4
477 */
478 zone_publish_time_window
479 = GNUNET_TIME_relative_min (GNUNET_TIME_relative_divide (min_relative_record_time, 4),
480 zone_publish_time_window_default);
481 put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
482 num_public_records);
483 }
484 /* reset for next iteration */
485 min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
486 put_interval = GNUNET_TIME_relative_max (MINIMUM_ZONE_ITERATION_INTERVAL,
487 put_interval);
488 put_interval = GNUNET_TIME_relative_min (put_interval,
489 MAXIMUM_ZONE_ITERATION_INTERVAL);
490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
491 "Zone iteration finished. Adjusted zone iteration interval to %s\n",
492 GNUNET_STRINGS_relative_time_to_string (put_interval,
493 GNUNET_YES));
494 GNUNET_STATISTICS_set (statistics,
495 "Current zone iteration interval (in ms)",
496 put_interval.rel_value_us / 1000LL,
497 GNUNET_NO);
498 GNUNET_STATISTICS_update (statistics,
499 "Number of zone iterations",
500 1,
501 GNUNET_NO);
502 GNUNET_STATISTICS_set (statistics,
503 "Number of public records in DHT",
504 last_num_public_records,
505 GNUNET_NO);
506 GNUNET_assert (NULL == zone_publish_task);
507 if (0 == num_public_records)
508 zone_publish_task = GNUNET_SCHEDULER_add_delayed (put_interval,
509 &publish_zone_dht_start,
510 NULL);
511 else
512 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
513 NULL);
514}
515
516
517/**
518 * Function used to put all records successively into the DHT.
519 *
520 * @param cls the closure (NULL)
521 * @param key the private key of the authority (ours)
522 * @param label the name of the records, NULL once the iteration is done
523 * @param rd_count the number of records in @a rd
524 * @param rd the record data
525 */
526static void
527put_gns_record (void *cls,
528 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
529 const char *label,
530 unsigned int rd_count,
531 const struct GNUNET_GNSRECORD_Data *rd)
532{
533 struct GNUNET_GNSRECORD_Data rd_public[rd_count];
534 unsigned int rd_public_count;
535
536 rd_public_count = convert_records_for_export (rd,
537 rd_count,
538 rd_public);
539
540 if (0 == rd_public_count)
541 {
542 GNUNET_assert (NULL == zone_publish_task);
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "Record set empty, moving to next record set\n");
545 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_next,
546 NULL);
547 return;
548 }
549 /* We got a set of records to publish */
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551 "Starting DHT PUT\n");
552 active_put = perform_dht_put (key,
553 label,
554 rd_public,
555 rd_public_count,
556 NULL);
557 if (NULL == active_put)
558 {
559 GNUNET_break (0);
560 dht_put_continuation (NULL, GNUNET_NO);
561 }
562}
563
564
565/**
566 * Periodically iterate over all zones and store everything in DHT
567 *
568 * @param cls NULL
569 */
570static void
571publish_zone_dht_start (void *cls)
572{
573 zone_publish_task = NULL;
574
575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576 "Starting DHT zone update!\n");
577 /* start counting again */
578 num_public_records = 0;
579 GNUNET_assert (NULL == namestore_iter);
580 namestore_iter
581 = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
582 NULL, /* All zones */
583 &zone_iteration_error,
584 NULL,
585 &put_gns_record,
586 NULL,
587 &zone_iteration_finished,
588 NULL);
589}
590
591
592/**
593 * Process a record that was stored in the namestore
594 * (invoked by the monitor).
595 *
596 * @param cls closure, NULL
597 * @param zone private key of the zone; NULL on disconnect
598 * @param label label of the records; NULL on disconnect
599 * @param rd_count number of entries in @a rd array, 0 if label was deleted
600 * @param rd array of records with data to store
601 */
602static void
603handle_monitor_event (void *cls,
604 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
605 const char *label,
606 unsigned int rd_count,
607 const struct GNUNET_GNSRECORD_Data *rd)
608{
609 struct GNUNET_GNSRECORD_Data rd_public[rd_count];
610 unsigned int rd_public_count;
611 struct MonitorActivity *ma;
612
613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
614 "Received %u records for label `%s' via namestore monitor\n",
615 rd_count,
616 label);
617 /* filter out records that are not public, and convert to
618 absolute expiration time. */
619 rd_public_count = convert_records_for_export (rd,
620 rd_count,
621 rd_public);
622 if (0 == rd_public_count)
623 return; /* nothing to do */
624 ma = GNUNET_new (struct MonitorActivity);
625 ma->ph = perform_dht_put (zone,
626 label,
627 rd,
628 rd_count,
629 ma);
630 if (NULL == ma->ph)
631 {
632 /* PUT failed, do not remember operation */
633 GNUNET_free (ma);
634 return;
635 }
636 GNUNET_CONTAINER_DLL_insert (ma_head,
637 ma_tail,
638 ma);
639}
640
641
642/**
643 * The zone monitor is now in SYNC with the current state of the
644 * name store. Start to perform periodic iterations.
645 *
646 * @param cls NULL
647 */
648static void
649monitor_sync_event (void *cls)
650{
651 GNUNET_assert (NULL == zone_publish_task);
652 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
653 NULL);
654}
655
656
657/**
658 * The zone monitor is now in SYNC with the current state of the
659 * name store. Start to perform periodic iterations.
660 *
661 * @param cls NULL
662 */
663static void
664handle_monitor_error (void *cls)
665{
666 if (NULL != zone_publish_task)
667 {
668 GNUNET_SCHEDULER_cancel (zone_publish_task);
669 zone_publish_task = NULL;
670 }
671 if (NULL != namestore_iter)
672 {
673 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
674 namestore_iter = NULL;
675 }
676 if (NULL != active_put)
677 {
678 GNUNET_DHT_put_cancel (active_put);
679 active_put = NULL;
680 }
681 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
682 NULL);
683}
684
685
686/**
687 * Performe zonemaster duties: watch namestore, publish records.
688 *
689 * @param cls closure
690 * @param server the initialized server
691 * @param c configuration to use
692 */
693static void
694run (void *cls,
695 const struct GNUNET_CONFIGURATION_Handle *c,
696 struct GNUNET_SERVICE_Handle *service)
697{
698 unsigned long long max_parallel_bg_queries = 0;
699
700 min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
701 namestore_handle = GNUNET_NAMESTORE_connect (c);
702 if (NULL == namestore_handle)
703 {
704 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
705 _("Failed to connect to the namestore!\n"));
706 GNUNET_SCHEDULER_shutdown ();
707 return;
708 }
709
710 put_interval = INITIAL_PUT_INTERVAL;
711 zone_publish_time_window_default = DEFAULT_ZONE_PUBLISH_TIME_WINDOW;
712 if (GNUNET_OK ==
713 GNUNET_CONFIGURATION_get_value_time (c, "gns",
714 "ZONE_PUBLISH_TIME_WINDOW",
715 &zone_publish_time_window_default))
716 {
717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718 "Time window for zone iteration: %s\n",
719 GNUNET_STRINGS_relative_time_to_string (zone_publish_time_window,
720 GNUNET_YES));
721 }
722 zone_publish_time_window = zone_publish_time_window_default;
723 if (GNUNET_OK ==
724 GNUNET_CONFIGURATION_get_value_number (c, "gns",
725 "MAX_PARALLEL_BACKGROUND_QUERIES",
726 &max_parallel_bg_queries))
727 {
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 "Number of allowed parallel background queries: %llu\n",
730 max_parallel_bg_queries);
731 }
732
733 dht_handle = GNUNET_DHT_connect (c,
734 (unsigned int) max_parallel_bg_queries);
735 if (NULL == dht_handle)
736 {
737 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
738 _("Could not connect to DHT!\n"));
739 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
740 return;
741 }
742
743 /* Schedule periodic put for our records. */
744 first_zone_iteration = GNUNET_YES;\
745 statistics = GNUNET_STATISTICS_create ("zonemaster", c);
746 zmon = GNUNET_NAMESTORE_zone_monitor_start (c,
747 NULL,
748 GNUNET_NO,
749 &handle_monitor_error,
750 NULL,
751 &handle_monitor_event,
752 NULL,
753 &monitor_sync_event,
754 NULL);
755 GNUNET_break (NULL != zmon);
756 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
757}
758
759
760/**
761 * Define "main" method using service macro.
762 */
763GNUNET_SERVICE_MAIN
764("zonemaster",
765 GNUNET_SERVICE_OPTION_NONE,
766 &run,
767 NULL,
768 NULL,
769 NULL,
770 GNUNET_MQ_handler_end());
771
772
773/* end of gnunet-service-zonemaster.c */