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