diff options
Diffstat (limited to 'src/zonemaster/gnunet-service-zonemaster.c')
-rw-r--r-- | src/zonemaster/gnunet-service-zonemaster.c | 904 |
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 | */ | ||
95 | struct 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 | */ | ||
122 | static struct GNUNET_STATISTICS_Handle *statistics; | ||
123 | |||
124 | /** | ||
125 | * Our handle to the DHT | ||
126 | */ | ||
127 | static struct GNUNET_DHT_Handle *dht_handle; | ||
128 | |||
129 | /** | ||
130 | * Our handle to the namestore service | ||
131 | */ | ||
132 | static struct GNUNET_NAMESTORE_Handle *namestore_handle; | ||
133 | |||
134 | /** | ||
135 | * Handle to iterate over our authoritative zone in namestore | ||
136 | */ | ||
137 | static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter; | ||
138 | |||
139 | /** | ||
140 | * Head of iteration put activities; kept in a DLL. | ||
141 | */ | ||
142 | static struct DhtPutActivity *it_head; | ||
143 | |||
144 | /** | ||
145 | * Tail of iteration put activities; kept in a DLL. | ||
146 | */ | ||
147 | static struct DhtPutActivity *it_tail; | ||
148 | |||
149 | /** | ||
150 | * Number of entries in the DHT queue #it_head. | ||
151 | */ | ||
152 | static unsigned int dht_queue_length; | ||
153 | |||
154 | /** | ||
155 | * Useful for zone update for DHT put | ||
156 | */ | ||
157 | static unsigned long long num_public_records; | ||
158 | |||
159 | /** | ||
160 | * Last seen record count | ||
161 | */ | ||
162 | static 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 | */ | ||
168 | static 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 | */ | ||
177 | static 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 | */ | ||
183 | static 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 | */ | ||
189 | static struct GNUNET_TIME_Relative last_min_relative_record_time; | ||
190 | |||
191 | /** | ||
192 | * Default time window for zone iteration | ||
193 | */ | ||
194 | static 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 | */ | ||
200 | static 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 | */ | ||
206 | static 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 | */ | ||
214 | static struct GNUNET_TIME_Relative sub_delta; | ||
215 | |||
216 | /** | ||
217 | * zone publish task | ||
218 | */ | ||
219 | static 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 | */ | ||
225 | static unsigned int ns_iteration_left; | ||
226 | |||
227 | /** | ||
228 | * #GNUNET_YES if zone has never been published before | ||
229 | */ | ||
230 | static int first_zone_iteration; | ||
231 | |||
232 | /** | ||
233 | * Optimize block insertion by caching map of private keys to | ||
234 | * public keys in memory? | ||
235 | */ | ||
236 | static int cache_keys; | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Task run during shutdown. | ||
241 | * | ||
242 | * @param cls unused | ||
243 | * @param tc unused | ||
244 | */ | ||
245 | static void | ||
246 | shutdown_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 | */ | ||
297 | static void | ||
298 | publish_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 | */ | ||
315 | static void | ||
316 | publish_zone_dht_start (void *cls); | ||
317 | |||
318 | |||
319 | /** | ||
320 | * Calculate #target_iteration_velocity_per_record. | ||
321 | */ | ||
322 | static void | ||
323 | calculate_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 | */ | ||
374 | static void | ||
375 | update_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 | */ | ||
476 | static void | ||
477 | check_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 | */ | ||
513 | static void | ||
514 | dht_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 | */ | ||
539 | static struct GNUNET_DHT_PutHandle * | ||
540 | perform_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 | */ | ||
606 | static void | ||
607 | zone_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 | */ | ||
631 | static void | ||
632 | zone_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 | */ | ||
681 | static void | ||
682 | put_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 | */ | ||
780 | static void | ||
781 | publish_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 | */ | ||
815 | static void | ||
816 | run (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 | */ | ||
894 | GNUNET_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 */ | ||