diff options
author | Martin Schanzenbach <schanzen@gnunet.org> | 2023-10-19 11:33:18 +0200 |
---|---|---|
committer | Martin Schanzenbach <schanzen@gnunet.org> | 2023-10-19 11:33:18 +0200 |
commit | 7c7d819e8e03dadb91935d5ae91aa921cc7b86c7 (patch) | |
tree | 9327ae110e5e64c99901cd853d3d36e23f39aaee /src/zonemaster | |
parent | df59c19d712a4339f7c75c76942c1a4f86bf2e5b (diff) | |
download | gnunet-7c7d819e8e03dadb91935d5ae91aa921cc7b86c7.tar.gz gnunet-7c7d819e8e03dadb91935d5ae91aa921cc7b86c7.zip |
BUILD: Move gns/zonemaster to service
Diffstat (limited to 'src/zonemaster')
-rw-r--r-- | src/zonemaster/.gitignore | 2 | ||||
-rw-r--r-- | src/zonemaster/Makefile.am | 32 | ||||
-rw-r--r-- | src/zonemaster/gnunet-service-zonemaster.c | 1469 | ||||
-rw-r--r-- | src/zonemaster/meson.build | 30 | ||||
-rw-r--r-- | src/zonemaster/zonemaster.conf.in | 27 |
5 files changed, 0 insertions, 1560 deletions
diff --git a/src/zonemaster/.gitignore b/src/zonemaster/.gitignore deleted file mode 100644 index cde57fa0a..000000000 --- a/src/zonemaster/.gitignore +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | gnunet-service-zonemaster | ||
2 | gnunet-service-zonemaster-monitor | ||
diff --git a/src/zonemaster/Makefile.am b/src/zonemaster/Makefile.am deleted file mode 100644 index 5a96afa83..000000000 --- a/src/zonemaster/Makefile.am +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | plugindir = $(libdir)/gnunet | ||
5 | |||
6 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
7 | |||
8 | libexecdir= $(pkglibdir)/libexec/ | ||
9 | |||
10 | pkgcfg_DATA = \ | ||
11 | zonemaster.conf | ||
12 | |||
13 | if USE_COVERAGE | ||
14 | AM_CFLAGS = --coverage -O0 | ||
15 | XLIBS = -lgcov | ||
16 | endif | ||
17 | |||
18 | libexec_PROGRAMS = \ | ||
19 | gnunet-service-zonemaster | ||
20 | |||
21 | gnunet_service_zonemaster_SOURCES = \ | ||
22 | gnunet-service-zonemaster.c | ||
23 | gnunet_service_zonemaster_LDADD = \ | ||
24 | $(top_builddir)/src/service/dht/libgnunetdht.la \ | ||
25 | $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \ | ||
26 | $(top_builddir)/src/service/identity/libgnunetidentity.la \ | ||
27 | $(top_builddir)/src/service/statistics/libgnunetstatistics.la \ | ||
28 | $(top_builddir)/src/lib/util/libgnunetutil.la \ | ||
29 | $(top_builddir)/src/service/namestore/libgnunetnamestore.la \ | ||
30 | $(top_builddir)/src/service/namecache/libgnunetnamecache.la \ | ||
31 | $(GN_LIBINTL) \ | ||
32 | -lpthread | ||
diff --git a/src/zonemaster/gnunet-service-zonemaster.c b/src/zonemaster/gnunet-service-zonemaster.c deleted file mode 100644 index 7c763576d..000000000 --- a/src/zonemaster/gnunet-service-zonemaster.c +++ /dev/null | |||
@@ -1,1469 +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 <pthread.h> | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_dht_service.h" | ||
30 | #include "gnunet_namestore_service.h" | ||
31 | #include "gnunet_namecache_service.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | |||
34 | #define LOG_STRERROR_FILE(kind, syscall, \ | ||
35 | filename) GNUNET_log_from_strerror_file (kind, "util", \ | ||
36 | syscall, \ | ||
37 | filename) | ||
38 | |||
39 | |||
40 | /** | ||
41 | * How often should we (re)publish each record before | ||
42 | * it expires? | ||
43 | */ | ||
44 | #define PUBLISH_OPS_PER_EXPIRATION 4 | ||
45 | |||
46 | /** | ||
47 | * How often do we measure the delta between desired zone | ||
48 | * iteration speed and actual speed, and tell statistics | ||
49 | * service about it? | ||
50 | */ | ||
51 | #define DELTA_INTERVAL 100 | ||
52 | |||
53 | /** | ||
54 | * How many records do we fetch in one shot from the namestore? | ||
55 | */ | ||
56 | #define NS_BLOCK_SIZE 1000 | ||
57 | |||
58 | /** | ||
59 | * How many open jobs (and with it maximum amount of pending DHT operations) do we allow at most | ||
60 | */ | ||
61 | #define JOB_QUEUE_LIMIT 5000 | ||
62 | |||
63 | /** | ||
64 | * How many events may the namestore give us before it has to wait | ||
65 | * for us to keep up? | ||
66 | */ | ||
67 | #define NAMESTORE_MONITOR_QUEUE_LIMIT 5 | ||
68 | |||
69 | /** | ||
70 | * The initial interval in milliseconds btween puts in | ||
71 | * a zone iteration | ||
72 | */ | ||
73 | #define INITIAL_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS | ||
74 | |||
75 | /** | ||
76 | * The upper bound for the zone iteration interval | ||
77 | * (per record). | ||
78 | */ | ||
79 | #define MAXIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_relative_multiply ( \ | ||
80 | GNUNET_TIME_UNIT_MINUTES, 15) | ||
81 | |||
82 | /** | ||
83 | * The factor the current zone iteration interval is divided by for each | ||
84 | * additional new record | ||
85 | */ | ||
86 | #define LATE_ITERATION_SPEEDUP_FACTOR 2 | ||
87 | |||
88 | /** | ||
89 | * What replication level do we use for DHT PUT operations? | ||
90 | */ | ||
91 | #define DHT_GNS_REPLICATION_LEVEL 5 | ||
92 | |||
93 | /** | ||
94 | * Our workers | ||
95 | */ | ||
96 | static pthread_t * worker; | ||
97 | |||
98 | /** | ||
99 | * Lock for the sign jobs queue. | ||
100 | */ | ||
101 | static pthread_mutex_t sign_jobs_lock; | ||
102 | |||
103 | /** | ||
104 | * Lock for the DHT put jobs queue. | ||
105 | */ | ||
106 | static pthread_mutex_t sign_results_lock; | ||
107 | |||
108 | /** | ||
109 | * Wait condition on new sign jobs | ||
110 | */ | ||
111 | static pthread_cond_t sign_jobs_cond; | ||
112 | |||
113 | /** | ||
114 | * For threads to know we are shutting down | ||
115 | */ | ||
116 | static int in_shutdown = GNUNET_NO; | ||
117 | |||
118 | /** | ||
119 | * Monitor halted? | ||
120 | */ | ||
121 | static int monitor_halted = GNUNET_NO; | ||
122 | |||
123 | /** | ||
124 | * Our notification pipe | ||
125 | */ | ||
126 | static struct GNUNET_DISK_PipeHandle *notification_pipe; | ||
127 | |||
128 | /** | ||
129 | * Pipe read task | ||
130 | */ | ||
131 | static struct GNUNET_SCHEDULER_Task *pipe_read_task; | ||
132 | |||
133 | struct RecordPublicationJob | ||
134 | { | ||
135 | |||
136 | /** | ||
137 | * DLL | ||
138 | */ | ||
139 | struct RecordPublicationJob *next; | ||
140 | |||
141 | /** | ||
142 | * DLL | ||
143 | */ | ||
144 | struct RecordPublicationJob *prev; | ||
145 | |||
146 | /** | ||
147 | * The zone key to sign the block with | ||
148 | */ | ||
149 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
150 | |||
151 | /** | ||
152 | * The block to sign | ||
153 | */ | ||
154 | struct GNUNET_GNSRECORD_Block *block; | ||
155 | |||
156 | /** | ||
157 | * The private block to sign, may point to block in case | ||
158 | * the public and private blocks are the same. | ||
159 | */ | ||
160 | struct GNUNET_GNSRECORD_Block *block_priv; | ||
161 | |||
162 | /** | ||
163 | * The size of the public block for the DHT put. | ||
164 | */ | ||
165 | size_t block_size; | ||
166 | |||
167 | /** | ||
168 | * The expiration time of the public block for the DHT put. | ||
169 | */ | ||
170 | struct GNUNET_TIME_Absolute expire_pub; | ||
171 | |||
172 | /** | ||
173 | * The label of the block needed for signing | ||
174 | */ | ||
175 | char *label; | ||
176 | |||
177 | /** | ||
178 | * Handle for the DHT PUT operation. | ||
179 | */ | ||
180 | struct GNUNET_DHT_PutHandle *ph; | ||
181 | |||
182 | /** | ||
183 | * When was this PUT initiated? | ||
184 | */ | ||
185 | struct GNUNET_TIME_Absolute start_date; | ||
186 | }; | ||
187 | |||
188 | |||
189 | /** | ||
190 | * The DLL for workers to retrieve open jobs that require | ||
191 | * signing of blocks. | ||
192 | */ | ||
193 | static struct RecordPublicationJob *sign_jobs_head; | ||
194 | |||
195 | /** | ||
196 | * See above | ||
197 | */ | ||
198 | static struct RecordPublicationJob *sign_jobs_tail; | ||
199 | |||
200 | /** | ||
201 | * The DLL for workers to place jobs that are signed. | ||
202 | */ | ||
203 | static struct RecordPublicationJob *sign_results_head; | ||
204 | |||
205 | /** | ||
206 | * See above | ||
207 | */ | ||
208 | static struct RecordPublicationJob *sign_results_tail; | ||
209 | |||
210 | |||
211 | /** | ||
212 | * The DLL for jobs currently in the process of being dispatched into the DHT. | ||
213 | */ | ||
214 | static struct RecordPublicationJob *dht_jobs_head; | ||
215 | |||
216 | /** | ||
217 | * See above | ||
218 | */ | ||
219 | static struct RecordPublicationJob *dht_jobs_tail; | ||
220 | |||
221 | |||
222 | /** | ||
223 | * Pending operation on the namecache. | ||
224 | */ | ||
225 | struct CacheOperation | ||
226 | { | ||
227 | /** | ||
228 | * Kept in a DLL. | ||
229 | */ | ||
230 | struct CacheOperation *prev; | ||
231 | |||
232 | /** | ||
233 | * Kept in a DLL. | ||
234 | */ | ||
235 | struct CacheOperation *next; | ||
236 | |||
237 | /** | ||
238 | * Handle to namecache queue. | ||
239 | */ | ||
240 | struct GNUNET_NAMECACHE_QueueEntry *qe; | ||
241 | |||
242 | }; | ||
243 | |||
244 | |||
245 | /** | ||
246 | * Handle to the statistics service | ||
247 | */ | ||
248 | static struct GNUNET_STATISTICS_Handle *statistics; | ||
249 | |||
250 | /** | ||
251 | * Our handle to the DHT | ||
252 | */ | ||
253 | static struct GNUNET_DHT_Handle *dht_handle; | ||
254 | |||
255 | /** | ||
256 | * Our handle to the namestore service | ||
257 | */ | ||
258 | static struct GNUNET_NAMESTORE_Handle *namestore_handle; | ||
259 | |||
260 | /** | ||
261 | * Handle to monitor namestore changes to instant propagation. | ||
262 | */ | ||
263 | static struct GNUNET_NAMESTORE_ZoneMonitor *zmon; | ||
264 | |||
265 | /** | ||
266 | * Our handle to the namecache service | ||
267 | */ | ||
268 | static struct GNUNET_NAMECACHE_Handle *namecache; | ||
269 | |||
270 | /** | ||
271 | * Use the namecache? Doing so creates additional cryptographic | ||
272 | * operations whenever we touch a record. | ||
273 | */ | ||
274 | static int disable_namecache; | ||
275 | |||
276 | /** | ||
277 | * Handle to iterate over our authoritative zone in namestore | ||
278 | */ | ||
279 | static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter; | ||
280 | |||
281 | /** | ||
282 | * Number of entries in the job queue #jobs_head. | ||
283 | */ | ||
284 | static unsigned int job_queue_length; | ||
285 | |||
286 | /** | ||
287 | * Useful for zone update for DHT put | ||
288 | */ | ||
289 | static unsigned long long num_public_records; | ||
290 | |||
291 | /** | ||
292 | * Last seen record count | ||
293 | */ | ||
294 | static unsigned long long last_num_public_records; | ||
295 | |||
296 | /** | ||
297 | * Number of successful put operations performed in the current | ||
298 | * measurement cycle (as measured in #check_zone_namestore_next()). | ||
299 | */ | ||
300 | static unsigned long long put_cnt; | ||
301 | |||
302 | /** | ||
303 | * What is the frequency at which we currently would like | ||
304 | * to perform DHT puts (per record)? Calculated in | ||
305 | * update_velocity() from the #zone_publish_time_window() | ||
306 | * and the total number of record sets we have (so far) | ||
307 | * observed in the zone. | ||
308 | */ | ||
309 | static struct GNUNET_TIME_Relative target_iteration_velocity_per_record; | ||
310 | |||
311 | /** | ||
312 | * Minimum relative expiration time of records seem during the current | ||
313 | * zone iteration. | ||
314 | */ | ||
315 | static struct GNUNET_TIME_Relative min_relative_record_time; | ||
316 | |||
317 | /** | ||
318 | * Minimum relative expiration time of records seem during the last | ||
319 | * zone iteration. | ||
320 | */ | ||
321 | static struct GNUNET_TIME_Relative last_min_relative_record_time; | ||
322 | |||
323 | /** | ||
324 | * Default time window for zone iteration | ||
325 | */ | ||
326 | static struct GNUNET_TIME_Relative zone_publish_time_window_default; | ||
327 | |||
328 | /** | ||
329 | * Time window for zone iteration, adjusted based on relative record | ||
330 | * expiration times in our zone. | ||
331 | */ | ||
332 | static struct GNUNET_TIME_Relative zone_publish_time_window; | ||
333 | |||
334 | /** | ||
335 | * When did we last start measuring the #DELTA_INTERVAL successful | ||
336 | * DHT puts? Used for velocity calculations. | ||
337 | */ | ||
338 | static struct GNUNET_TIME_Absolute last_put_100; | ||
339 | |||
340 | /** | ||
341 | * By how much should we try to increase our per-record iteration speed | ||
342 | * (over the desired speed calculated directly from the #put_interval)? | ||
343 | * Basically this value corresponds to the per-record CPU time overhead | ||
344 | * we have. | ||
345 | */ | ||
346 | static struct GNUNET_TIME_Relative sub_delta; | ||
347 | |||
348 | /** | ||
349 | * zone publish task | ||
350 | */ | ||
351 | static struct GNUNET_SCHEDULER_Task *zone_publish_task; | ||
352 | |||
353 | /** | ||
354 | * How many more values are left for the current query before we need | ||
355 | * to explicitly ask the namestore for more? | ||
356 | */ | ||
357 | static unsigned int ns_iteration_left; | ||
358 | |||
359 | /** | ||
360 | * #GNUNET_YES if zone has never been published before | ||
361 | */ | ||
362 | static int first_zone_iteration; | ||
363 | |||
364 | /** | ||
365 | * Optimize block insertion by caching map of private keys to | ||
366 | * public keys in memory? | ||
367 | */ | ||
368 | static int cache_keys; | ||
369 | |||
370 | /** | ||
371 | * Head of cop DLL. | ||
372 | */ | ||
373 | static struct CacheOperation *cop_head; | ||
374 | |||
375 | /** | ||
376 | * Tail of cop DLL. | ||
377 | */ | ||
378 | static struct CacheOperation *cop_tail; | ||
379 | |||
380 | |||
381 | static void | ||
382 | free_job (struct RecordPublicationJob *job) | ||
383 | { | ||
384 | if (job->block != job->block_priv) | ||
385 | GNUNET_free (job->block_priv); | ||
386 | GNUNET_free (job->block); | ||
387 | if (NULL != job->label) | ||
388 | GNUNET_free (job->label); | ||
389 | GNUNET_free (job); | ||
390 | } | ||
391 | |||
392 | /** | ||
393 | * Task run during shutdown. | ||
394 | * | ||
395 | * @param cls unused | ||
396 | * @param tc unused | ||
397 | */ | ||
398 | static void | ||
399 | shutdown_task (void *cls) | ||
400 | { | ||
401 | struct CacheOperation *cop; | ||
402 | struct RecordPublicationJob *job; | ||
403 | |||
404 | (void) cls; | ||
405 | in_shutdown = GNUNET_YES; | ||
406 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
407 | "Shutting down!\n"); | ||
408 | if (NULL != notification_pipe) | ||
409 | GNUNET_DISK_pipe_close (notification_pipe); | ||
410 | if (NULL != pipe_read_task) | ||
411 | GNUNET_SCHEDULER_cancel (pipe_read_task); | ||
412 | while (NULL != (cop = cop_head)) | ||
413 | { | ||
414 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
415 | "Aborting incomplete namecache operation\n"); | ||
416 | GNUNET_NAMECACHE_cancel (cop->qe); | ||
417 | GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); | ||
418 | GNUNET_free (cop); | ||
419 | } | ||
420 | GNUNET_assert (0 == pthread_mutex_lock (&sign_jobs_lock)); | ||
421 | while (NULL != (job = sign_jobs_head)) | ||
422 | { | ||
423 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
424 | "Removing incomplete jobs\n"); | ||
425 | GNUNET_CONTAINER_DLL_remove (sign_jobs_head, sign_jobs_tail, job); | ||
426 | job_queue_length--; | ||
427 | free_job (job); | ||
428 | } | ||
429 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_jobs_lock)); | ||
430 | GNUNET_assert (0 == pthread_mutex_lock (&sign_results_lock)); | ||
431 | while (NULL != (job = sign_results_head)) | ||
432 | { | ||
433 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
434 | "Removing incomplete jobs\n"); | ||
435 | GNUNET_CONTAINER_DLL_remove (sign_results_head, sign_results_tail, job); | ||
436 | free_job (job); | ||
437 | } | ||
438 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_results_lock)); | ||
439 | while (NULL != (job = dht_jobs_head)) | ||
440 | { | ||
441 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
442 | "Removing incomplete jobs\n"); | ||
443 | GNUNET_CONTAINER_DLL_remove (dht_jobs_head, dht_jobs_tail, job); | ||
444 | if (NULL != job->ph) | ||
445 | GNUNET_DHT_put_cancel (job->ph); | ||
446 | free_job (job); | ||
447 | } | ||
448 | if (NULL != statistics) | ||
449 | { | ||
450 | GNUNET_STATISTICS_destroy (statistics, | ||
451 | GNUNET_NO); | ||
452 | statistics = NULL; | ||
453 | } | ||
454 | if (NULL != zone_publish_task) | ||
455 | { | ||
456 | GNUNET_SCHEDULER_cancel (zone_publish_task); | ||
457 | zone_publish_task = NULL; | ||
458 | } | ||
459 | if (NULL != namestore_iter) | ||
460 | { | ||
461 | GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter); | ||
462 | namestore_iter = NULL; | ||
463 | } | ||
464 | if (NULL != zmon) | ||
465 | { | ||
466 | GNUNET_NAMESTORE_zone_monitor_stop (zmon); | ||
467 | zmon = NULL; | ||
468 | } | ||
469 | if (NULL != namestore_handle) | ||
470 | { | ||
471 | GNUNET_NAMESTORE_disconnect (namestore_handle); | ||
472 | namestore_handle = NULL; | ||
473 | } | ||
474 | if (NULL != namecache) | ||
475 | { | ||
476 | GNUNET_NAMECACHE_disconnect (namecache); | ||
477 | namecache = NULL; | ||
478 | } | ||
479 | if (NULL != dht_handle) | ||
480 | { | ||
481 | GNUNET_DHT_disconnect (dht_handle); | ||
482 | dht_handle = NULL; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | |||
487 | /** | ||
488 | * Cache operation complete, clean up. | ||
489 | * | ||
490 | * @param cls the `struct CacheOperation` | ||
491 | * @param success success | ||
492 | * @param emsg error messages | ||
493 | */ | ||
494 | static void | ||
495 | finish_cache_operation (void *cls, int32_t success, const char *emsg) | ||
496 | { | ||
497 | struct CacheOperation *cop = cls; | ||
498 | |||
499 | if (NULL != emsg) | ||
500 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
501 | _ ("Failed to replicate block in namecache: %s\n"), | ||
502 | emsg); | ||
503 | else | ||
504 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CACHE operation completed\n"); | ||
505 | GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); | ||
506 | GNUNET_free (cop); | ||
507 | } | ||
508 | |||
509 | |||
510 | /** | ||
511 | * Refresh the (encrypted) block in the namecache. | ||
512 | * | ||
513 | * @param zone_key private key of the zone | ||
514 | * @param name label for the records | ||
515 | * @param rd_count number of records | ||
516 | * @param rd records stored under the given @a name | ||
517 | */ | ||
518 | static void | ||
519 | refresh_block (const struct GNUNET_GNSRECORD_Block *block) | ||
520 | { | ||
521 | struct CacheOperation *cop; | ||
522 | |||
523 | if (GNUNET_YES == disable_namecache) | ||
524 | { | ||
525 | GNUNET_STATISTICS_update (statistics, | ||
526 | "Namecache updates skipped (NC disabled)", | ||
527 | 1, | ||
528 | GNUNET_NO); | ||
529 | return; | ||
530 | } | ||
531 | GNUNET_assert (NULL != block); | ||
532 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Caching block in namecache\n"); | ||
533 | GNUNET_STATISTICS_update (statistics, | ||
534 | "Namecache updates pushed", | ||
535 | 1, | ||
536 | GNUNET_NO); | ||
537 | cop = GNUNET_new (struct CacheOperation); | ||
538 | GNUNET_CONTAINER_DLL_insert (cop_head, cop_tail, cop); | ||
539 | cop->qe = GNUNET_NAMECACHE_block_cache (namecache, | ||
540 | block, | ||
541 | &finish_cache_operation, | ||
542 | cop); | ||
543 | } | ||
544 | |||
545 | |||
546 | /** | ||
547 | * Method called periodically that triggers iteration over authoritative records | ||
548 | * | ||
549 | * @param cls NULL | ||
550 | */ | ||
551 | static void | ||
552 | publish_zone_namestore_next (void *cls) | ||
553 | { | ||
554 | (void) cls; | ||
555 | zone_publish_task = NULL; | ||
556 | GNUNET_assert (NULL != namestore_iter); | ||
557 | GNUNET_assert (0 == ns_iteration_left); | ||
558 | ns_iteration_left = NS_BLOCK_SIZE; | ||
559 | GNUNET_NAMESTORE_zone_iterator_next (namestore_iter, | ||
560 | NS_BLOCK_SIZE); | ||
561 | } | ||
562 | |||
563 | |||
564 | /** | ||
565 | * Periodically iterate over our zone and store everything in dht | ||
566 | * | ||
567 | * @param cls NULL | ||
568 | */ | ||
569 | static void | ||
570 | publish_zone_dht_start (void *cls); | ||
571 | |||
572 | |||
573 | /** | ||
574 | * Calculate #target_iteration_velocity_per_record. | ||
575 | */ | ||
576 | static void | ||
577 | calculate_put_interval () | ||
578 | { | ||
579 | if (0 == num_public_records) | ||
580 | { | ||
581 | /** | ||
582 | * If no records are known (startup) or none present | ||
583 | * we can safely set the interval to the value for a single | ||
584 | * record | ||
585 | */target_iteration_velocity_per_record = zone_publish_time_window; | ||
586 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
587 | "No records in namestore database.\n"); | ||
588 | } | ||
589 | else | ||
590 | { | ||
591 | last_min_relative_record_time | ||
592 | = GNUNET_TIME_relative_min (last_min_relative_record_time, | ||
593 | min_relative_record_time); | ||
594 | zone_publish_time_window | ||
595 | = GNUNET_TIME_relative_min (GNUNET_TIME_relative_divide ( | ||
596 | last_min_relative_record_time, | ||
597 | PUBLISH_OPS_PER_EXPIRATION), | ||
598 | zone_publish_time_window_default); | ||
599 | target_iteration_velocity_per_record | ||
600 | = GNUNET_TIME_relative_divide (zone_publish_time_window, | ||
601 | last_num_public_records); | ||
602 | } | ||
603 | target_iteration_velocity_per_record | ||
604 | = GNUNET_TIME_relative_min (target_iteration_velocity_per_record, | ||
605 | MAXIMUM_ZONE_ITERATION_INTERVAL); | ||
606 | GNUNET_STATISTICS_set (statistics, | ||
607 | "Minimum relative record expiration (in μs)", | ||
608 | last_min_relative_record_time.rel_value_us, | ||
609 | GNUNET_NO); | ||
610 | GNUNET_STATISTICS_set (statistics, | ||
611 | "Zone publication time window (in μs)", | ||
612 | zone_publish_time_window.rel_value_us, | ||
613 | GNUNET_NO); | ||
614 | GNUNET_STATISTICS_set (statistics, | ||
615 | "Target zone iteration velocity (μs)", | ||
616 | target_iteration_velocity_per_record.rel_value_us, | ||
617 | GNUNET_NO); | ||
618 | } | ||
619 | |||
620 | |||
621 | /** | ||
622 | * Re-calculate our velocity and the desired velocity. | ||
623 | * We have succeeded in making #DELTA_INTERVAL puts, so | ||
624 | * now calculate the new desired delay between puts. | ||
625 | * | ||
626 | * @param cnt how many records were processed since the last call? | ||
627 | */ | ||
628 | static void | ||
629 | update_velocity (unsigned int cnt) | ||
630 | { | ||
631 | struct GNUNET_TIME_Relative delta; | ||
632 | unsigned long long pct = 0; | ||
633 | |||
634 | if (0 == cnt) | ||
635 | return; | ||
636 | /* How fast were we really? */ | ||
637 | delta = GNUNET_TIME_absolute_get_duration (last_put_100); | ||
638 | delta.rel_value_us /= cnt; | ||
639 | last_put_100 = GNUNET_TIME_absolute_get (); | ||
640 | |||
641 | /* calculate expected frequency */ | ||
642 | if ((num_public_records > last_num_public_records) && | ||
643 | (GNUNET_NO == first_zone_iteration)) | ||
644 | { | ||
645 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
646 | "Last record count was lower than current record count. Reducing interval.\n"); | ||
647 | last_num_public_records = num_public_records | ||
648 | * LATE_ITERATION_SPEEDUP_FACTOR; | ||
649 | calculate_put_interval (); | ||
650 | } | ||
651 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
652 | "Desired global zone iteration interval is %s/record!\n", | ||
653 | GNUNET_STRINGS_relative_time_to_string ( | ||
654 | target_iteration_velocity_per_record, | ||
655 | GNUNET_YES)); | ||
656 | |||
657 | /* Tell statistics actual vs. desired speed */ | ||
658 | GNUNET_STATISTICS_set (statistics, | ||
659 | "Current zone iteration velocity (μs/record)", | ||
660 | delta.rel_value_us, | ||
661 | GNUNET_NO); | ||
662 | /* update "sub_delta" based on difference, taking | ||
663 | previous sub_delta into account! */ | ||
664 | if (target_iteration_velocity_per_record.rel_value_us > delta.rel_value_us) | ||
665 | { | ||
666 | /* We were too fast, reduce sub_delta! */ | ||
667 | struct GNUNET_TIME_Relative corr; | ||
668 | |||
669 | corr = GNUNET_TIME_relative_subtract (target_iteration_velocity_per_record, | ||
670 | delta); | ||
671 | if (sub_delta.rel_value_us > delta.rel_value_us) | ||
672 | { | ||
673 | /* Reduce sub_delta by corr */ | ||
674 | sub_delta = GNUNET_TIME_relative_subtract (sub_delta, | ||
675 | corr); | ||
676 | } | ||
677 | else | ||
678 | { | ||
679 | /* We're doing fine with waiting the full time, this | ||
680 | should theoretically only happen if we run at | ||
681 | infinite speed. */ | ||
682 | sub_delta = GNUNET_TIME_UNIT_ZERO; | ||
683 | } | ||
684 | } | ||
685 | else if (target_iteration_velocity_per_record.rel_value_us < | ||
686 | delta.rel_value_us) | ||
687 | { | ||
688 | /* We were too slow, increase sub_delta! */ | ||
689 | struct GNUNET_TIME_Relative corr; | ||
690 | |||
691 | corr = GNUNET_TIME_relative_subtract (delta, | ||
692 | target_iteration_velocity_per_record); | ||
693 | sub_delta = GNUNET_TIME_relative_add (sub_delta, | ||
694 | corr); | ||
695 | if (sub_delta.rel_value_us > | ||
696 | target_iteration_velocity_per_record.rel_value_us) | ||
697 | { | ||
698 | /* CPU overload detected, we cannot go at desired speed, | ||
699 | as this would mean using a negative delay. */ | ||
700 | /* compute how much faster we would want to be for | ||
701 | the desired velocity */ | ||
702 | if (0 == target_iteration_velocity_per_record.rel_value_us) | ||
703 | pct = UINT64_MAX; /* desired speed is infinity ... */ | ||
704 | else | ||
705 | pct = (sub_delta.rel_value_us | ||
706 | - target_iteration_velocity_per_record.rel_value_us) * 100LLU | ||
707 | / target_iteration_velocity_per_record.rel_value_us; | ||
708 | sub_delta = target_iteration_velocity_per_record; | ||
709 | } | ||
710 | } | ||
711 | GNUNET_STATISTICS_set (statistics, | ||
712 | "# dispatched jobs", | ||
713 | job_queue_length, | ||
714 | GNUNET_NO); | ||
715 | GNUNET_STATISTICS_set (statistics, | ||
716 | "% speed increase needed for target velocity", | ||
717 | pct, | ||
718 | GNUNET_NO); | ||
719 | GNUNET_STATISTICS_set (statistics, | ||
720 | "# records processed in current iteration", | ||
721 | num_public_records, | ||
722 | GNUNET_NO); | ||
723 | } | ||
724 | |||
725 | |||
726 | /** | ||
727 | * Check if the current zone iteration needs to be continued | ||
728 | * by calling #publish_zone_namestore_next(), and if so with what delay. | ||
729 | */ | ||
730 | static void | ||
731 | check_zone_namestore_next () | ||
732 | { | ||
733 | struct GNUNET_TIME_Relative delay; | ||
734 | |||
735 | if (0 != ns_iteration_left) | ||
736 | return; /* current NAMESTORE iteration not yet done */ | ||
737 | if (job_queue_length >= JOB_QUEUE_LIMIT) | ||
738 | { | ||
739 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
740 | "Job queue length exceeded (%u/%u). Pausing namestore iteration.\n", | ||
741 | job_queue_length, | ||
742 | JOB_QUEUE_LIMIT); | ||
743 | return; | ||
744 | } | ||
745 | update_velocity (put_cnt); | ||
746 | put_cnt = 0; | ||
747 | delay = GNUNET_TIME_relative_subtract (target_iteration_velocity_per_record, | ||
748 | sub_delta); | ||
749 | /* We delay *once* per #NS_BLOCK_SIZE, so we need to multiply the | ||
750 | per-record delay calculated so far with the #NS_BLOCK_SIZE */ | ||
751 | GNUNET_STATISTICS_set (statistics, | ||
752 | "Current artificial NAMESTORE delay (μs/record)", | ||
753 | delay.rel_value_us, | ||
754 | GNUNET_NO); | ||
755 | delay = GNUNET_TIME_relative_multiply (delay, | ||
756 | NS_BLOCK_SIZE); | ||
757 | /* make sure we do not overshoot because of the #NS_BLOCK_SIZE factor */ | ||
758 | delay = GNUNET_TIME_relative_min (MAXIMUM_ZONE_ITERATION_INTERVAL, | ||
759 | delay); | ||
760 | /* no delays on first iteration */ | ||
761 | if (GNUNET_YES == first_zone_iteration) | ||
762 | delay = GNUNET_TIME_UNIT_ZERO; | ||
763 | GNUNET_assert (NULL == zone_publish_task); | ||
764 | zone_publish_task = GNUNET_SCHEDULER_add_delayed (delay, | ||
765 | &publish_zone_namestore_next, | ||
766 | NULL); | ||
767 | } | ||
768 | |||
769 | |||
770 | /** | ||
771 | * Continuation called from DHT once the PUT operation is done. | ||
772 | * | ||
773 | */ | ||
774 | static void | ||
775 | dht_put_continuation (void *cls) | ||
776 | { | ||
777 | struct RecordPublicationJob *job = cls; | ||
778 | |||
779 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
780 | "PUT complete; Pending jobs: %u\n", job_queue_length - 1); | ||
781 | /* When we just fall under the limit, trigger monitor/iterator again | ||
782 | * if halted. We can only safely trigger one, prefer iterator. */ | ||
783 | if (NULL == zone_publish_task) | ||
784 | check_zone_namestore_next (); | ||
785 | if (job_queue_length <= JOB_QUEUE_LIMIT) | ||
786 | { | ||
787 | if (GNUNET_YES == monitor_halted) | ||
788 | { | ||
789 | GNUNET_NAMESTORE_zone_monitor_next (zmon, 1); | ||
790 | monitor_halted = GNUNET_NO; | ||
791 | } | ||
792 | } | ||
793 | job_queue_length--; | ||
794 | GNUNET_CONTAINER_DLL_remove (dht_jobs_head, | ||
795 | dht_jobs_tail, | ||
796 | job); | ||
797 | free_job (job); | ||
798 | } | ||
799 | |||
800 | |||
801 | /** | ||
802 | * Store GNS records in the DHT. | ||
803 | * | ||
804 | * @param key key of the zone | ||
805 | * @param label label to store under | ||
806 | * @param rd_public public record data | ||
807 | * @param rd_public_count number of records in @a rd_public | ||
808 | * @param ma handle for the put operation | ||
809 | * @return DHT PUT handle, NULL on error | ||
810 | */ | ||
811 | static void | ||
812 | dispatch_job (const struct GNUNET_CRYPTO_PrivateKey *key, | ||
813 | const char *label, | ||
814 | const struct GNUNET_GNSRECORD_Data *rd, | ||
815 | unsigned int rd_count, | ||
816 | const struct GNUNET_TIME_Absolute expire) | ||
817 | { | ||
818 | struct GNUNET_GNSRECORD_Data rd_public[rd_count]; | ||
819 | struct GNUNET_GNSRECORD_Block *block; | ||
820 | struct GNUNET_GNSRECORD_Block *block_priv; | ||
821 | struct GNUNET_TIME_Absolute expire_pub; | ||
822 | size_t block_size; | ||
823 | unsigned int rd_public_count = 0; | ||
824 | char *emsg; | ||
825 | |||
826 | if (GNUNET_OK != | ||
827 | GNUNET_GNSRECORD_normalize_record_set (label, | ||
828 | rd, | ||
829 | rd_count, | ||
830 | rd_public, | ||
831 | &rd_public_count, | ||
832 | &expire_pub, | ||
833 | GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE, | ||
834 | &emsg)) | ||
835 | { | ||
836 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
837 | "%s\n", emsg); | ||
838 | GNUNET_free (emsg); | ||
839 | } | ||
840 | |||
841 | GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create_unsigned (key, | ||
842 | expire_pub, | ||
843 | label, | ||
844 | rd_public, | ||
845 | rd_public_count, | ||
846 | &block)); | ||
847 | if (NULL == block) | ||
848 | { | ||
849 | GNUNET_break (0); | ||
850 | return; /* whoops */ | ||
851 | } | ||
852 | if (rd_count != rd_public_count) | ||
853 | GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create_unsigned (key, | ||
854 | expire, | ||
855 | label, | ||
856 | rd, | ||
857 | rd_count, | ||
858 | & | ||
859 | block_priv)); | ||
860 | else | ||
861 | block_priv = block; | ||
862 | block_size = GNUNET_GNSRECORD_block_get_size (block); | ||
863 | GNUNET_assert (0 == pthread_mutex_lock (&sign_jobs_lock)); | ||
864 | struct RecordPublicationJob *job = GNUNET_new (struct RecordPublicationJob); | ||
865 | job->block = block; | ||
866 | job->block_size = block_size; | ||
867 | job->block_priv = block_priv; | ||
868 | job->zone = *key; | ||
869 | job->label = GNUNET_strdup (label); | ||
870 | job->expire_pub = expire_pub; | ||
871 | GNUNET_CONTAINER_DLL_insert (sign_jobs_head, sign_jobs_tail, job); | ||
872 | GNUNET_assert (0 == pthread_cond_signal (&sign_jobs_cond)); | ||
873 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_jobs_lock)); | ||
874 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
875 | "Creating job with %u record(s) for label `%s', expiration `%s'\n", | ||
876 | rd_public_count, | ||
877 | label, | ||
878 | GNUNET_STRINGS_absolute_time_to_string (expire)); | ||
879 | num_public_records++; | ||
880 | return; | ||
881 | } | ||
882 | |||
883 | |||
884 | static void | ||
885 | notification_pipe_cb (void *cls); | ||
886 | |||
887 | static void | ||
888 | initiate_put_from_pipe_trigger (void *cls) | ||
889 | { | ||
890 | struct GNUNET_HashCode query; | ||
891 | struct RecordPublicationJob *job; | ||
892 | const struct GNUNET_DISK_FileHandle *np_fh; | ||
893 | char buf[100]; | ||
894 | ssize_t nf_count; | ||
895 | |||
896 | pipe_read_task = NULL; | ||
897 | np_fh = GNUNET_DISK_pipe_handle (notification_pipe, | ||
898 | GNUNET_DISK_PIPE_END_READ); | ||
899 | pipe_read_task = | ||
900 | GNUNET_SCHEDULER_add_read_file ( | ||
901 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
902 | np_fh, | ||
903 | notification_pipe_cb, | ||
904 | NULL); | ||
905 | /* empty queue */ | ||
906 | nf_count = GNUNET_DISK_file_read (np_fh, buf, sizeof (buf)); | ||
907 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %lld notifications from pipe\n", | ||
908 | (long long) nf_count); | ||
909 | while (true) | ||
910 | { | ||
911 | GNUNET_assert (0 == pthread_mutex_lock (&sign_results_lock)); | ||
912 | if (NULL == sign_results_head) | ||
913 | { | ||
914 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
915 | "No more results. Back to sleep.\n"); | ||
916 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_results_lock)); | ||
917 | return; | ||
918 | } | ||
919 | job = sign_results_head; | ||
920 | GNUNET_CONTAINER_DLL_remove (sign_results_head, sign_results_tail, job); | ||
921 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_results_lock)); | ||
922 | GNUNET_GNSRECORD_query_from_private_key (&job->zone, | ||
923 | job->label, | ||
924 | &query); | ||
925 | job->ph = GNUNET_DHT_put (dht_handle, | ||
926 | &query, | ||
927 | DHT_GNS_REPLICATION_LEVEL, | ||
928 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, | ||
929 | GNUNET_BLOCK_TYPE_GNS_NAMERECORD, | ||
930 | job->block_size, | ||
931 | job->block, | ||
932 | job->expire_pub, | ||
933 | &dht_put_continuation, | ||
934 | job); | ||
935 | if (NULL == job->ph) | ||
936 | { | ||
937 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
938 | "Could not perform DHT PUT, is the DHT running?\n"); | ||
939 | free_job (job); | ||
940 | return; | ||
941 | } | ||
942 | GNUNET_STATISTICS_update (statistics, | ||
943 | "DHT put operations initiated", | ||
944 | 1, | ||
945 | GNUNET_NO); | ||
946 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
947 | "Storing record(s) for label `%s' in DHT under key %s\n", | ||
948 | job->label, | ||
949 | GNUNET_h2s (&query)); | ||
950 | refresh_block (job->block_priv); | ||
951 | GNUNET_CONTAINER_DLL_insert (dht_jobs_head, dht_jobs_tail, job); | ||
952 | } | ||
953 | } | ||
954 | |||
955 | |||
956 | /** | ||
957 | * We encountered an error in our zone iteration. | ||
958 | * | ||
959 | * @param cls NULL | ||
960 | */ | ||
961 | static void | ||
962 | zone_iteration_error (void *cls) | ||
963 | { | ||
964 | (void) cls; | ||
965 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
966 | "Got disconnected from namestore database, retrying.\n"); | ||
967 | namestore_iter = NULL; | ||
968 | /* We end up here on error/disconnect/shutdown, so potentially | ||
969 | while a zone publish task or a DHT put is still running; hence | ||
970 | we need to cancel those. */ | ||
971 | if (NULL != zone_publish_task) | ||
972 | { | ||
973 | GNUNET_SCHEDULER_cancel (zone_publish_task); | ||
974 | zone_publish_task = NULL; | ||
975 | } | ||
976 | zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start, | ||
977 | NULL); | ||
978 | } | ||
979 | |||
980 | |||
981 | /** | ||
982 | * Zone iteration is completed. | ||
983 | * | ||
984 | * @param cls NULL | ||
985 | */ | ||
986 | static void | ||
987 | zone_iteration_finished (void *cls) | ||
988 | { | ||
989 | (void) cls; | ||
990 | /* we're done with one iteration, calculate when to do the next one */ | ||
991 | namestore_iter = NULL; | ||
992 | last_num_public_records = num_public_records; | ||
993 | first_zone_iteration = GNUNET_NO; | ||
994 | last_min_relative_record_time = min_relative_record_time; | ||
995 | calculate_put_interval (); | ||
996 | /* reset for next iteration */ | ||
997 | min_relative_record_time | ||
998 | = GNUNET_TIME_UNIT_FOREVER_REL; | ||
999 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1000 | "Zone iteration finished. Adjusted zone iteration interval to %s\n", | ||
1001 | GNUNET_STRINGS_relative_time_to_string ( | ||
1002 | target_iteration_velocity_per_record, | ||
1003 | GNUNET_YES)); | ||
1004 | GNUNET_STATISTICS_set (statistics, | ||
1005 | "Target zone iteration velocity (μs)", | ||
1006 | target_iteration_velocity_per_record.rel_value_us, | ||
1007 | GNUNET_NO); | ||
1008 | GNUNET_STATISTICS_set (statistics, | ||
1009 | "Number of public records in DHT", | ||
1010 | last_num_public_records, | ||
1011 | GNUNET_NO); | ||
1012 | GNUNET_assert (NULL == zone_publish_task); | ||
1013 | if (0 == last_num_public_records) | ||
1014 | { | ||
1015 | zone_publish_task = GNUNET_SCHEDULER_add_delayed ( | ||
1016 | target_iteration_velocity_per_record, | ||
1017 | &publish_zone_dht_start, | ||
1018 | NULL); | ||
1019 | } | ||
1020 | else | ||
1021 | { | ||
1022 | zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start, | ||
1023 | NULL); | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | /** | ||
1029 | * Function used to put all records successively into the DHT. | ||
1030 | * | ||
1031 | * @param cls the closure (NULL) | ||
1032 | * @param key the private key of the authority (ours) | ||
1033 | * @param label the name of the records, NULL once the iteration is done | ||
1034 | * @param rd_count the number of records in @a rd | ||
1035 | * @param rd the record data | ||
1036 | */ | ||
1037 | static void | ||
1038 | handle_record (void *cls, | ||
1039 | const struct GNUNET_CRYPTO_PrivateKey *key, | ||
1040 | const char *label, | ||
1041 | unsigned int rd_count, | ||
1042 | const struct GNUNET_GNSRECORD_Data *rd, | ||
1043 | struct GNUNET_TIME_Absolute expire) | ||
1044 | { | ||
1045 | (void) cls; | ||
1046 | ns_iteration_left--; | ||
1047 | if (0 == rd_count) | ||
1048 | { | ||
1049 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1050 | "Record set empty, moving to next record set\n"); | ||
1051 | check_zone_namestore_next (); | ||
1052 | return; | ||
1053 | } | ||
1054 | for (unsigned int i = 0; i < rd_count; i++) | ||
1055 | { | ||
1056 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) | ||
1057 | { | ||
1058 | /* GNUNET_GNSRECORD_block_create will convert to absolute time; | ||
1059 | we just need to adjust our iteration frequency */ | ||
1060 | min_relative_record_time.rel_value_us = | ||
1061 | GNUNET_MIN (rd[i].expiration_time, | ||
1062 | min_relative_record_time.rel_value_us); | ||
1063 | } | ||
1064 | } | ||
1065 | |||
1066 | |||
1067 | /* We got a set of records to publish */ | ||
1068 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1069 | "Starting DHT PUT\n"); | ||
1070 | put_cnt++; | ||
1071 | if (0 == put_cnt % DELTA_INTERVAL) | ||
1072 | update_velocity (DELTA_INTERVAL); | ||
1073 | dispatch_job (key, | ||
1074 | label, | ||
1075 | rd, | ||
1076 | rd_count, | ||
1077 | expire); | ||
1078 | job_queue_length++; | ||
1079 | check_zone_namestore_next (); | ||
1080 | } | ||
1081 | |||
1082 | |||
1083 | /** | ||
1084 | * Periodically iterate over all zones and store everything in DHT | ||
1085 | * | ||
1086 | * @param cls NULL | ||
1087 | */ | ||
1088 | static void | ||
1089 | publish_zone_dht_start (void *cls) | ||
1090 | { | ||
1091 | (void) cls; | ||
1092 | zone_publish_task = NULL; | ||
1093 | GNUNET_STATISTICS_update (statistics, | ||
1094 | "Full zone iterations launched", | ||
1095 | 1, | ||
1096 | GNUNET_NO); | ||
1097 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1098 | "Starting DHT zone update!\n"); | ||
1099 | /* start counting again */ | ||
1100 | num_public_records = 0; | ||
1101 | GNUNET_assert (NULL == namestore_iter); | ||
1102 | ns_iteration_left = 1; | ||
1103 | namestore_iter | ||
1104 | = GNUNET_NAMESTORE_zone_iteration_start2 (namestore_handle, | ||
1105 | NULL, /* All zones */ | ||
1106 | &zone_iteration_error, | ||
1107 | NULL, | ||
1108 | &handle_record, | ||
1109 | NULL, | ||
1110 | &zone_iteration_finished, | ||
1111 | NULL, | ||
1112 | GNUNET_GNSRECORD_FILTER_NONE); | ||
1113 | GNUNET_assert (NULL != namestore_iter); | ||
1114 | } | ||
1115 | |||
1116 | |||
1117 | /** | ||
1118 | * Store GNS records in the DHT. | ||
1119 | * | ||
1120 | * @param key key of the zone | ||
1121 | * @param label label to store under | ||
1122 | * @param rd_public public record data | ||
1123 | * @param rd_public_count number of records in @a rd_public | ||
1124 | */ | ||
1125 | static void | ||
1126 | dispatch_job_monitor (const struct GNUNET_CRYPTO_PrivateKey *key, | ||
1127 | const char *label, | ||
1128 | const struct GNUNET_GNSRECORD_Data *rd, | ||
1129 | unsigned int rd_count, | ||
1130 | struct GNUNET_TIME_Absolute expire) | ||
1131 | { | ||
1132 | struct GNUNET_GNSRECORD_Data rd_public[rd_count]; | ||
1133 | struct GNUNET_GNSRECORD_Block *block; | ||
1134 | struct GNUNET_GNSRECORD_Block *block_priv; | ||
1135 | struct GNUNET_TIME_Absolute expire_pub; | ||
1136 | size_t block_size; | ||
1137 | unsigned int rd_public_count = 0; | ||
1138 | char *emsg; | ||
1139 | |||
1140 | if (GNUNET_OK != | ||
1141 | GNUNET_GNSRECORD_normalize_record_set (label, | ||
1142 | rd, | ||
1143 | rd_count, | ||
1144 | rd_public, | ||
1145 | &rd_public_count, | ||
1146 | &expire_pub, | ||
1147 | GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE, | ||
1148 | &emsg)) | ||
1149 | { | ||
1150 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1151 | "%s\n", emsg); | ||
1152 | GNUNET_free (emsg); | ||
1153 | } | ||
1154 | |||
1155 | GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create_unsigned (key, | ||
1156 | expire_pub, | ||
1157 | label, | ||
1158 | rd_public, | ||
1159 | rd_public_count, | ||
1160 | &block)); | ||
1161 | if (NULL == block) | ||
1162 | { | ||
1163 | GNUNET_break (0); | ||
1164 | return; /* whoops */ | ||
1165 | } | ||
1166 | if (rd_count != rd_public_count) | ||
1167 | GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create_unsigned (key, | ||
1168 | expire, | ||
1169 | label, | ||
1170 | rd, | ||
1171 | rd_count, | ||
1172 | & | ||
1173 | block_priv)); | ||
1174 | else | ||
1175 | block_priv = block; | ||
1176 | block_size = GNUNET_GNSRECORD_block_get_size (block); | ||
1177 | GNUNET_assert (0 == pthread_mutex_lock (&sign_jobs_lock)); | ||
1178 | struct RecordPublicationJob *job = GNUNET_new (struct RecordPublicationJob); | ||
1179 | job->block = block; | ||
1180 | job->block_size = block_size; | ||
1181 | job->block_priv = block_priv; | ||
1182 | job->zone = *key; | ||
1183 | job->label = GNUNET_strdup (label); | ||
1184 | job->expire_pub = expire_pub; | ||
1185 | GNUNET_CONTAINER_DLL_insert (sign_jobs_head, sign_jobs_tail, job); | ||
1186 | GNUNET_assert (0 == pthread_cond_signal (&sign_jobs_cond)); | ||
1187 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_jobs_lock)); | ||
1188 | } | ||
1189 | |||
1190 | |||
1191 | /** | ||
1192 | * Process a record that was stored in the namestore | ||
1193 | * (invoked by the monitor). | ||
1194 | * | ||
1195 | * @param cls closure, NULL | ||
1196 | * @param zone private key of the zone; NULL on disconnect | ||
1197 | * @param label label of the records; NULL on disconnect | ||
1198 | * @param rd_count number of entries in @a rd array, 0 if label was deleted | ||
1199 | * @param rd array of records with data to store | ||
1200 | * @param expire expiration of this record set | ||
1201 | */ | ||
1202 | static void | ||
1203 | handle_monitor_event (void *cls, | ||
1204 | const struct GNUNET_CRYPTO_PrivateKey *zone, | ||
1205 | const char *label, | ||
1206 | unsigned int rd_count, | ||
1207 | const struct GNUNET_GNSRECORD_Data *rd, | ||
1208 | struct GNUNET_TIME_Absolute expire) | ||
1209 | { | ||
1210 | (void) cls; | ||
1211 | GNUNET_STATISTICS_update (statistics, | ||
1212 | "Namestore monitor events received", | ||
1213 | 1, | ||
1214 | GNUNET_NO); | ||
1215 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1216 | "Received %u records for label `%s' via namestore monitor\n", | ||
1217 | rd_count, | ||
1218 | label); | ||
1219 | if (0 == rd_count) | ||
1220 | { | ||
1221 | GNUNET_NAMESTORE_zone_monitor_next (zmon, | ||
1222 | 1); | ||
1223 | return; /* nothing to do */ | ||
1224 | } | ||
1225 | dispatch_job_monitor (zone, | ||
1226 | label, | ||
1227 | rd, | ||
1228 | rd_count, | ||
1229 | expire); | ||
1230 | job_queue_length++; | ||
1231 | if (job_queue_length >= JOB_QUEUE_LIMIT) | ||
1232 | { | ||
1233 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1234 | "Job queue length exceeded (%u/%u). Halting monitor.\n", | ||
1235 | job_queue_length, | ||
1236 | JOB_QUEUE_LIMIT); | ||
1237 | monitor_halted = GNUNET_YES; | ||
1238 | return; | ||
1239 | } | ||
1240 | GNUNET_NAMESTORE_zone_monitor_next (zmon, | ||
1241 | 1); | ||
1242 | } | ||
1243 | |||
1244 | |||
1245 | /** | ||
1246 | * The zone monitor encountered an IPC error trying to to get in | ||
1247 | * sync. Restart from the beginning. | ||
1248 | * | ||
1249 | * @param cls NULL | ||
1250 | */ | ||
1251 | static void | ||
1252 | handle_monitor_error (void *cls) | ||
1253 | { | ||
1254 | (void) cls; | ||
1255 | GNUNET_STATISTICS_update (statistics, | ||
1256 | "Namestore monitor errors encountered", | ||
1257 | 1, | ||
1258 | GNUNET_NO); | ||
1259 | } | ||
1260 | |||
1261 | |||
1262 | static void* | ||
1263 | sign_worker (void *cls) | ||
1264 | { | ||
1265 | struct RecordPublicationJob *job; | ||
1266 | const struct GNUNET_DISK_FileHandle *fh; | ||
1267 | |||
1268 | fh = GNUNET_DISK_pipe_handle (notification_pipe, GNUNET_DISK_PIPE_END_WRITE); | ||
1269 | while (GNUNET_YES != in_shutdown) | ||
1270 | { | ||
1271 | GNUNET_assert (0 == pthread_mutex_lock (&sign_jobs_lock)); | ||
1272 | while (NULL == sign_jobs_head) | ||
1273 | GNUNET_assert (0 == pthread_cond_wait (&sign_jobs_cond, &sign_jobs_lock)); | ||
1274 | if (GNUNET_YES == in_shutdown) | ||
1275 | { | ||
1276 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_jobs_lock)); | ||
1277 | return NULL; | ||
1278 | } | ||
1279 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1280 | "Taking on Job for %s\n", sign_jobs_head->label); | ||
1281 | job = sign_jobs_head; | ||
1282 | GNUNET_CONTAINER_DLL_remove (sign_jobs_head, sign_jobs_tail, job); | ||
1283 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_jobs_lock)); | ||
1284 | GNUNET_GNSRECORD_block_sign (&job->zone, job->label, job->block); | ||
1285 | if (job->block != job->block_priv) | ||
1286 | GNUNET_GNSRECORD_block_sign (&job->zone, job->label, job->block_priv); | ||
1287 | GNUNET_assert (0 == pthread_mutex_lock (&sign_results_lock)); | ||
1288 | GNUNET_CONTAINER_DLL_insert (sign_results_head, sign_results_tail, job); | ||
1289 | GNUNET_assert (0 == pthread_mutex_unlock (&sign_results_lock)); | ||
1290 | job = NULL; | ||
1291 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1292 | "Done, notifying main thread through pipe!\n"); | ||
1293 | GNUNET_DISK_file_write (fh, "!", 1); | ||
1294 | } | ||
1295 | return NULL; | ||
1296 | } | ||
1297 | |||
1298 | |||
1299 | static void | ||
1300 | notification_pipe_cb (void *cls) | ||
1301 | { | ||
1302 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1303 | "Received wake up notification through pipe, checking results\n"); | ||
1304 | GNUNET_SCHEDULER_add_now (&initiate_put_from_pipe_trigger, NULL); | ||
1305 | } | ||
1306 | |||
1307 | |||
1308 | /** | ||
1309 | * Perform zonemaster duties: watch namestore, publish records. | ||
1310 | * | ||
1311 | * @param cls closure | ||
1312 | * @param server the initialized server | ||
1313 | * @param c configuration to use | ||
1314 | */ | ||
1315 | static void | ||
1316 | run (void *cls, | ||
1317 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1318 | struct GNUNET_SERVICE_Handle *service) | ||
1319 | { | ||
1320 | unsigned long long max_parallel_bg_queries = 128; | ||
1321 | |||
1322 | (void) cls; | ||
1323 | (void) service; | ||
1324 | pthread_mutex_init (&sign_jobs_lock, NULL); | ||
1325 | pthread_mutex_init (&sign_results_lock, NULL); | ||
1326 | pthread_cond_init (&sign_jobs_cond, NULL); | ||
1327 | last_put_100 = GNUNET_TIME_absolute_get (); /* first time! */ | ||
1328 | min_relative_record_time | ||
1329 | = GNUNET_TIME_UNIT_FOREVER_REL; | ||
1330 | target_iteration_velocity_per_record = INITIAL_ZONE_ITERATION_INTERVAL; | ||
1331 | namestore_handle = GNUNET_NAMESTORE_connect (c); | ||
1332 | if (NULL == namestore_handle) | ||
1333 | { | ||
1334 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1335 | _ ("Failed to connect to the namestore!\n")); | ||
1336 | GNUNET_SCHEDULER_shutdown (); | ||
1337 | return; | ||
1338 | } | ||
1339 | disable_namecache = GNUNET_CONFIGURATION_get_value_yesno (c, | ||
1340 | "namecache", | ||
1341 | "DISABLE"); | ||
1342 | if (GNUNET_NO == disable_namecache) | ||
1343 | { | ||
1344 | namecache = GNUNET_NAMECACHE_connect (c); | ||
1345 | if (NULL == namecache) | ||
1346 | { | ||
1347 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1348 | _ ("Failed to connect to the namecache!\n")); | ||
1349 | GNUNET_SCHEDULER_shutdown (); | ||
1350 | return; | ||
1351 | } | ||
1352 | } | ||
1353 | cache_keys = GNUNET_CONFIGURATION_get_value_yesno (c, | ||
1354 | "namestore", | ||
1355 | "CACHE_KEYS"); | ||
1356 | zone_publish_time_window_default = GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY; | ||
1357 | if (GNUNET_OK == | ||
1358 | GNUNET_CONFIGURATION_get_value_time (c, | ||
1359 | "zonemaster", | ||
1360 | "ZONE_PUBLISH_TIME_WINDOW", | ||
1361 | &zone_publish_time_window_default)) | ||
1362 | { | ||
1363 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1364 | "Time window for zone iteration: %s\n", | ||
1365 | GNUNET_STRINGS_relative_time_to_string ( | ||
1366 | zone_publish_time_window, | ||
1367 | GNUNET_YES)); | ||
1368 | } | ||
1369 | zone_publish_time_window = zone_publish_time_window_default; | ||
1370 | if (GNUNET_OK == | ||
1371 | GNUNET_CONFIGURATION_get_value_number (c, | ||
1372 | "zonemaster", | ||
1373 | "MAX_PARALLEL_BACKGROUND_QUERIES", | ||
1374 | &max_parallel_bg_queries)) | ||
1375 | { | ||
1376 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1377 | "Number of allowed parallel background queries: %llu\n", | ||
1378 | max_parallel_bg_queries); | ||
1379 | } | ||
1380 | if (0 == max_parallel_bg_queries) | ||
1381 | max_parallel_bg_queries = 1; | ||
1382 | dht_handle = GNUNET_DHT_connect (c, | ||
1383 | (unsigned int) max_parallel_bg_queries); | ||
1384 | if (NULL == dht_handle) | ||
1385 | { | ||
1386 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1387 | _ ("Could not connect to DHT!\n")); | ||
1388 | GNUNET_SCHEDULER_add_now (&shutdown_task, | ||
1389 | NULL); | ||
1390 | return; | ||
1391 | } | ||
1392 | |||
1393 | /* Schedule periodic put for our records. */ | ||
1394 | first_zone_iteration = GNUNET_YES; | ||
1395 | statistics = GNUNET_STATISTICS_create ("zonemaster", | ||
1396 | c); | ||
1397 | GNUNET_STATISTICS_set (statistics, | ||
1398 | "Target zone iteration velocity (μs)", | ||
1399 | target_iteration_velocity_per_record.rel_value_us, | ||
1400 | GNUNET_NO); | ||
1401 | zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start, | ||
1402 | NULL); | ||
1403 | zmon = GNUNET_NAMESTORE_zone_monitor_start2 (c, | ||
1404 | NULL, | ||
1405 | GNUNET_NO, | ||
1406 | &handle_monitor_error, | ||
1407 | NULL, | ||
1408 | &handle_monitor_event, | ||
1409 | NULL, | ||
1410 | NULL /* sync_cb */, | ||
1411 | NULL, | ||
1412 | GNUNET_GNSRECORD_FILTER_NONE); | ||
1413 | GNUNET_NAMESTORE_zone_monitor_next (zmon, | ||
1414 | NAMESTORE_MONITOR_QUEUE_LIMIT - 1); | ||
1415 | GNUNET_break (NULL != zmon); | ||
1416 | |||
1417 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1418 | NULL); | ||
1419 | |||
1420 | notification_pipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE); | ||
1421 | const struct GNUNET_DISK_FileHandle *np_fh = GNUNET_DISK_pipe_handle ( | ||
1422 | notification_pipe, | ||
1423 | GNUNET_DISK_PIPE_END_READ); | ||
1424 | pipe_read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1425 | np_fh, | ||
1426 | notification_pipe_cb, NULL); | ||
1427 | |||
1428 | long long unsigned int worker_count = 1; | ||
1429 | if (GNUNET_OK != | ||
1430 | GNUNET_CONFIGURATION_get_value_number (c, | ||
1431 | "zonemaster", | ||
1432 | "WORKER_COUNT", | ||
1433 | &worker_count)) | ||
1434 | { | ||
1435 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1436 | "Number of workers not defined falling back to 1\n"); | ||
1437 | } | ||
1438 | worker = GNUNET_malloc (sizeof (pthread_t) * worker_count); | ||
1439 | /** Start worker */ | ||
1440 | for (int i = 0; i < worker_count; i++) | ||
1441 | { | ||
1442 | if (0 != | ||
1443 | pthread_create (&worker[i], | ||
1444 | NULL, | ||
1445 | &sign_worker, | ||
1446 | NULL)) | ||
1447 | { | ||
1448 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
1449 | "pthread_create"); | ||
1450 | GNUNET_SCHEDULER_shutdown (); | ||
1451 | } | ||
1452 | } | ||
1453 | } | ||
1454 | |||
1455 | |||
1456 | /** | ||
1457 | * Define "main" method using service macro. | ||
1458 | */ | ||
1459 | GNUNET_SERVICE_MAIN | ||
1460 | ("zonemaster", | ||
1461 | GNUNET_SERVICE_OPTION_NONE, | ||
1462 | &run, | ||
1463 | NULL, | ||
1464 | NULL, | ||
1465 | NULL, | ||
1466 | GNUNET_MQ_handler_end ()); | ||
1467 | |||
1468 | |||
1469 | /* end of gnunet-service-zonemaster.c */ | ||
diff --git a/src/zonemaster/meson.build b/src/zonemaster/meson.build deleted file mode 100644 index 44c67edf2..000000000 --- a/src/zonemaster/meson.build +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | gnunetservicezonemaster_src = ['gnunet-service-zonemaster.c'] | ||
2 | |||
3 | configure_file(input : 'zonemaster.conf.in', | ||
4 | output : 'zonemaster.conf', | ||
5 | configuration : cdata, | ||
6 | install: true, | ||
7 | install_dir: pkgcfgdir) | ||
8 | |||
9 | |||
10 | if get_option('monolith') | ||
11 | foreach p : gnunetservicezonemaster_src | ||
12 | gnunet_src += 'zonemaster/' + p | ||
13 | endforeach | ||
14 | subdir_done() | ||
15 | endif | ||
16 | |||
17 | executable ('gnunet-service-zonemaster', | ||
18 | gnunetservicezonemaster_src, | ||
19 | dependencies: [ | ||
20 | libgnunetutil_dep, | ||
21 | libgnunetdht_dep, | ||
22 | libgnunetidentity_dep, | ||
23 | libgnunetstatistics_dep, | ||
24 | libgnunetnamecache_dep, | ||
25 | libgnunetnamestore_dep, | ||
26 | libgnunetgnsrecord_dep], | ||
27 | include_directories: [incdir, configuration_inc], | ||
28 | install: true, | ||
29 | install_dir: get_option('libdir')/'gnunet'/'libexec') | ||
30 | |||
diff --git a/src/zonemaster/zonemaster.conf.in b/src/zonemaster/zonemaster.conf.in deleted file mode 100644 index 549394d6c..000000000 --- a/src/zonemaster/zonemaster.conf.in +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | [zonemaster] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | RUN_PER_USER = YES | ||
4 | IMMEDIATE_START = YES | ||
5 | HOSTNAME = localhost | ||
6 | BINARY = gnunet-service-zonemaster | ||
7 | UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-zonemaster.sock | ||
8 | @JAVAPORT@PORT = 2123 | ||
9 | WORKER_COUNT = 4 | ||
10 | |||
11 | # Do we require users that want to access GNS to run this process | ||
12 | # (usually not a good idea) | ||
13 | UNIX_MATCH_UID = NO | ||
14 | |||
15 | # Do we require users that want to access GNS to be in the 'gnunet' group? | ||
16 | UNIX_MATCH_GID = NO | ||
17 | |||
18 | # How many queries is GNS allowed to perform in the background at the same time? | ||
19 | MAX_PARALLEL_BACKGROUND_QUERIES = 1000 | ||
20 | |||
21 | # How frequently do we try to publish our full zone? | ||
22 | ZONE_PUBLISH_TIME_WINDOW = 4 h | ||
23 | |||
24 | # Using caching or always ask DHT | ||
25 | # USE_CACHE = YES | ||
26 | |||
27 | # PREFIX = valgrind --leak-check=full --track-origins=yes | ||