diff options
Diffstat (limited to 'src/zonemaster/gnunet-service-zonemaster.c')
-rw-r--r-- | src/zonemaster/gnunet-service-zonemaster.c | 773 |
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 | */ | ||
82 | struct 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 | */ | ||
104 | static struct GNUNET_STATISTICS_Handle *statistics; | ||
105 | |||
106 | /** | ||
107 | * Our handle to the DHT | ||
108 | */ | ||
109 | static struct GNUNET_DHT_Handle *dht_handle; | ||
110 | |||
111 | /** | ||
112 | * Active DHT put operation (or NULL) | ||
113 | */ | ||
114 | static struct GNUNET_DHT_PutHandle *active_put; | ||
115 | |||
116 | /** | ||
117 | * Our handle to the namestore service | ||
118 | */ | ||
119 | static struct GNUNET_NAMESTORE_Handle *namestore_handle; | ||
120 | |||
121 | /** | ||
122 | * Handle to iterate over our authoritative zone in namestore | ||
123 | */ | ||
124 | static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter; | ||
125 | |||
126 | /** | ||
127 | * Handle to monitor namestore changes to instant propagation. | ||
128 | */ | ||
129 | static struct GNUNET_NAMESTORE_ZoneMonitor *zmon; | ||
130 | |||
131 | /** | ||
132 | * Head of monitor activities; kept in a DLL. | ||
133 | */ | ||
134 | static struct MonitorActivity *ma_head; | ||
135 | |||
136 | /** | ||
137 | * Tail of monitor activities; kept in a DLL. | ||
138 | */ | ||
139 | static struct MonitorActivity *ma_tail; | ||
140 | |||
141 | /** | ||
142 | * Useful for zone update for DHT put | ||
143 | */ | ||
144 | static unsigned long long num_public_records; | ||
145 | |||
146 | /** | ||
147 | * Last seen record count | ||
148 | */ | ||
149 | static unsigned long long last_num_public_records; | ||
150 | |||
151 | /** | ||
152 | * Minimum relative expiration time of records seem during the current | ||
153 | * zone iteration. | ||
154 | */ | ||
155 | static struct GNUNET_TIME_Relative min_relative_record_time; | ||
156 | |||
157 | /** | ||
158 | * Zone iteration PUT interval. | ||
159 | */ | ||
160 | static struct GNUNET_TIME_Relative put_interval; | ||
161 | |||
162 | /** | ||
163 | * Default time window for zone iteration | ||
164 | */ | ||
165 | static 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 | */ | ||
171 | static struct GNUNET_TIME_Relative zone_publish_time_window; | ||
172 | |||
173 | /** | ||
174 | * zone publish task | ||
175 | */ | ||
176 | static struct GNUNET_SCHEDULER_Task *zone_publish_task; | ||
177 | |||
178 | /** | ||
179 | * #GNUNET_YES if zone has never been published before | ||
180 | */ | ||
181 | static int first_zone_iteration; | ||
182 | |||
183 | /** | ||
184 | * Task run during shutdown. | ||
185 | * | ||
186 | * @param cls unused | ||
187 | * @param tc unused | ||
188 | */ | ||
189 | static void | ||
190 | shutdown_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 | */ | ||
248 | static void | ||
249 | publish_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 | */ | ||
262 | static void | ||
263 | publish_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 | */ | ||
273 | static void | ||
274 | dht_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 | */ | ||
332 | static unsigned int | ||
333 | convert_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 | */ | ||
376 | static struct GNUNET_DHT_PutHandle * | ||
377 | perform_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 | */ | ||
428 | static void | ||
429 | zone_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 | */ | ||
455 | static void | ||
456 | zone_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 | */ | ||
526 | static void | ||
527 | put_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 | */ | ||
570 | static void | ||
571 | publish_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 | */ | ||
602 | static void | ||
603 | handle_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 | */ | ||
648 | static void | ||
649 | monitor_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 | */ | ||
663 | static void | ||
664 | handle_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 | */ | ||
693 | static void | ||
694 | run (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 | */ | ||
763 | GNUNET_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 */ | ||