aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/.gitignore83
-rw-r--r--src/util/Makefile.am665
-rw-r--r--src/util/bandwidth.c549
-rw-r--r--src/util/benchmark.c293
-rw-r--r--src/util/benchmark.h174
-rw-r--r--src/util/bio.c1560
-rw-r--r--src/util/buffer.c283
-rw-r--r--src/util/child_management.c247
-rwxr-xr-xsrc/util/child_management_test.sh2
-rw-r--r--src/util/client.c1119
-rw-r--r--src/util/common_allocation.c520
-rw-r--r--src/util/common_endian.c104
-rw-r--r--src/util/common_logging.c1568
-rw-r--r--src/util/configuration.c2524
-rw-r--r--src/util/configuration_helper.c302
-rw-r--r--src/util/consttime_memcmp.c279
-rw-r--r--src/util/container_bloomfilter.c896
-rw-r--r--src/util/container_heap.c562
-rw-r--r--src/util/container_meta_data.c1191
-rw-r--r--src/util/container_multihashmap.c1098
-rw-r--r--src/util/container_multihashmap32.c678
-rw-r--r--src/util/container_multipeermap.c1031
-rw-r--r--src/util/container_multishortmap.c1015
-rw-r--r--src/util/container_multiuuidmap.c1013
-rw-r--r--src/util/crypto-test-vectors.json56
-rw-r--r--src/util/crypto_abe.c438
-rw-r--r--src/util/crypto_crc.c201
-rw-r--r--src/util/crypto_ecc.c791
-rw-r--r--src/util/crypto_ecc_dlog.c336
-rw-r--r--src/util/crypto_ecc_gnsrecord.c445
-rw-r--r--src/util/crypto_ecc_setup.c306
-rw-r--r--src/util/crypto_hash.c389
-rw-r--r--src/util/crypto_hash_file.c243
-rw-r--r--src/util/crypto_hkdf.c360
-rw-r--r--src/util/crypto_kdf.c175
-rw-r--r--src/util/crypto_mpi.c177
-rw-r--r--src/util/crypto_paillier.c484
-rw-r--r--src/util/crypto_pow.c59
-rw-r--r--src/util/crypto_random.c421
-rw-r--r--src/util/crypto_rsa.c1256
-rw-r--r--src/util/crypto_symmetric.c262
-rw-r--r--src/util/disk.c1688
-rw-r--r--src/util/disk.h45
-rw-r--r--src/util/dnsparser.c1400
-rw-r--r--src/util/dnsstub.c706
-rw-r--r--src/util/getopt.c1014
-rw-r--r--src/util/getopt_helpers.c1104
-rw-r--r--src/util/gnunet-base32.c154
-rw-r--r--src/util/gnunet-config-diff.c23
-rw-r--r--src/util/gnunet-config.c186
-rw-r--r--src/util/gnunet-crypto-tvg.c1092
-rw-r--r--src/util/gnunet-ecc.c509
-rw-r--r--src/util/gnunet-qr.c596
-rw-r--r--src/util/gnunet-resolver.c190
-rw-r--r--src/util/gnunet-scrypt.c342
-rw-r--r--src/util/gnunet-service-resolver.c1383
-rw-r--r--src/util/gnunet-timeout.c118
-rw-r--r--src/util/gnunet-uri.c191
-rw-r--r--src/util/helper.c720
-rw-r--r--src/util/load.c256
-rw-r--r--src/util/mq.c1335
-rw-r--r--src/util/mst.c418
-rw-r--r--src/util/nc.c227
-rw-r--r--src/util/network.c1333
-rw-r--r--src/util/op.c334
-rw-r--r--src/util/os_installation.c828
-rw-r--r--src/util/os_network.c443
-rw-r--r--src/util/os_priority.c1186
-rw-r--r--src/util/peer.c253
-rw-r--r--src/util/perf_crypto_asymmetric.c132
-rw-r--r--src/util/perf_crypto_ecc_dlog.c183
-rw-r--r--src/util/perf_crypto_hash.c114
-rw-r--r--src/util/perf_crypto_paillier.c95
-rw-r--r--src/util/perf_crypto_rsa.c211
-rw-r--r--src/util/perf_crypto_symmetric.c77
-rw-r--r--src/util/perf_malloc.c97
-rw-r--r--src/util/perf_mq.c300
-rw-r--r--src/util/perf_scheduler.c103
-rw-r--r--src/util/plugin.c460
-rw-r--r--src/util/proc_compat.c49
-rw-r--r--src/util/program.c418
-rw-r--r--src/util/regex.c846
-rw-r--r--src/util/resolver.conf.in20
-rw-r--r--src/util/resolver.h93
-rw-r--r--src/util/resolver_api.c1294
-rw-r--r--src/util/scheduler.c2570
-rw-r--r--src/util/service.c2444
-rw-r--r--src/util/signal.c109
-rw-r--r--src/util/socks.c689
-rw-r--r--src/util/speedup.c119
-rw-r--r--src/util/speedup.h45
-rw-r--r--src/util/strings.c1935
-rw-r--r--src/util/test_bio.c476
-rw-r--r--src/util/test_child_management.c177
-rw-r--r--src/util/test_client.c196
-rw-r--r--src/util/test_client_data.conf3
-rw-r--r--src/util/test_client_unix.conf6
-rw-r--r--src/util/test_common_allocation.c177
-rw-r--r--src/util/test_common_endian.c43
-rw-r--r--src/util/test_common_logging.c99
-rw-r--r--src/util/test_common_logging_dummy.c122
-rw-r--r--src/util/test_common_logging_runtime_loglevels.c456
-rw-r--r--src/util/test_configuration.c580
-rw-r--r--src/util/test_configuration_data.conf30
-rw-r--r--src/util/test_container_bloomfilter.c253
-rw-r--r--src/util/test_container_dll.c113
-rw-r--r--src/util/test_container_heap.c293
-rw-r--r--src/util/test_container_meta_data.c375
-rw-r--r--src/util/test_container_multihashmap.c139
-rw-r--r--src/util/test_container_multihashmap32.c109
-rw-r--r--src/util/test_container_multipeermap.c139
-rw-r--r--src/util/test_crypto_crc.c220
-rw-r--r--src/util/test_crypto_ecc_dlog.c218
-rw-r--r--src/util/test_crypto_ecdh_ecdsa.c94
-rw-r--r--src/util/test_crypto_ecdh_eddsa.c95
-rw-r--r--src/util/test_crypto_ecdhe.c70
-rw-r--r--src/util/test_crypto_ecdsa.c281
-rw-r--r--src/util/test_crypto_eddsa.c316
-rw-r--r--src/util/test_crypto_hash.c168
-rw-r--r--src/util/test_crypto_hash_context.c49
-rw-r--r--src/util/test_crypto_hkdf.c338
-rw-r--r--src/util/test_crypto_kdf.c71
-rw-r--r--src/util/test_crypto_paillier.c247
-rw-r--r--src/util/test_crypto_random.c73
-rw-r--r--src/util/test_crypto_rsa.c148
-rw-r--r--src/util/test_crypto_symmetric.c175
-rwxr-xr-xsrc/util/test_crypto_vectors.sh3
-rw-r--r--src/util/test_disk.c290
-rw-r--r--src/util/test_getopt.c182
-rw-r--r--src/util/test_hexcoder.c56
-rw-r--r--src/util/test_mq.c341
-rw-r--r--src/util/test_os_network.c91
-rw-r--r--src/util/test_os_start_process.c289
-rw-r--r--src/util/test_peer.c139
-rw-r--r--src/util/test_plugin.c87
-rw-r--r--src/util/test_plugin_plug.c45
-rw-r--r--src/util/test_program.c138
-rw-r--r--src/util/test_program_data.conf2
-rw-r--r--src/util/test_regex.c189
-rw-r--r--src/util/test_resolver_api.c377
-rw-r--r--src/util/test_resolver_api_data.conf7
-rw-r--r--src/util/test_scheduler.c293
-rw-r--r--src/util/test_scheduler_delay.c95
-rw-r--r--src/util/test_service.c238
-rw-r--r--src/util/test_service_data.conf28
-rw-r--r--src/util/test_socks.c257
-rw-r--r--src/util/test_speedup.c126
-rw-r--r--src/util/test_speedup_data.conf3
-rw-r--r--src/util/test_strings.c162
-rw-r--r--src/util/test_strings_to_data.c65
-rw-r--r--src/util/test_time.c264
-rw-r--r--src/util/test_tun.c76
-rw-r--r--src/util/test_uri.c837
-rw-r--r--src/util/time.c789
-rw-r--r--src/util/tun.c319
-rw-r--r--src/util/uri.c344
-rw-r--r--src/util/util.conf79
-rw-r--r--src/util/util.supp11
158 files changed, 0 insertions, 67203 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore
deleted file mode 100644
index 7c7b7045d..000000000
--- a/src/util/.gitignore
+++ /dev/null
@@ -1,83 +0,0 @@
1test_common_logging_dummy
2gnunet-config
3gnunet-config-diff
4gnunet-crypto-tvg
5gnunet-ecc
6gnunet-qr
7gnunet-resolver
8gnunet-scrypt
9gnunet-service-resolver
10gnunet-uri
11test_bio
12test_client.nc
13test_client_unix.nc
14test_common_allocation
15test_common_endian
16test_common_logging
17test_common_logging_runtime_loglevels
18test_configuration
19test_connection.nc
20test_connection_addressing.nc
21test_connection_receive_cancel.nc
22test_connection_timeout.nc
23test_connection_timeout_no_connect.nc
24test_connection_transmit_cancel.nc
25test_container_bloomfilter
26test_container_dll
27test_container_heap
28test_container_meta_data
29test_container_multihashmap
30test_container_multihashmap32
31test_container_multipeermap
32test_crypto_crc
33test_crypto_ecc_dlog
34test_crypto_ecdh_ecdsa
35test_crypto_ecdh_eddsa
36test_crypto_ecdhe
37test_crypto_ecdsa
38test_crypto_eddsa
39test_crypto_hash
40test_crypto_hash_context
41test_crypto_hkdf
42test_crypto_kdf
43test_crypto_paillier
44test_crypto_random
45test_crypto_rsa
46test_crypto_symmetric
47test_disk
48test_getopt
49test_mq
50test_os_network
51test_os_start_process
52test_peer
53test_plugin
54test_program
55test_resolver_api.nc
56test_scheduler
57test_scheduler_delay
58test_server.nc
59test_server_disconnect.nc
60test_server_mst_interrupt.nc
61test_server_with_client.nc
62test_server_with_client_unix
63test_service
64test_speedup
65test_strings
66test_strings_to_data
67test_time
68test_socks.nc
69perf_crypto_asymmetric
70perf_crypto_hash
71perf_crypto_symmetric
72perf_crypto_rsa
73perf_crypto_ecc_dlog
74test_hexcoder
75test_regex
76test_tun
77test_uri
78gnunet-timeout
79python27_location
80perf_malloc
81perf_mq
82perf_scheduler
83gnunet-base32
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
deleted file mode 100644
index d21ac5e86..000000000
--- a/src/util/Makefile.am
+++ /dev/null
@@ -1,665 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6libexecdir= $(pkglibdir)/libexec/
7
8pkgcfgdir= $(pkgdatadir)/config.d/
9
10dist_pkgcfg_DATA = \
11 util.conf
12
13pkgcfg_DATA = \
14 resolver.conf
15
16TEST_CLIENT_UNIX_NC = test_client_unix.nc
17
18if USE_COVERAGE
19 AM_CFLAGS = --coverage -O0
20 XLIB = -lgcov
21endif
22
23if ENABLE_BENCHMARK
24 BENCHMARK = benchmark.c benchmark.h
25 PTHREAD = -lpthread
26endif
27
28DLOG = crypto_ecc_dlog.c
29DLOG_TEST = test_crypto_ecc_dlog
30
31gnunet_config_diff_SOURCES = \
32 gnunet-config-diff.c
33gnunet_config_diff_LDADD = \
34 libgnunetutil.la
35
36test_common_logging_dummy_SOURCES = \
37 test_common_logging_dummy.c
38test_common_logging_dummy_LDADD = \
39 libgnunetutil.la
40
41libgnunetutil_la_SOURCES = \
42 bandwidth.c \
43 $(BENCHMARK) \
44 bio.c \
45 buffer.c \
46 child_management.c \
47 client.c \
48 common_allocation.c \
49 common_endian.c \
50 common_logging.c \
51 configuration.c \
52 configuration_helper.c \
53 consttime_memcmp.c \
54 container_bloomfilter.c \
55 container_heap.c \
56 container_meta_data.c \
57 container_multihashmap.c \
58 container_multishortmap.c \
59 container_multiuuidmap.c \
60 container_multipeermap.c \
61 container_multihashmap32.c \
62 crypto_symmetric.c \
63 crypto_crc.c \
64 crypto_ecc.c \
65 crypto_ecc_gnsrecord.c \
66 $(DLOG) \
67 crypto_ecc_setup.c \
68 crypto_hash.c \
69 crypto_hash_file.c \
70 crypto_hkdf.c \
71 crypto_kdf.c \
72 crypto_mpi.c \
73 crypto_paillier.c \
74 crypto_pow.c \
75 crypto_random.c \
76 crypto_rsa.c \
77 disk.c \
78 disk.h \
79 dnsparser.c \
80 dnsstub.c \
81 getopt.c \
82 getopt_helpers.c \
83 helper.c \
84 load.c \
85 mst.c \
86 mq.c \
87 nc.c \
88 network.c \
89 op.c \
90 os_installation.c \
91 os_network.c \
92 os_priority.c \
93 peer.c \
94 plugin.c \
95 program.c \
96 regex.c \
97 resolver_api.c resolver.h \
98 scheduler.c \
99 service.c \
100 signal.c \
101 strings.c \
102 time.c \
103 tun.c \
104 uri.c \
105 speedup.c speedup.h \
106 proc_compat.c
107
108if HAVE_LIBATOMIC
109if DARWIN
110 LIBATOMIC=
111else
112 LIBATOMIC= -latomic
113endif
114else
115 LIBATOMIC=
116endif
117
118if HAVE_LIBIDN
119 LIBIDN= -lidn
120else
121 LIBIDN=
122endif
123
124if HAVE_LIBIDN2
125 LIBIDN2= -lidn2
126else
127 LIBIDN2=
128endif
129
130libgnunetutil_la_LIBADD = \
131 $(GCLIBADD) $(WINLIB) \
132 $(LIBATOMIC) \
133 $(LIBGCRYPT_LIBS) \
134 $(LTLIBICONV) \
135 $(LTLIBINTL) \
136 -lltdl \
137 $(LIBIDN) $(LIBIDN2) \
138 $(Z_LIBS) \
139 -lunistring \
140 -lsodium \
141 $(XLIB) \
142 $(PTHREAD)
143
144libgnunetutil_la_LDFLAGS = \
145 $(GN_LIB_LDFLAGS) \
146 -version-info 14:0:0
147
148GNUNET_ECC = gnunet-ecc
149GNUNET_SCRYPT = gnunet-scrypt
150
151lib_LTLIBRARIES = libgnunetutil.la
152
153libexec_PROGRAMS = \
154 gnunet-service-resolver \
155 gnunet-timeout
156
157bin_PROGRAMS = \
158 gnunet-base32 \
159 gnunet-config \
160 gnunet-crypto-tvg \
161 gnunet-resolver \
162 $(GNUNET_ECC) \
163 $(GNUNET_SCRYPT) \
164 gnunet-uri
165if HAVE_ZBAR
166bin_PROGRAMS += gnunet-qr
167endif
168
169noinst_PROGRAMS = \
170 gnunet-config-diff \
171 test_common_logging_dummy
172
173
174if ENABLE_TEST_RUN
175AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
176TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
177endif
178
179gnunet_timeout_SOURCES = \
180 gnunet-timeout.c
181
182gnunet_service_resolver_SOURCES = \
183 gnunet-service-resolver.c
184gnunet_service_resolver_LDADD = \
185 libgnunetutil.la \
186 $(GN_LIBINTL)
187if HAVE_GETADDRINFO_A
188gnunet_service_resolver_LDADD += -lanl
189endif
190
191
192gnunet_resolver_SOURCES = \
193 gnunet-resolver.c
194gnunet_resolver_LDADD = \
195 libgnunetutil.la \
196 $(GN_LIBINTL)
197
198gnunet_crypto_tvg_SOURCES = \
199 gnunet-crypto-tvg.c
200gnunet_crypto_tvg_LDADD = \
201 libgnunetutil.la \
202 $(GN_LIBINTL) -lgcrypt -ljansson
203
204gnunet_ecc_SOURCES = \
205 gnunet-ecc.c
206gnunet_ecc_LDADD = \
207 libgnunetutil.la \
208 $(GN_LIBINTL) -lgcrypt
209
210gnunet_base32_SOURCES = \
211 gnunet-base32.c
212gnunet_base32_LDADD = \
213 libgnunetutil.la \
214 $(GN_LIBINTL)
215
216gnunet_scrypt_SOURCES = \
217 gnunet-scrypt.c
218gnunet_scrypt_LDADD = \
219 libgnunetutil.la \
220 $(GN_LIBINTL) -lgcrypt
221
222
223gnunet_config_SOURCES = \
224 gnunet-config.c
225gnunet_config_LDADD = \
226 libgnunetutil.la \
227 $(GN_LIBINTL)
228
229gnunet_uri_SOURCES = \
230 gnunet-uri.c
231gnunet_uri_LDADD = \
232 libgnunetutil.la \
233 $(GN_LIBINTL)
234
235
236gnunet_qr_SOURCES = \
237 gnunet-qr.c
238gnunet_qr_LDADD = \
239 libgnunetutil.la \
240 $(GN_LIBINTL)
241gnunet_qr_LDFLAGS= -lzbar
242if HAVE_PNG
243gnunet_qr_LDFLAGS += -lpng
244endif
245
246plugin_LTLIBRARIES = \
247 libgnunet_plugin_utiltest.la
248
249libgnunet_plugin_utiltest_la_SOURCES = \
250 test_plugin_plug.c
251libgnunet_plugin_utiltest_la_LDFLAGS = \
252 $(GN_PLUGIN_LDFLAGS)
253
254if HAVE_BENCHMARKS
255 BENCHMARKS = \
256 perf_crypto_hash \
257 perf_crypto_rsa \
258 perf_crypto_paillier \
259 perf_crypto_symmetric \
260 perf_crypto_asymmetric \
261 perf_malloc \
262 perf_mq \
263 perf_scheduler \
264 perf_crypto_ecc_dlog
265endif
266
267if HAVE_SSH_KEY
268# SSH_USING_TESTS = test_socks.nc
269endif
270
271check_SCRIPTS = \
272 test_crypto_vectors.sh
273
274check_PROGRAMS = \
275 test_bio \
276 test_child_management \
277 test_client.nc \
278 $(TEST_CLIENT_UNIX_NC) \
279 test_common_allocation \
280 test_common_endian \
281 test_common_logging \
282 test_configuration \
283 test_container_bloomfilter \
284 test_container_dll \
285 test_container_meta_data \
286 test_container_multihashmap \
287 test_container_multihashmap32 \
288 test_container_multipeermap \
289 test_container_heap \
290 test_crypto_symmetric \
291 test_crypto_crc \
292 test_crypto_ecdsa \
293 test_crypto_eddsa \
294 test_crypto_ecdhe \
295 test_crypto_ecdh_eddsa \
296 test_crypto_ecdh_ecdsa \
297 $(DLOG_TEST) \
298 test_crypto_hash \
299 test_crypto_hash_context \
300 test_crypto_hkdf \
301 test_crypto_kdf \
302 test_crypto_paillier \
303 test_crypto_random \
304 test_crypto_rsa \
305 test_disk \
306 test_getopt \
307 test_hexcoder \
308 test_mq \
309 test_os_network \
310 test_peer \
311 test_plugin \
312 test_program \
313 test_regex \
314 test_resolver_api.nc \
315 test_scheduler \
316 test_scheduler_delay \
317 test_service \
318 test_strings \
319 test_strings_to_data \
320 test_speedup \
321 test_time \
322 test_tun \
323 test_uri \
324 $(BENCHMARKS) \
325 test_os_start_process \
326 test_common_logging_runtime_loglevels
327
328
329test_child_management_SOURCES = \
330 test_child_management.c
331test_child_management_LDADD = \
332 libgnunetutil.la \
333 $(XLIB)
334
335
336
337# Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart
338# sequential execution order for them
339TEST_EXTENSIONS = .nc
340test_test_client_unix.log: test_client.log
341
342test_bio_SOURCES = \
343 test_bio.c
344test_bio_LDADD = \
345 libgnunetutil.la
346
347test_hexcoder_SOURCES = \
348 test_hexcoder.c
349test_hexcoder_LDADD = \
350 libgnunetutil.la
351
352test_tun_SOURCES = \
353 test_tun.c
354test_tun_LDADD = \
355 libgnunetutil.la
356
357test_regex_SOURCES = \
358 test_regex.c
359test_regex_LDADD = \
360 libgnunetutil.la
361
362test_os_start_process_SOURCES = \
363 test_os_start_process.c
364test_os_start_process_LDADD = \
365 libgnunetutil.la
366
367test_client_nc_SOURCES = \
368 test_client.c
369test_client_nc_LDADD = \
370 libgnunetutil.la
371
372test_client_unix_nc_SOURCES = \
373 test_client.c
374test_client_unix_nc_LDADD = \
375 libgnunetutil.la
376
377#test_socks_nc_SOURCES = \
378# test_socks.c
379#test_socks_nc_LDADD = \
380# libgnunetutil.la
381
382test_common_allocation_SOURCES = \
383 test_common_allocation.c
384test_common_allocation_LDADD = \
385 libgnunetutil.la
386
387test_common_endian_SOURCES = \
388 test_common_endian.c
389test_common_endian_LDADD = \
390 libgnunetutil.la
391
392test_common_logging_SOURCES = \
393 test_common_logging.c
394test_common_logging_LDADD = \
395 libgnunetutil.la
396
397test_common_logging_runtime_loglevels_SOURCES = \
398 test_common_logging_runtime_loglevels.c
399test_common_logging_runtime_loglevels_LDADD = \
400 libgnunetutil.la
401
402test_configuration_SOURCES = \
403 test_configuration.c
404test_configuration_LDADD = \
405 libgnunetutil.la
406
407test_container_bloomfilter_SOURCES = \
408 test_container_bloomfilter.c
409test_container_bloomfilter_LDADD = \
410 libgnunetutil.la
411
412test_container_dll_SOURCES = \
413 test_container_dll.c
414test_container_dll_LDADD = \
415 libgnunetutil.la
416
417test_container_meta_data_SOURCES = \
418 test_container_meta_data.c
419test_container_meta_data_LDADD = \
420 libgnunetutil.la
421
422test_container_multihashmap_SOURCES = \
423 test_container_multihashmap.c
424test_container_multihashmap_LDADD = \
425 libgnunetutil.la
426
427test_container_multihashmap32_SOURCES = \
428 test_container_multihashmap32.c
429test_container_multihashmap32_LDADD = \
430 libgnunetutil.la
431
432test_container_multipeermap_SOURCES = \
433 test_container_multipeermap.c
434test_container_multipeermap_LDADD = \
435 libgnunetutil.la
436
437test_container_heap_SOURCES = \
438 test_container_heap.c
439test_container_heap_LDADD = \
440 libgnunetutil.la
441
442test_crypto_symmetric_SOURCES = \
443 test_crypto_symmetric.c
444test_crypto_symmetric_LDADD = \
445 libgnunetutil.la
446
447test_crypto_crc_SOURCES = \
448 test_crypto_crc.c
449test_crypto_crc_LDADD = \
450 libgnunetutil.la
451
452test_crypto_ecdsa_SOURCES = \
453 test_crypto_ecdsa.c
454test_crypto_ecdsa_LDADD = \
455 libgnunetutil.la \
456 $(LIBGCRYPT_LIBS)
457
458test_crypto_eddsa_SOURCES = \
459 test_crypto_eddsa.c
460test_crypto_eddsa_LDADD = \
461 libgnunetutil.la \
462 $(LIBGCRYPT_LIBS)
463
464test_crypto_ecc_dlog_SOURCES = \
465 test_crypto_ecc_dlog.c
466test_crypto_ecc_dlog_LDADD = \
467 -lsodium \
468 libgnunetutil.la \
469 $(LIBGCRYPT_LIBS)
470
471test_crypto_ecdhe_SOURCES = \
472 test_crypto_ecdhe.c
473test_crypto_ecdhe_LDADD = \
474 libgnunetutil.la \
475 $(LIBGCRYPT_LIBS)
476
477test_crypto_ecdh_eddsa_SOURCES = \
478 test_crypto_ecdh_eddsa.c
479test_crypto_ecdh_eddsa_LDADD = \
480 libgnunetutil.la \
481 $(LIBGCRYPT_LIBS)
482
483test_crypto_ecdh_ecdsa_SOURCES = \
484 test_crypto_ecdh_ecdsa.c
485test_crypto_ecdh_ecdsa_LDADD = \
486 libgnunetutil.la \
487 $(LIBGCRYPT_LIBS)
488
489
490test_crypto_hash_SOURCES = \
491 test_crypto_hash.c
492test_crypto_hash_LDADD = \
493 libgnunetutil.la
494
495test_crypto_hash_context_SOURCES = \
496 test_crypto_hash_context.c
497test_crypto_hash_context_LDADD = \
498 libgnunetutil.la
499
500test_crypto_hkdf_SOURCES = \
501 test_crypto_hkdf.c
502test_crypto_hkdf_LDADD = \
503 libgnunetutil.la
504
505test_crypto_kdf_SOURCES = \
506 test_crypto_kdf.c
507test_crypto_kdf_LDADD = \
508 libgnunetutil.la -lgcrypt
509
510test_crypto_paillier_SOURCES = \
511 test_crypto_paillier.c
512test_crypto_paillier_LDADD = \
513 $(LIBGCRYPT_LIBS) \
514 libgnunetutil.la
515
516test_crypto_random_SOURCES = \
517 test_crypto_random.c
518test_crypto_random_LDADD = \
519 libgnunetutil.la
520
521test_crypto_rsa_SOURCES = \
522 test_crypto_rsa.c
523test_crypto_rsa_LDADD = \
524 libgnunetutil.la -lgcrypt
525
526test_disk_SOURCES = \
527 test_disk.c
528test_disk_LDADD = \
529 libgnunetutil.la
530
531test_getopt_SOURCES = \
532 test_getopt.c
533test_getopt_LDADD = \
534 libgnunetutil.la
535
536test_mq_SOURCES = \
537 test_mq.c
538test_mq_LDADD = \
539 libgnunetutil.la
540
541test_os_network_SOURCES = \
542 test_os_network.c
543test_os_network_LDADD = \
544 libgnunetutil.la
545
546test_peer_SOURCES = \
547 test_peer.c
548test_peer_LDADD = \
549 libgnunetutil.la -lgcrypt
550
551test_plugin_SOURCES = \
552 test_plugin.c
553test_plugin_LDADD = \
554 libgnunetutil.la
555
556test_program_SOURCES = \
557 test_program.c
558test_program_LDADD = \
559 libgnunetutil.la
560
561test_resolver_api_nc_SOURCES = \
562 test_resolver_api.c
563test_resolver_api_nc_LDADD = \
564 libgnunetutil.la
565
566test_scheduler_SOURCES = \
567 test_scheduler.c
568test_scheduler_LDADD = \
569 libgnunetutil.la
570
571test_scheduler_delay_SOURCES = \
572 test_scheduler_delay.c
573test_scheduler_delay_LDADD = \
574 libgnunetutil.la
575
576test_service_SOURCES = \
577 test_service.c
578test_service_LDADD = \
579 libgnunetutil.la
580
581test_strings_SOURCES = \
582 test_strings.c
583test_strings_LDADD = \
584 libgnunetutil.la
585
586test_strings_to_data_SOURCES = \
587 test_strings_to_data.c
588test_strings_to_data_LDADD = \
589 libgnunetutil.la
590
591
592test_time_SOURCES = \
593 test_time.c
594test_time_LDADD = \
595 libgnunetutil.la
596
597test_speedup_SOURCES = \
598 test_speedup.c
599test_speedup_LDADD = \
600 libgnunetutil.la
601
602test_uri_SOURCES = \
603 test_uri.c
604test_uri_LDADD = \
605 libgnunetutil.la
606
607perf_crypto_hash_SOURCES = \
608 perf_crypto_hash.c
609perf_crypto_hash_LDADD = \
610 libgnunetutil.la
611
612perf_crypto_ecc_dlog_SOURCES = \
613 perf_crypto_ecc_dlog.c
614perf_crypto_ecc_dlog_LDADD = \
615 libgnunetutil.la \
616 -lsodium
617
618perf_crypto_rsa_SOURCES = \
619 perf_crypto_rsa.c
620perf_crypto_rsa_LDADD = \
621 libgnunetutil.la
622
623perf_crypto_symmetric_SOURCES = \
624 perf_crypto_symmetric.c
625perf_crypto_symmetric_LDADD = \
626 libgnunetutil.la
627
628perf_crypto_asymmetric_SOURCES = \
629 perf_crypto_asymmetric.c
630perf_crypto_asymmetric_LDADD = \
631 libgnunetutil.la
632
633perf_crypto_paillier_SOURCES = \
634 perf_crypto_paillier.c
635perf_crypto_paillier_LDADD = \
636 libgnunetutil.la \
637 -lgcrypt
638
639perf_malloc_SOURCES = \
640 perf_malloc.c
641perf_malloc_LDADD = \
642 libgnunetutil.la
643
644perf_mq_SOURCES = \
645 perf_mq.c
646perf_mq_LDADD = \
647 libgnunetutil.la
648
649perf_scheduler_SOURCES = \
650 perf_scheduler.c
651perf_scheduler_LDADD = \
652 libgnunetutil.la
653
654
655EXTRA_DIST = \
656 test_client_data.conf \
657 test_client_unix.conf \
658 test_configuration_data.conf \
659 test_program_data.conf \
660 test_resolver_api_data.conf \
661 test_service_data.conf \
662 test_speedup_data.conf \
663 child_management_test.sh \
664 test_crypto_vectors.sh \
665 crypto-test-vectors.json
diff --git a/src/util/bandwidth.c b/src/util/bandwidth.c
deleted file mode 100644
index 1f889d678..000000000
--- a/src/util/bandwidth.c
+++ /dev/null
@@ -1,549 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2013 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 util/bandwidth.c
23 * @brief functions related to bandwidth (unit)
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "util-bandwidth", __VA_ARGS__)
31
32/**
33 * Create a new bandwidth value.
34 *
35 * @param bytes_per_second value to create
36 * @return the new bandwidth value
37 */
38struct GNUNET_BANDWIDTH_Value32NBO
39GNUNET_BANDWIDTH_value_init (uint32_t bytes_per_second)
40{
41 struct GNUNET_BANDWIDTH_Value32NBO ret;
42
43 ret.value__ = htonl (bytes_per_second);
44 return ret;
45}
46
47
48/**
49 * Compute the MIN of two bandwidth values.
50 *
51 * @param b1 first value
52 * @param b2 second value
53 * @return the min of b1 and b2
54 */
55struct GNUNET_BANDWIDTH_Value32NBO
56GNUNET_BANDWIDTH_value_min (struct GNUNET_BANDWIDTH_Value32NBO b1,
57 struct GNUNET_BANDWIDTH_Value32NBO b2)
58{
59 return GNUNET_BANDWIDTH_value_init (
60 GNUNET_MIN (ntohl (b1.value__), ntohl (b2.value__)));
61}
62
63
64/**
65 * Compute the MAX of two bandwidth values.
66 *
67 * @param b1 first value
68 * @param b2 second value
69 * @return the min of b1 and b2
70 */
71struct GNUNET_BANDWIDTH_Value32NBO
72GNUNET_BANDWIDTH_value_max (struct GNUNET_BANDWIDTH_Value32NBO b1,
73 struct GNUNET_BANDWIDTH_Value32NBO b2)
74{
75 return GNUNET_BANDWIDTH_value_init (
76 GNUNET_MAX (ntohl (b1.value__), ntohl (b2.value__)));
77}
78
79
80/**
81 * Compute the SUM of two bandwidth values.
82 *
83 * @param b1 first value
84 * @param b2 second value
85 * @return the sum of b1 and b2
86 */
87struct GNUNET_BANDWIDTH_Value32NBO
88GNUNET_BANDWIDTH_value_sum (struct GNUNET_BANDWIDTH_Value32NBO b1,
89 struct GNUNET_BANDWIDTH_Value32NBO b2)
90{
91 return GNUNET_BANDWIDTH_value_init (ntohl (b1.value__) + ntohl (b2.value__));
92}
93
94
95/**
96 * At the given bandwidth, calculate how much traffic will be
97 * available until the given deadline.
98 *
99 * @param bps bandwidth
100 * @param deadline when is the deadline
101 * @return number of bytes available at bps until deadline
102 */
103uint64_t
104GNUNET_BANDWIDTH_value_get_available_until (
105 struct GNUNET_BANDWIDTH_Value32NBO bps,
106 struct GNUNET_TIME_Relative deadline)
107{
108 uint64_t b;
109
110 b = ntohl (bps.value__);
111 LOG (GNUNET_ERROR_TYPE_DEBUG,
112 "Bandwidth has %llu bytes available until deadline in %s\n",
113 (unsigned long long) ((b * deadline.rel_value_us + 500000LL)
114 / 1000000LL),
115 GNUNET_STRINGS_relative_time_to_string (deadline, GNUNET_YES));
116 return (b * deadline.rel_value_us + 500000LL) / 1000000LL;
117}
118
119
120/**
121 * At the given bandwidth, calculate how long it would take for
122 * @a size bytes to be transmitted.
123 *
124 * @param bps bandwidth
125 * @param size number of bytes we want to have available
126 * @return how long it would take
127 */
128struct GNUNET_TIME_Relative
129GNUNET_BANDWIDTH_value_get_delay_for (struct GNUNET_BANDWIDTH_Value32NBO bps,
130 uint64_t size)
131{
132 uint64_t b;
133 struct GNUNET_TIME_Relative ret;
134
135 b = ntohl (bps.value__);
136 if (0 == b)
137 {
138 LOG (GNUNET_ERROR_TYPE_DEBUG,
139 "Bandwidth suggests delay of infinity (zero bandwidth)\n");
140 return GNUNET_TIME_UNIT_FOREVER_REL;
141 }
142 ret.rel_value_us = size * 1000LL * 1000LL / b;
143 LOG (GNUNET_ERROR_TYPE_DEBUG,
144 "Bandwidth suggests delay of %s for %llu bytes of traffic\n",
145 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES),
146 (unsigned long long) size);
147 return ret;
148}
149
150
151/**
152 * Task run whenever we hit the bandwidth limit for a tracker.
153 *
154 * @param cls the `struct GNUNET_BANDWIDTH_Tracker`
155 */
156static void
157excess_trigger (void *cls)
158{
159 struct GNUNET_BANDWIDTH_Tracker *av = cls;
160
161 av->excess_task = NULL;
162 if (NULL != av->excess_cb)
163 {
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
165 "Notifying application about excess bandwidth\n");
166 av->excess_cb (av->excess_cb_cls);
167 }
168}
169
170
171/**
172 * Recalculate when we might need to call the excess callback.
173 */
174static void
175update_excess (struct GNUNET_BANDWIDTH_Tracker *av)
176{
177 struct GNUNET_TIME_Relative delay;
178 struct GNUNET_TIME_Absolute now;
179 uint64_t delta_time;
180 uint64_t delta_avail;
181 int64_t left_bytes;
182 uint64_t max_carry;
183 int64_t current_consumption;
184
185 if (NULL == av->excess_cb)
186 return; /* nothing to do */
187 now = GNUNET_TIME_absolute_get ();
188 delta_time = now.abs_value_us - av->last_update__.abs_value_us;
189 delta_avail =
190 (delta_time * ((unsigned long long) av->available_bytes_per_s__)
191 + 500000LL)
192 / 1000000LL;
193 current_consumption = av->consumption_since_last_update__ - delta_avail;
194 if (current_consumption > av->consumption_since_last_update__)
195 {
196 /* integer underflow, cap! */
197 current_consumption = INT64_MIN;
198 }
199 /* negative current_consumption means that we have savings */
200 max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__;
201 if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
202 max_carry = GNUNET_MAX_MESSAGE_SIZE;
203 if (max_carry > INT64_MAX)
204 max_carry = INT64_MAX;
205 left_bytes = current_consumption + max_carry;
206 if (left_bytes < current_consumption)
207 {
208 /* integer overflow, cap! */
209 left_bytes = INT64_MAX;
210 }
211 /* left_bytes now contains the number of bytes needed until
212 we have more savings than allowed */
213 if (left_bytes < 0)
214 {
215 /* having excess already */
216 delay = GNUNET_TIME_UNIT_ZERO;
217 }
218 else
219 {
220 double factor = 1.0 * left_bytes / (double) av->available_bytes_per_s__;
221 delay =
222 GNUNET_TIME_relative_saturating_multiply (GNUNET_TIME_UNIT_SECONDS,
223 (unsigned long long) factor);
224 }
225 GNUNET_log (
226 GNUNET_ERROR_TYPE_DEBUG,
227 "At %llu bps it will take us %s for %lld bytes to reach excess threshold\n",
228 (unsigned long long) av->available_bytes_per_s__,
229 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO),
230 (long long) left_bytes);
231 if (NULL != av->excess_task)
232 GNUNET_SCHEDULER_cancel (av->excess_task);
233 av->excess_task = GNUNET_SCHEDULER_add_delayed (delay, &excess_trigger, av);
234}
235
236
237/**
238 * Initialize bandwidth tracker. Note that in addition to the
239 * 'max_carry_s' limit, we also always allow at least
240 * #GNUNET_MAX_MESSAGE_SIZE to accumulate. So if the
241 * bytes-per-second limit is so small that within 'max_carry_s' not
242 * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
243 * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in
244 * bytes).
245 *
246 * To stop notifications about updates and excess callbacks use
247 * #GNUNET_BANDWIDTH_tracker_notification_stop().
248 *
249 * @param av tracker to initialize
250 * @param update_cb callback to notify a client about the tracker being updated
251 * @param update_cb_cls cls for the callback
252 * @param bytes_per_second_limit initial limit to assume
253 * @param max_carry_s maximum number of seconds unused bandwidth
254 * may accumulate before it expires
255 * @param excess_cb callback to notify if we have excess bandwidth
256 * @param excess_cb_cls closure for @a excess_cb
257 */
258void
259GNUNET_BANDWIDTH_tracker_init2 (
260 struct GNUNET_BANDWIDTH_Tracker *av,
261 GNUNET_BANDWIDTH_TrackerUpdateCallback update_cb,
262 void *update_cb_cls,
263 struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit,
264 uint32_t max_carry_s,
265 GNUNET_BANDWIDTH_ExcessNotificationCallback excess_cb,
266 void *excess_cb_cls)
267{
268 av->update_cb = update_cb;
269 av->update_cb_cls = update_cb_cls;
270 av->consumption_since_last_update__ = 0;
271 av->last_update__ = GNUNET_TIME_absolute_get ();
272 av->available_bytes_per_s__ = ntohl (bytes_per_second_limit.value__);
273 av->max_carry_s__ = max_carry_s;
274 av->excess_cb = excess_cb;
275 av->excess_cb_cls = excess_cb_cls;
276 LOG (GNUNET_ERROR_TYPE_DEBUG,
277 "Tracker %p initialized with %u Bps and max carry %u\n",
278 av,
279 (unsigned int) av->available_bytes_per_s__,
280 (unsigned int) max_carry_s);
281 update_excess (av);
282}
283
284
285/**
286 * Initialize bandwidth tracker. Note that in addition to the
287 * 'max_carry_s' limit, we also always allow at least
288 * #GNUNET_MAX_MESSAGE_SIZE to accumulate. So if the
289 * bytes-per-second limit is so small that within 'max_carry_s' not
290 * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
291 * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in
292 * bytes).
293 *
294 * @param av tracker to initialize
295 * @param update_cb callback to notify a client about the tracker being updated
296 * @param update_cb_cls cls for the callback
297 * @param bytes_per_second_limit initial limit to assume
298 * @param max_carry_s maximum number of seconds unused bandwidth
299 * may accumulate before it expires
300 */
301void
302GNUNET_BANDWIDTH_tracker_init (
303 struct GNUNET_BANDWIDTH_Tracker *av,
304 GNUNET_BANDWIDTH_TrackerUpdateCallback update_cb,
305 void *update_cb_cls,
306 struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit,
307 uint32_t max_carry_s)
308{
309 GNUNET_BANDWIDTH_tracker_init2 (av,
310 update_cb,
311 update_cb_cls,
312 bytes_per_second_limit,
313 max_carry_s,
314 NULL,
315 NULL);
316}
317
318
319/**
320 * Stop notifying about tracker updates and excess notifications
321 *
322 * @param av the respective trackers
323 */
324void
325GNUNET_BANDWIDTH_tracker_notification_stop (struct GNUNET_BANDWIDTH_Tracker *av)
326{
327 if (NULL != av->excess_task)
328 GNUNET_SCHEDULER_cancel (av->excess_task);
329 av->excess_task = NULL;
330 av->excess_cb = NULL;
331 av->excess_cb_cls = NULL;
332 av->update_cb = NULL;
333 av->update_cb_cls = NULL;
334}
335
336
337/**
338 * Update the tracker, looking at the current time and
339 * bandwidth consumption data.
340 *
341 * @param av tracker to update
342 */
343static void
344update_tracker (struct GNUNET_BANDWIDTH_Tracker *av)
345{
346 struct GNUNET_TIME_Absolute now;
347 uint64_t delta_time;
348 uint64_t delta_avail;
349 uint64_t left_bytes;
350 uint64_t max_carry;
351
352 now = GNUNET_TIME_absolute_get ();
353 delta_time = now.abs_value_us - av->last_update__.abs_value_us;
354 delta_avail =
355 (delta_time * ((unsigned long long) av->available_bytes_per_s__)
356 + 500000LL)
357 / 1000000LL;
358 av->consumption_since_last_update__ -= delta_avail;
359 av->last_update__ = now;
360 if (av->consumption_since_last_update__ < 0)
361 {
362 left_bytes = -av->consumption_since_last_update__;
363 max_carry =
364 ((unsigned long long) av->available_bytes_per_s__) * av->max_carry_s__;
365 if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
366 max_carry = GNUNET_MAX_MESSAGE_SIZE;
367 if (max_carry > INT64_MAX)
368 max_carry = INT64_MAX;
369 if (max_carry > left_bytes)
370 av->consumption_since_last_update__ = -left_bytes;
371 else
372 av->consumption_since_last_update__ = -max_carry;
373 }
374#if ! defined(GNUNET_CULL_LOGGING)
375 {
376 struct GNUNET_TIME_Relative delta;
377
378 delta.rel_value_us = delta_time;
379 LOG (GNUNET_ERROR_TYPE_DEBUG,
380 "Tracker %p updated, consumption at %lld at %u Bps, last update was %s ago\n",
381 av,
382 (long long) av->consumption_since_last_update__,
383 (unsigned int) av->available_bytes_per_s__,
384 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_YES));
385 }
386#endif
387}
388
389
390/**
391 * Notify the tracker that a certain number of bytes of bandwidth have
392 * been consumed. Note that it is legal to consume bytes even if not
393 * enough bandwidth is available (in that case,
394 * #GNUNET_BANDWIDTH_tracker_get_delay may return non-zero delay values
395 * even for a size of zero for a while).
396 *
397 * @param av tracker to update
398 * @param size number of bytes consumed
399 * @return #GNUNET_YES if this consumption is above the limit
400 */
401int
402GNUNET_BANDWIDTH_tracker_consume (struct GNUNET_BANDWIDTH_Tracker *av,
403 ssize_t size)
404{
405 int64_t nc;
406
407 LOG (GNUNET_ERROR_TYPE_DEBUG,
408 "Tracker %p consumes %d bytes\n",
409 av,
410 (int) size);
411 if (size > 0)
412 {
413 nc = av->consumption_since_last_update__ + size;
414 if (nc < av->consumption_since_last_update__)
415 {
416 /* integer overflow, very bad */
417 GNUNET_break (0);
418 return GNUNET_SYSERR;
419 }
420 av->consumption_since_last_update__ = nc;
421 update_tracker (av);
422 update_excess (av);
423 if (av->consumption_since_last_update__ > 0)
424 {
425 LOG (GNUNET_ERROR_TYPE_DEBUG,
426 "Tracker %p consumption %llu bytes above limit\n",
427 av,
428 (unsigned long long) av->consumption_since_last_update__);
429 return GNUNET_YES;
430 }
431 }
432 else
433 {
434 nc = av->consumption_since_last_update__ + size;
435 if (nc > av->consumption_since_last_update__)
436 {
437 /* integer underflow, very bad */
438 GNUNET_break (0);
439 return GNUNET_SYSERR;
440 }
441 av->consumption_since_last_update__ = nc;
442 update_excess (av);
443 }
444 return GNUNET_NO;
445}
446
447
448/**
449 * Compute how long we should wait until consuming 'size'
450 * bytes of bandwidth in order to stay within the given
451 * quota.
452 *
453 * @param av tracker to query
454 * @param size number of bytes we would like to consume
455 * @return time in ms to wait for consumption to be OK
456 */
457struct GNUNET_TIME_Relative
458GNUNET_BANDWIDTH_tracker_get_delay (struct GNUNET_BANDWIDTH_Tracker *av,
459 size_t size)
460{
461 struct GNUNET_TIME_Relative ret;
462 int64_t bytes_needed;
463
464 if (0 == av->available_bytes_per_s__)
465 {
466 LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay is infinity\n", av);
467 return GNUNET_TIME_UNIT_FOREVER_REL;
468 }
469 update_tracker (av);
470 bytes_needed = size + av->consumption_since_last_update__;
471 if (bytes_needed <= 0)
472 {
473 LOG (GNUNET_ERROR_TYPE_DEBUG,
474 "Tracker %p delay for %u bytes is zero\n",
475 av,
476 (unsigned int) size);
477 return GNUNET_TIME_UNIT_ZERO;
478 }
479 ret.rel_value_us = (1000LL * 1000LL * bytes_needed)
480 / (unsigned long long) av->available_bytes_per_s__;
481 LOG (GNUNET_ERROR_TYPE_DEBUG,
482 "Tracker %p delay for %u bytes is %s\n",
483 av,
484 (unsigned int) size,
485 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
486 return ret;
487}
488
489
490/**
491 * Compute how many bytes are available for consumption right now.
492 * quota.
493 *
494 * @param av tracker to query
495 * @return number of bytes available for consumption right now
496 */
497int64_t
498GNUNET_BANDWIDTH_tracker_get_available (struct GNUNET_BANDWIDTH_Tracker *av)
499{
500 struct GNUNET_BANDWIDTH_Value32NBO bps;
501 uint64_t avail;
502 int64_t used;
503
504 update_tracker (av);
505 bps = GNUNET_BANDWIDTH_value_init (av->available_bytes_per_s__);
506 avail =
507 GNUNET_BANDWIDTH_value_get_available_until (bps,
508 GNUNET_TIME_absolute_get_duration (
509 av->last_update__));
510 used = av->consumption_since_last_update__;
511 LOG (GNUNET_ERROR_TYPE_DEBUG,
512 "Tracker %p available bandwidth is %lld bytes\n",
513 av,
514 (long long) (int64_t) (avail - used));
515 return (int64_t) (avail - used);
516}
517
518
519/**
520 * Update quota of bandwidth tracker.
521 *
522 * @param av tracker to initialize
523 * @param bytes_per_second_limit new limit to assume
524 */
525void
526GNUNET_BANDWIDTH_tracker_update_quota (
527 struct GNUNET_BANDWIDTH_Tracker *av,
528 struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit)
529{
530 uint32_t old_limit;
531 uint32_t new_limit;
532
533 new_limit = ntohl (bytes_per_second_limit.value__);
534 LOG (GNUNET_ERROR_TYPE_DEBUG,
535 "Tracker %p bandwidth changed to %u Bps\n",
536 av,
537 (unsigned int) new_limit);
538 update_tracker (av);
539 old_limit = av->available_bytes_per_s__;
540 av->available_bytes_per_s__ = new_limit;
541 if (NULL != av->update_cb)
542 av->update_cb (av->update_cb_cls);
543 if (old_limit > new_limit)
544 update_tracker (av); /* maximum excess might be less now */
545 update_excess (av);
546}
547
548
549/* end of bandwidth.c */
diff --git a/src/util/benchmark.c b/src/util/benchmark.c
deleted file mode 100644
index 12efde706..000000000
--- a/src/util/benchmark.c
+++ /dev/null
@@ -1,293 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 util/benchmark.c
23 * @brief benchmarking for various operations
24 * @author Florian Dold <flo@dold.me>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "benchmark.h"
30#include <pthread.h>
31#include <sys/syscall.h>
32
33/**
34 * Thread-local storage key for the benchmark data.
35 */
36static pthread_key_t key;
37
38/**
39 * One-time initialization marker for key.
40 */
41static pthread_once_t key_once = PTHREAD_ONCE_INIT;
42
43
44/**
45 * Write benchmark data to a file.
46 *
47 * @param bd the benchmark data
48 */
49static void
50write_benchmark_data (struct BenchmarkData *bd)
51{
52 struct GNUNET_DISK_FileHandle *fh;
53 pid_t pid = getpid ();
54 pid_t tid = syscall (SYS_gettid);
55 char *benchmark_dir;
56 char *s;
57
58 benchmark_dir = getenv ("GNUNET_BENCHMARK_DIR");
59
60 if (NULL == benchmark_dir)
61 return;
62
63 if (GNUNET_OK != GNUNET_DISK_directory_create (benchmark_dir))
64 {
65 GNUNET_break (0);
66 return;
67 }
68
69 GNUNET_asprintf (&s, "%s/gnunet-benchmark-ops-%s-%llu-%llu.txt",
70 benchmark_dir,
71 (pid == tid) ? "main" : "thread",
72 (unsigned long long) pid,
73 (unsigned long long) tid);
74
75 fh = GNUNET_DISK_file_open (s,
76 (GNUNET_DISK_OPEN_WRITE
77 | GNUNET_DISK_OPEN_TRUNCATE
78 | GNUNET_DISK_OPEN_CREATE),
79 (GNUNET_DISK_PERM_USER_READ
80 | GNUNET_DISK_PERM_USER_WRITE));
81 GNUNET_assert (NULL != fh);
82 GNUNET_free (s);
83
84#define WRITE_BENCHMARK_OP(opname) do { \
85 GNUNET_asprintf (&s, "op " #opname " count %llu time_us %llu\n", \
86 (unsigned long long) bd->opname ## _count, \
87 (unsigned long long) bd->opname ## _time.rel_value_us); \
88 GNUNET_assert (GNUNET_SYSERR != GNUNET_DISK_file_write_blocking (fh, s, \
89 strlen ( \
90 s))); \
91 GNUNET_free (s); \
92} while (0)
93
94 WRITE_BENCHMARK_OP (ecc_ecdh);
95 WRITE_BENCHMARK_OP (ecdh_eddsa);
96 WRITE_BENCHMARK_OP (ecdhe_key_create);
97 WRITE_BENCHMARK_OP (ecdhe_key_get_public);
98 WRITE_BENCHMARK_OP (ecdsa_ecdh);
99 WRITE_BENCHMARK_OP (ecdsa_key_create);
100 WRITE_BENCHMARK_OP (ecdsa_key_get_public);
101 WRITE_BENCHMARK_OP (ecdsa_sign);
102 WRITE_BENCHMARK_OP (ecdsa_verify);
103 WRITE_BENCHMARK_OP (eddsa_ecdh);
104 WRITE_BENCHMARK_OP (eddsa_key_create);
105 WRITE_BENCHMARK_OP (eddsa_key_get_public);
106 WRITE_BENCHMARK_OP (eddsa_sign);
107 WRITE_BENCHMARK_OP (eddsa_verify);
108 WRITE_BENCHMARK_OP (hash);
109 WRITE_BENCHMARK_OP (hash_context_finish);
110 WRITE_BENCHMARK_OP (hash_context_read);
111 WRITE_BENCHMARK_OP (hash_context_start);
112 WRITE_BENCHMARK_OP (hkdf);
113 WRITE_BENCHMARK_OP (rsa_blind);
114 WRITE_BENCHMARK_OP (rsa_private_key_create);
115 WRITE_BENCHMARK_OP (rsa_private_key_get_public);
116 WRITE_BENCHMARK_OP (rsa_sign_blinded);
117 WRITE_BENCHMARK_OP (rsa_unblind);
118 WRITE_BENCHMARK_OP (rsa_verify);
119
120#undef WRITE_BENCHMARK_OP
121
122 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
123
124 GNUNET_asprintf (&s, "%s/gnunet-benchmark-urls-%s-%llu-%llu.txt",
125 benchmark_dir,
126 (pid == tid) ? "main" : "thread",
127 (unsigned long long) pid,
128 (unsigned long long) tid);
129
130 fh = GNUNET_DISK_file_open (s,
131 (GNUNET_DISK_OPEN_WRITE
132 | GNUNET_DISK_OPEN_TRUNCATE
133 | GNUNET_DISK_OPEN_CREATE),
134 (GNUNET_DISK_PERM_USER_READ
135 | GNUNET_DISK_PERM_USER_WRITE));
136 GNUNET_assert (NULL != fh);
137 GNUNET_free (s);
138
139 for (unsigned int i = 0; i < bd->urd_len; i++)
140 {
141 struct UrlRequestData *urd = &bd->urd[i];
142 GNUNET_asprintf (&s,
143 "url %s status %u count %llu time_us %llu time_us_max %llu bytes_sent %llu bytes_received %llu\n",
144 urd->request_url,
145 urd->status,
146 (unsigned long long) urd->count,
147 (unsigned long long) urd->time.rel_value_us,
148 (unsigned long long) urd->time_max.rel_value_us,
149 (unsigned long long) urd->bytes_sent,
150 (unsigned long long) urd->bytes_received);
151 GNUNET_assert (GNUNET_SYSERR != GNUNET_DISK_file_write_blocking (fh, s,
152 strlen (
153 s)));
154 GNUNET_free (s);
155 }
156
157 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
158}
159
160
161/**
162 * Called when the main thread exits and benchmark data for it was created.
163 */
164static void
165main_thread_destructor ()
166{
167 struct BenchmarkData *bd;
168
169 bd = pthread_getspecific (key);
170 if (NULL != bd)
171 write_benchmark_data (bd);
172}
173
174
175/**
176 * Called when a thread exits and benchmark data for it was created.
177 *
178 * @param cls closure
179 */
180static void
181thread_destructor (void *cls)
182{
183 struct BenchmarkData *bd = cls;
184
185 // main thread will be handled by atexit
186 if (getpid () == (pid_t) syscall (SYS_gettid))
187 return;
188
189 GNUNET_assert (NULL != bd);
190 write_benchmark_data (bd);
191}
192
193
194/**
195 * Initialize the thread-local variable key for benchmark data.
196 */
197static void
198make_key ()
199{
200 (void) pthread_key_create (&key, &thread_destructor);
201}
202
203
204/**
205 * Acquire the benchmark data for the current thread, allocate if necessary.
206 * Installs handler to collect the benchmark data on thread termination.
207 *
208 * @return benchmark data for the current thread
209 */
210struct BenchmarkData *
211get_benchmark_data (void)
212{
213 struct BenchmarkData *bd;
214
215 (void) pthread_once (&key_once, &make_key);
216
217 if (NULL == (bd = pthread_getspecific (key)))
218 {
219 bd = GNUNET_new (struct BenchmarkData);
220 (void) pthread_setspecific (key, bd);
221 if (getpid () == (pid_t) syscall (SYS_gettid))
222 {
223 // We're the main thread!
224 atexit (main_thread_destructor);
225 }
226 }
227 return bd;
228}
229
230
231/**
232 * Get benchmark data for a URL. If the URL is too long, it's truncated
233 * before looking up the corresponding benchmark data.
234 *
235 * Statistics are bucketed by URL and status code.
236 *
237 * @param url url to get request data for
238 * @param status http status code
239 */
240struct UrlRequestData *
241get_url_benchmark_data (char *url, unsigned int status)
242{
243 char trunc[MAX_BENCHMARK_URL_LEN];
244 struct BenchmarkData *bd;
245
246 if (NULL == url)
247 {
248 /* Should not happen unless curl barfs */
249 GNUNET_break (0);
250 url = "<empty>";
251 }
252
253 memcpy (trunc, url, MAX_BENCHMARK_URL_LEN);
254 trunc[MAX_BENCHMARK_URL_LEN - 1] = 0;
255
256 /* We're not interested in what's after the query string */
257 for (size_t i = 0; i < strlen (trunc); i++)
258 {
259 if (trunc[i] == '?')
260 {
261 trunc[i] = 0;
262 break;
263 }
264 }
265
266 bd = get_benchmark_data ();
267
268 GNUNET_assert (bd->urd_len <= bd->urd_capacity);
269
270 for (unsigned int i = 0; i < bd->urd_len; i++)
271 {
272 if ((0 == strcmp (trunc, bd->urd[i].request_url)) &&
273 (bd->urd[i].status == status))
274 return &bd->urd[i];
275 }
276
277 {
278 struct UrlRequestData urd = { 0 };
279
280 memcpy (&urd.request_url, trunc, MAX_BENCHMARK_URL_LEN);
281 urd.status = status;
282
283 if (bd->urd_len == bd->urd_capacity)
284 {
285 bd->urd_capacity = 2 * (bd->urd_capacity + 1);
286 bd->urd = GNUNET_realloc (bd->urd, bd->urd_capacity * sizeof(struct
287 UrlRequestData));
288 }
289
290 bd->urd[bd->urd_len++] = urd;
291 return &bd->urd[bd->urd_len - 1];
292 }
293}
diff --git a/src/util/benchmark.h b/src/util/benchmark.h
deleted file mode 100644
index e35fa50bd..000000000
--- a/src/util/benchmark.h
+++ /dev/null
@@ -1,174 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 util/benchmark.h
23 * @brief benchmarking for various operations
24 * @author Florian Dold <flo@dold.me>
25 */
26
27#ifndef BENCHMARK_H_
28#define BENCHMARK_H_
29
30#include "gnunet_time_lib.h"
31
32/**
33 * Maximum length of URLs considered for benchmarking.
34 * Shorter URLs are simply truncated.
35 */
36#define MAX_BENCHMARK_URL_LEN 128
37
38#if ENABLE_BENCHMARK
39#define BENCHMARK_START(opname) \
40 struct GNUNET_TIME_Absolute _benchmark_ ## opname ## _start = \
41 GNUNET_TIME_absolute_get ()
42#define BENCHMARK_END(opname) do { \
43 { \
44 struct GNUNET_TIME_Absolute _benchmark_ ## opname ## _end = \
45 GNUNET_TIME_absolute_get (); \
46 struct BenchmarkData *bd = get_benchmark_data (); \
47 bd->opname ## _count++; \
48 bd->opname ## _time = \
49 GNUNET_TIME_relative_add (bd->opname ## _time, \
50 GNUNET_TIME_absolute_get_difference ( \
51 _benchmark_ ## opname ## _start, \
52 _benchmark_ \
53 ## opname ## _end)); \
54 } \
55} while (0)
56#else
57#define BENCHMARK_START(opname) do { } while (0)
58#define BENCHMARK_END(opname) do { } while (0)
59#endif
60
61
62/**
63 * Struct for benchmark data for one URL.
64 */
65struct UrlRequestData
66{
67 /**
68 * Request URL, truncated (but 0-terminated).
69 */
70 char request_url[MAX_BENCHMARK_URL_LEN];
71
72 /**
73 * HTTP status code.
74 */
75 unsigned int status;
76
77 /**
78 * How often was the URL requested?
79 */
80 uint64_t count;
81
82 /**
83 * How many bytes were sent in total to request the URL.
84 */
85 uint64_t bytes_sent;
86
87 /**
88 * How many bytes were received in total as response to requesting this URL.
89 */
90 uint64_t bytes_received;
91
92 /**
93 * Total time spent requesting this URL.
94 */
95 struct GNUNET_TIME_Relative time;
96
97 /**
98 * Slowest time to response.
99 */
100 struct GNUNET_TIME_Relative time_max;
101
102 /**
103 * Fastest time to response.
104 */
105 struct GNUNET_TIME_Relative time_min;
106};
107
108#define GNUNET_DECLARE_BENCHMARK_OP(opname) \
109 uint64_t opname ## _count; \
110 struct GNUNET_TIME_Relative opname ## _time
111
112/**
113 * Thread-local struct for benchmarking data.
114 */
115struct BenchmarkData
116{
117 GNUNET_DECLARE_BENCHMARK_OP (ecc_ecdh);
118 GNUNET_DECLARE_BENCHMARK_OP (ecdh_eddsa);
119 GNUNET_DECLARE_BENCHMARK_OP (ecdhe_key_create);
120 GNUNET_DECLARE_BENCHMARK_OP (ecdhe_key_get_public);
121 GNUNET_DECLARE_BENCHMARK_OP (ecdsa_ecdh);
122 GNUNET_DECLARE_BENCHMARK_OP (ecdsa_key_create);
123 GNUNET_DECLARE_BENCHMARK_OP (ecdsa_key_get_public);
124 GNUNET_DECLARE_BENCHMARK_OP (ecdsa_sign);
125 GNUNET_DECLARE_BENCHMARK_OP (ecdsa_verify);
126 GNUNET_DECLARE_BENCHMARK_OP (eddsa_ecdh);
127 GNUNET_DECLARE_BENCHMARK_OP (eddsa_key_create);
128 GNUNET_DECLARE_BENCHMARK_OP (eddsa_key_get_public);
129 GNUNET_DECLARE_BENCHMARK_OP (eddsa_sign);
130 GNUNET_DECLARE_BENCHMARK_OP (eddsa_verify);
131 GNUNET_DECLARE_BENCHMARK_OP (hash);
132 GNUNET_DECLARE_BENCHMARK_OP (hash_context_finish);
133 GNUNET_DECLARE_BENCHMARK_OP (hash_context_read);
134 GNUNET_DECLARE_BENCHMARK_OP (hash_context_start);
135 GNUNET_DECLARE_BENCHMARK_OP (hkdf);
136 GNUNET_DECLARE_BENCHMARK_OP (rsa_blind);
137 GNUNET_DECLARE_BENCHMARK_OP (rsa_private_key_create);
138 GNUNET_DECLARE_BENCHMARK_OP (rsa_private_key_get_public);
139 GNUNET_DECLARE_BENCHMARK_OP (rsa_sign_blinded);
140 GNUNET_DECLARE_BENCHMARK_OP (rsa_unblind);
141 GNUNET_DECLARE_BENCHMARK_OP (rsa_verify);
142
143 struct UrlRequestData *urd;
144
145 unsigned int urd_len;
146
147 unsigned int urd_capacity;
148};
149
150#undef GNUNET_DECLARE_BENCHMARK_OP
151
152
153/**
154 * Acquire the benchmark data for the current thread, allocate if necessary.
155 * Installs handler to collect the benchmark data on thread termination.
156 *
157 * @return benchmark data for the current thread
158 */
159struct BenchmarkData *
160get_benchmark_data (void);
161
162/**
163 * Get benchmark data for a URL. If the URL is too long, it's truncated
164 * before looking up the corresponding benchmark data.
165 *
166 * Statistics are bucketed by URL and status code.
167 *
168 * @param url url to get request data for
169 * @param status http status code
170 */
171struct UrlRequestData *
172get_url_benchmark_data (char *url, unsigned int status);
173
174#endif /* BENCHMARK_H_ */
diff --git a/src/util/bio.c b/src/util/bio.c
deleted file mode 100644
index d221d0a21..000000000
--- a/src/util/bio.c
+++ /dev/null
@@ -1,1560 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2013 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 * @file util/bio.c
22 * @brief functions for buffering IO
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28#define LOG(kind, ...) GNUNET_log_from (kind, "util-bio", __VA_ARGS__)
29
30#ifndef PATH_MAX
31/**
32 * Assumed maximum path length (for source file names).
33 */
34#define PATH_MAX 4096
35#endif
36
37
38/**
39 * Size for I/O buffers.
40 */
41#define BIO_BUFFER_SIZE 65536
42
43/**
44 * Maximum size allowed for meta data written/read from disk.
45 * File-sharing limits to 64k, so this should be rather generous.
46 */
47#define MAX_META_DATA (1024 * 1024)
48
49
50/**
51 * Enum used internally to know how buffering is handled.
52 *
53 * The idea is that by using an enum, BIO can be extended to support other
54 * kinds of "backend" for buffering (or just formatted I/O.)
55 */
56enum IOType
57{
58 /**
59 * The handle uses a file to read/write data.
60 */
61 IO_FILE = 0,
62
63 /**
64 * The data is stored entirely in memory.
65 */
66 IO_BUFFER,
67};
68
69
70/**
71 * Handle for buffered reading.
72 */
73struct GNUNET_BIO_ReadHandle
74{
75 /**
76 * The "backend" type.
77 */
78 enum IOType type;
79
80 /**
81 * Handle to a file on disk, if @e type is #IO_FILE.
82 */
83 struct GNUNET_DISK_FileHandle *fd;
84
85 /**
86 * Error message, NULL if there were no errors.
87 */
88 char *emsg;
89
90 /**
91 * I/O buffer. Do @b not free!
92 */
93 char *buffer;
94
95 /**
96 * Number of bytes available in @e buffer.
97 */
98 size_t have;
99
100 /**
101 * Total size of @e buffer.
102 */
103 size_t size;
104
105 /**
106 * Current read offset in @e buffer.
107 */
108 off_t pos;
109};
110
111
112/**
113 * Open a file for reading.
114 *
115 * @param fn file name to be opened
116 * @return IO handle on success, NULL on error
117 */
118struct GNUNET_BIO_ReadHandle *
119GNUNET_BIO_read_open_file (const char *fn)
120{
121 struct GNUNET_DISK_FileHandle *fd;
122 struct GNUNET_BIO_ReadHandle *h;
123
124 fd = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
125 if (NULL == fd)
126 return NULL;
127 h = GNUNET_malloc (sizeof(struct GNUNET_BIO_ReadHandle) + BIO_BUFFER_SIZE);
128 h->type = IO_FILE;
129 h->buffer = (char *) &h[1];
130 h->size = BIO_BUFFER_SIZE;
131 h->fd = fd;
132 return h;
133}
134
135
136/**
137 * Create a handle from an existing allocated buffer.
138 *
139 * @param buffer the buffer to use as source
140 * @param size the total size in bytes of the buffer
141 * @return IO handle on success, NULL on error
142 */
143struct GNUNET_BIO_ReadHandle *
144GNUNET_BIO_read_open_buffer (void *buffer, size_t size)
145{
146 struct GNUNET_BIO_ReadHandle *h;
147
148 h = GNUNET_new (struct GNUNET_BIO_ReadHandle);
149 h->type = IO_BUFFER;
150 h->buffer = buffer;
151 h->size = size;
152 return h;
153}
154
155
156/**
157 * Close an open handle. Reports if any errors reading
158 * from the file were encountered.
159 *
160 * @param h file handle
161 * @param emsg set to the (allocated) error message
162 * if the handle has an error message, the return value is #GNUNET_SYSERR
163 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
164 */
165int
166GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg)
167{
168 int err;
169
170 err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR;
171 if (NULL != emsg)
172 *emsg = h->emsg;
173 else
174 GNUNET_free (h->emsg);
175 switch (h->type)
176 {
177 case IO_FILE:
178 GNUNET_DISK_file_close (h->fd);
179 break;
180 case IO_BUFFER:
181 break;
182 default:
183 break;
184 }
185 GNUNET_free (h);
186 return err;
187}
188
189
190/**
191 * Function used internally to read the contents of a file into a buffer.
192 *
193 * @param h the IO handle to read from
194 * @param what describes what is being read (for error message creation)
195 * @param result the buffer to write the data to
196 * @param len the number of bytes to read
197 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
198 */
199static int
200read_from_file (struct GNUNET_BIO_ReadHandle *h,
201 const char *what,
202 char *result,
203 size_t len)
204{
205 size_t pos = 0;
206 size_t min;
207 ssize_t ret;
208
209 do
210 {
211 min = h->have - h->pos;
212 if (0 < min)
213 {
214 if (len - pos < min)
215 min = len - pos;
216 GNUNET_memcpy (&result[pos], &h->buffer[h->pos], min);
217 h->pos += min;
218 pos += min;
219 }
220 if (len == pos)
221 return GNUNET_OK;
222 GNUNET_assert (((off_t) h->have) == h->pos);
223 ret = GNUNET_DISK_file_read (h->fd, h->buffer, h->size);
224 if (-1 == ret)
225 {
226 GNUNET_asprintf (&h->emsg,
227 _ ("Error reading `%s' from file: %s"),
228 what,
229 strerror (errno));
230 return GNUNET_SYSERR;
231 }
232 if (0 == ret)
233 {
234 GNUNET_asprintf (&h->emsg,
235 _ ("Error reading `%s' from file: %s"),
236 what,
237 _ ("End of file"));
238 return GNUNET_SYSERR;
239 }
240 h->pos = 0;
241 h->have = ret;
242 }
243 while (pos < len);
244 return GNUNET_OK;
245}
246
247
248/**
249 * Function used internally to read the content of a buffer into a buffer.
250 *
251 * @param h the IO handle to read from
252 * @param what describes what is being read (for error message creation)
253 * @param result the buffer to write the result to
254 * @param len the number of bytes to read
255 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
256 */
257static int
258read_from_buffer (struct GNUNET_BIO_ReadHandle *h,
259 const char *what,
260 char *result,
261 size_t len)
262{
263 if ((h->size < len) || (h->size - h->pos < len))
264 {
265 GNUNET_asprintf (&h->emsg,
266 _ ("Error while reading `%s' from buffer: %s"),
267 what,
268 _ ("Not enough data left"));
269 return GNUNET_SYSERR;
270 }
271 GNUNET_memcpy (result, h->buffer + h->pos, len);
272 h->pos += len;
273 return GNUNET_OK;
274}
275
276
277/**
278 * Read some contents into a buffer.
279 *
280 * @param h the IO handle to read from
281 * @param what describes what is being read (for error message creation)
282 * @param result the buffer to write the result to
283 * @param len the number of bytes to read
284 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
285 */
286int
287GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h,
288 const char *what,
289 void *result,
290 size_t len)
291{
292 char *dst = result;
293
294 if (NULL != h->emsg)
295 return GNUNET_SYSERR;
296
297 if (0 == len)
298 return GNUNET_OK;
299
300 switch (h->type)
301 {
302 case IO_FILE:
303 return read_from_file (h, what, dst, len);
304 case IO_BUFFER:
305 return read_from_buffer (h, what, dst, len);
306 default:
307 GNUNET_asprintf (&h->emsg,
308 _ ("Invalid handle type while reading `%s'"),
309 what);
310 return GNUNET_SYSERR;
311 }
312}
313
314
315/**
316 * Read 0-terminated string.
317 *
318 * @param h the IO handle to read from
319 * @param what describes what is being read (for error message creation)
320 * @param result where to store the pointer to the (allocated) string
321 * (note that *result could be set to NULL as well)
322 * @param max_length maximum allowed length for the string
323 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
324 */
325int
326GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h,
327 const char *what,
328 char **result,
329 size_t max_length)
330{
331 char *buf;
332 uint32_t big;
333
334 if (GNUNET_OK != GNUNET_BIO_read_int32 (h,
335 _ ("string length"),
336 (int32_t *) &big))
337 {
338 char *tmp = h->emsg;
339 if (NULL != tmp)
340 GNUNET_asprintf (&h->emsg,
341 _ ("%s (while reading `%s')"),
342 tmp,
343 what);
344 else
345 GNUNET_asprintf (&h->emsg,
346 _ ("Error reading length of string `%s'"),
347 what);
348 GNUNET_free (tmp);
349 return GNUNET_SYSERR;
350 }
351 if (0 == big)
352 {
353 *result = NULL;
354 return GNUNET_OK;
355 }
356 if (big > max_length)
357 {
358 GNUNET_asprintf (&h->emsg,
359 _ ("String `%s' longer than allowed (%u > %lu)"),
360 what,
361 big,
362 (unsigned long) max_length);
363 return GNUNET_SYSERR;
364 }
365 buf = GNUNET_malloc (big);
366 *result = buf;
367 buf[--big] = '\0';
368 if (0 == big)
369 return GNUNET_OK;
370 if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, big))
371 {
372 GNUNET_free (buf);
373 *result = NULL;
374 return GNUNET_SYSERR;
375 }
376 return GNUNET_OK;
377}
378
379
380/**
381 * Read a metadata container.
382 *
383 * @param h handle to an open file
384 * @param what describes what is being read (for error message creation)
385 * @param result the buffer to store a pointer to the (allocated) metadata
386 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
387 */
388int
389GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h,
390 const char *what,
391 struct GNUNET_CONTAINER_MetaData **result)
392{
393 uint32_t size;
394 char *buf;
395 struct GNUNET_CONTAINER_MetaData *meta;
396
397 if (GNUNET_OK != GNUNET_BIO_read_int32 (h,
398 _ ("metadata length"),
399 (int32_t *) &size))
400 return GNUNET_SYSERR;
401 if (0 == size)
402 {
403 *result = NULL;
404 return GNUNET_OK;
405 }
406 if (MAX_META_DATA < size)
407 {
408 GNUNET_asprintf (
409 &h->emsg,
410 _ ("Serialized metadata `%s' larger than allowed (%u > %u)"),
411 what,
412 size,
413 MAX_META_DATA);
414 return GNUNET_SYSERR;
415 }
416 buf = GNUNET_malloc (size);
417 if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, size))
418 {
419 GNUNET_free (buf);
420 return GNUNET_SYSERR;
421 }
422 meta = GNUNET_CONTAINER_meta_data_deserialize (buf, size);
423 if (NULL == meta)
424 {
425 GNUNET_free (buf);
426 GNUNET_asprintf (&h->emsg, _ ("Failed to deserialize metadata `%s'"), what);
427 return GNUNET_SYSERR;
428 }
429 GNUNET_free (buf);
430 *result = meta;
431 return GNUNET_OK;
432}
433
434
435/**
436 * Read a float.
437 *
438 * @param h the IO handle to read from
439 * @param what describes what is being read (for error message creation)
440 * @param f address of float to read
441 */
442int
443GNUNET_BIO_read_float (struct GNUNET_BIO_ReadHandle *h,
444 const char *what,
445 float *f)
446{
447 int32_t *i = (int32_t *) f;
448 return GNUNET_BIO_read_int32 (h, what, i);
449}
450
451
452/**
453 * Read a double.
454 *
455 * @param h the IO handle to read from
456 * @param what describes what is being read (for error message creation)
457 * @param f address of double to read
458 */
459int
460GNUNET_BIO_read_double (struct GNUNET_BIO_ReadHandle *h,
461 const char *what,
462 double *f)
463{
464 int64_t *i = (int64_t *) f;
465 return GNUNET_BIO_read_int64 (h, what, i);
466}
467
468
469/**
470 * Read an (u)int32_t.
471 *
472 * @param h the IO handle to read from
473 * @param what describes what is being read (for error message creation)
474 * @param i where to store the data
475 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
476 */
477int
478GNUNET_BIO_read_int32 (struct GNUNET_BIO_ReadHandle *h,
479 const char *what,
480 int32_t *i)
481{
482 int32_t big;
483
484 if (GNUNET_OK != GNUNET_BIO_read (h, what, &big, sizeof(int32_t)))
485 return GNUNET_SYSERR;
486 *i = ntohl (big);
487 return GNUNET_OK;
488}
489
490
491/**
492 * Read an (u)int64_t.
493 *
494 * @param h the IO handle to read from
495 * @param what describes what is being read (for error message creation)
496 * @param i where to store the data
497 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
498 */
499int
500GNUNET_BIO_read_int64 (struct GNUNET_BIO_ReadHandle *h,
501 const char *what,
502 int64_t *i)
503{
504 int64_t big;
505
506 if (GNUNET_OK != GNUNET_BIO_read (h, what, &big, sizeof(int64_t)))
507 return GNUNET_SYSERR;
508 *i = GNUNET_ntohll (big);
509 return GNUNET_OK;
510}
511
512
513/**
514 * Handle for buffered writing.
515 */
516struct GNUNET_BIO_WriteHandle
517{
518 /**
519 * The "backend" type.
520 */
521 enum IOType type;
522
523 /**
524 * Handle to a file on disk, if @e type is #IO_FILE.
525 */
526 struct GNUNET_DISK_FileHandle *fd;
527
528 /**
529 * Error message, NULL if there were no errors.
530 */
531 char *emsg;
532
533 /**
534 * I/O buffer.
535 * This field is a void * because it is used to hold pointers to allocated
536 * structures or arrays and will be casted to the appropriate type.
537 */
538 void *buffer;
539
540 /**
541 * Number of bytes available in @e buffer.
542 */
543 size_t have;
544
545 /**
546 * Total size of @e buffer.
547 */
548 size_t size;
549};
550
551
552/**
553 * Open a file for writing.
554 *
555 * @param fn name of the file to be opened
556 * @return IO handle on success, NULL on error
557 */
558struct GNUNET_BIO_WriteHandle *
559GNUNET_BIO_write_open_file (const char *fn)
560{
561 struct GNUNET_DISK_FileHandle *fd;
562 struct GNUNET_BIO_WriteHandle *h;
563
564 fd =
565 GNUNET_DISK_file_open (fn,
566 GNUNET_DISK_OPEN_WRITE
567 | GNUNET_DISK_OPEN_TRUNCATE
568 | GNUNET_DISK_OPEN_CREATE,
569 GNUNET_DISK_PERM_USER_READ
570 | GNUNET_DISK_PERM_USER_WRITE);
571 if (NULL == fd)
572 return NULL;
573 h = GNUNET_malloc (sizeof(struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE);
574 h->buffer = &h[1];
575 h->size = BIO_BUFFER_SIZE;
576 h->fd = fd;
577 return h;
578}
579
580
581/**
582 * Create a handle backed by an in-memory buffer.
583 *
584 * @return IO handle on success, NULL on error
585 */
586struct GNUNET_BIO_WriteHandle *
587GNUNET_BIO_write_open_buffer (void)
588{
589 struct GNUNET_BIO_WriteHandle *h;
590
591 h = GNUNET_new (struct GNUNET_BIO_WriteHandle);
592 h->type = IO_BUFFER;
593 h->buffer = (void *) GNUNET_malloc (sizeof (struct GNUNET_Buffer));
594 return h;
595}
596
597
598/**
599 * Close an IO handle.
600 * If the handle was using a file, the file will be closed.
601 *
602 * @param h file handle
603 * @param emsg set to the (allocated) error message
604 * if the handle has an error message, the return value is #GNUNET_SYSERR
605 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
606 */
607int
608GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h, char **emsg)
609{
610 int err;
611
612 err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR;
613 if (NULL != emsg)
614 *emsg = h->emsg;
615 else
616 GNUNET_free (h->emsg);
617 switch (h->type)
618 {
619 case IO_FILE:
620 if (NULL == h->fd)
621 return GNUNET_SYSERR;
622 if (GNUNET_OK != GNUNET_BIO_flush (h))
623 {
624 if (NULL != emsg)
625 *emsg = h->emsg;
626 else
627 GNUNET_free (h->emsg);
628 err = GNUNET_SYSERR;
629 }
630 else
631 {
632 GNUNET_DISK_file_close (h->fd);
633 }
634 break;
635 case IO_BUFFER:
636 GNUNET_buffer_clear ((struct GNUNET_Buffer *) h->buffer);
637 GNUNET_free (h->buffer);
638 break;
639 }
640 GNUNET_free (h);
641 return err;
642}
643
644
645/**
646 * Force a file-based buffered writer to flush its buffer.
647 * If the handle does not use a file, this function returns #GNUNET_OK
648 * without doing anything.
649 *
650 * @param h the IO handle
651 * @return #GNUNET_OK upon success. Upon failure #GNUNET_SYSERR is returned
652 * and the file is closed
653 */
654int
655GNUNET_BIO_flush (struct GNUNET_BIO_WriteHandle *h)
656{
657 ssize_t ret;
658
659 if (IO_FILE != h->type)
660 return GNUNET_OK;
661
662 ret = GNUNET_DISK_file_write (h->fd, h->buffer, h->have);
663 if (ret != (ssize_t) h->have)
664 {
665 GNUNET_DISK_file_close (h->fd);
666 h->fd = NULL;
667 GNUNET_free (h->emsg);
668 GNUNET_asprintf (&h->emsg, _ ("Unable to flush buffer to file"));
669 return GNUNET_SYSERR;
670 }
671 h->have = 0;
672 return GNUNET_OK;
673}
674
675
676/**
677 * Get the IO handle's contents.
678 * If the handle doesn't use an in-memory buffer, this function returns
679 * #GNUNET_SYSERR.
680 *
681 * @param h the IO handle
682 * @param emsg set to the (allocated) error message
683 * if the handle has an error message the return value is #GNUNET_SYSERR
684 * @param contents where to store the pointer to the handle's contents
685 * @param size where to store the size of @e contents
686 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
687 */
688int
689GNUNET_BIO_get_buffer_contents (struct GNUNET_BIO_WriteHandle *h,
690 char **emsg,
691 void **contents,
692 size_t *size)
693{
694 if (IO_BUFFER != h->type)
695 return GNUNET_SYSERR;
696 if ((NULL == contents) || (NULL == size))
697 return GNUNET_SYSERR;
698 int ret = (NULL != h->emsg) ? GNUNET_SYSERR : GNUNET_OK;
699 if (NULL != emsg)
700 *emsg = h->emsg;
701 else
702 GNUNET_free (h->emsg);
703 *contents = GNUNET_buffer_reap ((struct GNUNET_Buffer *) h->buffer, size);
704 return ret;
705}
706
707
708/**
709 * Function used internally to write the contents of a buffer into a file.
710 *
711 * @param h the IO handle to write to
712 * @param what describes what is being written (for error message creation)
713 * @param source the buffer to write
714 * @param len the number of bytes to write
715 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
716 */
717static int
718write_to_file (struct GNUNET_BIO_WriteHandle *h,
719 const char *what,
720 const char *source,
721 size_t len)
722{
723 size_t min;
724 size_t pos = 0;
725 char *buffer = (char *) h->buffer;
726
727 if (NULL == h->fd)
728 {
729 GNUNET_asprintf (&h->emsg,
730 _ ("Error while writing `%s' to file: %s"),
731 what,
732 _ ("No associated file"));
733 return GNUNET_SYSERR;
734 }
735
736 do
737 {
738 min = h->size - h->have;
739 if (len - pos < min)
740 min = len - pos;
741 GNUNET_memcpy (&buffer[h->have], &source[pos], min);
742 pos += min;
743 h->have += min;
744 if (len == pos)
745 return GNUNET_OK;
746 GNUNET_assert (h->have == h->size);
747 if (GNUNET_OK != GNUNET_BIO_flush (h))
748 {
749 char *tmp = h->emsg;
750 GNUNET_asprintf (&h->emsg,
751 _ ("Error while writing `%s' to file: %s"),
752 what,
753 tmp);
754 GNUNET_free (tmp);
755 return GNUNET_SYSERR;
756 }
757 }
758 while (pos < len);
759 GNUNET_break (0);
760 return GNUNET_OK;
761}
762
763
764/**
765 * Function used internally to write the contents of a buffer to another buffer.
766 *
767 * @param h the IO handle to write to
768 * @param what describes what is being written (for error message creation)
769 * @param source the buffer to write
770 * @param len the number of bytes to write
771 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
772 */
773static int
774write_to_buffer (struct GNUNET_BIO_WriteHandle *h,
775 const char *what,
776 const char *source,
777 size_t len)
778{
779 GNUNET_buffer_write ((struct GNUNET_Buffer *) h->buffer, source, len);
780 h->have += len;
781 return GNUNET_OK;
782}
783
784
785/**
786 * Write a buffer to a handle.
787 *
788 * @param h the IO handle to write to
789 * @param what what is being written (for error message creation)
790 * @param buffer the data to write
791 * @param n number of bytes to write
792 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
793 */
794int
795GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h,
796 const char *what,
797 const void *buffer,
798 size_t n)
799{
800 const char *src = buffer;
801
802 if (NULL != h->emsg)
803 return GNUNET_SYSERR;
804
805 if (0 == n)
806 return GNUNET_OK;
807
808 switch (h->type)
809 {
810 case IO_FILE:
811 return write_to_file (h, what, src, n);
812 case IO_BUFFER:
813 return write_to_buffer (h, what, src, n);
814 default:
815 GNUNET_asprintf (&h->emsg,
816 _ ("Invalid handle type while writing `%s'"),
817 what);
818 return GNUNET_SYSERR;
819 }
820}
821
822
823/**
824 * Write a 0-terminated string.
825 *
826 * @param h the IO handle to write to
827 * @param what what is being written (for error message creation)
828 * @param s string to write (can be NULL)
829 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
830 */
831int
832GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h,
833 const char *what,
834 const char *s)
835{
836 uint32_t slen;
837
838 slen = (uint32_t) ((s == NULL) ? 0 : strlen (s) + 1);
839 if (GNUNET_OK != GNUNET_BIO_write_int32 (h, _ ("string length"), slen))
840 return GNUNET_SYSERR;
841 if (0 != slen)
842 return GNUNET_BIO_write (h, what, s, slen - 1);
843 return GNUNET_OK;
844}
845
846
847/**
848 * Write a metadata container.
849 *
850 * @param h the IO handle to write to
851 * @param what what is being written (for error message creation)
852 * @param m metadata to write
853 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
854 */
855int
856GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h,
857 const char *what,
858 const struct GNUNET_CONTAINER_MetaData *m)
859{
860 ssize_t size;
861 char *buf;
862
863 if (m == NULL)
864 return GNUNET_BIO_write_int32 (h, _ ("metadata length"), 0);
865 buf = NULL;
866 size = GNUNET_CONTAINER_meta_data_serialize (
867 m,
868 &buf,
869 MAX_META_DATA,
870 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
871 if (-1 == size)
872 {
873 GNUNET_free (buf);
874 GNUNET_free (h->emsg);
875 GNUNET_asprintf (&h->emsg,
876 _ ("Failed to serialize metadata `%s'"),
877 what);
878 return GNUNET_SYSERR;
879 }
880 if ((GNUNET_OK != GNUNET_BIO_write_int32 (h,
881 _ ("metadata length"),
882 (uint32_t) size))
883 || (GNUNET_OK != GNUNET_BIO_write (h, what, buf, size)))
884 {
885 GNUNET_free (buf);
886 return GNUNET_SYSERR;
887 }
888 GNUNET_free (buf);
889 return GNUNET_OK;
890}
891
892
893/**
894 * Write a float.
895 *
896 * @param h the IO handle to write to
897 * @param what what is being written (for error message creation)
898 * @param f float to write
899 */
900int
901GNUNET_BIO_write_float (struct GNUNET_BIO_WriteHandle *h,
902 const char *what,
903 float f)
904{
905 int32_t i = f;
906 return GNUNET_BIO_write_int32 (h, what, i);
907}
908
909
910/**
911 * Write a double.
912 *
913 * @param h the IO handle to write to
914 * @param what what is being written (for error message creation)
915 * @param f double to write
916 */
917int
918GNUNET_BIO_write_double (struct GNUNET_BIO_WriteHandle *h,
919 const char *what,
920 double f)
921{
922 int64_t i = f;
923 return GNUNET_BIO_write_int64 (h, what, i);
924}
925
926
927/**
928 * Write an (u)int32_t.
929 *
930 * @param h the IO handle to write to
931 * @param what what is being written (for error message creation)
932 * @param i 32-bit integer to write
933 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
934 */
935int
936GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h,
937 const char *what,
938 int32_t i)
939{
940 int32_t big;
941
942 big = htonl (i);
943 return GNUNET_BIO_write (h, what, &big, sizeof(int32_t));
944}
945
946
947/**
948 * Write an (u)int64_t.
949 *
950 * @param h the IO handle to write to
951 * @param what what is being written (for error message creation)
952 * @param i 64-bit integer to write
953 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
954 */
955int
956GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h,
957 const char *what,
958 int64_t i)
959{
960 int64_t big;
961
962 big = GNUNET_htonll (i);
963 return GNUNET_BIO_write (h, what, &big, sizeof(int64_t));
964}
965
966
967/**
968 * Function used internally to read some bytes from within a read spec.
969 *
970 * @param cls ignored, always NULL
971 * @param h the IO handle to read from
972 * @param what what is being read (for error message creation)
973 * @param target where to store the data
974 * @param target_size how many bytes to read
975 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
976 */
977static int
978read_spec_handler_object (void *cls,
979 struct GNUNET_BIO_ReadHandle *h,
980 const char *what,
981 void *target,
982 size_t target_size)
983{
984 return GNUNET_BIO_read (h, what, target, target_size);
985}
986
987
988/**
989 * Create the specification to read a certain amount of bytes.
990 *
991 * @param what describes what is being read (for error message creation)
992 * @param result the buffer to write the result to
993 * @param len the number of bytes to read
994 * @return the read spec
995 */
996struct GNUNET_BIO_ReadSpec
997GNUNET_BIO_read_spec_object (const char *what,
998 void *result,
999 size_t len)
1000{
1001 struct GNUNET_BIO_ReadSpec rs = {
1002 .rh = &read_spec_handler_object,
1003 .cls = NULL,
1004 .what = what,
1005 .target = result,
1006 .size = len,
1007 };
1008
1009 return rs;
1010}
1011
1012
1013/**
1014 * Function used internally to read a string from within a read spec.
1015 *
1016 * @param cls ignored, always NULL
1017 * @param h the IO handle to read from
1018 * @param what what is being read (for error message creation)
1019 * @param target where to store the data
1020 * @param target_size how many bytes to read
1021 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1022 */
1023static int
1024read_spec_handler_string (void *cls,
1025 struct GNUNET_BIO_ReadHandle *h,
1026 const char *what,
1027 void *target,
1028 size_t target_size)
1029{
1030 char **result = target;
1031 return GNUNET_BIO_read_string (h, what, result, target_size);
1032}
1033
1034
1035/**
1036 * Create the specification to read a 0-terminated string.
1037 *
1038 * @param what describes what is being read (for error message creation)
1039 * @param result where to store the pointer to the (allocated) string
1040 * (note that *result could be set to NULL as well)
1041 * @param max_length maximum allowed length for the string
1042 * @return the read spec
1043 */
1044struct GNUNET_BIO_ReadSpec
1045GNUNET_BIO_read_spec_string (const char *what,
1046 char **result,
1047 size_t max_length)
1048{
1049 struct GNUNET_BIO_ReadSpec rs = {
1050 .rh = &read_spec_handler_string,
1051 .cls = NULL,
1052 .target = result,
1053 .size = max_length,
1054 };
1055
1056 return rs;
1057}
1058
1059
1060/**
1061 * Function used internally to read a metadata container from within a read
1062 * spec.
1063 *
1064 * @param cls ignored, always NULL
1065 * @param h the IO handle to read from
1066 * @param what what is being read (for error message creation)
1067 * @param target where to store the data
1068 * @param target_size ignored
1069 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1070 */
1071static int
1072read_spec_handler_meta_data (void *cls,
1073 struct GNUNET_BIO_ReadHandle *h,
1074 const char *what,
1075 void *target,
1076 size_t target_size)
1077{
1078 struct GNUNET_CONTAINER_MetaData **result = target;
1079 return GNUNET_BIO_read_meta_data (h, what, result);
1080}
1081
1082
1083/**
1084 * Create the specification to read a metadata container.
1085 *
1086 * @param what describes what is being read (for error message creation)
1087 * @param result the buffer to store a pointer to the (allocated) metadata
1088 * @return the read spec
1089 */
1090struct GNUNET_BIO_ReadSpec
1091GNUNET_BIO_read_spec_meta_data (const char *what,
1092 struct GNUNET_CONTAINER_MetaData **result)
1093{
1094 struct GNUNET_BIO_ReadSpec rs = {
1095 .rh = &read_spec_handler_meta_data,
1096 .cls = NULL,
1097 .target = result,
1098 .size = 0,
1099 };
1100
1101 return rs;
1102}
1103
1104
1105/**
1106 * Function used internally to read an (u)int32_t from within a read spec.
1107 *
1108 * @param cls ignored, always NULL
1109 * @param h the IO handle to read from
1110 * @param what what is being read (for error message creation)
1111 * @param target where to store the data
1112 * @param target_size ignored
1113 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1114 */
1115static int
1116read_spec_handler_int32 (void *cls,
1117 struct GNUNET_BIO_ReadHandle *h,
1118 const char *what,
1119 void *target,
1120 size_t target_size)
1121{
1122 int32_t *result = target;
1123 return GNUNET_BIO_read_int32 (h, what, result);
1124}
1125
1126
1127/**
1128 * Create the specification to read an (u)int32_t.
1129 *
1130 * @param what describes what is being read (for error message creation)
1131 * @param i where to store the data
1132 * @return the read spec
1133 */
1134struct GNUNET_BIO_ReadSpec
1135GNUNET_BIO_read_spec_int32 (const char *what,
1136 int32_t *i)
1137{
1138 struct GNUNET_BIO_ReadSpec rs = {
1139 .rh = &read_spec_handler_int32,
1140 .cls = NULL,
1141 .target = i,
1142 .size = 0,
1143 };
1144
1145 return rs;
1146}
1147
1148
1149/**
1150 * Function used internally to read an (u)int64_t from within a read spec.
1151 *
1152 * @param cls ignored, always NULL
1153 * @param h the IO handle to read from
1154 * @param what what is being read (for error message creation)
1155 * @param target where to store the data
1156 * @param target_size ignored
1157 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1158 */
1159static int
1160read_spec_handler_int64 (void *cls,
1161 struct GNUNET_BIO_ReadHandle *h,
1162 const char *what,
1163 void *target,
1164 size_t target_size)
1165{
1166 int64_t *result = target;
1167 return GNUNET_BIO_read_int64 (h, what, result);
1168}
1169
1170
1171/**
1172 * Create the specification to read an (u)int64_t.
1173 *
1174 * @param what describes what is being read (for error message creation)
1175 * @param i where to store the data
1176 * @return the read spec
1177 */
1178struct GNUNET_BIO_ReadSpec
1179GNUNET_BIO_read_spec_int64 (const char *what,
1180 int64_t *i)
1181{
1182 struct GNUNET_BIO_ReadSpec rs = {
1183 .rh = &read_spec_handler_int64,
1184 .cls = NULL,
1185 .target = i,
1186 .size = 0,
1187 };
1188
1189 return rs;
1190}
1191
1192
1193/**
1194 * Create the specification to read a float.
1195 *
1196 * @param what describes what is being read (for error message creation)
1197 * @param f address of float to read
1198 */
1199struct GNUNET_BIO_ReadSpec
1200GNUNET_BIO_read_spec_float (const char *what, float *f)
1201{
1202 struct GNUNET_BIO_ReadSpec rs = {
1203 .rh = &read_spec_handler_int32,
1204 .cls = NULL,
1205 .target = (int32_t *) f,
1206 .size = 0,
1207 };
1208
1209 return rs;
1210}
1211
1212
1213/**
1214 * Create the specification to read a double.
1215 *
1216 * @param what describes what is being read (for error message creation)
1217 * @param f address of double to read
1218 */
1219struct GNUNET_BIO_ReadSpec
1220GNUNET_BIO_read_spec_double (const char *what, double *f)
1221{
1222 struct GNUNET_BIO_ReadSpec rs = {
1223 .rh = &read_spec_handler_int64,
1224 .cls = NULL,
1225 .target = (int64_t *) f,
1226 .size = 0,
1227 };
1228
1229 return rs;
1230}
1231
1232
1233/**
1234 * Execute the read specifications in order.
1235 *
1236 * @param h the IO handle to read from
1237 * @param rs array of read specs
1238 * the last element must be #GNUNET_BIO_read_spec_end
1239 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1240 */
1241int
1242GNUNET_BIO_read_spec_commit (struct GNUNET_BIO_ReadHandle *h,
1243 struct GNUNET_BIO_ReadSpec *rs)
1244{
1245 int ret = GNUNET_OK;
1246
1247 for (size_t i = 0; NULL!=rs[i].rh; ++i)
1248 {
1249 ret = rs[i].rh (rs[i].cls, h, rs[i].what, rs[i].target, rs[i].size);
1250 if (GNUNET_OK != ret)
1251 return ret;
1252 }
1253
1254 return ret;
1255}
1256
1257
1258/**
1259 * Function used internally to write some bytes from within a write spec.
1260 *
1261 * @param cls ignored, always NULL
1262 * @param h the IO handle to write to
1263 * @param what what is being written (for error message creation)
1264 * @param source the data to write
1265 * @param source_size how many bytes to write
1266 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1267 */
1268static int
1269write_spec_handler_object (void *cls,
1270 struct GNUNET_BIO_WriteHandle *h,
1271 const char *what,
1272 void *source,
1273 size_t source_size)
1274{
1275 return GNUNET_BIO_write (h, what, source, source_size);
1276}
1277
1278
1279/**
1280 * Create the specification to read some bytes.
1281 *
1282 * @param what describes what is being written (for error message creation)
1283 * @param source the data to write
1284 * @param size how many bytes should be written
1285 * @return the write spec
1286 */
1287struct GNUNET_BIO_WriteSpec
1288GNUNET_BIO_write_spec_object (const char *what,
1289 void *source,
1290 size_t size)
1291{
1292 struct GNUNET_BIO_WriteSpec ws = {
1293 .wh = &write_spec_handler_object,
1294 .cls = NULL,
1295 .what = what,
1296 .source = source,
1297 .source_size = size,
1298 };
1299
1300 return ws;
1301}
1302
1303
1304/**
1305 * Function used internally to write a 0-terminated string from within a write
1306 * spec.
1307 *
1308 * @param cls ignored, always NULL
1309 * @param h the IO handle to write to
1310 * @param what what is being written (for error message creation)
1311 * @param source the data to write
1312 * @param source_size ignored
1313 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1314 */
1315static int
1316write_spec_handler_string (void *cls,
1317 struct GNUNET_BIO_WriteHandle *h,
1318 const char *what,
1319 void *source,
1320 size_t source_size)
1321{
1322 const char *s = source;
1323 return GNUNET_BIO_write_string (h, what, s);
1324}
1325
1326
1327/**
1328 * Create the specification to write a 0-terminated string.
1329 *
1330 * @param what describes what is being read (for error message creation)
1331 * @param s string to write (can be NULL)
1332 * @return the read spec
1333 */
1334struct GNUNET_BIO_WriteSpec
1335GNUNET_BIO_write_spec_string (const char *what,
1336 const char *s)
1337{
1338 struct GNUNET_BIO_WriteSpec ws = {
1339 .wh = &write_spec_handler_string,
1340 .cls = NULL,
1341 .what = what,
1342 .source = (void *) s,
1343 .source_size = 0,
1344 };
1345
1346 return ws;
1347}
1348
1349
1350/**
1351 * Function used internally to write a metadata container from within a write
1352 * spec.
1353 *
1354 * @param cls ignored, always NULL
1355 * @param h the IO handle to write to
1356 * @param what what is being written (for error message creation)
1357 * @param source the data to write
1358 * @param source_size ignored
1359 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1360 */
1361static int
1362write_spec_handler_meta_data (void *cls,
1363 struct GNUNET_BIO_WriteHandle *h,
1364 const char *what,
1365 void *source,
1366 size_t source_size)
1367{
1368 const struct GNUNET_CONTAINER_MetaData *m = source;
1369 return GNUNET_BIO_write_meta_data (h, what, m);
1370}
1371
1372
1373/**
1374 * Create the specification to write a metadata container.
1375 *
1376 * @param what what is being written (for error message creation)
1377 * @param m metadata to write
1378 * @return the write spec
1379 */
1380struct GNUNET_BIO_WriteSpec
1381GNUNET_BIO_write_spec_meta_data (const char *what,
1382 const struct GNUNET_CONTAINER_MetaData *m)
1383{
1384 struct GNUNET_BIO_WriteSpec ws = {
1385 .wh = &write_spec_handler_meta_data,
1386 .cls = NULL,
1387 .what = what,
1388 .source = (void *) m,
1389 .source_size = 0,
1390 };
1391
1392 return ws;
1393}
1394
1395
1396/**
1397 * Function used internally to write an (u)int32_t from within a write spec.
1398 *
1399 * @param cls ignored, always NULL
1400 * @param h the IO handle to write to
1401 * @param what what is being written (for error message creation)
1402 * @param source the data to write
1403 * @param source_size ignored
1404 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1405 */
1406static int
1407write_spec_handler_int32 (void *cls,
1408 struct GNUNET_BIO_WriteHandle *h,
1409 const char *what,
1410 void *source,
1411 size_t source_size)
1412{
1413 int32_t i = *(int32_t *) source;
1414 return GNUNET_BIO_write_int32 (h, what, i);
1415}
1416
1417
1418/**
1419 * Create the specification to write an (u)int32_t.
1420 *
1421 * @param what describes what is being written (for error message creation)
1422 * @param i pointer to a 32-bit integer
1423 * @return the write spec
1424 */
1425struct GNUNET_BIO_WriteSpec
1426GNUNET_BIO_write_spec_int32 (const char *what,
1427 int32_t *i)
1428{
1429 struct GNUNET_BIO_WriteSpec ws = {
1430 .wh = &write_spec_handler_int32,
1431 .cls = NULL,
1432 .what = what,
1433 .source = i,
1434 .source_size = 0,
1435 };
1436
1437 return ws;
1438}
1439
1440
1441/**
1442 * Function used internally to write an (u)int64_t from within a write spec.
1443 *
1444 * @param cls ignored, always NULL
1445 * @param h the IO handle to write to
1446 * @param what what is being written (for error message creation)
1447 * @param source the data to write
1448 * @param source_size ignored
1449 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1450 */
1451static int
1452write_spec_handler_int64 (void *cls,
1453 struct GNUNET_BIO_WriteHandle *h,
1454 const char *what,
1455 void *source,
1456 size_t source_size)
1457{
1458 int64_t i = *(int64_t *) source;
1459 return GNUNET_BIO_write_int64 (h, what, i);
1460}
1461
1462
1463/**
1464 * Create the specification to write an (u)int64_t.
1465 *
1466 * @param what describes what is being written (for error message creation)
1467 * @param i pointer to a 64-bit integer
1468 * @return the write spec
1469 */
1470struct GNUNET_BIO_WriteSpec
1471GNUNET_BIO_write_spec_int64 (const char *what,
1472 int64_t *i)
1473{
1474 struct GNUNET_BIO_WriteSpec ws = {
1475 .wh = &write_spec_handler_int64,
1476 .cls = NULL,
1477 .what = what,
1478 .source = i,
1479 .source_size = 0,
1480 };
1481
1482 return ws;
1483}
1484
1485
1486/**
1487 * Create the specification to write a float.
1488 *
1489 * @param what describes what is being written (for error message creation)
1490 * @param f pointer to a float
1491 * @return the write spec
1492 */
1493struct GNUNET_BIO_WriteSpec
1494GNUNET_BIO_write_spec_float (const char *what, float *f)
1495{
1496 struct GNUNET_BIO_WriteSpec ws = {
1497 .wh = &write_spec_handler_int32,
1498 .cls = NULL,
1499 .what = what,
1500 .source = (int32_t *) f,
1501 .source_size = 0,
1502 };
1503
1504 return ws;
1505}
1506
1507
1508/**
1509 * Create the specification to write an double.
1510 *
1511 * @param what describes what is being written (for error message creation)
1512 * @param f pointer to a double
1513 * @return the write spec
1514 */
1515struct GNUNET_BIO_WriteSpec
1516GNUNET_BIO_write_spec_double (const char *what, double *f)
1517{
1518 struct GNUNET_BIO_WriteSpec ws = {
1519 .wh = &write_spec_handler_int64,
1520 .cls = NULL,
1521 .what = what,
1522 .source = (int64_t *) f,
1523 .source_size = 0,
1524 };
1525
1526 return ws;
1527}
1528
1529
1530/**
1531 * Execute the write specifications in order.
1532 *
1533 * @param h the IO handle to write to
1534 * @param ws array of write specs
1535 * the last element must be #GNUNET_BIO_write_spec_end
1536 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1537 */
1538int
1539GNUNET_BIO_write_spec_commit (struct GNUNET_BIO_WriteHandle *h,
1540 struct GNUNET_BIO_WriteSpec *ws)
1541{
1542 int ret = GNUNET_OK;
1543
1544 for (size_t i = 0; NULL!=ws[i].wh; ++i)
1545 {
1546 ret = ws[i].wh (ws[i].cls, h, ws[i].what, ws[i].source, ws[i].source_size);
1547 if (GNUNET_OK != ret)
1548 return ret;
1549 }
1550
1551 /* If it's a file-based handle, the flush makes sure that the data in the
1552 buffer is actually written to the disk. */
1553 if (IO_FILE == h->type)
1554 ret = GNUNET_BIO_flush (h);
1555
1556 return ret;
1557}
1558
1559
1560/* end of bio.c */
diff --git a/src/util/buffer.c b/src/util/buffer.c
deleted file mode 100644
index 662e4d0f2..000000000
--- a/src/util/buffer.c
+++ /dev/null
@@ -1,283 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU Affero General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
12
13 You should have received a copy of the GNU Affero General Public License along with
14 GNUnet; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file buffer.c
18 * @brief Common buffer management functions.
19 * @author Florian Dold
20 */
21#include "platform.h"
22#include "gnunet_util_lib.h"
23#include "gnunet_buffer_lib.h"
24
25/**
26 * Initialize a buffer with the given capacity.
27 *
28 * When a buffer is allocated with this function, a warning is logged
29 * when the buffer exceeds the initial capacity.
30 *
31 * @param buf the buffer to initialize
32 * @param capacity the capacity (in bytes) to allocate for @a buf
33 */
34void
35GNUNET_buffer_prealloc (struct GNUNET_Buffer *buf,
36 size_t capacity)
37{
38 /* Buffer should be zero-initialized */
39 GNUNET_assert (0 == buf->mem);
40 GNUNET_assert (0 == buf->capacity);
41 GNUNET_assert (0 == buf->position);
42 buf->mem = GNUNET_malloc (capacity);
43 buf->capacity = capacity;
44 buf->warn_grow = GNUNET_YES;
45}
46
47
48/**
49 * Make sure that at least @a n bytes remaining in the buffer.
50 *
51 * @param buf buffer to potentially grow
52 * @param n number of bytes that should be available to write
53 */
54void
55GNUNET_buffer_ensure_remaining (struct GNUNET_Buffer *buf,
56 size_t n)
57{
58 size_t new_capacity = buf->position + n;
59
60 /* guard against overflow */
61 GNUNET_assert (new_capacity >= buf->position);
62 if (new_capacity <= buf->capacity)
63 return;
64 /* warn if calculation of expected size was wrong */
65 GNUNET_break (GNUNET_YES != buf->warn_grow);
66 if (new_capacity < buf->capacity * 2)
67 new_capacity = buf->capacity * 2;
68 buf->capacity = new_capacity;
69 if (NULL != buf->mem)
70 buf->mem = GNUNET_realloc (buf->mem, new_capacity);
71 else
72 buf->mem = GNUNET_malloc (new_capacity);
73}
74
75
76/**
77 * Write bytes to the buffer.
78 *
79 * Grows the buffer if necessary.
80 *
81 * @param buf buffer to write to
82 * @param data data to read from
83 * @param len number of bytes to copy from @a data to @a buf
84 */
85void
86GNUNET_buffer_write (struct GNUNET_Buffer *buf,
87 const char *data,
88 size_t len)
89{
90 GNUNET_buffer_ensure_remaining (buf, len);
91 memcpy (buf->mem + buf->position, data, len);
92 buf->position += len;
93}
94
95
96/**
97 * Write a 0-terminated string to a buffer, excluding the 0-terminator.
98 *
99 * @param buf the buffer to write to
100 * @param str the string to write to @a buf
101 */
102void
103GNUNET_buffer_write_str (struct GNUNET_Buffer *buf,
104 const char *str)
105{
106 size_t len = strlen (str);
107
108 GNUNET_buffer_write (buf, str, len);
109}
110
111
112/**
113 * Clear the buffer and return the string it contained.
114 * The caller is responsible to eventually #GNUNET_free
115 * the returned string.
116 *
117 * The returned string is always 0-terminated.
118 *
119 * @param buf the buffer to reap the string from
120 * @returns the buffer contained in the string
121 */
122char *
123GNUNET_buffer_reap_str (struct GNUNET_Buffer *buf)
124{
125 char *res;
126
127 /* ensure 0-termination */
128 if ( (0 == buf->position) || ('\0' != buf->mem[buf->position - 1]))
129 {
130 GNUNET_buffer_ensure_remaining (buf, 1);
131 buf->mem[buf->position++] = '\0';
132 }
133 res = buf->mem;
134 memset (buf, 0, sizeof (struct GNUNET_Buffer));
135 return res;
136}
137
138
139/**
140 * Clear the buffer and return its contents.
141 * The caller is responsible to eventually #GNUNET_free
142 * the returned data.
143 *
144 * @param buf the buffer to reap the contents from
145 * @param size where to store the size of the returned data
146 * @returns the data contained in the string
147 */
148void *
149GNUNET_buffer_reap (struct GNUNET_Buffer *buf, size_t *size)
150{
151 *size = buf->position;
152 void *res = buf->mem;
153 memset (buf, 0, sizeof (struct GNUNET_Buffer));
154 return res;
155}
156
157
158/**
159 * Free the backing memory of the given buffer.
160 * Does not free the memory of the buffer control structure,
161 * which is typically stack-allocated.
162 */
163void
164GNUNET_buffer_clear (struct GNUNET_Buffer *buf)
165{
166 GNUNET_free (buf->mem);
167 memset (buf, 0, sizeof (struct GNUNET_Buffer));
168}
169
170
171/**
172 * Write a path component to a buffer, ensuring that
173 * there is exactly one slash between the previous contents
174 * of the buffer and the new string.
175 *
176 * @param buf buffer to write to
177 * @param str string containing the new path component
178 */
179void
180GNUNET_buffer_write_path (struct GNUNET_Buffer *buf, const char *str)
181{
182 size_t len = strlen (str);
183
184 while ( (0 != len) && ('/' == str[0]) )
185 {
186 str++;
187 len--;
188 }
189 if ( (0 == buf->position) || ('/' != buf->mem[buf->position - 1]) )
190 {
191 GNUNET_buffer_ensure_remaining (buf, 1);
192 buf->mem[buf->position++] = '/';
193 }
194 GNUNET_buffer_write (buf, str, len);
195}
196
197
198/**
199 * Write a 0-terminated formatted string to a buffer, excluding the
200 * 0-terminator.
201 *
202 * Grows the buffer if necessary.
203 *
204 * @param buf the buffer to write to
205 * @param fmt format string
206 * @param ... format arguments
207 */
208void
209GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...)
210{
211 va_list args;
212
213 va_start (args, fmt);
214 GNUNET_buffer_write_vfstr (buf, fmt, args);
215 va_end (args);
216}
217
218
219/**
220 * Write a 0-terminated formatted string to a buffer, excluding the
221 * 0-terminator.
222 *
223 * Grows the buffer if necessary.
224 *
225 * @param buf the buffer to write to
226 * @param fmt format string
227 * @param args format argument list
228 */
229void
230GNUNET_buffer_write_vfstr (struct GNUNET_Buffer *buf,
231 const char *fmt,
232 va_list args)
233{
234 int res;
235 va_list args2;
236
237 va_copy (args2, args);
238 res = vsnprintf (NULL, 0, fmt, args2);
239 va_end (args2);
240
241 GNUNET_assert (res >= 0);
242 GNUNET_buffer_ensure_remaining (buf, res + 1);
243
244 va_copy (args2, args);
245 res = vsnprintf (buf->mem + buf->position, res + 1, fmt, args2);
246 va_end (args2);
247
248 GNUNET_assert (res >= 0);
249 buf->position += res;
250 GNUNET_assert (buf->position <= buf->capacity);
251}
252
253
254/**
255 * Write data encoded via #GNUNET_STRINGS_data_to_string to the buffer.
256 *
257 * Grows the buffer if necessary.
258 *
259 * @param buf buffer to write to
260 * @param data data to read from
261 * @param data_len number of bytes to copy from @a data to @a buf
262 */
263void
264GNUNET_buffer_write_data_encoded (struct GNUNET_Buffer *buf,
265 const void *data,
266 size_t data_len)
267{
268 size_t outlen = data_len * 8;
269
270 if (outlen % 5 > 0)
271 outlen += 5 - outlen % 5;
272 outlen /= 5;
273 GNUNET_buffer_ensure_remaining (buf,
274 outlen);
275 GNUNET_assert (NULL !=
276 GNUNET_STRINGS_data_to_string (data,
277 data_len,
278 (buf->mem
279 + buf->position),
280 outlen));
281 buf->position += outlen;
282 GNUNET_assert (buf->position <= buf->capacity);
283}
diff --git a/src/util/child_management.c b/src/util/child_management.c
deleted file mode 100644
index 832e05ece..000000000
--- a/src/util/child_management.c
+++ /dev/null
@@ -1,247 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 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 util/child_management.c
23 * @brief Handling of child processes in GNUnet.
24 * @author Christian Grothoff (ANASTASIS)
25 * @author Dominik Meister (ANASTASIS)
26 * @author t3sserakt
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_child_management_lib.h"
31
32/**
33 * Generic logging shortcut
34 */
35#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
36
37
38/**
39 * Struct which defines a Child Wait handle
40 */
41struct GNUNET_ChildWaitHandle
42{
43 /**
44 * Linked list to the next child
45 */
46 struct GNUNET_ChildWaitHandle *next;
47 /**
48 * Linked list to the previous child
49 */
50 struct GNUNET_ChildWaitHandle *prev;
51 /**
52 * Child process which is managed
53 */
54 struct GNUNET_OS_Process *proc;
55 /**
56 * Callback which is called upon completion/death of the child task
57 */
58 GNUNET_ChildCompletedCallback cb;
59 /**
60 * Closure for the handle
61 */
62 void *cb_cls;
63};
64
65
66/**
67 * Pipe used to communicate shutdown via signal.
68 */
69static struct GNUNET_DISK_PipeHandle *sigpipe;
70
71static struct GNUNET_SIGNAL_Context *shc_chld;
72
73static struct GNUNET_SCHEDULER_Task *sig_task;
74
75static struct GNUNET_ChildWaitHandle *cwh_head;
76
77static struct GNUNET_ChildWaitHandle *cwh_tail;
78
79/**
80 * Task triggered whenever we receive a SIGCHLD (child
81 * process died) or when user presses CTRL-C.
82 *
83 * @param cls closure, NULL
84 */
85static void
86maint_child_death (void *cls)
87{
88 char buf[16];
89 const struct GNUNET_DISK_FileHandle *pr;
90 struct GNUNET_ChildWaitHandle *nxt;
91
92 (void) cls;
93 sig_task = NULL;
94 /* drain pipe */
95 pr = GNUNET_DISK_pipe_handle (sigpipe,
96 GNUNET_DISK_PIPE_END_READ);
97 GNUNET_assert (! GNUNET_DISK_handle_invalid (pr));
98 (void) GNUNET_DISK_file_read (pr,
99 buf,
100 sizeof(buf));
101
102 /* find applicable processes that exited */
103 for (struct GNUNET_ChildWaitHandle *cwh = cwh_head;
104 NULL != cwh;
105 cwh = nxt)
106 {
107 enum GNUNET_OS_ProcessStatusType type;
108 long unsigned int exit_code = 0;
109
110 nxt = cwh->next;
111 if (GNUNET_OK ==
112 GNUNET_OS_process_status (cwh->proc,
113 &type,
114 &exit_code))
115 {
116 GNUNET_CONTAINER_DLL_remove (cwh_head,
117 cwh_tail,
118 cwh);
119 cwh->cb (cwh->cb_cls,
120 type,
121 exit_code);
122 GNUNET_free (cwh);
123 }
124 }
125 if (NULL == cwh_head)
126 return;
127 /* wait for more */
128 sig_task = GNUNET_SCHEDULER_add_read_file (
129 GNUNET_TIME_UNIT_FOREVER_REL,
130 GNUNET_DISK_pipe_handle (sigpipe,
131 GNUNET_DISK_PIPE_END_READ),
132 &maint_child_death,
133 NULL);
134}
135
136
137/**
138 * Signal handler called for SIGCHLD. Triggers the
139 * respective handler by writing to the trigger pipe.
140 */
141static void
142sighandler_child_death (void)
143{
144 static char c;
145 int old_errno = errno; /* back-up errno */
146
147 GNUNET_break (
148 1 ==
149 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
150 GNUNET_DISK_PIPE_END_WRITE),
151 &c,
152 sizeof(c)));
153 errno = old_errno; /* restore errno */
154}
155
156/**
157 * Initializing the signal pipe for child handling.
158 */
159static void
160child_management_start (void)
161{
162 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
163 "Trying to start child management.\n");
164 if (NULL != sigpipe)
165 return; /* already initialized */
166 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
167 GNUNET_assert (sigpipe != NULL);
168 shc_chld =
169 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
170 &sighandler_child_death);
171 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
172 "Child management started.\n");
173}
174
175
176/**
177 * Clean up.
178 */
179static void
180child_management_done (void)
181{
182 if (NULL != sig_task)
183 {
184 GNUNET_SCHEDULER_cancel (sig_task);
185 sig_task = NULL;
186 }
187 GNUNET_SIGNAL_handler_uninstall (shc_chld);
188 shc_chld = NULL;
189 GNUNET_DISK_pipe_close (sigpipe);
190 sigpipe = NULL;
191 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
192 "Child management stopped.\n");
193}
194
195
196/**
197 * Adding a child process to be monitored by the child management.
198 *
199 * @param proc The child process to be monitored.
200 * @param cp The callback to be called, when the child process completed.
201 * @param cb_cls The closure for the callback.
202 * @return An handle for the the child being monitored.
203 */
204struct GNUNET_ChildWaitHandle *
205GNUNET_wait_child (struct GNUNET_OS_Process *proc,
206 GNUNET_ChildCompletedCallback cb,
207 void *cb_cls)
208{
209 struct GNUNET_ChildWaitHandle *cwh;
210
211 child_management_start ();
212 cwh = GNUNET_new (struct GNUNET_ChildWaitHandle);
213 cwh->proc = proc;
214 cwh->cb = cb;
215 cwh->cb_cls = cb_cls;
216 GNUNET_CONTAINER_DLL_insert (cwh_head,
217 cwh_tail,
218 cwh);
219 if (NULL == sig_task)
220 {
221 sig_task = GNUNET_SCHEDULER_add_read_file (
222 GNUNET_TIME_UNIT_FOREVER_REL,
223 GNUNET_DISK_pipe_handle (sigpipe,
224 GNUNET_DISK_PIPE_END_READ),
225 &maint_child_death,
226 NULL);
227 }
228 return cwh;
229}
230
231
232/**
233 * Removing child handle.
234 *
235 * @param cwh The handle to be removed.
236 */
237void
238GNUNET_wait_child_cancel (struct GNUNET_ChildWaitHandle *cwh)
239{
240 GNUNET_CONTAINER_DLL_remove (cwh_head,
241 cwh_tail,
242 cwh);
243 GNUNET_free (cwh);
244 if (NULL != cwh_head)
245 return;
246 child_management_done ();
247}
diff --git a/src/util/child_management_test.sh b/src/util/child_management_test.sh
deleted file mode 100755
index a35b865f3..000000000
--- a/src/util/child_management_test.sh
+++ /dev/null
@@ -1,2 +0,0 @@
1#!/usr/bin/env bash
2echo "$1$2" >> child_management_test.txt
diff --git a/src/util/client.c b/src/util/client.c
deleted file mode 100644
index 4e5eca32a..000000000
--- a/src/util/client.c
+++ /dev/null
@@ -1,1119 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2016, 2019 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 util/client.c
23 * @brief code for access to services
24 * @author Christian Grothoff
25 *
26 * Generic TCP code for reliable, record-oriented TCP
27 * connections between clients and service providers.
28 */
29#include "platform.h"
30#include "gnunet_protocols.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_resolver_service.h"
33#include "gnunet_socks.h"
34
35
36#define LOG(kind, ...) GNUNET_log_from (kind, "util-client", __VA_ARGS__)
37
38/**
39 * Timeout we use on TCP connect before trying another
40 * result from the DNS resolver. Actual value used
41 * is this value divided by the number of address families.
42 * Default is 5s.
43 */
44#define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply ( \
45 GNUNET_TIME_UNIT_SECONDS, 5)
46
47
48/**
49 * Internal state for a client connected to a GNUnet service.
50 */
51struct ClientState;
52
53
54/**
55 * During connect, we try multiple possible IP addresses
56 * to find out which one might work.
57 */
58struct AddressProbe
59{
60 /**
61 * This is a linked list.
62 */
63 struct AddressProbe *next;
64
65 /**
66 * This is a doubly-linked list.
67 */
68 struct AddressProbe *prev;
69
70 /**
71 * The address; do not free (allocated at the end of this struct).
72 */
73 const struct sockaddr *addr;
74
75 /**
76 * Underlying OS's socket.
77 */
78 struct GNUNET_NETWORK_Handle *sock;
79
80 /**
81 * Connection for which we are probing.
82 */
83 struct ClientState *cstate;
84
85 /**
86 * Length of addr.
87 */
88 socklen_t addrlen;
89
90 /**
91 * Task waiting for the connection to finish connecting.
92 */
93 struct GNUNET_SCHEDULER_Task *task;
94};
95
96
97/**
98 * Internal state for a client connected to a GNUnet service.
99 */
100struct ClientState
101{
102 /**
103 * The connection handle, NULL if not live
104 */
105 struct GNUNET_NETWORK_Handle *sock;
106
107 /**
108 * Handle to a pending DNS lookup request, NULL if DNS is finished.
109 */
110 struct GNUNET_RESOLVER_RequestHandle *dns_active;
111
112 /**
113 * Our configuration.
114 */
115 const struct GNUNET_CONFIGURATION_Handle *cfg;
116
117 /**
118 * Linked list of sockets we are currently trying out
119 * (during connect).
120 */
121 struct AddressProbe *ap_head;
122
123 /**
124 * Linked list of sockets we are currently trying out
125 * (during connect).
126 */
127 struct AddressProbe *ap_tail;
128
129 /**
130 * Name of the service we interact with.
131 */
132 char *service_name;
133
134 /**
135 * Hostname, if any.
136 */
137 char *hostname;
138
139 /**
140 * Next message to transmit to the service. NULL for none.
141 */
142 const struct GNUNET_MessageHeader *msg;
143
144 /**
145 * Task for trying to connect to the service.
146 */
147 struct GNUNET_SCHEDULER_Task *retry_task;
148
149 /**
150 * Task for sending messages to the service.
151 */
152 struct GNUNET_SCHEDULER_Task *send_task;
153
154 /**
155 * Task for sending messages to the service.
156 */
157 struct GNUNET_SCHEDULER_Task *recv_task;
158
159 /**
160 * Tokenizer for inbound messages.
161 */
162 struct GNUNET_MessageStreamTokenizer *mst;
163
164 /**
165 * Message queue under our control.
166 */
167 struct GNUNET_MQ_Handle *mq;
168
169 /**
170 * Timeout for receiving a response (absolute time).
171 */
172 struct GNUNET_TIME_Absolute receive_timeout;
173
174 /**
175 * Current value for our incremental back-off (for
176 * connect re-tries).
177 */
178 struct GNUNET_TIME_Relative back_off;
179
180 /**
181 * TCP port (0 for disabled).
182 */
183 unsigned long long port;
184
185 /**
186 * Offset in the message where we are for transmission.
187 */
188 size_t msg_off;
189
190 /**
191 * How often have we tried to connect?
192 */
193 unsigned int attempts;
194
195 /**
196 * Are we supposed to die? #GNUNET_SYSERR if destruction must be
197 * deferred, #GNUNET_NO by default, #GNUNET_YES if destruction was
198 * deferred.
199 */
200 int in_destroy;
201};
202
203
204/**
205 * Try to connect to the service.
206 *
207 * @param cls the `struct ClientState` to try to connect to the service
208 */
209static void
210start_connect (void *cls);
211
212
213/**
214 * We've failed for good to establish a connection (timeout or
215 * no more addresses to try).
216 *
217 * @param cstate the connection we tried to establish
218 */
219static void
220connect_fail_continuation (struct ClientState *cstate)
221{
222 GNUNET_break (NULL == cstate->ap_head);
223 GNUNET_break (NULL == cstate->ap_tail);
224 GNUNET_break (NULL == cstate->dns_active);
225 GNUNET_break (NULL == cstate->sock);
226 GNUNET_assert (NULL == cstate->send_task);
227 GNUNET_assert (NULL == cstate->recv_task);
228 // GNUNET_assert (NULL == cstate->proxy_handshake);
229
230 cstate->back_off = GNUNET_TIME_STD_BACKOFF (cstate->back_off);
231 LOG (GNUNET_ERROR_TYPE_DEBUG,
232 "Failed to establish connection to `%s', no further addresses to try, will try again in %s.\n",
233 cstate->service_name,
234 GNUNET_STRINGS_relative_time_to_string (cstate->back_off,
235 GNUNET_YES));
236 cstate->retry_task
237 = GNUNET_SCHEDULER_add_delayed (cstate->back_off,
238 &start_connect,
239 cstate);
240}
241
242
243/**
244 * We are ready to send a message to the service.
245 *
246 * @param cls the `struct ClientState` with the `msg` to transmit
247 */
248static void
249transmit_ready (void *cls)
250{
251 struct ClientState *cstate = cls;
252 ssize_t ret;
253 size_t len;
254 const char *pos;
255 int notify_in_flight;
256
257 cstate->send_task = NULL;
258 if (GNUNET_YES == cstate->in_destroy)
259 return;
260 pos = (const char *) cstate->msg;
261 len = ntohs (cstate->msg->size);
262 GNUNET_assert (cstate->msg_off < len);
263 LOG (GNUNET_ERROR_TYPE_DEBUG,
264 "message of type %u trying to send with socket %p (MQ: %p\n",
265 ntohs (cstate->msg->type),
266 cstate->sock,
267 cstate->mq);
268
269RETRY:
270 ret = GNUNET_NETWORK_socket_send (cstate->sock,
271 &pos[cstate->msg_off],
272 len - cstate->msg_off);
273 if ( (-1 == ret) &&
274 ( (EAGAIN == errno) ||
275 (EINTR == errno) ) )
276 {
277 /* ignore */
278 ret = 0;
279 }
280 if (-1 == ret)
281 {
282 LOG (GNUNET_ERROR_TYPE_WARNING,
283 "Error during sending message of type %u: %s\n",
284 ntohs (cstate->msg->type),
285 strerror (errno));
286 if (EINTR == errno)
287 {
288 LOG (GNUNET_ERROR_TYPE_DEBUG,
289 "Retrying message of type %u\n",
290 ntohs (cstate->msg->type));
291 goto RETRY;
292 }
293 GNUNET_MQ_inject_error (cstate->mq,
294 GNUNET_MQ_ERROR_WRITE);
295 return;
296 }
297 notify_in_flight = (0 == cstate->msg_off);
298 cstate->msg_off += ret;
299 if (cstate->msg_off < len)
300 {
301 LOG (GNUNET_ERROR_TYPE_DEBUG,
302 "rescheduling message of type %u\n",
303 ntohs (cstate->msg->type));
304 cstate->send_task
305 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
306 cstate->sock,
307 &transmit_ready,
308 cstate);
309 if (notify_in_flight)
310 GNUNET_MQ_impl_send_in_flight (cstate->mq);
311 return;
312 }
313 LOG (GNUNET_ERROR_TYPE_DEBUG,
314 "sending message of type %u successful\n",
315 ntohs (cstate->msg->type));
316 cstate->msg = NULL;
317 GNUNET_MQ_impl_send_continue (cstate->mq);
318}
319
320
321/**
322 * We have received a full message, pass to the MQ dispatcher.
323 * Called by the tokenizer via #receive_ready().
324 *
325 * @param cls the `struct ClientState`
326 * @param msg message we received.
327 * @return #GNUNET_OK on success,
328 * #GNUNET_NO to stop further processing due to disconnect (no error)
329 * #GNUNET_SYSERR to stop further processing due to error
330 */
331static int
332recv_message (void *cls,
333 const struct GNUNET_MessageHeader *msg)
334{
335 struct ClientState *cstate = cls;
336
337 if (GNUNET_YES == cstate->in_destroy)
338 return GNUNET_NO;
339 LOG (GNUNET_ERROR_TYPE_DEBUG,
340 "Received message of type %u and size %u from %s\n",
341 ntohs (msg->type),
342 ntohs (msg->size),
343 cstate->service_name);
344 GNUNET_MQ_inject_message (cstate->mq,
345 msg);
346 if (GNUNET_YES == cstate->in_destroy)
347 return GNUNET_NO;
348 return GNUNET_OK;
349}
350
351
352/**
353 * Cancel all remaining connect attempts
354 *
355 * @param cstate handle of the client state to process
356 */
357static void
358cancel_aps (struct ClientState *cstate)
359{
360 struct AddressProbe *pos;
361
362 while (NULL != (pos = cstate->ap_head))
363 {
364 GNUNET_break (GNUNET_OK ==
365 GNUNET_NETWORK_socket_close (pos->sock));
366 GNUNET_SCHEDULER_cancel (pos->task);
367 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
368 cstate->ap_tail,
369 pos);
370 GNUNET_free (pos);
371 }
372}
373
374
375/**
376 * Implement the destruction of a message queue. Implementations must
377 * not free @a mq, but should take care of @a impl_state.
378 *
379 * @param mq the message queue to destroy
380 * @param impl_state our `struct ClientState`
381 */
382static void
383connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
384 void *impl_state)
385{
386 struct ClientState *cstate = impl_state;
387
388 (void) mq;
389 if (NULL != cstate->dns_active)
390 {
391 GNUNET_RESOLVER_request_cancel (cstate->dns_active);
392 cstate->dns_active = NULL;
393 }
394 if (NULL != cstate->send_task)
395 {
396 GNUNET_SCHEDULER_cancel (cstate->send_task);
397 cstate->send_task = NULL;
398 }
399 if (NULL != cstate->retry_task)
400 {
401 GNUNET_SCHEDULER_cancel (cstate->retry_task);
402 cstate->retry_task = NULL;
403 }
404 if (GNUNET_SYSERR == cstate->in_destroy)
405 {
406 /* defer destruction */
407 cstate->in_destroy = GNUNET_YES;
408 cstate->mq = NULL;
409 return;
410 }
411 if (NULL != cstate->recv_task)
412 {
413 GNUNET_SCHEDULER_cancel (cstate->recv_task);
414 cstate->recv_task = NULL;
415 }
416 if (NULL != cstate->sock)
417 {
418 LOG (GNUNET_ERROR_TYPE_DEBUG,
419 "destroying socket: %p\n",
420 cstate->sock);
421 GNUNET_NETWORK_socket_close (cstate->sock);
422 }
423 cancel_aps (cstate);
424 GNUNET_free (cstate->service_name);
425 GNUNET_free (cstate->hostname);
426 GNUNET_MST_destroy (cstate->mst);
427 GNUNET_free (cstate);
428}
429
430
431/**
432 * This function is called once we have data ready to read.
433 *
434 * @param cls `struct ClientState` with connection to read from
435 */
436static void
437receive_ready (void *cls)
438{
439 struct ClientState *cstate = cls;
440 int ret;
441
442 cstate->recv_task = NULL;
443 cstate->in_destroy = GNUNET_SYSERR;
444 ret = GNUNET_MST_read (cstate->mst,
445 cstate->sock,
446 GNUNET_NO,
447 GNUNET_NO);
448 if (GNUNET_SYSERR == ret)
449 {
450 if (NULL != cstate->mq)
451 GNUNET_MQ_inject_error (cstate->mq,
452 GNUNET_MQ_ERROR_READ);
453 if (GNUNET_YES == cstate->in_destroy)
454 connection_client_destroy_impl (cstate->mq,
455 cstate);
456 return;
457 }
458 if (GNUNET_YES == cstate->in_destroy)
459 {
460 connection_client_destroy_impl (cstate->mq,
461 cstate);
462 return;
463 }
464 cstate->in_destroy = GNUNET_NO;
465 cstate->recv_task
466 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
467 cstate->sock,
468 &receive_ready,
469 cstate);
470}
471
472
473/**
474 * We've succeeded in establishing a connection.
475 *
476 * @param cstate the connection we tried to establish
477 */
478static void
479connect_success_continuation (struct ClientState *cstate)
480{
481 GNUNET_assert (NULL == cstate->recv_task);
482 cstate->recv_task
483 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
484 cstate->sock,
485 &receive_ready,
486 cstate);
487 if (NULL != cstate->msg)
488 {
489 GNUNET_assert (NULL == cstate->send_task);
490 cstate->send_task
491 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
492 cstate->sock,
493 &transmit_ready,
494 cstate);
495 }
496}
497
498
499/**
500 * Try connecting to the server using UNIX domain sockets.
501 *
502 * @param service_name name of service to connect to
503 * @param cfg configuration to use
504 * @return NULL on error, socket connected to UNIX otherwise
505 */
506static struct GNUNET_NETWORK_Handle *
507try_unixpath (const char *service_name,
508 const struct GNUNET_CONFIGURATION_Handle *cfg)
509{
510#if AF_UNIX
511 struct GNUNET_NETWORK_Handle *sock;
512 char *unixpath;
513 struct sockaddr_un s_un;
514
515 unixpath = NULL;
516 if ((GNUNET_OK ==
517 GNUNET_CONFIGURATION_get_value_filename (cfg,
518 service_name,
519 "UNIXPATH",
520 &unixpath)) &&
521 (0 < strlen (unixpath)))
522 {
523 /* We have a non-NULL unixpath, need to validate it */
524 if (strlen (unixpath) >= sizeof(s_un.sun_path))
525 {
526 LOG (GNUNET_ERROR_TYPE_WARNING,
527 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
528 unixpath,
529 (unsigned long long) sizeof(s_un.sun_path));
530 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
531 LOG (GNUNET_ERROR_TYPE_INFO,
532 _ ("Using `%s' instead\n"),
533 unixpath);
534 if (NULL == unixpath)
535 return NULL;
536 }
537 memset (&s_un,
538 0,
539 sizeof(s_un));
540 s_un.sun_family = AF_UNIX;
541 GNUNET_strlcpy (s_un.sun_path,
542 unixpath,
543 sizeof(s_un.sun_path));
544#if HAVE_SOCKADDR_UN_SUN_LEN
545 s_un.sun_len = (u_char) sizeof(struct sockaddr_un);
546#endif
547 sock = GNUNET_NETWORK_socket_create (AF_UNIX,
548 SOCK_STREAM,
549 0);
550 if ((NULL != sock) &&
551 ((GNUNET_OK ==
552 GNUNET_NETWORK_socket_connect (sock,
553 (struct sockaddr *) &s_un,
554 sizeof(s_un))) ||
555 (EINPROGRESS == errno)))
556 {
557 LOG (GNUNET_ERROR_TYPE_DEBUG,
558 "Successfully connected to unixpath `%s'!\n",
559 unixpath);
560 GNUNET_free (unixpath);
561 return sock;
562 }
563 if (NULL != sock)
564 GNUNET_NETWORK_socket_close (sock);
565 }
566 GNUNET_free (unixpath);
567#endif
568 return NULL;
569}
570
571
572/**
573 * Scheduler let us know that we're either ready to write on the
574 * socket OR connect timed out. Do the right thing.
575 *
576 * @param cls the `struct AddressProbe *` with the address that we are probing
577 */
578static void
579connect_probe_continuation (void *cls)
580{
581 struct AddressProbe *ap = cls;
582 struct ClientState *cstate = ap->cstate;
583 const struct GNUNET_SCHEDULER_TaskContext *tc;
584 int error;
585 socklen_t len;
586
587 ap->task = NULL;
588 GNUNET_assert (NULL != ap->sock);
589 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
590 cstate->ap_tail,
591 ap);
592 len = sizeof(error);
593 error = 0;
594 tc = GNUNET_SCHEDULER_get_task_context ();
595 if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
596 (GNUNET_OK !=
597 GNUNET_NETWORK_socket_getsockopt (ap->sock,
598 SOL_SOCKET,
599 SO_ERROR,
600 &error,
601 &len)) ||
602 (0 != error))
603 {
604 GNUNET_break (GNUNET_OK ==
605 GNUNET_NETWORK_socket_close (ap->sock));
606 GNUNET_free (ap);
607 if ((NULL == cstate->ap_head) &&
608 // (NULL == cstate->proxy_handshake) &&
609 (NULL == cstate->dns_active))
610 connect_fail_continuation (cstate);
611 return;
612 }
613 LOG (GNUNET_ERROR_TYPE_DEBUG,
614 "Connection to `%s' succeeded!\n",
615 cstate->service_name);
616 /* trigger jobs that waited for the connection */
617 GNUNET_assert (NULL == cstate->sock);
618 cstate->sock = ap->sock;
619 GNUNET_free (ap);
620 cancel_aps (cstate);
621 connect_success_continuation (cstate);
622}
623
624
625/**
626 * Try to establish a connection given the specified address.
627 * This function is called by the resolver once we have a DNS reply.
628 *
629 * @param cls our `struct ClientState *`
630 * @param addr address to try, NULL for "last call"
631 * @param addrlen length of @a addr
632 */
633static void
634try_connect_using_address (void *cls,
635 const struct sockaddr *addr,
636 socklen_t addrlen)
637{
638 struct ClientState *cstate = cls;
639 struct AddressProbe *ap;
640
641 if (NULL == addr)
642 {
643 cstate->dns_active = NULL;
644 if ((NULL == cstate->ap_head) &&
645 // (NULL == cstate->proxy_handshake) &&
646 (NULL == cstate->sock))
647 connect_fail_continuation (cstate);
648 return;
649 }
650 if (NULL != cstate->sock)
651 return; /* already connected */
652 /* try to connect */
653 LOG (GNUNET_ERROR_TYPE_DEBUG,
654 "Trying to connect using address `%s:%u'\n",
655 GNUNET_a2s (addr,
656 addrlen),
657 (unsigned int) cstate->port);
658 ap = GNUNET_malloc (sizeof(struct AddressProbe) + addrlen);
659 ap->addr = (const struct sockaddr *) &ap[1];
660 GNUNET_memcpy (&ap[1],
661 addr,
662 addrlen);
663 ap->addrlen = addrlen;
664 ap->cstate = cstate;
665
666 switch (ap->addr->sa_family)
667 {
668 case AF_INET:
669 ((struct sockaddr_in *) ap->addr)->sin_port = htons (cstate->port);
670 break;
671
672 case AF_INET6:
673 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (cstate->port);
674 break;
675
676 default:
677 GNUNET_break (0);
678 GNUNET_free (ap);
679 return; /* not supported by us */
680 }
681 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
682 SOCK_STREAM,
683 0);
684 if (NULL == ap->sock)
685 {
686 GNUNET_free (ap);
687 return; /* not supported by OS */
688 }
689 if ((GNUNET_OK !=
690 GNUNET_NETWORK_socket_connect (ap->sock,
691 ap->addr,
692 ap->addrlen)) &&
693 (EINPROGRESS != errno))
694 {
695 /* maybe refused / unsupported address, try next */
696 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
697 "connect");
698 GNUNET_break (GNUNET_OK ==
699 GNUNET_NETWORK_socket_close (ap->sock));
700 GNUNET_free (ap);
701 return;
702 }
703 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
704 cstate->ap_tail,
705 ap);
706 ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
707 ap->sock,
708 &connect_probe_continuation,
709 ap);
710}
711
712
713/**
714 * Test whether the configuration has proper values for connection
715 * (UNIXPATH || (PORT && HOSTNAME)).
716 *
717 * @param service_name name of service to connect to
718 * @param cfg configuration to use
719 * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
720 */
721static int
722test_service_configuration (const char *service_name,
723 const struct GNUNET_CONFIGURATION_Handle *cfg)
724{
725 int ret = GNUNET_SYSERR;
726 char *hostname = NULL;
727 unsigned long long port;
728
729#if AF_UNIX
730 char *unixpath = NULL;
731
732 if ((GNUNET_OK ==
733 GNUNET_CONFIGURATION_get_value_filename (cfg,
734 service_name,
735 "UNIXPATH",
736 &unixpath)) &&
737 (0 < strlen (unixpath)))
738 ret = GNUNET_OK;
739 else if ((GNUNET_OK ==
740 GNUNET_CONFIGURATION_have_value (cfg,
741 service_name,
742 "UNIXPATH")))
743 {
744 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
745 service_name,
746 "UNIXPATH",
747 _ ("not a valid filename"));
748 GNUNET_free (unixpath);
749 return GNUNET_SYSERR; /* UNIXPATH specified but invalid! */
750 }
751 GNUNET_free (unixpath);
752#endif
753
754 if ((GNUNET_YES ==
755 GNUNET_CONFIGURATION_have_value (cfg,
756 service_name,
757 "PORT")) &&
758 (GNUNET_OK ==
759 GNUNET_CONFIGURATION_get_value_number (cfg,
760 service_name,
761 "PORT",
762 &port)) &&
763 (port <= 65535) &&
764 (0 != port) &&
765 (GNUNET_OK ==
766 GNUNET_CONFIGURATION_get_value_string (cfg,
767 service_name,
768 "HOSTNAME",
769 &hostname)) &&
770 (0 != strlen (hostname)))
771 ret = GNUNET_OK;
772 GNUNET_free (hostname);
773 return ret;
774}
775
776
777/**
778 * Try to connect to the service.
779 *
780 * @param cls the `struct ClientState` to try to connect to the service
781 */
782static void
783start_connect (void *cls)
784{
785 struct ClientState *cstate = cls;
786
787 cstate->retry_task = NULL;
788#if 0
789 /* Never use a local source if a proxy is configured */
790 if (GNUNET_YES ==
791 GNUNET_SOCKS_check_service (cstate->service_name,
792 cstate->cfg))
793 {
794 socks_connect (cstate);
795 return;
796 }
797#endif
798
799 if ((0 == (cstate->attempts++ % 2)) ||
800 (0 == cstate->port) ||
801 (NULL == cstate->hostname))
802 {
803 /* on even rounds, try UNIX first, or always
804 if we do not have a DNS name and TCP port. */
805 cstate->sock = try_unixpath (cstate->service_name,
806 cstate->cfg);
807 if (NULL != cstate->sock)
808 {
809 connect_success_continuation (cstate);
810 return;
811 }
812 }
813 if ((NULL == cstate->hostname) ||
814 (0 == cstate->port))
815 {
816 /* All options failed. Boo! */
817 connect_fail_continuation (cstate);
818 return;
819 }
820 cstate->dns_active
821 = GNUNET_RESOLVER_ip_get (cstate->hostname,
822 AF_UNSPEC,
823 CONNECT_RETRY_TIMEOUT,
824 &try_connect_using_address,
825 cstate);
826}
827
828
829/**
830 * Implements the transmission functionality of a message queue.
831 *
832 * @param mq the message queue
833 * @param msg the message to send
834 * @param impl_state our `struct ClientState`
835 */
836static void
837connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
838 const struct GNUNET_MessageHeader *msg,
839 void *impl_state)
840{
841 struct ClientState *cstate = impl_state;
842
843 (void) mq;
844 /* only one message at a time allowed */
845 GNUNET_assert (NULL == cstate->msg);
846 GNUNET_assert (NULL == cstate->send_task);
847 cstate->msg = msg;
848 cstate->msg_off = 0;
849 if (NULL == cstate->sock)
850 {
851 LOG (GNUNET_ERROR_TYPE_DEBUG,
852 "message of type %u waiting for socket\n",
853 ntohs (msg->type));
854 return; /* still waiting for connection */
855 }
856 cstate->send_task
857 = GNUNET_SCHEDULER_add_now (&transmit_ready,
858 cstate);
859}
860
861
862/**
863 * Cancel the currently sent message.
864 *
865 * @param mq message queue
866 * @param impl_state our `struct ClientState`
867 */
868static void
869connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
870 void *impl_state)
871{
872 struct ClientState *cstate = impl_state;
873
874 (void) mq;
875 GNUNET_assert (NULL != cstate->msg);
876 GNUNET_assert (0 == cstate->msg_off);
877 cstate->msg = NULL;
878 if (NULL != cstate->send_task)
879 {
880 GNUNET_SCHEDULER_cancel (cstate->send_task);
881 cstate->send_task = NULL;
882 }
883}
884
885
886/**
887 * Test if the port or UNIXPATH of the given @a service_name
888 * is in use and thus (most likely) the respective service is up.
889 *
890 * @param cfg our configuration
891 * @param service_name name of the service to connect to
892 * @return #GNUNET_YES if the service is (likely) up,
893 * #GNUNET_NO if the service is (definitively) down,
894 * #GNUNET_SYSERR if the configuration does not give us
895 * the necessary information about the service, or if
896 * we could not check (e.g. socket() failed)
897 */
898int
899GNUNET_CLIENT_test (const struct GNUNET_CONFIGURATION_Handle *cfg,
900 const char *service_name)
901{
902 char *hostname = NULL;
903 unsigned long long port;
904 int ret;
905
906#if AF_UNIX
907 {
908 char *unixpath = NULL;
909
910 if (GNUNET_OK ==
911 GNUNET_CONFIGURATION_get_value_filename (cfg,
912 service_name,
913 "UNIXPATH",
914 &unixpath))
915 {
916 if (0 == strlen (unixpath))
917 {
918 GNUNET_free (unixpath);
919 return GNUNET_SYSERR; /* empty string not OK */
920 }
921 if (0 == access (unixpath,
922 F_OK))
923 {
924 GNUNET_free (unixpath);
925 return GNUNET_OK; /* file exists, we assume service is running */
926 }
927 GNUNET_free (unixpath);
928 }
929 else if (GNUNET_OK ==
930 GNUNET_CONFIGURATION_have_value (cfg,
931 service_name,
932 "UNIXPATH"))
933 {
934 /* UNIXPATH specified but not a valid path! */
935 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
936 service_name,
937 "UNIXPATH",
938 _ ("not a valid filename"));
939 return GNUNET_SYSERR;
940 }
941 }
942#endif
943
944 if ( (GNUNET_OK !=
945 GNUNET_CONFIGURATION_get_value_number (cfg,
946 service_name,
947 "PORT",
948 &port)) ||
949 (port > 65535) ||
950 (0 == port) )
951 {
952 return GNUNET_SYSERR;
953 }
954 if (GNUNET_OK ==
955 GNUNET_CONFIGURATION_get_value_string (cfg,
956 service_name,
957 "HOSTNAME",
958 &hostname))
959 {
960 /* We always assume remotes are up */
961 ret = GNUNET_YES;
962 }
963 else
964 {
965 /* We look for evidence the service is up */
966 ret = GNUNET_NO;
967 }
968 if ( (NULL == hostname) ||
969 (0 == strcasecmp (hostname,
970 "localhost")) ||
971 (0 == strcasecmp (hostname,
972 "ip6-localnet")) )
973 {
974 /* service runs on loopback */
975 struct sockaddr_in v4;
976 struct sockaddr_in6 v6;
977 int sock;
978
979 memset (&v4, 0, sizeof (v4));
980 memset (&v6, 0, sizeof (v6));
981 v4.sin_family = AF_INET;
982 v4.sin_port = htons ((uint16_t) port);
983#if HAVE_SOCKADDR_IN_SUN_LEN
984 v4.sin_len = (u_char) sizeof(struct sockaddr_in);
985#endif
986 inet_pton (AF_INET,
987 "127.0.0.1",
988 &v4.sin_addr);
989 ret = GNUNET_NO;
990 sock = socket (AF_INET,
991 SOCK_STREAM,
992 0);
993 if (-1 != sock)
994 {
995 if (0 != bind (sock,
996 (struct sockaddr *) &v4,
997 sizeof (v4)))
998 {
999 /* bind failed, so someone is listening! */
1000 ret = GNUNET_YES;
1001 }
1002 (void) close (sock);
1003 }
1004 else
1005 {
1006 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1007 "socket");
1008 if (GNUNET_NO == ret)
1009 ret = GNUNET_SYSERR;
1010 }
1011 v6.sin6_family = AF_INET6;
1012 v6.sin6_port = htons ((uint16_t) port);
1013#if HAVE_SOCKADDR_IN_SUN_LEN
1014 v6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
1015#endif
1016 inet_pton (AF_INET6,
1017 "::1",
1018 &v6.sin6_addr);
1019 sock = socket (AF_INET6,
1020 SOCK_STREAM,
1021 0);
1022 if (-1 != sock)
1023 {
1024 if (0 != bind (sock,
1025 (struct sockaddr *) &v6,
1026 sizeof (v6)))
1027 {
1028 /* bind failed, so someone is listening! */
1029 ret = GNUNET_YES;
1030 }
1031 (void) close (sock);
1032 }
1033 else
1034 {
1035 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1036 "socket");
1037 /* not changing 'ret' intentionally here, as
1038 v4 succeeding and v6 failing just means we
1039 should use v4 */
1040 }
1041 }
1042 else
1043 {
1044 /* service running remotely */
1045 ret = GNUNET_OK;
1046 }
1047 GNUNET_free (hostname);
1048 return ret;
1049}
1050
1051
1052/**
1053 * Create a message queue to connect to a GNUnet service.
1054 * If handlers are specified, receive messages from the connection.
1055 *
1056 * @param cfg our configuration
1057 * @param service_name name of the service to connect to
1058 * @param handlers handlers for receiving messages, can be NULL
1059 * @param error_handler error handler
1060 * @param error_handler_cls closure for the @a error_handler
1061 * @return the message queue, NULL on error
1062 */
1063struct GNUNET_MQ_Handle *
1064GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1065 const char *service_name,
1066 const struct GNUNET_MQ_MessageHandler *handlers,
1067 GNUNET_MQ_ErrorHandler error_handler,
1068 void *error_handler_cls)
1069{
1070 struct ClientState *cstate;
1071
1072 if (GNUNET_OK !=
1073 test_service_configuration (service_name,
1074 cfg))
1075 return NULL;
1076 cstate = GNUNET_new (struct ClientState);
1077 cstate->service_name = GNUNET_strdup (service_name);
1078 cstate->cfg = cfg;
1079 cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
1080 cstate);
1081 cstate->mst = GNUNET_MST_create (&recv_message,
1082 cstate);
1083 if (GNUNET_YES ==
1084 GNUNET_CONFIGURATION_have_value (cfg,
1085 service_name,
1086 "PORT"))
1087 {
1088 if (! ((GNUNET_OK !=
1089 GNUNET_CONFIGURATION_get_value_number (cfg,
1090 service_name,
1091 "PORT",
1092 &cstate->port)) ||
1093 (cstate->port > 65535) ||
1094 (GNUNET_OK !=
1095 GNUNET_CONFIGURATION_get_value_string (cfg,
1096 service_name,
1097 "HOSTNAME",
1098 &cstate->hostname))) &&
1099 (0 == strlen (cstate->hostname)))
1100 {
1101 GNUNET_free (cstate->hostname);
1102 cstate->hostname = NULL;
1103 LOG (GNUNET_ERROR_TYPE_WARNING,
1104 _ ("Need a non-empty hostname for service `%s'.\n"),
1105 service_name);
1106 }
1107 }
1108 cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
1109 &connection_client_destroy_impl,
1110 &connection_client_cancel_impl,
1111 cstate,
1112 handlers,
1113 error_handler,
1114 error_handler_cls);
1115 return cstate->mq;
1116}
1117
1118
1119/* end of client.c */
diff --git a/src/util/common_allocation.c b/src/util/common_allocation.c
deleted file mode 100644
index f48f87167..000000000
--- a/src/util/common_allocation.c
+++ /dev/null
@@ -1,520 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2005, 2006 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 util/common_allocation.c
23 * @brief wrapper around malloc/free
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_crypto_lib.h"
28#if HAVE_MALLOC_H
29#include <malloc.h>
30#endif
31#if HAVE_MALLOC_MALLOC_H
32#include <malloc/malloc.h>
33#endif
34
35#define LOG(kind, ...) \
36 GNUNET_log_from (kind, "util-common-allocation", __VA_ARGS__)
37
38#define LOG_STRERROR(kind, syscall) \
39 GNUNET_log_from_strerror (kind, "util-common-allocation", syscall)
40
41#ifndef INT_MAX
42#define INT_MAX 0x7FFFFFFF
43#endif
44
45
46/**
47 * Allocate memory. Checks the return value, aborts if no more
48 * memory is available.
49 *
50 * @param size how many bytes of memory to allocate, do NOT use
51 * this function (or GNUNET_malloc()) to allocate more than several MB
52 * of memory, if you are possibly needing a very large chunk use
53 * #GNUNET_xmalloc_unchecked_() instead.
54 * @param filename where in the code was the call to GNUNET_malloc()
55 * @param linenumber where in the code was the call to GNUNET_malloc()
56 * @return pointer to size bytes of memory
57 */
58void *
59GNUNET_xmalloc_ (size_t size, const char *filename, int linenumber)
60{
61 void *ret;
62
63 /* As a security precaution, we generally do not allow very large
64 * allocations using the default 'GNUNET_malloc()' macro */
65 GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber);
66 ret = GNUNET_xmalloc_unchecked_ (size, filename, linenumber);
67 if (NULL == ret)
68 {
69 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc");
70 GNUNET_assert (0);
71 }
72 return ret;
73}
74
75
76/**
77 * Allocate memory for a two dimensional array in one block
78 * and set up pointers. Aborts if no more memory is available.
79 * Don't use GNUNET_xnew_array_2d_ directly. Use the
80 * #GNUNET_new_array_2d macro.
81 * The memory of the elements will be zero'ed out.
82 *
83 * @param n size of the first dimension
84 * @param m size of the second dimension
85 * @param elementSize size of a single element in bytes
86 * @param filename where is this call being made (for debugging)
87 * @param linenumber line where this call is being made (for debugging)
88 * @return allocated memory, never NULL
89 */
90void **
91GNUNET_xnew_array_2d_ (size_t n,
92 size_t m,
93 size_t elementSize,
94 const char *filename,
95 int linenumber)
96{
97 /* use char pointer internally to avoid void pointer arithmetic warnings */
98 char **ret = GNUNET_xmalloc_ (n * sizeof(void *) /* 1. dim header */
99 + n * m * elementSize, /* element data */
100 filename,
101 linenumber);
102
103 for (size_t i = 0; i < n; i++)
104 ret[i] = (char *) ret /* base address */
105 + n * sizeof(void *) /* skip 1. dim header */
106 + i * m * elementSize; /* skip to 2. dim row header */
107 return (void **) ret;
108}
109
110
111/**
112 * Allocate memory for a three dimensional array in one block
113 * and set up pointers. Aborts if no more memory is available.
114 * Don't use GNUNET_xnew_array_3d_ directly. Use the
115 * #GNUNET_new_array_3d macro.
116 * The memory of the elements will be zero'ed out.
117 *
118 * @param n size of the first dimension
119 * @param m size of the second dimension
120 * @param o size of the third dimension
121 * @param elementSize size of a single element in bytes
122 * @param filename where is this call being made (for debugging)
123 * @param linenumber line where this call is being made (for debugging)
124 * @return allocated memory, never NULL
125 */
126void ***
127GNUNET_xnew_array_3d_ (size_t n,
128 size_t m,
129 size_t o,
130 size_t elementSize,
131 const char *filename,
132 int linenumber)
133{
134 /* use char pointer internally to avoid void pointer arithmetic warnings */
135 char ***ret = GNUNET_xmalloc_ (n * sizeof(void **) /* 1. dim header */
136 + n * m * sizeof(void *) /* 2. dim header */
137 + n * m * o * elementSize, /* element data */
138 filename,
139 linenumber);
140
141 for (size_t i = 0; i < n; i++)
142 {
143 /* need to cast to (char *) temporarily for byte level accuracy */
144 ret[i] = (char **) ((char *) ret /* base address */
145 + n * sizeof(void **) /* skip 1. dim header */
146 + i * m * sizeof(void *)); /* skip to 2. dim header */
147 for (size_t j = 0; j < m; j++)
148 ret[i][j] = (char *) ret /* base address */
149 + n * sizeof(void **) /* skip 1. dim header */
150 + n * m * sizeof(void *) /* skip 2. dim header */
151 + i * m * o * elementSize /* skip to 2. dim part */
152 + j * o * elementSize; /* skip to 3. dim row data */
153 }
154 return (void ***) ret;
155}
156
157
158/**
159 * Allocate and initialize memory. Checks the return value, aborts if no more
160 * memory is available. Don't use #GNUNET_xmemdup_() directly. Use the
161 * GNUNET_memdup() macro.
162 *
163 * @param buf buffer to initialize from (must contain size bytes)
164 * @param size number of bytes to allocate
165 * @param filename where is this call being made (for debugging)
166 * @param linenumber line where this call is being made (for debugging)
167 * @return allocated memory, never NULL
168 */
169void *
170GNUNET_xmemdup_ (const void *buf,
171 size_t size,
172 const char *filename,
173 int linenumber)
174{
175 void *ret;
176
177 /* As a security precaution, we generally do not allow very large
178 * allocations here */
179 GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber);
180 GNUNET_assert_at (size < INT_MAX, filename, linenumber);
181 ret = malloc (size);
182 if (ret == NULL)
183 {
184 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc");
185 GNUNET_assert (0);
186 }
187 GNUNET_memcpy (ret, buf, size);
188 return ret;
189}
190
191
192/**
193 * Wrapper around malloc(). Allocates size bytes of memory.
194 * The memory will be zero'ed out.
195 *
196 * @param size the number of bytes to allocate
197 * @param filename where in the code was the call to GNUNET_malloc_unchecked()
198 * @param linenumber where in the code was the call to GNUNET_malloc_unchecked()
199 * @return pointer to size bytes of memory, NULL if we do not have enough memory
200 */
201void *
202GNUNET_xmalloc_unchecked_ (size_t size, const char *filename, int linenumber)
203{
204 void *result;
205
206 (void) filename;
207 (void) linenumber;
208
209 result = malloc (size);
210 if (NULL == result)
211 return NULL;
212 memset (result, 0, size);
213
214 return result;
215}
216
217
218/**
219 * Reallocate memory. Checks the return value, aborts if no more
220 * memory is available.
221 * The content of the intersection of the new and old size will be unchanged.
222 *
223 * @param ptr the pointer to reallocate
224 * @param n how many bytes of memory to allocate
225 * @param filename where in the code was the call to GNUNET_realloc()
226 * @param linenumber where in the code was the call to GNUNET_realloc()
227 * @return pointer to size bytes of memory
228 */
229void *
230GNUNET_xrealloc_ (void *ptr, size_t n, const char *filename, int linenumber)
231{
232 (void) filename;
233 (void) linenumber;
234
235#if defined(M_SIZE)
236#if ENABLE_POISONING
237 {
238 uint64_t *base = ptr;
239 size_t s = M_SIZE (ptr);
240
241 if (s > n)
242 {
243 const uint64_t baadfood = GNUNET_ntohll (0xBAADF00DBAADF00DLL);
244 char *cbase = ptr;
245
246 GNUNET_memcpy (&cbase[n],
247 &baadfood,
248 GNUNET_MIN (8 - (n % 8),
249 s - n));
250 for (size_t i = 1 + (n + 7) / 8; i < s / 8; i++)
251 base[i] = baadfood;
252 GNUNET_memcpy (&base[s / 8],
253 &baadfood,
254 s % 8);
255 }
256 }
257#endif
258#endif
259 ptr = realloc (ptr, n);
260 if ((NULL == ptr) && (n > 0))
261 {
262 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "realloc");
263 GNUNET_assert (0);
264 }
265 return ptr;
266}
267
268
269#if __BYTE_ORDER == __LITTLE_ENDIAN
270#define BAADFOOD_STR "\x0D\xF0\xAD\xBA"
271#endif
272#if __BYTE_ORDER == __BIG_ENDIAN
273#define BAADFOOD_STR "\xBA\xAD\xF0\x0D"
274#endif
275
276#if HAVE_MALLOC_NP_H
277#include <malloc_np.h>
278#endif
279#if HAVE_MALLOC_USABLE_SIZE
280#define M_SIZE(p) malloc_usable_size (p)
281#elif HAVE_MALLOC_SIZE
282#define M_SIZE(p) malloc_size (p)
283#endif
284
285/**
286 * Free memory. Merely a wrapper for the case that we
287 * want to keep track of allocations.
288 *
289 * @param ptr the pointer to free
290 * @param filename where in the code was the call to GNUNET_free()
291 * @param linenumber where in the code was the call to GNUNET_free()
292 */
293void
294GNUNET_xfree_ (void *ptr,
295 const char *filename,
296 int linenumber)
297{
298 if (NULL == ptr)
299 return;
300#if defined(M_SIZE)
301#if ENABLE_POISONING
302 {
303 const uint64_t baadfood = GNUNET_ntohll (0xBAADF00DBAADF00DLL);
304 uint64_t *base = ptr;
305 size_t s = M_SIZE (ptr);
306
307 for (size_t i = 0; i < s / 8; i++)
308 base[i] = baadfood;
309 GNUNET_memcpy (&base[s / 8], &baadfood, s % 8);
310 }
311#endif
312#endif
313 free (ptr);
314}
315
316
317/**
318 * Dup a string (same semantics as strdup).
319 *
320 * @param str the string to dup
321 * @param filename where in the code was the call to GNUNET_strdup()
322 * @param linenumber where in the code was the call to GNUNET_strdup()
323 * @return `strdup(@a str)`
324 */
325char *
326GNUNET_xstrdup_ (const char *str, const char *filename, int linenumber)
327{
328 char *res;
329 size_t slen;
330
331 GNUNET_assert_at (str != NULL, filename, linenumber);
332 slen = strlen (str) + 1;
333 res = GNUNET_xmalloc_ (slen, filename, linenumber);
334 GNUNET_memcpy (res, str, slen);
335 return res;
336}
337
338
339#if ! HAVE_STRNLEN
340static size_t
341strnlen (const char *s, size_t n)
342{
343 const char *e;
344
345 e = memchr (s, '\0', n);
346 if (NULL == e)
347 return n;
348 return e - s;
349}
350
351
352#endif
353
354
355/**
356 * Dup partially a string (same semantics as strndup).
357 *
358 * @param str the string to dup
359 * @param len the length of the string to dup
360 * @param filename where in the code was the call to GNUNET_strndup()
361 * @param linenumber where in the code was the call to GNUNET_strndup()
362 * @return `strndup(@a str,@a len)`
363 */
364char *
365GNUNET_xstrndup_ (const char *str,
366 size_t len,
367 const char *filename,
368 int linenumber)
369{
370 char *res;
371
372 if (0 == len)
373 return GNUNET_strdup ("");
374 GNUNET_assert_at (NULL != str, filename, linenumber);
375 len = strnlen (str, len);
376 res = GNUNET_xmalloc_ (len + 1, filename, linenumber);
377 GNUNET_memcpy (res, str, len);
378 /* res[len] = '\0'; 'malloc' zeros out anyway */
379 return res;
380}
381
382
383/**
384 * Grow an array. Grows old by (*oldCount-newCount)*elementSize bytes
385 * and sets *oldCount to newCount.
386 *
387 * @param old address of the pointer to the array
388 * *old may be NULL
389 * @param elementSize the size of the elements of the array
390 * @param oldCount address of the number of elements in the *old array
391 * @param newCount number of elements in the new array, may be 0
392 * @param filename where in the code was the call to GNUNET_array_grow()
393 * @param linenumber where in the code was the call to GNUNET_array_grow()
394 */
395void
396GNUNET_xgrow_ (void **old,
397 size_t elementSize,
398 unsigned int *oldCount,
399 unsigned int newCount,
400 const char *filename,
401 int linenumber)
402{
403 void *tmp;
404 size_t size;
405
406 GNUNET_assert_at (INT_MAX / elementSize > newCount, filename, linenumber);
407 size = newCount * elementSize;
408 if (0 == size)
409 {
410 tmp = NULL;
411 }
412 else
413 {
414 tmp = GNUNET_xmalloc_ (size, filename, linenumber);
415 if (NULL != *old)
416 {
417 GNUNET_memcpy (tmp, *old, elementSize * GNUNET_MIN (*oldCount, newCount));
418 }
419 }
420
421 if (NULL != *old)
422 {
423 GNUNET_xfree_ (*old, filename, linenumber);
424 }
425 *old = tmp;
426 *oldCount = newCount;
427}
428
429
430/**
431 * Like asprintf(), just portable.
432 *
433 * @param buf set to a buffer of sufficient size (allocated, caller must free)
434 * @param format format string (see printf(), fprintf(), etc.)
435 * @param ... data for format string
436 * @return number of bytes in `*@a buf`, excluding 0-termination
437 */
438int
439GNUNET_asprintf (char **buf, const char *format, ...)
440{
441 int ret;
442 va_list args;
443
444 va_start (args, format);
445 ret = vsnprintf (NULL, 0, format, args);
446 va_end (args);
447 GNUNET_assert (ret >= 0);
448 *buf = GNUNET_malloc (ret + 1);
449 va_start (args, format);
450 ret = vsprintf (*buf, format, args);
451 va_end (args);
452 return ret;
453}
454
455
456/**
457 * Like snprintf(), just aborts if the buffer is of insufficient size.
458 *
459 * @param buf pointer to buffer that is written to
460 * @param size number of bytes in buf
461 * @param format format strings
462 * @param ... data for format string
463 * @return number of bytes written to buf or negative value on error
464 */
465int
466GNUNET_snprintf (char *buf, size_t size, const char *format, ...)
467{
468 int ret;
469 va_list args;
470
471 va_start (args, format);
472 ret = vsnprintf (buf, size, format, args);
473 va_end (args);
474 GNUNET_assert ((ret >= 0) && (((size_t) ret) < size));
475 return ret;
476}
477
478
479/**
480 * Create a copy of the given message.
481 *
482 * @param msg message to copy
483 * @return duplicate of the message
484 */
485struct GNUNET_MessageHeader *
486GNUNET_copy_message (const struct GNUNET_MessageHeader *msg)
487{
488 struct GNUNET_MessageHeader *ret;
489 uint16_t msize;
490
491 msize = ntohs (msg->size);
492 GNUNET_assert (msize >= sizeof(struct GNUNET_MessageHeader));
493 ret = GNUNET_malloc (msize);
494 GNUNET_memcpy (ret, msg, msize);
495 return ret;
496}
497
498
499/**
500 * Check that memory in @a a is all zeros. @a a must be a pointer.
501 *
502 * @param a pointer to @a n bytes which should be tested for the
503 * entire memory being zero'ed out.
504 * @param n number of bytes in @a to be tested
505 * @return GNUNET_YES if a is zero, GNUNET_NO otherwise
506 */
507enum GNUNET_GenericReturnValue
508GNUNET_is_zero_ (const void *a,
509 size_t n)
510{
511 const char *b = a;
512
513 for (size_t i = 0; i < n; i++)
514 if (b[i])
515 return GNUNET_NO;
516 return GNUNET_YES;
517}
518
519
520/* end of common_allocation.c */
diff --git a/src/util/common_endian.c b/src/util/common_endian.c
deleted file mode 100644
index d69cc1da5..000000000
--- a/src/util/common_endian.c
+++ /dev/null
@@ -1,104 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2004, 2006, 2012 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 util/common_endian.c
23 * @brief endian conversion helpers
24 * @author Christian Grothoff
25 * @author Gabor X Toth
26 */
27
28#include "platform.h"
29#include "gnunet_crypto_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-common-endian", __VA_ARGS__)
32
33
34#ifndef htonbe64
35uint64_t
36GNUNET_htonll (uint64_t n)
37{
38#if __BYTE_ORDER == __BIG_ENDIAN
39 return n;
40#elif __BYTE_ORDER == __LITTLE_ENDIAN
41 return (((uint64_t) htonl (n)) << 32) + htonl (n >> 32);
42#else
43 #error byteorder undefined
44#endif
45}
46
47
48#endif
49
50
51#ifndef be64toh
52uint64_t
53GNUNET_ntohll (uint64_t n)
54{
55#if __BYTE_ORDER == __BIG_ENDIAN
56 return n;
57#elif __BYTE_ORDER == __LITTLE_ENDIAN
58 return (((uint64_t) ntohl (n)) << 32) + ntohl (n >> 32);
59#else
60 #error byteorder undefined
61#endif
62}
63
64
65#endif
66
67
68/**
69 * Convert double to network-byte-order.
70 * @param d the value in network byte order
71 * @return the same value in host byte order
72 */
73double
74GNUNET_hton_double (double d)
75{
76 double res;
77 uint64_t *in = (uint64_t *) &d;
78 uint64_t *out = (uint64_t *) &res;
79
80 out[0] = GNUNET_htonll (in[0]);
81
82 return res;
83}
84
85
86/**
87 * Convert double to host-byte-order
88 * @param d the value in network byte order
89 * @return the same value in host byte order
90 */
91double
92GNUNET_ntoh_double (double d)
93{
94 double res;
95 uint64_t *in = (uint64_t *) &d;
96 uint64_t *out = (uint64_t *) &res;
97
98 out[0] = GNUNET_ntohll (in[0]);
99
100 return res;
101}
102
103
104/* end of common_endian.c */
diff --git a/src/util/common_logging.c b/src/util/common_logging.c
deleted file mode 100644
index cba37cd2f..000000000
--- a/src/util/common_logging.c
+++ /dev/null
@@ -1,1568 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006-2013 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 util/common_logging.c
23 * @brief error handling API
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_crypto_lib.h"
28#include "gnunet_disk_lib.h"
29#include "gnunet_strings_lib.h"
30#include <regex.h>
31
32
33/**
34 * After how many milliseconds do we always print
35 * that "message X was repeated N times"? Use 12h.
36 */
37#define BULK_DELAY_THRESHOLD (12 * 60 * 60 * 1000LL * 1000LL)
38
39/**
40 * After how many repetitions do we always print
41 * that "message X was repeated N times"? (even if
42 * we have not yet reached the delay threshold)
43 */
44#define BULK_REPEAT_THRESHOLD 1000
45
46/**
47 * How many characters do we use for matching of
48 * bulk messages?
49 */
50#define BULK_TRACK_SIZE 256
51
52/**
53 * How many characters do we use for matching of
54 * bulk components?
55 */
56#define COMP_TRACK_SIZE 32
57
58/**
59 * How many characters can a date/time string
60 * be at most?
61 */
62#define DATE_STR_SIZE 64
63
64/**
65 * How many log files to keep?
66 */
67#define ROTATION_KEEP 3
68
69#ifndef PATH_MAX
70/**
71 * Assumed maximum path length (for the log file name).
72 */
73#define PATH_MAX 4096
74#endif
75
76
77/**
78 * Linked list of active loggers.
79 */
80struct CustomLogger
81{
82 /**
83 * This is a linked list.
84 */
85 struct CustomLogger *next;
86
87 /**
88 * Log function.
89 */
90 GNUNET_Logger logger;
91
92 /**
93 * Closure for logger.
94 */
95 void *logger_cls;
96};
97
98
99/**
100 * Asynchronous scope of the current thread, or NULL if we have not
101 * entered an async scope yet.
102 */
103static GNUNET_THREAD_LOCAL struct GNUNET_AsyncScopeSave current_async_scope;
104
105/**
106 * The last "bulk" error message that we have been logging.
107 * Note that this message maybe truncated to the first BULK_TRACK_SIZE
108 * characters, in which case it is NOT 0-terminated!
109 */
110static GNUNET_THREAD_LOCAL char last_bulk[BULK_TRACK_SIZE] __nonstring;
111
112/**
113 * Type of the last bulk message.
114 */
115static GNUNET_THREAD_LOCAL enum GNUNET_ErrorType last_bulk_kind;
116
117/**
118 * Time of the last bulk error message (0 for none)
119 */
120static GNUNET_THREAD_LOCAL struct GNUNET_TIME_Absolute last_bulk_time;
121
122/**
123 * Number of times that bulk message has been repeated since.
124 */
125static GNUNET_THREAD_LOCAL unsigned int last_bulk_repeat;
126
127/**
128 * Component when the last bulk was logged. Will be 0-terminated.
129 */
130static GNUNET_THREAD_LOCAL char last_bulk_comp[COMP_TRACK_SIZE + 1];
131
132/**
133 * Running component.
134 */
135static char *component;
136
137/**
138 * Running component (without pid).
139 */
140static char *component_nopid;
141
142/**
143 * Format string describing the name of the log file.
144 */
145static char *log_file_name;
146
147/**
148 * Minimum log level.
149 */
150static enum GNUNET_ErrorType min_level;
151
152/**
153 * Linked list of our custom loggres.
154 */
155static struct CustomLogger *loggers;
156
157/**
158 * Number of log calls to ignore.
159 */
160static GNUNET_THREAD_LOCAL int skip_log = 0;
161
162/**
163 * File descriptor to use for "stderr", or NULL for none.
164 */
165static FILE *GNUNET_stderr;
166
167/**
168 * Represents a single logging definition
169 */
170struct LogDef
171{
172 /**
173 * Component name regex
174 */
175 regex_t component_regex;
176
177 /**
178 * File name regex
179 */
180 regex_t file_regex;
181
182 /**
183 * Function name regex
184 */
185 regex_t function_regex;
186
187 /**
188 * Lowest line at which this definition matches.
189 * Defaults to 0. Must be <= to_line.
190 */
191 int from_line;
192
193 /**
194 * Highest line at which this definition matches.
195 * Defaults to INT_MAX. Must be >= from_line.
196 */
197 int to_line;
198
199 /**
200 * Maximal log level allowed for calls that match this definition.
201 * Calls with higher log level will be disabled.
202 * Must be >= 0
203 */
204 int level;
205
206 /**
207 * 1 if this definition comes from GNUNET_FORCE_LOG, which means that it
208 * overrides any configuration options. 0 otherwise.
209 */
210 int force;
211};
212
213
214#if ! defined(GNUNET_CULL_LOGGING)
215/**
216 * Dynamic array of logging definitions
217 */
218static struct LogDef *logdefs;
219
220/**
221 * Allocated size of logdefs array (in units)
222 */
223static int logdefs_size;
224
225/**
226 * The number of units used in logdefs array.
227 */
228static int logdefs_len;
229
230/**
231 * #GNUNET_YES if GNUNET_LOG environment variable is already parsed.
232 */
233static int gnunet_log_parsed;
234
235/**
236 * #GNUNET_YES if GNUNET_FORCE_LOG environment variable is already parsed.
237 */
238static int gnunet_force_log_parsed;
239
240/**
241 * #GNUNET_YES if at least one definition with forced == 1 is available.
242 */
243static int gnunet_force_log_present;
244#endif
245
246
247/**
248 * Convert a textual description of a loglevel
249 * to the respective enumeration type.
250 *
251 * @param log loglevel to parse
252 * @return GNUNET_ERROR_TYPE_INVALID if log does not parse
253 */
254static enum GNUNET_ErrorType
255get_type (const char *log)
256{
257 if (NULL == log)
258 return GNUNET_ERROR_TYPE_UNSPECIFIED;
259 if (0 == strcasecmp (log, "DEBUG"))
260 return GNUNET_ERROR_TYPE_DEBUG;
261 if (0 == strcasecmp (log, "INFO"))
262 return GNUNET_ERROR_TYPE_INFO;
263 if (0 == strcasecmp (log, "MESSAGE"))
264 return GNUNET_ERROR_TYPE_MESSAGE;
265 if (0 == strcasecmp (log, "WARNING"))
266 return GNUNET_ERROR_TYPE_WARNING;
267 if (0 == strcasecmp (log, "ERROR"))
268 return GNUNET_ERROR_TYPE_ERROR;
269 if (0 == strcasecmp (log, "NONE"))
270 return GNUNET_ERROR_TYPE_NONE;
271 return GNUNET_ERROR_TYPE_INVALID;
272}
273
274
275/**
276 * Abort the process, generate a core dump if possible.
277 */
278void
279GNUNET_abort_ ()
280{
281 abort ();
282}
283
284
285#if ! defined(GNUNET_CULL_LOGGING)
286/**
287 * Utility function - reallocates logdefs array to be twice as large.
288 */
289static void
290resize_logdefs (void)
291{
292 logdefs_size = (logdefs_size + 1) * 2;
293 logdefs = GNUNET_realloc (logdefs, logdefs_size * sizeof(struct LogDef));
294}
295
296
297/**
298 * Rotate logs, deleting the oldest log.
299 *
300 * @param new_name new name to add to the rotation
301 */
302static void
303log_rotate (const char *new_name)
304{
305 static char *rotation[ROTATION_KEEP];
306 static unsigned int rotation_off;
307 char *discard;
308
309 if ('\0' == *new_name)
310 return; /* not a real log file name */
311 discard = rotation[rotation_off % ROTATION_KEEP];
312 if (NULL != discard)
313 {
314 /* Note: can't log errors during logging (recursion!), so this
315 operation MUST silently fail... */
316 (void) unlink (discard);
317 GNUNET_free (discard);
318 }
319 rotation[rotation_off % ROTATION_KEEP] = GNUNET_strdup (new_name);
320 rotation_off++;
321}
322
323
324/**
325 * Setup the log file.
326 *
327 * @param tm timestamp for which we should setup logging
328 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
329 */
330static int
331setup_log_file (const struct tm *tm)
332{
333 static char last_fn[PATH_MAX + 1];
334 char fn[PATH_MAX + 1];
335 int altlog_fd;
336 int dup_return;
337 FILE *altlog;
338 char *leftsquare;
339
340 if (NULL == log_file_name)
341 return GNUNET_SYSERR;
342 if (0 == strftime (fn, sizeof(fn), log_file_name, tm))
343 return GNUNET_SYSERR;
344 leftsquare = strrchr (fn, '[');
345 if ((NULL != leftsquare) && (']' == leftsquare[1]))
346 {
347 char *logfile_copy = GNUNET_strdup (fn);
348
349 logfile_copy[leftsquare - fn] = '\0';
350 logfile_copy[leftsquare - fn + 1] = '\0';
351 snprintf (fn,
352 PATH_MAX,
353 "%s%d%s",
354 logfile_copy,
355 getpid (),
356 &logfile_copy[leftsquare - fn + 2]);
357 GNUNET_free (logfile_copy);
358 }
359 if (0 == strcmp (fn, last_fn))
360 return GNUNET_OK; /* no change */
361 log_rotate (last_fn);
362 strcpy (last_fn, fn);
363 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (fn))
364 {
365 fprintf (stderr,
366 "Failed to create directory for `%s': %s\n",
367 fn,
368 strerror (errno));
369 return GNUNET_SYSERR;
370 }
371 altlog_fd = open (fn,
372 O_APPEND | O_WRONLY | O_CREAT,
373 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
374
375 if (-1 != altlog_fd)
376 {
377 if (NULL != GNUNET_stderr)
378 fclose (GNUNET_stderr);
379 dup_return = dup2 (altlog_fd, 2);
380 (void) close (altlog_fd);
381 if (-1 != dup_return)
382 {
383 altlog = fdopen (2, "ab");
384 if (NULL == altlog)
385 {
386 (void) close (2);
387 altlog_fd = -1;
388 }
389 }
390 else
391 {
392 altlog_fd = -1;
393 }
394 }
395 if (-1 == altlog_fd)
396 {
397 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
398 return GNUNET_SYSERR;
399 }
400 GNUNET_stderr = altlog;
401 return GNUNET_OK;
402}
403
404
405/**
406 * Utility function - adds a parsed definition to logdefs array.
407 *
408 * @param component see struct LogDef, can't be NULL
409 * @param file see struct LogDef, can't be NULL
410 * @param function see struct LogDef, can't be NULL
411 * @param from_line see struct LogDef
412 * @param to_line see struct LogDef
413 * @param level see struct LogDef, must be >= 0
414 * @param force see struct LogDef
415 * @return 0 on success, regex-specific error otherwise
416 */
417static int
418add_definition (const char *component,
419 const char *file,
420 const char *function,
421 int from_line,
422 int to_line,
423 int level,
424 int force)
425{
426 struct LogDef n;
427 int r;
428
429 if (logdefs_size == logdefs_len)
430 resize_logdefs ();
431 memset (&n, 0, sizeof(n));
432 if (0 == strlen (component))
433 component = (char *) ".*";
434 r = regcomp (&n.component_regex, (const char *) component, REG_NOSUB);
435 if (0 != r)
436 {
437 return r;
438 }
439 if (0 == strlen (file))
440 file = (char *) ".*";
441 r = regcomp (&n.file_regex, (const char *) file, REG_NOSUB);
442 if (0 != r)
443 {
444 regfree (&n.component_regex);
445 return r;
446 }
447 if ((NULL == function) || (0 == strlen (function)))
448 function = (char *) ".*";
449 r = regcomp (&n.function_regex, (const char *) function, REG_NOSUB);
450 if (0 != r)
451 {
452 regfree (&n.component_regex);
453 regfree (&n.file_regex);
454 return r;
455 }
456 n.from_line = from_line;
457 n.to_line = to_line;
458 n.level = level;
459 n.force = force;
460 logdefs[logdefs_len++] = n;
461 return 0;
462}
463
464
465/**
466 * Decides whether a particular logging call should or should not be allowed
467 * to be made. Used internally by GNUNET_log*()
468 *
469 * @param caller_level loglevel the caller wants to use
470 * @param comp component name the caller uses (NULL means that global
471 * component name is used)
472 * @param file file name containing the logging call, usually __FILE__
473 * @param function function which tries to make a logging call,
474 * usually __FUNCTION__
475 * @param line line at which the call is made, usually __LINE__
476 * @return 0 to disallow the call, 1 to allow it
477 */
478int
479GNUNET_get_log_call_status (int caller_level,
480 const char *comp,
481 const char *file,
482 const char *function,
483 int line)
484{
485 struct LogDef *ld;
486 int i;
487 int force_only;
488
489 if (NULL == comp)
490 /* Use default component */
491 comp = component_nopid;
492
493 /* We have no definitions to override globally configured log level,
494 * so just use it right away.
495 */
496 if ((min_level >= 0) && (GNUNET_NO == gnunet_force_log_present))
497 return caller_level <= min_level;
498
499 /* Only look for forced definitions? */
500 force_only = min_level >= 0;
501 for (i = 0; i < logdefs_len; i++)
502 {
503 ld = &logdefs[i];
504 if (((! force_only) || ld->force) &&
505 ((line >= ld->from_line) && (line <= ld->to_line) ) &&
506 (0 == regexec (&ld->component_regex, comp, 0, NULL, 0)) &&
507 (0 == regexec (&ld->file_regex, file, 0, NULL, 0)) &&
508 (0 == regexec (&ld->function_regex, function, 0, NULL, 0)))
509 {
510 /* We're finished */
511 return caller_level <= ld->level;
512 }
513 }
514 /* No matches - use global level, if defined */
515 if (min_level >= 0)
516 return caller_level <= min_level;
517 /* All programs/services previously defaulted to WARNING.
518 * Now *we* default to WARNING, and THEY default to NULL.
519 * Or rather we default to MESSAGE, since things aren't always bad.
520 */
521 return caller_level <= GNUNET_ERROR_TYPE_MESSAGE;
522}
523
524
525/**
526 * Utility function - parses a definition
527 *
528 * Definition format:
529 * component;file;function;from_line-to_line;level[/component...]
530 * All entries are mandatory, but may be empty.
531 * Empty entries for component, file and function are treated as
532 * "matches anything".
533 * Empty line entry is treated as "from 0 to INT_MAX"
534 * Line entry with only one line is treated as "this line only"
535 * Entry for level MUST NOT be empty.
536 * Entries for component, file and function that consist of a
537 * single character "*" are treated (at the moment) the same way
538 * empty entries are treated (wildcard matching is not implemented (yet?)).
539 * file entry is matched to the end of __FILE__. That is, it might be
540 * a base name, or a base name with leading directory names (some compilers
541 * define __FILE__ to absolute file path).
542 *
543 * @param constname name of the environment variable from which to get the
544 * string to be parsed
545 * @param force 1 if definitions found in constname are to be forced
546 * @return number of added definitions
547 */
548static int
549parse_definitions (const char *constname, int force)
550{
551 char *def;
552 const char *tmp;
553 char *comp = NULL;
554 char *file = NULL;
555 char *function = NULL;
556 char *p;
557 char *start;
558 char *t;
559 short state;
560 int level;
561 int from_line, to_line;
562 int counter = 0;
563 int keep_looking = 1;
564
565 tmp = getenv (constname);
566 if (NULL == tmp)
567 return 0;
568 def = GNUNET_strdup (tmp);
569 from_line = 0;
570 to_line = INT_MAX;
571 for (p = def, state = 0, start = def; keep_looking; p++)
572 {
573 switch (p[0])
574 {
575 case ';': /* found a field separator */
576 p[0] = '\0';
577 switch (state)
578 {
579 case 0: /* within a component name */
580 comp = start;
581 break;
582
583 case 1: /* within a file name */
584 file = start;
585 break;
586
587 case 2: /* within a function name */
588 /* after a file name there must be a function name */
589 function = start;
590 break;
591
592 case 3: /* within a from-to line range */
593 if (strlen (start) > 0)
594 {
595 errno = 0;
596 from_line = strtol (start, &t, 10);
597 if ((0 != errno) || (from_line < 0))
598 {
599 GNUNET_free (def);
600 return counter;
601 }
602 if ((t < p) && ('-' == t[0]))
603 {
604 errno = 0;
605 start = t + 1;
606 to_line = strtol (start, &t, 10);
607 if ((0 != errno) || (to_line < 0) || (t != p))
608 {
609 GNUNET_free (def);
610 return counter;
611 }
612 }
613 else /* one number means "match this line only" */
614 to_line = from_line;
615 }
616 else /* default to 0-max */
617 {
618 from_line = 0;
619 to_line = INT_MAX;
620 }
621 break;
622
623 default:
624 fprintf (
625 stderr,
626 _ ("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"),
627 p);
628 break;
629 }
630 start = p + 1;
631 state++;
632 break;
633
634 case '\0': /* found EOL */
635 keep_looking = 0;
636
637 /* fall through to '/' */
638 case '/': /* found a definition separator */
639 switch (state)
640 {
641 case 4: /* within a log level */
642 p[0] = '\0';
643 state = 0;
644 level = get_type ((const char *) start);
645 if ((GNUNET_ERROR_TYPE_INVALID == level) ||
646 (GNUNET_ERROR_TYPE_UNSPECIFIED == level) ||
647 (0 != add_definition (comp,
648 file,
649 function,
650 from_line,
651 to_line,
652 level,
653 force)))
654 {
655 GNUNET_free (def);
656 return counter;
657 }
658 counter++;
659 start = p + 1;
660 break;
661
662 default:
663 fprintf (
664 stderr,
665 _ ("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"),
666 p);
667 break;
668 }
669
670 default:
671 break;
672 }
673 }
674 GNUNET_free (def);
675 return counter;
676}
677
678
679/**
680 * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG.
681 */
682static void
683parse_all_definitions ()
684{
685 if (GNUNET_NO == gnunet_force_log_parsed)
686 gnunet_force_log_present =
687 parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO;
688 gnunet_force_log_parsed = GNUNET_YES;
689
690 if (GNUNET_NO == gnunet_log_parsed)
691 parse_definitions ("GNUNET_LOG", 0);
692 gnunet_log_parsed = GNUNET_YES;
693}
694
695
696#endif
697
698
699/**
700 * Setup logging.
701 *
702 * @param comp default component to use
703 * @param loglevel what types of messages should be logged
704 * @param logfile which file to write log messages to (can be NULL)
705 * @return #GNUNET_OK on success
706 */
707int
708GNUNET_log_setup (const char *comp,
709 const char *loglevel,
710 const char *logfile)
711{
712 const char *env_logfile;
713
714 min_level = get_type (loglevel);
715#if ! defined(GNUNET_CULL_LOGGING)
716 parse_all_definitions ();
717#endif
718 GNUNET_free (component);
719 GNUNET_asprintf (&component, "%s-%d", comp, getpid ());
720 GNUNET_free (component_nopid);
721 component_nopid = GNUNET_strdup (comp);
722
723 env_logfile = getenv ("GNUNET_FORCE_LOGFILE");
724 if ((NULL != env_logfile) && (strlen (env_logfile) > 0))
725 logfile = env_logfile;
726 if (NULL == logfile)
727 return GNUNET_OK;
728 GNUNET_free (log_file_name);
729 log_file_name = GNUNET_STRINGS_filename_expand (logfile);
730 if (NULL == log_file_name)
731 return GNUNET_SYSERR;
732#if defined(GNUNET_CULL_LOGGING)
733 /* log file option not allowed for wallet logic */
734 GNUNET_assert (NULL == logfile);
735 return GNUNET_OK;
736#else
737 {
738 time_t t;
739 const struct tm *tm;
740
741 t = time (NULL);
742 tm = gmtime (&t);
743 return setup_log_file (tm);
744 }
745#endif
746}
747
748
749/**
750 * Add a custom logger. Note that installing any custom logger
751 * will disable the standard logger. When multiple custom loggers
752 * are installed, all will be called. The standard logger will
753 * only be used if no custom loggers are present.
754 *
755 * @param logger log function
756 * @param logger_cls closure for @a logger
757 */
758void
759GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls)
760{
761 struct CustomLogger *entry;
762
763 entry = GNUNET_new (struct CustomLogger);
764 entry->logger = logger;
765 entry->logger_cls = logger_cls;
766 entry->next = loggers;
767 loggers = entry;
768}
769
770
771/**
772 * Remove a custom logger.
773 *
774 * @param logger log function
775 * @param logger_cls closure for @a logger
776 */
777void
778GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls)
779{
780 struct CustomLogger *pos;
781 struct CustomLogger *prev;
782
783 prev = NULL;
784 pos = loggers;
785 while ((NULL != pos) &&
786 ((pos->logger != logger) || (pos->logger_cls != logger_cls)))
787 {
788 prev = pos;
789 pos = pos->next;
790 }
791 GNUNET_assert (NULL != pos);
792 if (NULL == prev)
793 loggers = pos->next;
794 else
795 prev->next = pos->next;
796 GNUNET_free (pos);
797}
798
799
800/**
801 * Actually output the log message.
802 *
803 * @param kind how severe was the issue
804 * @param comp component responsible
805 * @param datestr current date/time
806 * @param msg the actual message
807 */
808static void
809output_message (enum GNUNET_ErrorType kind,
810 const char *comp,
811 const char *datestr,
812 const char *msg)
813{
814 struct CustomLogger *pos;
815
816 /* only use the standard logger if no custom loggers are present */
817 if ((NULL != GNUNET_stderr) && (NULL == loggers))
818 {
819 if (kind == GNUNET_ERROR_TYPE_MESSAGE)
820 {
821 /* The idea here is to produce "normal" output messages
822 * for end users while still having the power of the
823 * logging engine for developer needs. So ideally this
824 * is what it should look like when CLI tools are used
825 * interactively, yet the same message shouldn't look
826 * this way if the output is going to logfiles or robots
827 * instead.
828 */fprintf (GNUNET_stderr, "* %s", msg);
829 }
830 else if (GNUNET_YES == current_async_scope.have_scope)
831 {
832 static GNUNET_THREAD_LOCAL char id_buf[27];
833 char *end;
834
835 /* We're logging, so skip_log must be currently 0. */
836 skip_log = 100;
837 end = GNUNET_STRINGS_data_to_string (&current_async_scope.scope_id,
838 sizeof(struct GNUNET_AsyncScopeId),
839 id_buf,
840 sizeof(id_buf) - 1);
841 GNUNET_assert (NULL != end);
842 *end = '\0';
843 skip_log = 0;
844 fprintf (GNUNET_stderr,
845 "%s %s(%s) %s %s",
846 datestr,
847 comp,
848 id_buf,
849 GNUNET_error_type_to_string (kind),
850 msg);
851 }
852 else
853 {
854 fprintf (GNUNET_stderr,
855 "%s %s %s %s",
856 datestr,
857 comp,
858 GNUNET_error_type_to_string (kind),
859 msg);
860 }
861 fflush (GNUNET_stderr);
862 }
863 pos = loggers;
864 while (NULL != pos)
865 {
866 pos->logger (pos->logger_cls, kind, comp, datestr, msg);
867 pos = pos->next;
868 }
869}
870
871
872/**
873 * Flush an existing bulk report to the output.
874 *
875 * @param datestr our current timestamp
876 */
877static void
878flush_bulk (const char *datestr)
879{
880 char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256];
881 int rev;
882 char *last;
883 const char *ft;
884
885 if ((0 == last_bulk_time.abs_value_us) || (0 == last_bulk_repeat))
886 return;
887 rev = 0;
888 last = memchr (last_bulk, '\0', BULK_TRACK_SIZE);
889 if (last == NULL)
890 last = &last_bulk[BULK_TRACK_SIZE - 1];
891 else if (last != last_bulk)
892 last--;
893 if (last[0] == '\n')
894 {
895 rev = 1;
896 last[0] = '\0';
897 }
898 ft =
899 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (
900 last_bulk_time),
901 GNUNET_YES);
902 snprintf (msg,
903 sizeof(msg),
904 _ ("Message `%.*s' repeated %u times in the last %s\n"),
905 BULK_TRACK_SIZE,
906 last_bulk,
907 last_bulk_repeat,
908 ft);
909 if (rev == 1)
910 last[0] = '\n';
911 output_message (last_bulk_kind, last_bulk_comp, datestr, msg);
912 last_bulk_time = GNUNET_TIME_absolute_get ();
913 last_bulk_repeat = 0;
914}
915
916
917/**
918 * Ignore the next n calls to the log function.
919 *
920 * @param n number of log calls to ignore (could be negative)
921 * @param check_reset #GNUNET_YES to assert that the log skip counter is currently zero
922 */
923void
924GNUNET_log_skip (int n, int check_reset)
925{
926 int ok;
927
928 if (0 == n)
929 {
930 ok = (0 == skip_log);
931 skip_log = 0;
932 if (check_reset)
933 GNUNET_break (ok);
934 }
935 else
936 {
937 skip_log += n;
938 }
939}
940
941
942/**
943 * Get the number of log calls that are going to be skipped
944 *
945 * @return number of log calls to be ignored
946 */
947int
948GNUNET_get_log_skip ()
949{
950 return skip_log;
951}
952
953
954/**
955 * Output a log message using the default mechanism.
956 *
957 * @param kind how severe was the issue
958 * @param comp component responsible
959 * @param message the actual message
960 * @param va arguments to the format string "message"
961 */
962static void
963mylog (enum GNUNET_ErrorType kind,
964 const char *comp,
965 const char *message,
966 va_list va)
967{
968 char date[DATE_STR_SIZE];
969 char date2[DATE_STR_SIZE];
970 struct tm *tmptr;
971 size_t size;
972 va_list vacp;
973
974 va_copy (vacp, va);
975 size = vsnprintf (NULL, 0, message, vacp) + 1;
976 GNUNET_assert (0 != size);
977 va_end (vacp);
978 memset (date, 0, DATE_STR_SIZE);
979 {
980 char buf[size];
981 long long offset;
982
983 struct timeval timeofday;
984
985 gettimeofday (&timeofday, NULL);
986 offset = GNUNET_TIME_get_offset ();
987 if (offset > 0)
988 {
989 timeofday.tv_sec += offset / 1000LL;
990 timeofday.tv_usec += (offset % 1000LL) * 1000LL;
991 if (timeofday.tv_usec > 1000000LL)
992 {
993 timeofday.tv_usec -= 1000000LL;
994 timeofday.tv_sec++;
995 }
996 }
997 else
998 {
999 timeofday.tv_sec += offset / 1000LL;
1000 if (timeofday.tv_usec > -(offset % 1000LL) * 1000LL)
1001 {
1002 timeofday.tv_usec += (offset % 1000LL) * 1000LL;
1003 }
1004 else
1005 {
1006 timeofday.tv_usec += 1000000LL + (offset % 1000LL) * 1000LL;
1007 timeofday.tv_sec--;
1008 }
1009 }
1010 tmptr = localtime (&timeofday.tv_sec);
1011 if (NULL == tmptr)
1012 {
1013 strcpy (date, "localtime error");
1014 }
1015 else
1016 {
1017 /* RFC 3339 timestamp, with snprintf placeholder for microseconds */
1018 if (0 == strftime (date2, DATE_STR_SIZE, "%Y-%m-%dT%H:%M:%S.%%06u%z", tmptr))
1019 abort ();
1020 /* Fill in microseconds */
1021 if (0 > snprintf (date, sizeof(date), date2, timeofday.tv_usec))
1022 abort ();
1023 }
1024
1025 vsnprintf (buf, size, message, va);
1026#if ! defined(GNUNET_CULL_LOGGING)
1027 if (NULL != tmptr)
1028 (void) setup_log_file (tmptr);
1029#endif
1030 if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
1031 (0 != last_bulk_time.abs_value_us) &&
1032 (0 == strncmp (buf, last_bulk, sizeof(last_bulk))))
1033 {
1034 last_bulk_repeat++;
1035 if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value_us >
1036 BULK_DELAY_THRESHOLD) ||
1037 (last_bulk_repeat > BULK_REPEAT_THRESHOLD))
1038 flush_bulk (date);
1039 return;
1040 }
1041 flush_bulk (date);
1042 GNUNET_strlcpy (last_bulk, buf, sizeof(last_bulk));
1043 last_bulk_repeat = 0;
1044 last_bulk_kind = kind;
1045 last_bulk_time = GNUNET_TIME_absolute_get ();
1046 GNUNET_strlcpy (last_bulk_comp, comp, sizeof(last_bulk_comp));
1047 output_message (kind, comp, date, buf);
1048 }
1049}
1050
1051
1052/**
1053 * Main log function.
1054 *
1055 * @param kind how serious is the error?
1056 * @param message what is the message (format string)
1057 * @param ... arguments for format string
1058 */
1059void
1060GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...)
1061{
1062 va_list va;
1063
1064 va_start (va, message);
1065 mylog (kind, component, message, va);
1066 va_end (va);
1067}
1068
1069
1070/**
1071 * Log function that specifies an alternative component.
1072 * This function should be used by plugins.
1073 *
1074 * @param kind how serious is the error?
1075 * @param comp component responsible for generating the message
1076 * @param message what is the message (format string)
1077 * @param ... arguments for format string
1078 */
1079void
1080GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind,
1081 const char *comp,
1082 const char *message,
1083 ...)
1084{
1085 va_list va;
1086 char comp_w_pid[128];
1087
1088 if (comp == NULL)
1089 comp = component_nopid;
1090
1091 va_start (va, message);
1092 GNUNET_snprintf (comp_w_pid, sizeof(comp_w_pid), "%s-%d", comp, getpid ());
1093 mylog (kind, comp_w_pid, message, va);
1094 va_end (va);
1095}
1096
1097
1098/**
1099 * Convert error type to string.
1100 *
1101 * @param kind type to convert
1102 * @return string corresponding to the type
1103 */
1104const char *
1105GNUNET_error_type_to_string (enum GNUNET_ErrorType kind)
1106{
1107 if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0)
1108 return _ ("ERROR");
1109 if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0)
1110 return _ ("WARNING");
1111 if ((kind & GNUNET_ERROR_TYPE_MESSAGE) > 0)
1112 return _ ("MESSAGE");
1113 if ((kind & GNUNET_ERROR_TYPE_INFO) > 0)
1114 return _ ("INFO");
1115 if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0)
1116 return _ ("DEBUG");
1117 if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0)
1118 return _ ("NONE");
1119 return _ ("INVALID");
1120}
1121
1122
1123/**
1124 * Convert a hash to a string (for printing debug messages).
1125 *
1126 * @param hc the hash code
1127 * @return string form; will be overwritten by next call to GNUNET_h2s.
1128 */
1129const char *
1130GNUNET_h2s (const struct GNUNET_HashCode *hc)
1131{
1132 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1133
1134 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1135 ret.encoding[8] = '\0';
1136 return (const char *) ret.encoding;
1137}
1138
1139
1140/**
1141 * Convert a hash to a string (for printing debug messages).
1142 * This is one of the very few calls in the entire API that is
1143 * NOT reentrant! Identical to #GNUNET_h2s(), except that another
1144 * buffer is used so both #GNUNET_h2s() and #GNUNET_h2s2() can be
1145 * used within the same log statement.
1146 *
1147 * @param hc the hash code
1148 * @return string form; will be overwritten by next call to GNUNET_h2s.
1149 */
1150const char *
1151GNUNET_h2s2 (const struct GNUNET_HashCode *hc)
1152{
1153 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1154
1155 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1156 ret.encoding[8] = '\0';
1157 return (const char *) ret.encoding;
1158}
1159
1160
1161/**
1162 * @ingroup logging
1163 * Convert a public key value to a string (for printing debug messages).
1164 * This is one of the very few calls in the entire API that is
1165 * NOT reentrant!
1166 *
1167 * @param hc the hash code
1168 * @return string
1169 */
1170const char *
1171GNUNET_p2s (const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1172{
1173 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1174 struct GNUNET_HashCode hc;
1175
1176 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1177 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1178 ret.encoding[6] = '\0';
1179 return (const char *) ret.encoding;
1180}
1181
1182
1183/**
1184 * @ingroup logging
1185 * Convert a public key value to a string (for printing debug messages).
1186 * This is one of the very few calls in the entire API that is
1187 * NOT reentrant!
1188 *
1189 * @param hc the hash code
1190 * @return string
1191 */
1192const char *
1193GNUNET_p2s2 (const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1194{
1195 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1196 struct GNUNET_HashCode hc;
1197
1198 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1199 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1200 ret.encoding[6] = '\0';
1201 return (const char *) ret.encoding;
1202}
1203
1204
1205/**
1206 * @ingroup logging
1207 * Convert a public key value to a string (for printing debug messages).
1208 * This is one of the very few calls in the entire API that is
1209 * NOT reentrant!
1210 *
1211 * @param hc the hash code
1212 * @return string
1213 */
1214const char *
1215GNUNET_e2s (const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1216{
1217 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1218 struct GNUNET_HashCode hc;
1219
1220 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1221 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1222 ret.encoding[6] = '\0';
1223 return (const char *) ret.encoding;
1224}
1225
1226
1227/**
1228 * @ingroup logging
1229 * Convert a public key value to a string (for printing debug messages).
1230 * This is one of the very few calls in the entire API that is
1231 * NOT reentrant!
1232 *
1233 * @param hc the hash code
1234 * @return string
1235 */
1236const char *
1237GNUNET_e2s2 (const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1238{
1239 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1240 struct GNUNET_HashCode hc;
1241
1242 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1243 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1244 ret.encoding[6] = '\0';
1245 return (const char *) ret.encoding;
1246}
1247
1248
1249/**
1250 * @ingroup logging
1251 * Convert a short hash value to a string (for printing debug messages).
1252 * This is one of the very few calls in the entire API that is
1253 * NOT reentrant!
1254 *
1255 * @param shc the hash code
1256 * @return string
1257 */
1258const char *
1259GNUNET_sh2s (const struct GNUNET_ShortHashCode *shc)
1260{
1261 static GNUNET_THREAD_LOCAL char buf[64];
1262
1263 GNUNET_STRINGS_data_to_string (shc, sizeof(*shc), buf, sizeof(buf));
1264 buf[6] = '\0';
1265 return (const char *) buf;
1266}
1267
1268
1269/**
1270 * @ingroup logging
1271 * Convert a UUID to a string (for printing debug messages).
1272 * This is one of the very few calls in the entire API that is
1273 * NOT reentrant!
1274 *
1275 * @param uuid the UUID
1276 * @return string
1277 */
1278const char *
1279GNUNET_uuid2s (const struct GNUNET_Uuid *uuid)
1280{
1281 static GNUNET_THREAD_LOCAL char buf[32];
1282
1283 GNUNET_STRINGS_data_to_string (uuid, sizeof(*uuid), buf, sizeof(buf));
1284 buf[6] = '\0';
1285 return (const char *) buf;
1286}
1287
1288
1289/**
1290 * Convert a hash to a string (for printing debug messages).
1291 * This is one of the very few calls in the entire API that is
1292 * NOT reentrant!
1293 *
1294 * @param hc the hash code
1295 * @return string form; will be overwritten by next call to GNUNET_h2s_full.
1296 */
1297const char *
1298GNUNET_h2s_full (const struct GNUNET_HashCode *hc)
1299{
1300 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1301
1302 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1303 ret.encoding[sizeof(ret) - 1] = '\0';
1304 return (const char *) ret.encoding;
1305}
1306
1307
1308/**
1309 * Convert a peer identity to a string (for printing debug messages).
1310 *
1311 * @param pid the peer identity
1312 * @return string form of the pid; will be overwritten by next
1313 * call to #GNUNET_i2s.
1314 */
1315const char *
1316GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
1317{
1318 static GNUNET_THREAD_LOCAL char buf[5];
1319 char *ret;
1320
1321 if (NULL == pid)
1322 return "NULL";
1323 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1324 GNUNET_strlcpy (buf, ret, sizeof(buf));
1325 GNUNET_free (ret);
1326 return buf;
1327}
1328
1329
1330/**
1331 * Convert a peer identity to a string (for printing debug messages).
1332 * Identical to #GNUNET_i2s(), except that another
1333 * buffer is used so both #GNUNET_i2s() and #GNUNET_i2s2() can be
1334 * used within the same log statement.
1335 *
1336 * @param pid the peer identity
1337 * @return string form of the pid; will be overwritten by next
1338 * call to #GNUNET_i2s.
1339 */
1340const char *
1341GNUNET_i2s2 (const struct GNUNET_PeerIdentity *pid)
1342{
1343 static GNUNET_THREAD_LOCAL char buf[5];
1344 char *ret;
1345
1346 if (NULL == pid)
1347 return "NULL";
1348 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1349 GNUNET_strlcpy (buf, ret, sizeof(buf));
1350 GNUNET_free (ret);
1351 return buf;
1352}
1353
1354
1355/**
1356 * Convert a peer identity to a string (for printing debug messages).
1357 *
1358 * @param pid the peer identity
1359 * @return string form of the pid; will be overwritten by next
1360 * call to #GNUNET_i2s_full.
1361 */
1362const char *
1363GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid)
1364{
1365 static GNUNET_THREAD_LOCAL char buf[256];
1366 char *ret;
1367
1368 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1369 strcpy (buf, ret);
1370 GNUNET_free (ret);
1371 return buf;
1372}
1373
1374
1375/**
1376 * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string
1377 * (for printing debug messages). This is one of the very few calls
1378 * in the entire API that is NOT reentrant!
1379 *
1380 * @param addr the address
1381 * @param addrlen the length of the address in @a addr
1382 * @return nicely formatted string for the address
1383 * will be overwritten by next call to #GNUNET_a2s.
1384 */
1385const char *
1386GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
1387{
1388#define LEN \
1389 GNUNET_MAX ((INET6_ADDRSTRLEN + 8), \
1390 (1 + sizeof(struct sockaddr_un) - sizeof(sa_family_t)))
1391 static GNUNET_THREAD_LOCAL char buf[LEN];
1392#undef LEN
1393 static GNUNET_THREAD_LOCAL char b2[6];
1394 const struct sockaddr_in *v4;
1395 const struct sockaddr_un *un;
1396 const struct sockaddr_in6 *v6;
1397 unsigned int off;
1398
1399 if (addr == NULL)
1400 return _ ("unknown address");
1401 switch (addr->sa_family)
1402 {
1403 case AF_INET:
1404 if (addrlen != sizeof(struct sockaddr_in))
1405 return "<invalid v4 address>";
1406 v4 = (const struct sockaddr_in *) addr;
1407 inet_ntop (AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN);
1408 if (0 == ntohs (v4->sin_port))
1409 return buf;
1410 strcat (buf, ":");
1411 GNUNET_snprintf (b2, sizeof(b2), "%u", ntohs (v4->sin_port));
1412 strcat (buf, b2);
1413 return buf;
1414
1415 case AF_INET6:
1416 if (addrlen != sizeof(struct sockaddr_in6))
1417 return "<invalid v6 address>";
1418 v6 = (const struct sockaddr_in6 *) addr;
1419 buf[0] = '[';
1420 inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN);
1421 if (0 == ntohs (v6->sin6_port))
1422 return &buf[1];
1423 strcat (buf, "]:");
1424 GNUNET_snprintf (b2, sizeof(b2), "%u", ntohs (v6->sin6_port));
1425 strcat (buf, b2);
1426 return buf;
1427
1428 case AF_UNIX:
1429 if (addrlen <= sizeof(sa_family_t))
1430 return "<unbound UNIX client>";
1431 un = (const struct sockaddr_un *) addr;
1432 off = 0;
1433 if ('\0' == un->sun_path[0])
1434 off++;
1435 memset (buf, 0, sizeof(buf));
1436 GNUNET_snprintf (buf,
1437 sizeof(buf),
1438 "%s%.*s",
1439 (1 == off) ? "@" : "",
1440 (int) (addrlen - sizeof(sa_family_t) - off),
1441 &un->sun_path[off]);
1442 return buf;
1443
1444 default:
1445 return _ ("invalid address");
1446 }
1447}
1448
1449
1450/**
1451 * Log error message about missing configuration option.
1452 *
1453 * @param kind log level
1454 * @param section section with missing option
1455 * @param option name of missing option
1456 */
1457void
1458GNUNET_log_config_missing (enum GNUNET_ErrorType kind,
1459 const char *section,
1460 const char *option)
1461{
1462 GNUNET_log (kind,
1463 _ (
1464 "Configuration fails to specify option `%s' in section `%s'!\n"),
1465 option,
1466 section);
1467}
1468
1469
1470/**
1471 * Log error message about invalid configuration option value.
1472 *
1473 * @param kind log level
1474 * @param section section with invalid option
1475 * @param option name of invalid option
1476 * @param required what is required that is invalid about the option
1477 */
1478void
1479GNUNET_log_config_invalid (enum GNUNET_ErrorType kind,
1480 const char *section,
1481 const char *option,
1482 const char *required)
1483{
1484 GNUNET_log (
1485 kind,
1486 _ (
1487 "Configuration specifies invalid value for option `%s' in section `%s': %s\n"),
1488 option,
1489 section,
1490 required);
1491}
1492
1493
1494/**
1495 * Set the async scope for the current thread.
1496 *
1497 * @param aid the async scope identifier
1498 * @param old_scope[out] location to save the old scope
1499 */
1500void
1501GNUNET_async_scope_enter (const struct GNUNET_AsyncScopeId *aid,
1502 struct GNUNET_AsyncScopeSave *old_scope)
1503{
1504 *old_scope = current_async_scope;
1505 current_async_scope.have_scope = GNUNET_YES;
1506 current_async_scope.scope_id = *aid;
1507}
1508
1509
1510/**
1511 * Clear the current thread's async scope.
1512 *
1513 * @param old_scope scope to restore
1514 */
1515void
1516GNUNET_async_scope_restore (struct GNUNET_AsyncScopeSave *old_scope)
1517{
1518 current_async_scope = *old_scope;
1519}
1520
1521
1522/**
1523 * Generate a fresh async scope identifier.
1524 *
1525 * @param[out] aid_ret pointer to where the result is stored
1526 */
1527void
1528GNUNET_async_scope_fresh (struct GNUNET_AsyncScopeId *aid_ret)
1529{
1530 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1531 aid_ret,
1532 sizeof(struct GNUNET_AsyncScopeId));
1533}
1534
1535
1536/**
1537 * Get the current async scope.
1538 *
1539 * @param[out] scope_ret pointer to where the result is stored
1540 */
1541void
1542GNUNET_async_scope_get (struct GNUNET_AsyncScopeSave *scope_ret)
1543{
1544 *scope_ret = current_async_scope;
1545}
1546
1547
1548/**
1549 * Initializer
1550 */
1551void __attribute__ ((constructor))
1552GNUNET_util_cl_init ()
1553{
1554 GNUNET_stderr = stderr;
1555}
1556
1557
1558/**
1559 * Destructor
1560 */
1561void __attribute__ ((destructor))
1562GNUNET_util_cl_fini ()
1563{
1564
1565}
1566
1567
1568/* end of common_logging.c */
diff --git a/src/util/configuration.c b/src/util/configuration.c
deleted file mode 100644
index d9d6721cc..000000000
--- a/src/util/configuration.c
+++ /dev/null
@@ -1,2524 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2007, 2008, 2009, 2013, 2020, 2021 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 * @file src/util/configuration.c
22 * @brief configuration management
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_crypto_lib.h"
27#include "gnunet_strings_lib.h"
28#include "gnunet_os_lib.h"
29#include "gnunet_configuration_lib.h"
30#include "gnunet_disk_lib.h"
31#include "gnunet_buffer_lib.h"
32#include "gnunet_container_lib.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__)
35
36#define LOG_STRERROR_FILE(kind, syscall, filename) \
37 GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
38
39/**
40 * @brief configuration entry
41 */
42struct ConfigEntry
43{
44 /**
45 * This is a linked list.
46 */
47 struct ConfigEntry *next;
48
49 /**
50 * key for this entry
51 */
52 char *key;
53
54 /**
55 * current, committed value
56 */
57 char *val;
58
59 /**
60 * Diagnostics information for the filename.
61 */
62 char *hint_filename;
63
64 /**
65 * Diagnostics information for the line number.
66 */
67 unsigned int hint_lineno;
68};
69
70
71/**
72 * @brief configuration section
73 */
74struct ConfigSection
75{
76 /**
77 * This is a linked list.
78 */
79 struct ConfigSection *next;
80
81 /**
82 * entries in the section
83 */
84 struct ConfigEntry *entries;
85
86 /**
87 * name of the section
88 */
89 char *name;
90
91 /**
92 * Is the configuration section marked as inaccessible?
93 *
94 * This can happen if the section name is used in an @inline-secret@
95 * directive, but the referenced file can't be found or accessed.
96 */
97 bool inaccessible;
98
99 /**
100 * Diagnostics hint for the secret file.
101 */
102 char *hint_secret_filename;
103
104 /**
105 * Extra information regarding permissions of the secret file.
106 */
107 char *hint_secret_stat;
108
109 /**
110 * For secret sections: Where was this inlined from?
111 */
112 char *hint_inlined_from_filename;
113
114 /**
115 * For secret sections: Where was this inlined from?
116 */
117 unsigned int hint_inlined_from_line;
118};
119
120struct ConfigFile
121{
122 /**
123 * Source filename.
124 */
125 char *source_filename;
126
127 /**
128 * Level in the tree of loaded config files.
129 */
130 unsigned int level;
131
132 struct ConfigFile *prev;
133
134 struct ConfigFile *next;
135
136 /**
137 * Was this configuration file parsed via
138 * @inline-secret@?
139 */
140 char *hint_restrict_section;
141
142 /**
143 * Was this configuration file inaccessible?
144 */
145 bool hint_inaccessible;
146};
147
148
149/**
150 * @brief configuration data
151 */
152struct GNUNET_CONFIGURATION_Handle
153{
154 /**
155 * Configuration sections.
156 */
157 struct ConfigSection *sections;
158
159 /**
160 * Linked list of loaded files.
161 */
162 struct ConfigFile *loaded_files_head;
163
164 /**
165 * Linked list of loaded files.
166 */
167 struct ConfigFile *loaded_files_tail;
168
169 /**
170 * Current nesting level of file loading.
171 */
172 unsigned int current_nest_level;
173
174 /**
175 * Enable diagnostics.
176 */
177 bool diagnostics;
178
179 /**
180 * Modification indication since last save
181 * #GNUNET_NO if clean, #GNUNET_YES if dirty,
182 * #GNUNET_SYSERR on error (i.e. last save failed)
183 */
184 enum GNUNET_GenericReturnValue dirty;
185
186 /**
187 * Was the configuration ever loaded via GNUNET_CONFIGURATION_load?
188 */
189 bool load_called;
190
191 /**
192 * Name of the entry point configuration file.
193 */
194 char *main_filename;
195
196 /**
197 * When parsing into this configuration, and this value
198 * is non-NULL, only parse sections of the same name,
199 * and ban import statements.
200 */
201 const char *restrict_section;
202};
203
204
205/**
206 * Used for diffing a configuration object against
207 * the default one
208 */
209struct DiffHandle
210{
211 const struct GNUNET_CONFIGURATION_Handle *cfg_default;
212
213 struct GNUNET_CONFIGURATION_Handle *cfgDiff;
214};
215
216
217void
218GNUNET_CONFIGURATION_enable_diagnostics (struct
219 GNUNET_CONFIGURATION_Handle *cfg)
220{
221 cfg->diagnostics = true;
222}
223
224
225struct GNUNET_CONFIGURATION_Handle *
226GNUNET_CONFIGURATION_create ()
227{
228 struct GNUNET_CONFIGURATION_Handle *cfg;
229 char *p;
230
231 cfg = GNUNET_new (struct GNUNET_CONFIGURATION_Handle);
232 /* make certain values from the project data available
233 as PATHS */
234 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
235 if (NULL != p)
236 {
237 GNUNET_CONFIGURATION_set_value_string (cfg,
238 "PATHS",
239 "DATADIR",
240 p);
241 GNUNET_free (p);
242 }
243 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
244 if (NULL != p)
245 {
246 GNUNET_CONFIGURATION_set_value_string (cfg,
247 "PATHS",
248 "LIBDIR",
249 p);
250 GNUNET_free (p);
251 }
252 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
253 if (NULL != p)
254 {
255 GNUNET_CONFIGURATION_set_value_string (cfg,
256 "PATHS",
257 "BINDIR",
258 p);
259 GNUNET_free (p);
260 }
261 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_PREFIX);
262 if (NULL != p)
263 {
264 GNUNET_CONFIGURATION_set_value_string (cfg,
265 "PATHS",
266 "PREFIX",
267 p);
268 GNUNET_free (p);
269 }
270 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
271 if (NULL != p)
272 {
273 GNUNET_CONFIGURATION_set_value_string (cfg,
274 "PATHS",
275 "LOCALEDIR",
276 p);
277 GNUNET_free (p);
278 }
279 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_ICONDIR);
280 if (NULL != p)
281 {
282 GNUNET_CONFIGURATION_set_value_string (cfg,
283 "PATHS",
284 "ICONDIR",
285 p);
286 GNUNET_free (p);
287 }
288 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DOCDIR);
289 if (NULL != p)
290 {
291 GNUNET_CONFIGURATION_set_value_string (cfg,
292 "PATHS",
293 "DOCDIR",
294 p);
295 GNUNET_free (p);
296 }
297 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
298 if (NULL != p)
299 {
300 GNUNET_CONFIGURATION_set_value_string (cfg,
301 "PATHS",
302 "LIBEXECDIR",
303 p);
304 GNUNET_free (p);
305 }
306 return cfg;
307}
308
309
310void
311GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
312{
313 struct ConfigSection *sec;
314 struct ConfigFile *cf;
315
316 while (NULL != (sec = cfg->sections))
317 GNUNET_CONFIGURATION_remove_section (cfg, sec->name);
318 while (NULL != (cf = cfg->loaded_files_head))
319 {
320 GNUNET_free (cf->hint_restrict_section);
321 GNUNET_free (cf->source_filename);
322 GNUNET_CONTAINER_DLL_remove (cfg->loaded_files_head,
323 cfg->loaded_files_tail,
324 cf);
325 GNUNET_free (cf);
326 }
327 GNUNET_free (cfg->main_filename);
328 GNUNET_free (cfg);
329}
330
331
332enum GNUNET_GenericReturnValue
333GNUNET_CONFIGURATION_parse_and_run (const char *filename,
334 GNUNET_CONFIGURATION_Callback cb,
335 void *cb_cls)
336{
337 struct GNUNET_CONFIGURATION_Handle *cfg;
338 enum GNUNET_GenericReturnValue ret;
339
340 cfg = GNUNET_CONFIGURATION_create ();
341 if (GNUNET_OK !=
342 GNUNET_CONFIGURATION_load (cfg,
343 filename))
344 {
345 GNUNET_break (0);
346 GNUNET_CONFIGURATION_destroy (cfg);
347 return GNUNET_SYSERR;
348 }
349 ret = cb (cb_cls, cfg);
350 GNUNET_CONFIGURATION_destroy (cfg);
351 return ret;
352}
353
354
355/**
356 * Closure to collect_files_cb.
357 */
358struct CollectFilesContext
359{
360 /**
361 * Collected files from globbing.
362 */
363 char **files;
364
365 /**
366 * Size of the files array.
367 */
368 unsigned int files_length;
369};
370
371
372/**
373 * Function called with a filename.
374 *
375 * @param cls closure
376 * @param filename complete filename (absolute path)
377 * @return #GNUNET_OK to continue to iterate,
378 * #GNUNET_NO to stop iteration with no error,
379 * #GNUNET_SYSERR to abort iteration with error!
380 */
381static int
382collect_files_cb (void *cls,
383 const char *filename)
384{
385 struct CollectFilesContext *igc = cls;
386
387 GNUNET_array_append (igc->files,
388 igc->files_length,
389 GNUNET_strdup (filename));
390 return GNUNET_OK;
391}
392
393
394/**
395 * Find a section entry from a configuration.
396 *
397 * @param cfg configuration to search in
398 * @param section name of the section to look for
399 * @return matching entry, NULL if not found
400 */
401static struct ConfigSection *
402find_section (const struct GNUNET_CONFIGURATION_Handle *cfg,
403 const char *section)
404{
405 struct ConfigSection *pos;
406
407 pos = cfg->sections;
408 while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
409 pos = pos->next;
410 return pos;
411}
412
413
414static int
415pstrcmp (const void *a, const void *b)
416{
417 return strcmp (*((const char **) a), *((const char **) b));
418}
419
420
421/**
422 * Handle an inline directive.
423 *
424 * @returns #GNUNET_SYSERR on error, #GNUNET_OK otherwise
425 */
426enum GNUNET_GenericReturnValue
427handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
428 const char *path_or_glob,
429 bool path_is_glob,
430 const char *restrict_section,
431 const char *source_filename,
432 unsigned int source_lineno)
433{
434 char *inline_path = NULL;
435 struct GNUNET_CONFIGURATION_Handle *other_cfg = NULL;
436 struct CollectFilesContext igc = {
437 .files = NULL,
438 .files_length = 0,
439 };
440 enum GNUNET_GenericReturnValue fun_ret;
441 unsigned int old_nest_level = cfg->current_nest_level++;
442
443 /* We support the section restriction only for non-globs */
444 GNUNET_assert (! (path_is_glob && (NULL != restrict_section)));
445
446 if (NULL == source_filename)
447 {
448 LOG (GNUNET_ERROR_TYPE_DEBUG,
449 "Refusing to parse inline configurations, "
450 "not allowed without source filename!\n");
451 fun_ret = GNUNET_SYSERR;
452 goto cleanup;
453 }
454
455 if ('/' == *path_or_glob)
456 inline_path = GNUNET_strdup (path_or_glob);
457 else
458 {
459 /* We compute the canonical, absolute path first,
460 so that relative imports resolve properly with symlinked
461 config files. */
462 char *source_realpath;
463 char *endsep;
464
465 source_realpath = realpath (source_filename,
466 NULL);
467 if (NULL == source_realpath)
468 {
469 /* Couldn't even resolve path of base dir. */
470 GNUNET_break (0);
471 /* failed to parse included config */
472 fun_ret = GNUNET_SYSERR;
473 goto cleanup;
474 }
475 endsep = strrchr (source_realpath, '/');
476 GNUNET_assert (NULL != endsep);
477 *endsep = '\0';
478 GNUNET_asprintf (&inline_path,
479 "%s/%s",
480 source_realpath,
481 path_or_glob);
482 free (source_realpath);
483 }
484
485 if (path_is_glob)
486 {
487 int nret;
488
489 LOG (GNUNET_ERROR_TYPE_DEBUG,
490 "processing config glob '%s'\n",
491 inline_path);
492
493 nret = GNUNET_DISK_glob (inline_path, collect_files_cb, &igc);
494 if (-1 == nret)
495 {
496 fun_ret = GNUNET_SYSERR;
497 goto cleanup;
498 }
499 GNUNET_assert (nret == igc.files_length);
500 qsort (igc.files, igc.files_length, sizeof (char *), pstrcmp);
501 for (int i = 0; i < nret; i++)
502 {
503 if (GNUNET_OK !=
504 GNUNET_CONFIGURATION_parse (cfg,
505 igc.files[i]))
506 {
507 fun_ret = GNUNET_SYSERR;
508 goto cleanup;
509 }
510 }
511 fun_ret = GNUNET_OK;
512 }
513 else if (NULL != restrict_section)
514 {
515 enum GNUNET_GenericReturnValue inner_ret;
516 struct ConfigSection *cs;
517 struct ConfigFile *cf = GNUNET_new (struct ConfigFile);
518
519 inner_ret = GNUNET_DISK_file_test_read (inline_path);
520
521 cs = find_section (cfg, restrict_section);
522
523 if (NULL == cs)
524 {
525 cs = GNUNET_new (struct ConfigSection);
526 cs->name = GNUNET_strdup (restrict_section);
527 cs->next = cfg->sections;
528 cfg->sections = cs;
529 cs->entries = NULL;
530 }
531 if (cfg->diagnostics)
532 {
533 char *sfn = GNUNET_STRINGS_filename_expand (inline_path);
534 struct stat istat;
535
536 cs->hint_secret_filename = sfn;
537 if (0 == stat (sfn, &istat))
538 {
539 struct passwd *pw = getpwuid (istat.st_uid);
540 struct group *gr = getgrgid (istat.st_gid);
541 char *pwname = (NULL == pw) ? "<unknown>" : pw->pw_name;
542 char *grname = (NULL == gr) ? "<unknown>" : gr->gr_name;
543
544 GNUNET_asprintf (&cs->hint_secret_stat,
545 "%s:%s %o",
546 pwname,
547 grname,
548 istat.st_mode);
549 }
550 else
551 {
552 cs->hint_secret_stat = GNUNET_strdup ("<can't stat file>");
553 }
554 if (source_filename)
555 {
556 /* Possible that this secret section has been inlined before */
557 GNUNET_free (cs->hint_inlined_from_filename);
558 cs->hint_inlined_from_filename = GNUNET_strdup (source_filename);
559 cs->hint_inlined_from_line = source_lineno;
560 }
561 }
562
563 /* Put file in the load list for diagnostics, even if we can't access it. */
564 {
565 cf->level = cfg->current_nest_level;
566 cf->source_filename = GNUNET_strdup (inline_path);
567 cf->hint_restrict_section = GNUNET_strdup (restrict_section);
568 GNUNET_CONTAINER_DLL_insert_tail (cfg->loaded_files_head,
569 cfg->loaded_files_tail,
570 cf);
571 }
572
573 if (GNUNET_OK != inner_ret)
574 {
575 cs->inaccessible = true;
576 cf->hint_inaccessible = true;
577 /* File can't be accessed, but that's okay. */
578 fun_ret = GNUNET_OK;
579 goto cleanup;
580 }
581
582 other_cfg = GNUNET_CONFIGURATION_create ();
583 other_cfg->restrict_section = restrict_section;
584 inner_ret = GNUNET_CONFIGURATION_parse (other_cfg,
585 inline_path);
586 if (GNUNET_OK != inner_ret)
587 {
588 cf->hint_inaccessible = true;
589 fun_ret = inner_ret;
590 goto cleanup;
591 }
592
593 cs = find_section (other_cfg, restrict_section);
594 if (NULL == cs)
595 {
596 LOG (GNUNET_ERROR_TYPE_INFO,
597 "Configuration file '%s' loaded with @inline-secret@ "
598 "does not contain section '%s'.\n",
599 inline_path,
600 restrict_section);
601 /* Inlined onfiguration is accessible but doesn't contain any values.
602 We treat this as if the inlined section was empty, and do not
603 consider it an error. */
604 fun_ret = GNUNET_OK;
605 goto cleanup;
606 }
607 for (struct ConfigEntry *ce = cs->entries;
608 NULL != ce;
609 ce = ce->next)
610 GNUNET_CONFIGURATION_set_value_string (cfg,
611 restrict_section,
612 ce->key,
613 ce->val);
614 fun_ret = GNUNET_OK;
615 }
616 else if (GNUNET_OK !=
617 GNUNET_CONFIGURATION_parse (cfg,
618 inline_path))
619 {
620 fun_ret = GNUNET_SYSERR;
621 goto cleanup;
622 }
623 else
624 {
625 fun_ret = GNUNET_OK;
626 }
627cleanup:
628 cfg->current_nest_level = old_nest_level;
629 if (NULL != other_cfg)
630 GNUNET_CONFIGURATION_destroy (other_cfg);
631 GNUNET_free (inline_path);
632 if (igc.files_length > 0)
633 {
634 for (size_t i = 0; i < igc.files_length; i++)
635 GNUNET_free (igc.files[i]);
636 GNUNET_array_grow (igc.files, igc.files_length, 0);
637 }
638 return fun_ret;
639}
640
641
642/**
643 * Find an entry from a configuration.
644 *
645 * @param cfg handle to the configuration
646 * @param section section the option is in
647 * @param key the option
648 * @return matching entry, NULL if not found
649 */
650static struct ConfigEntry *
651find_entry (const struct GNUNET_CONFIGURATION_Handle *cfg,
652 const char *section,
653 const char *key)
654{
655 struct ConfigSection *sec;
656 struct ConfigEntry *pos;
657
658 if (NULL == (sec = find_section (cfg, section)))
659 return NULL;
660 if (sec->inaccessible)
661 {
662 LOG (GNUNET_ERROR_TYPE_WARNING,
663 "Section '%s' is marked as inaccessible, because the configuration "
664 " file that contains the section can't be read. Attempts to use "
665 "option '%s' will fail.\n",
666 section,
667 key);
668 return NULL;
669 }
670 pos = sec->entries;
671 while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
672 pos = pos->next;
673 return pos;
674}
675
676
677/**
678 * Set a configuration hint.
679 *
680 * @param cfg configuration handle
681 * @param section section
682 * @param option config option
683 * @param hint_filename
684 * @param hint_line
685 */
686static void
687set_entry_hint (struct GNUNET_CONFIGURATION_Handle *cfg,
688 const char *section,
689 const char *option,
690 const char *hint_filename,
691 unsigned int hint_line)
692{
693 struct ConfigEntry *e = find_entry (cfg, section, option);
694 if (! cfg->diagnostics)
695 return;
696 if (! e)
697 return;
698 e->hint_filename = GNUNET_strdup (hint_filename);
699 e->hint_lineno = hint_line;
700}
701
702
703enum GNUNET_GenericReturnValue
704GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
705 const char *mem,
706 size_t size,
707 const char *source_filename)
708{
709 size_t line_size;
710 unsigned int nr;
711 size_t r_bytes;
712 size_t to_read;
713 enum GNUNET_GenericReturnValue ret;
714 char *section;
715 char *eq;
716 char *tag;
717 char *value;
718 char *line_orig = NULL;
719
720 ret = GNUNET_OK;
721 section = NULL;
722 nr = 0;
723 r_bytes = 0;
724 while (r_bytes < size)
725 {
726 char *pos;
727 char *line;
728 bool emptyline;
729
730 GNUNET_free (line_orig);
731 /* fgets-like behaviour on buffer */
732 to_read = size - r_bytes;
733 pos = memchr (&mem[r_bytes], '\n', to_read);
734 if (NULL == pos)
735 {
736 line_orig = GNUNET_strndup (&mem[r_bytes],
737 line_size = to_read);
738 r_bytes += line_size;
739 }
740 else
741 {
742 line_orig = GNUNET_strndup (&mem[r_bytes],
743 line_size = (pos - &mem[r_bytes]));
744 r_bytes += line_size + 1;
745 }
746 line = line_orig;
747 /* increment line number */
748 nr++;
749 /* tabs and '\r' are whitespace */
750 emptyline = GNUNET_YES;
751 for (size_t i = 0; i < line_size; i++)
752 {
753 if (line[i] == '\t')
754 line[i] = ' ';
755 if (line[i] == '\r')
756 line[i] = ' ';
757 if (' ' != line[i])
758 emptyline = GNUNET_NO;
759 }
760 /* ignore empty lines */
761 if (GNUNET_YES == emptyline)
762 continue;
763
764 /* remove tailing whitespace */
765 for (size_t i = line_size - 1;
766 (i >= 1) && (isspace ((unsigned char) line[i]));
767 i--)
768 line[i] = '\0';
769
770 /* remove leading whitespace */
771 for (; line[0] != '\0' && (isspace ((unsigned char) line[0])); line++)
772 ;
773
774 /* ignore comments */
775 if ( ('#' == line[0]) ||
776 ('%' == line[0]) )
777 continue;
778
779 /* Handle special directives. */
780 if ('@' == line[0])
781 {
782 char *end = strchr (line + 1, '@');
783 char *directive;
784 enum GNUNET_GenericReturnValue directive_ret;
785
786 if (NULL != cfg->restrict_section)
787 {
788 LOG (GNUNET_ERROR_TYPE_WARNING,
789 _ (
790 "Illegal directive in line %u (parsing restricted section %s)\n"),
791 nr,
792 cfg->restrict_section);
793 ret = GNUNET_SYSERR;
794 break;
795 }
796
797 if (NULL == end)
798 {
799 LOG (GNUNET_ERROR_TYPE_WARNING,
800 _ ("Bad directive in line %u\n"),
801 nr);
802 ret = GNUNET_SYSERR;
803 break;
804 }
805 *end = '\0';
806 directive = line + 1;
807
808 if (0 == strcasecmp (directive, "INLINE"))
809 {
810 const char *path = end + 1;
811
812 /* Skip space before path */
813 for (; isspace (*path); path++)
814 ;
815
816 directive_ret = handle_inline (cfg,
817 path,
818 false,
819 NULL,
820 source_filename,
821 nr);
822 }
823 else if (0 == strcasecmp (directive, "INLINE-MATCHING"))
824 {
825 const char *path = end + 1;
826
827 /* Skip space before path */
828 for (; isspace (*path); path++)
829 ;
830
831 directive_ret = handle_inline (cfg,
832 path,
833 true,
834 NULL,
835 source_filename,
836 nr);
837 }
838 else if (0 == strcasecmp (directive, "INLINE-SECRET"))
839 {
840 char *secname = end + 1;
841 char *secname_end;
842 const char *path;
843
844 /* Skip space before secname */
845 for (; isspace (*secname); secname++)
846 ;
847
848 secname_end = strchr (secname, ' ');
849
850 if (NULL == secname_end)
851 {
852 LOG (GNUNET_ERROR_TYPE_WARNING,
853 _ ("Bad inline-secret directive in line %u\n"),
854 nr);
855 ret = GNUNET_SYSERR;
856 break;
857 }
858 *secname_end = '\0';
859 path = secname_end + 1;
860
861 /* Skip space before path */
862 for (; isspace (*path); path++)
863 ;
864
865 directive_ret = handle_inline (cfg,
866 path,
867 false,
868 secname,
869 source_filename,
870 nr);
871 }
872 else
873 {
874 LOG (GNUNET_ERROR_TYPE_WARNING,
875 _ ("Unknown or malformed directive '%s' in line %u\n"),
876 directive,
877 nr);
878 ret = GNUNET_SYSERR;
879 break;
880 }
881 if (GNUNET_OK != directive_ret)
882 {
883 ret = directive_ret;
884 break;
885 }
886 continue;
887 }
888 if (('[' == line[0]) && (']' == line[line_size - 1]))
889 {
890 /* [value] */
891 line[line_size - 1] = '\0';
892 value = &line[1];
893 GNUNET_free (section);
894 section = GNUNET_strdup (value);
895 continue;
896 }
897 if (NULL != (eq = strchr (line, '=')))
898 {
899 size_t i;
900
901 if (NULL == section)
902 {
903 LOG (GNUNET_ERROR_TYPE_WARNING,
904 _ (
905 "Syntax error while deserializing in line %u (option without section)\n"),
906 nr);
907 ret = GNUNET_SYSERR;
908 break;
909 }
910
911 /* tag = value */
912 tag = GNUNET_strndup (line, eq - line);
913 /* remove tailing whitespace */
914 for (i = strlen (tag) - 1;
915 (i >= 1) && (isspace ((unsigned char) tag[i]));
916 i--)
917 tag[i] = '\0';
918
919 /* Strip whitespace */
920 value = eq + 1;
921 while (isspace ((unsigned char) value[0]))
922 value++;
923 for (i = strlen (value) - 1;
924 (i >= 1) && (isspace ((unsigned char) value[i]));
925 i--)
926 value[i] = '\0';
927
928 /* remove quotes */
929 i = 0;
930 if (('"' == value[0]) && ('"' == value[strlen (value) - 1]))
931 {
932 value[strlen (value) - 1] = '\0';
933 value++;
934 }
935 GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]);
936 if (cfg->diagnostics)
937 {
938 set_entry_hint (cfg,
939 section,
940 tag,
941 source_filename ? source_filename : "<input>",
942 nr);
943 }
944 GNUNET_free (tag);
945 continue;
946 }
947 /* parse error */
948 LOG (GNUNET_ERROR_TYPE_WARNING,
949 _ ("Syntax error while deserializing in line %u\n"),
950 nr);
951 ret = GNUNET_SYSERR;
952 break;
953 }
954 GNUNET_free (line_orig);
955 GNUNET_free (section);
956 GNUNET_assert ( (GNUNET_OK != ret) ||
957 (r_bytes == size) );
958 return ret;
959}
960
961
962enum GNUNET_GenericReturnValue
963GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
964 const char *filename)
965{
966 uint64_t fs64;
967 size_t fs;
968 char *fn;
969 char *mem;
970 int dirty;
971 enum GNUNET_GenericReturnValue ret;
972 ssize_t sret;
973
974 fn = GNUNET_STRINGS_filename_expand (filename);
975 LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn);
976 if (NULL == fn)
977 return GNUNET_SYSERR;
978
979
980 /* Check for cycles */
981 {
982 unsigned int lvl = cfg->current_nest_level;
983 struct ConfigFile *cf = cfg->loaded_files_tail;
984 struct ConfigFile *parent = NULL;
985
986
987 for (; NULL != cf; parent = cf, cf = cf->prev)
988 {
989 /* Check parents based on level, skipping children of siblings. */
990 if (cf->level >= lvl)
991 continue;
992 lvl = cf->level;
993 if ( (NULL == cf->source_filename) || (NULL == filename))
994 continue;
995 if (0 == strcmp (cf->source_filename, filename))
996 {
997 if (NULL == parent)
998 {
999 LOG (GNUNET_ERROR_TYPE_ERROR,
1000 "Forbidden direct cyclic configuration import (%s -> %s)\n",
1001 cf->source_filename,
1002 filename);
1003 }
1004 else
1005 LOG (GNUNET_ERROR_TYPE_ERROR,
1006 "Forbidden indirect cyclic configuration import (%s -> ... -> %s -> %s)\n",
1007 cf->source_filename,
1008 parent->source_filename,
1009 filename);
1010 GNUNET_free (fn);
1011 return GNUNET_SYSERR;
1012 }
1013 }
1014
1015 }
1016
1017 /* Keep track of loaded files.*/
1018 {
1019 struct ConfigFile *cf = GNUNET_new (struct ConfigFile);
1020
1021 cf->level = cfg->current_nest_level;
1022 cf->source_filename = GNUNET_strdup (filename ? filename : "<input>");
1023 GNUNET_CONTAINER_DLL_insert_tail (cfg->loaded_files_head,
1024 cfg->loaded_files_tail,
1025 cf);
1026 }
1027
1028 dirty = cfg->dirty; /* back up value! */
1029 if (GNUNET_SYSERR ==
1030 GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES))
1031 {
1032 LOG (GNUNET_ERROR_TYPE_WARNING,
1033 "Error while determining the file size of `%s'\n",
1034 fn);
1035 GNUNET_free (fn);
1036 return GNUNET_SYSERR;
1037 }
1038 if (fs64 > SIZE_MAX)
1039 {
1040 GNUNET_break (0); /* File size is more than the heap size */
1041 GNUNET_free (fn);
1042 return GNUNET_SYSERR;
1043 }
1044 fs = fs64;
1045 mem = GNUNET_malloc (fs);
1046 sret = GNUNET_DISK_fn_read (fn, mem, fs);
1047 if ((sret < 0) || (fs != (size_t) sret))
1048 {
1049 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Error while reading file `%s'\n"), fn);
1050 GNUNET_free (fn);
1051 GNUNET_free (mem);
1052 return GNUNET_SYSERR;
1053 }
1054 LOG (GNUNET_ERROR_TYPE_DEBUG, "Deserializing contents of file `%s'\n", fn);
1055 ret = GNUNET_CONFIGURATION_deserialize (cfg,
1056 mem,
1057 fs,
1058 fn);
1059 if (GNUNET_SYSERR == ret)
1060 {
1061 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1062 _ ("Failed to parse configuration file `%s'\n"),
1063 fn);
1064 }
1065 GNUNET_free (fn);
1066 GNUNET_free (mem);
1067 /* restore dirty flag - anything we set in the meantime
1068 * came from disk */
1069 cfg->dirty = dirty;
1070 return ret;
1071}
1072
1073
1074enum GNUNET_GenericReturnValue
1075GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg)
1076{
1077 return cfg->dirty;
1078}
1079
1080
1081/**
1082 * Should we skip this configuration entry when serializing?
1083 *
1084 * @param sec section name
1085 * @param key key
1086 * @return true if we should skip it
1087 */
1088static bool
1089do_skip (const char *sec,
1090 const char *key)
1091{
1092 if (0 != strcasecmp ("PATHS",
1093 sec))
1094 return false;
1095 return ( (0 == strcasecmp ("DATADIR",
1096 key)) ||
1097 (0 == strcasecmp ("LIBDIR",
1098 key)) ||
1099 (0 == strcasecmp ("BINDIR",
1100 key)) ||
1101 (0 == strcasecmp ("PREFIX",
1102 key)) ||
1103 (0 == strcasecmp ("LOCALEDIR",
1104 key)) ||
1105 (0 == strcasecmp ("ICONDIR",
1106 key)) ||
1107 (0 == strcasecmp ("DOCDIR",
1108 key)) ||
1109 (0 == strcasecmp ("DEFAULTCONFIG",
1110 key)) ||
1111 (0 == strcasecmp ("LIBEXECDIR",
1112 key)) );
1113}
1114
1115
1116char *
1117GNUNET_CONFIGURATION_serialize (const struct GNUNET_CONFIGURATION_Handle *cfg,
1118 size_t *size)
1119{
1120 char *mem;
1121 char *cbuf;
1122 char *val;
1123 char *pos;
1124 size_t m_size;
1125 size_t c_size;
1126
1127 /* Pass1 : calculate the buffer size required */
1128 m_size = 0;
1129 for (struct ConfigSection *sec = cfg->sections;
1130 NULL != sec;
1131 sec = sec->next)
1132 {
1133 if (sec->inaccessible)
1134 continue;
1135 /* For each section we need to add 3 characters: {'[',']','\n'} */
1136 m_size += strlen (sec->name) + 3;
1137 for (struct ConfigEntry *ent = sec->entries;
1138 NULL != ent;
1139 ent = ent->next)
1140 {
1141 if (do_skip (sec->name,
1142 ent->key))
1143 continue;
1144 if (NULL != ent->val)
1145 {
1146 /* if val has any '\n' then they occupy +1 character as '\n'->'\\','n' */
1147 pos = ent->val;
1148 while (NULL != (pos = strstr (pos, "\n")))
1149 {
1150 m_size++;
1151 pos++;
1152 }
1153 /* For each key = value pair we need to add 4 characters (2
1154 spaces and 1 equal-to character and 1 new line) */
1155 m_size += strlen (ent->key) + strlen (ent->val) + 4;
1156 }
1157 }
1158 /* A new line after section end */
1159 m_size++;
1160 }
1161
1162 /* Pass2: Allocate memory and write the configuration to it */
1163 mem = GNUNET_malloc (m_size);
1164 c_size = 0;
1165 *size = c_size;
1166 for (struct ConfigSection *sec = cfg->sections;
1167 NULL != sec;
1168 sec = sec->next)
1169 {
1170 int len;
1171
1172 len = GNUNET_asprintf (&cbuf,
1173 "[%s]\n",
1174 sec->name);
1175 GNUNET_assert (0 < len);
1176 GNUNET_memcpy (mem + c_size,
1177 cbuf,
1178 len);
1179 c_size += len;
1180 GNUNET_free (cbuf);
1181 for (struct ConfigEntry *ent = sec->entries;
1182 NULL != ent;
1183 ent = ent->next)
1184 {
1185 if (do_skip (sec->name,
1186 ent->key))
1187 continue;
1188 if (NULL != ent->val)
1189 {
1190 val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
1191 strcpy (val, ent->val);
1192 while (NULL != (pos = strstr (val, "\n")))
1193 {
1194 memmove (&pos[2], &pos[1], strlen (&pos[1]));
1195 pos[0] = '\\';
1196 pos[1] = 'n';
1197 }
1198 len = GNUNET_asprintf (&cbuf, "%s = %s\n", ent->key, val);
1199 GNUNET_free (val);
1200 GNUNET_memcpy (mem + c_size, cbuf, len);
1201 c_size += len;
1202 GNUNET_free (cbuf);
1203 }
1204 }
1205 GNUNET_memcpy (mem + c_size, "\n", 1);
1206 c_size++;
1207 }
1208 GNUNET_assert (c_size == m_size);
1209 *size = c_size;
1210 return mem;
1211}
1212
1213
1214char *
1215GNUNET_CONFIGURATION_serialize_diagnostics (const struct
1216 GNUNET_CONFIGURATION_Handle *cfg)
1217{
1218 struct GNUNET_Buffer buf = { 0 };
1219
1220 GNUNET_buffer_write_fstr (&buf,
1221 "#\n# Configuration file diagnostics\n#\n");
1222 GNUNET_buffer_write_fstr (&buf,
1223 "# Entry point: %s\n",
1224 cfg->main_filename ? cfg->main_filename :
1225 "<none>");
1226 GNUNET_buffer_write_fstr (&buf,
1227 "#\n# Files Loaded:\n");
1228
1229 for (struct ConfigFile *cfil = cfg->loaded_files_head;
1230 NULL != cfil;
1231 cfil = cfil->next)
1232 {
1233 GNUNET_buffer_write_fstr (&buf,
1234 "# ");
1235 for (unsigned int i = 0; i < cfil->level; i++)
1236 GNUNET_buffer_write_fstr (&buf,
1237 "+");
1238 if (0 != cfil->level)
1239 GNUNET_buffer_write_fstr (&buf,
1240 " ");
1241
1242 GNUNET_buffer_write_fstr (&buf,
1243 "%s",
1244 cfil->source_filename);
1245
1246 if (NULL != cfil->hint_restrict_section)
1247 GNUNET_buffer_write_fstr (&buf,
1248 " (%s secret section %s)",
1249 cfil->hint_inaccessible
1250 ? "inaccessible"
1251 : "loaded",
1252 cfil->hint_restrict_section);
1253
1254 GNUNET_buffer_write_str (&buf,
1255 "\n");
1256 }
1257
1258 GNUNET_buffer_write_fstr (&buf,
1259 "#\n\n");
1260
1261 for (struct ConfigSection *sec = cfg->sections;
1262 NULL != sec;
1263 sec = sec->next)
1264 {
1265 if (sec->hint_secret_filename)
1266 GNUNET_buffer_write_fstr (&buf,
1267 "# secret section from %s\n# secret file stat %s\n",
1268 sec->hint_secret_filename,
1269 sec->hint_secret_stat);
1270 if (sec->hint_inlined_from_filename)
1271 {
1272 GNUNET_buffer_write_fstr (&buf,
1273 "# inlined from %s:%u\n",
1274 sec->hint_inlined_from_filename,
1275 sec->hint_inlined_from_line);
1276 }
1277 GNUNET_buffer_write_fstr (&buf,
1278 "[%s]\n\n",
1279 sec->name);
1280 if (sec->inaccessible)
1281 {
1282 GNUNET_buffer_write_fstr (&buf,
1283 "# <section contents inaccessible>\n\n\n");
1284 continue;
1285 }
1286 for (struct ConfigEntry *ent = sec->entries;
1287 NULL != ent;
1288 ent = ent->next)
1289 {
1290 if (do_skip (sec->name,
1291 ent->key))
1292 continue;
1293 if (NULL != ent->val)
1294 {
1295 char *pos;
1296 char *val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
1297 strcpy (val, ent->val);
1298 while (NULL != (pos = strstr (val, "\n")))
1299 {
1300 memmove (&pos[2], &pos[1], strlen (&pos[1]));
1301 pos[0] = '\\';
1302 pos[1] = 'n';
1303 }
1304 if (NULL != ent->hint_filename)
1305 {
1306 GNUNET_buffer_write_fstr (&buf,
1307 "# %s:%u\n",
1308 ent->hint_filename,
1309 ent->hint_lineno);
1310 }
1311 GNUNET_buffer_write_fstr (&buf,
1312 "%s = %s\n",
1313 ent->key,
1314 val);
1315 GNUNET_free (val);
1316 }
1317 GNUNET_buffer_write_str (&buf, "\n");
1318 }
1319 GNUNET_buffer_write_str (&buf, "\n");
1320 }
1321 return GNUNET_buffer_reap_str (&buf);
1322}
1323
1324
1325enum GNUNET_GenericReturnValue
1326GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
1327 const char *filename)
1328{
1329 char *fn;
1330 char *cfg_buf;
1331 size_t size;
1332
1333 fn = GNUNET_STRINGS_filename_expand (filename);
1334 if (fn == NULL)
1335 return GNUNET_SYSERR;
1336 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))
1337 {
1338 GNUNET_free (fn);
1339 return GNUNET_SYSERR;
1340 }
1341 cfg_buf = GNUNET_CONFIGURATION_serialize (cfg,
1342 &size);
1343 {
1344 struct GNUNET_DISK_FileHandle *h;
1345
1346 h = GNUNET_DISK_file_open (fn,
1347 GNUNET_DISK_OPEN_WRITE
1348 | GNUNET_DISK_OPEN_TRUNCATE
1349 | GNUNET_DISK_OPEN_CREATE,
1350 GNUNET_DISK_PERM_USER_READ
1351 | GNUNET_DISK_PERM_USER_WRITE
1352 | GNUNET_DISK_PERM_GROUP_READ
1353 | GNUNET_DISK_PERM_GROUP_WRITE);
1354 if (NULL == h)
1355 {
1356 GNUNET_free (fn);
1357 GNUNET_free (cfg_buf);
1358 return GNUNET_SYSERR;
1359 }
1360 if (((ssize_t) size) !=
1361 GNUNET_DISK_file_write (h,
1362 cfg_buf,
1363 size))
1364 {
1365 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1366 "write",
1367 fn);
1368 GNUNET_DISK_file_close (h);
1369 (void) GNUNET_DISK_directory_remove (fn);
1370 GNUNET_free (fn);
1371 GNUNET_free (cfg_buf);
1372 cfg->dirty = GNUNET_SYSERR; /* last write failed */
1373 return GNUNET_SYSERR;
1374 }
1375 GNUNET_assert (GNUNET_OK ==
1376 GNUNET_DISK_file_close (h));
1377 }
1378 GNUNET_free (fn);
1379 GNUNET_free (cfg_buf);
1380 cfg->dirty = GNUNET_NO; /* last write succeeded */
1381 return GNUNET_OK;
1382}
1383
1384
1385void
1386GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
1387 GNUNET_CONFIGURATION_Iterator iter,
1388 void *iter_cls)
1389{
1390 for (struct ConfigSection *spos = cfg->sections;
1391 NULL != spos;
1392 spos = spos->next)
1393 for (struct ConfigEntry *epos = spos->entries;
1394 NULL != epos;
1395 epos = epos->next)
1396 if (NULL != epos->val)
1397 iter (iter_cls,
1398 spos->name,
1399 epos->key,
1400 epos->val);
1401}
1402
1403
1404void
1405GNUNET_CONFIGURATION_iterate_section_values (
1406 const struct GNUNET_CONFIGURATION_Handle *cfg,
1407 const char *section,
1408 GNUNET_CONFIGURATION_Iterator iter,
1409 void *iter_cls)
1410{
1411 struct ConfigSection *spos;
1412 struct ConfigEntry *epos;
1413
1414 spos = cfg->sections;
1415 while ((spos != NULL) && (0 != strcasecmp (spos->name, section)))
1416 spos = spos->next;
1417 if (NULL == spos)
1418 return;
1419 if (spos->inaccessible)
1420 {
1421 LOG (GNUNET_ERROR_TYPE_WARNING,
1422 "Section '%s' is marked as inaccessible, because the configuration "
1423 " file that contains the section can't be read.\n",
1424 section);
1425 return;
1426 }
1427 for (epos = spos->entries; NULL != epos; epos = epos->next)
1428 if (NULL != epos->val)
1429 iter (iter_cls, spos->name, epos->key, epos->val);
1430}
1431
1432
1433void
1434GNUNET_CONFIGURATION_iterate_sections (
1435 const struct GNUNET_CONFIGURATION_Handle *cfg,
1436 GNUNET_CONFIGURATION_Section_Iterator iter,
1437 void *iter_cls)
1438{
1439 struct ConfigSection *spos;
1440 struct ConfigSection *next;
1441
1442 next = cfg->sections;
1443 while (next != NULL)
1444 {
1445 spos = next;
1446 next = spos->next;
1447 iter (iter_cls, spos->name);
1448 }
1449}
1450
1451
1452void
1453GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
1454 const char *section)
1455{
1456 struct ConfigSection *spos;
1457 struct ConfigSection *prev;
1458 struct ConfigEntry *ent;
1459
1460 prev = NULL;
1461 spos = cfg->sections;
1462 while (NULL != spos)
1463 {
1464 if (0 == strcasecmp (section, spos->name))
1465 {
1466 if (NULL == prev)
1467 cfg->sections = spos->next;
1468 else
1469 prev->next = spos->next;
1470 while (NULL != (ent = spos->entries))
1471 {
1472 spos->entries = ent->next;
1473 GNUNET_free (ent->key);
1474 GNUNET_free (ent->val);
1475 GNUNET_free (ent->hint_filename);
1476 GNUNET_free (ent);
1477 cfg->dirty = GNUNET_YES;
1478 }
1479 GNUNET_free (spos->name);
1480 GNUNET_free (spos->hint_secret_filename);
1481 GNUNET_free (spos->hint_secret_stat);
1482 GNUNET_free (spos->hint_inlined_from_filename);
1483 GNUNET_free (spos);
1484 return;
1485 }
1486 prev = spos;
1487 spos = spos->next;
1488 }
1489}
1490
1491
1492/**
1493 * Copy a configuration value to the given target configuration.
1494 * Overwrites existing entries.
1495 *
1496 * @param cls the destination configuration (`struct GNUNET_CONFIGURATION_Handle *`)
1497 * @param section section for the value
1498 * @param option option name of the value
1499 * @param value value to copy
1500 */
1501static void
1502copy_entry (void *cls,
1503 const char *section,
1504 const char *option,
1505 const char *value)
1506{
1507 struct GNUNET_CONFIGURATION_Handle *dst = cls;
1508
1509 GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
1510}
1511
1512
1513struct GNUNET_CONFIGURATION_Handle *
1514GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
1515{
1516 struct GNUNET_CONFIGURATION_Handle *ret;
1517
1518 ret = GNUNET_CONFIGURATION_create ();
1519 GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
1520 return ret;
1521}
1522
1523
1524/**
1525 * A callback function, compares entries from two configurations
1526 * (default against a new configuration) and write the diffs in a
1527 * diff-configuration object (the callback object).
1528 *
1529 * @param cls the diff configuration (`struct DiffHandle *`)
1530 * @param section section for the value (of the default conf.)
1531 * @param option option name of the value (of the default conf.)
1532 * @param value value to copy (of the default conf.)
1533 */
1534static void
1535compare_entries (void *cls,
1536 const char *section,
1537 const char *option,
1538 const char *value)
1539{
1540 struct DiffHandle *dh = cls;
1541 struct ConfigEntry *entNew;
1542
1543 entNew = find_entry (dh->cfg_default, section, option);
1544 if ((NULL != entNew) && (NULL != entNew->val) &&
1545 (0 == strcmp (entNew->val, value)))
1546 return;
1547 GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, section, option, value);
1548}
1549
1550
1551struct GNUNET_CONFIGURATION_Handle *
1552GNUNET_CONFIGURATION_get_diff (
1553 const struct GNUNET_CONFIGURATION_Handle *cfg_default,
1554 const struct GNUNET_CONFIGURATION_Handle *cfg_new)
1555{
1556 struct DiffHandle diffHandle;
1557
1558 diffHandle.cfgDiff = GNUNET_CONFIGURATION_create ();
1559 diffHandle.cfg_default = cfg_default;
1560 GNUNET_CONFIGURATION_iterate (cfg_new, &compare_entries, &diffHandle);
1561 return diffHandle.cfgDiff;
1562}
1563
1564
1565enum GNUNET_GenericReturnValue
1566GNUNET_CONFIGURATION_write_diffs (
1567 const struct GNUNET_CONFIGURATION_Handle *cfg_default,
1568 const struct GNUNET_CONFIGURATION_Handle *cfg_new,
1569 const char *filename)
1570{
1571 int ret;
1572 struct GNUNET_CONFIGURATION_Handle *diff;
1573
1574 diff = GNUNET_CONFIGURATION_get_diff (cfg_default, cfg_new);
1575 ret = GNUNET_CONFIGURATION_write (diff, filename);
1576 GNUNET_CONFIGURATION_destroy (diff);
1577 return ret;
1578}
1579
1580
1581void
1582GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg,
1583 const char *section,
1584 const char *option,
1585 const char *value)
1586{
1587 struct ConfigSection *sec;
1588 struct ConfigEntry *e;
1589 char *nv;
1590
1591 e = find_entry (cfg, section, option);
1592 if (NULL != e)
1593 {
1594 if (NULL == value)
1595 {
1596 GNUNET_free (e->val);
1597 e->val = NULL;
1598 }
1599 else
1600 {
1601 nv = GNUNET_strdup (value);
1602 GNUNET_free (e->val);
1603 e->val = nv;
1604 }
1605 return;
1606 }
1607 sec = find_section (cfg, section);
1608 if (sec == NULL)
1609 {
1610 sec = GNUNET_new (struct ConfigSection);
1611 sec->name = GNUNET_strdup (section);
1612 sec->next = cfg->sections;
1613 cfg->sections = sec;
1614 }
1615 e = GNUNET_new (struct ConfigEntry);
1616 e->key = GNUNET_strdup (option);
1617 e->val = GNUNET_strdup (value);
1618 e->next = sec->entries;
1619 sec->entries = e;
1620}
1621
1622
1623void
1624GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg,
1625 const char *section,
1626 const char *option,
1627 unsigned long long number)
1628{
1629 char s[64];
1630
1631 GNUNET_snprintf (s, 64, "%llu", number);
1632 GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
1633}
1634
1635
1636enum GNUNET_GenericReturnValue
1637GNUNET_CONFIGURATION_get_value_number (
1638 const struct GNUNET_CONFIGURATION_Handle *cfg,
1639 const char *section,
1640 const char *option,
1641 unsigned long long *number)
1642{
1643 struct ConfigEntry *e;
1644 char dummy[2];
1645
1646 if (NULL == (e = find_entry (cfg, section, option)))
1647 return GNUNET_SYSERR;
1648 if (NULL == e->val)
1649 return GNUNET_SYSERR;
1650 if (1 != sscanf (e->val, "%llu%1s", number, dummy))
1651 return GNUNET_SYSERR;
1652 return GNUNET_OK;
1653}
1654
1655
1656enum GNUNET_GenericReturnValue
1657GNUNET_CONFIGURATION_get_value_float (
1658 const struct GNUNET_CONFIGURATION_Handle *cfg,
1659 const char *section,
1660 const char *option,
1661 float *number)
1662{
1663 struct ConfigEntry *e;
1664 char dummy[2];
1665
1666 if (NULL == (e = find_entry (cfg, section, option)))
1667 return GNUNET_SYSERR;
1668 if (NULL == e->val)
1669 return GNUNET_SYSERR;
1670 if (1 != sscanf (e->val, "%f%1s", number, dummy))
1671 return GNUNET_SYSERR;
1672 return GNUNET_OK;
1673}
1674
1675
1676enum GNUNET_GenericReturnValue
1677GNUNET_CONFIGURATION_get_value_time (
1678 const struct GNUNET_CONFIGURATION_Handle *cfg,
1679 const char *section,
1680 const char *option,
1681 struct GNUNET_TIME_Relative *time)
1682{
1683 struct ConfigEntry *e;
1684 int ret;
1685
1686 if (NULL == (e = find_entry (cfg, section, option)))
1687 return GNUNET_SYSERR;
1688 if (NULL == e->val)
1689 return GNUNET_SYSERR;
1690 ret = GNUNET_STRINGS_fancy_time_to_relative (e->val, time);
1691 if (GNUNET_OK != ret)
1692 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1693 section,
1694 option,
1695 _ ("Not a valid relative time specification"));
1696 return ret;
1697}
1698
1699
1700enum GNUNET_GenericReturnValue
1701GNUNET_CONFIGURATION_get_value_size (
1702 const struct GNUNET_CONFIGURATION_Handle *cfg,
1703 const char *section,
1704 const char *option,
1705 unsigned long long *size)
1706{
1707 struct ConfigEntry *e;
1708
1709 if (NULL == (e = find_entry (cfg, section, option)))
1710 return GNUNET_SYSERR;
1711 if (NULL == e->val)
1712 return GNUNET_SYSERR;
1713 return GNUNET_STRINGS_fancy_size_to_bytes (e->val, size);
1714}
1715
1716
1717/**
1718 * Get a configuration value that should be a string.
1719 *
1720 * @param cfg configuration to inspect
1721 * @param section section of interest
1722 * @param option option of interest
1723 * @param value will be set to a freshly allocated configuration
1724 * value, or NULL if option is not specified
1725 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1726 */
1727enum GNUNET_GenericReturnValue
1728GNUNET_CONFIGURATION_get_value_string (
1729 const struct GNUNET_CONFIGURATION_Handle *cfg,
1730 const char *section,
1731 const char *option,
1732 char **value)
1733{
1734 struct ConfigEntry *e;
1735
1736 if ((NULL == (e = find_entry (cfg, section, option))) || (NULL == e->val))
1737 {
1738 *value = NULL;
1739 return GNUNET_SYSERR;
1740 }
1741 *value = GNUNET_strdup (e->val);
1742 return GNUNET_OK;
1743}
1744
1745
1746enum GNUNET_GenericReturnValue
1747GNUNET_CONFIGURATION_get_value_choice (
1748 const struct GNUNET_CONFIGURATION_Handle *cfg,
1749 const char *section,
1750 const char *option,
1751 const char *const *choices,
1752 const char **value)
1753{
1754 struct ConfigEntry *e;
1755 unsigned int i;
1756
1757 if (NULL == (e = find_entry (cfg, section, option)))
1758 return GNUNET_SYSERR;
1759 for (i = 0; NULL != choices[i]; i++)
1760 if (0 == strcasecmp (choices[i], e->val))
1761 break;
1762 if (NULL == choices[i])
1763 {
1764 LOG (GNUNET_ERROR_TYPE_ERROR,
1765 _ ("Configuration value '%s' for '%s'"
1766 " in section '%s' is not in set of legal choices\n"),
1767 e->val,
1768 option,
1769 section);
1770 return GNUNET_SYSERR;
1771 }
1772 *value = choices[i];
1773 return GNUNET_OK;
1774}
1775
1776
1777enum GNUNET_GenericReturnValue
1778GNUNET_CONFIGURATION_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
1779 const char *section,
1780 const char *option,
1781 void *buf,
1782 size_t buf_size)
1783{
1784 char *enc;
1785 int res;
1786 size_t data_size;
1787
1788 if (GNUNET_OK !=
1789 (res =
1790 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &enc)))
1791 return res;
1792 data_size = (strlen (enc) * 5) / 8;
1793 if (data_size != buf_size)
1794 {
1795 GNUNET_free (enc);
1796 return GNUNET_SYSERR;
1797 }
1798 if (GNUNET_OK !=
1799 GNUNET_STRINGS_string_to_data (enc, strlen (enc), buf, buf_size))
1800 {
1801 GNUNET_free (enc);
1802 return GNUNET_SYSERR;
1803 }
1804 GNUNET_free (enc);
1805 return GNUNET_OK;
1806}
1807
1808
1809enum GNUNET_GenericReturnValue
1810GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg,
1811 const char *section,
1812 const char *option)
1813{
1814 struct ConfigEntry *e;
1815
1816 if ((NULL == (e = find_entry (cfg, section, option))) || (NULL == e->val))
1817 return GNUNET_NO;
1818 return GNUNET_YES;
1819}
1820
1821
1822/**
1823 * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
1824 * where either in the "PATHS" section or the environment "FOO" is
1825 * set to "DIRECTORY". We also support default expansion,
1826 * i.e. ${VARIABLE:-default} will expand to $VARIABLE if VARIABLE is
1827 * set in PATHS or the environment, and otherwise to "default". Note
1828 * that "default" itself can also be a $-expression, thus
1829 * "${VAR1:-{$VAR2}}" will expand to VAR1 and if that is not defined
1830 * to VAR2.
1831 *
1832 * @param cfg configuration to use for path expansion
1833 * @param orig string to $-expand (will be freed!)
1834 * @param depth recursion depth, used to detect recursive expansions
1835 * @return $-expanded string, never NULL unless @a orig was NULL
1836 */
1837static char *
1838expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cfg,
1839 char *orig,
1840 unsigned int depth)
1841{
1842 char *prefix;
1843 char *result;
1844 char *start;
1845 const char *post;
1846 const char *env;
1847 char *def;
1848 char *end;
1849 unsigned int lopen;
1850 char erased_char;
1851 char *erased_pos;
1852 size_t len;
1853
1854 if (NULL == orig)
1855 return NULL;
1856 if (depth > 128)
1857 {
1858 LOG (GNUNET_ERROR_TYPE_WARNING,
1859 _ (
1860 "Recursive expansion suspected, aborting $-expansion for term `%s'\n"),
1861 orig);
1862 return orig;
1863 }
1864 LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to $-expand %s\n", orig);
1865 if ('$' != orig[0])
1866 {
1867 LOG (GNUNET_ERROR_TYPE_DEBUG, "Doesn't start with $ - not expanding\n");
1868 return orig;
1869 }
1870 erased_char = 0;
1871 erased_pos = NULL;
1872 if ('{' == orig[1])
1873 {
1874 start = &orig[2];
1875 lopen = 1;
1876 end = &orig[1];
1877 while (lopen > 0)
1878 {
1879 end++;
1880 switch (*end)
1881 {
1882 case '}':
1883 lopen--;
1884 break;
1885
1886 case '{':
1887 lopen++;
1888 break;
1889
1890 case '\0':
1891 LOG (GNUNET_ERROR_TYPE_WARNING,
1892 _ ("Missing closing `%s' in option `%s'\n"),
1893 "}",
1894 orig);
1895 return orig;
1896
1897 default:
1898 break;
1899 }
1900 }
1901 erased_char = *end;
1902 erased_pos = end;
1903 *end = '\0';
1904 post = end + 1;
1905 def = strchr (orig, ':');
1906 if (NULL != def)
1907 {
1908 *def = '\0';
1909 def++;
1910 if (('-' == *def) || ('=' == *def))
1911 def++;
1912 def = GNUNET_strdup (def);
1913 }
1914 }
1915 else
1916 {
1917 int i;
1918
1919 start = &orig[1];
1920 def = NULL;
1921 i = 0;
1922 while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0') &&
1923 (orig[i] != ' '))
1924 i++;
1925 if (orig[i] == '\0')
1926 {
1927 post = "";
1928 }
1929 else
1930 {
1931 erased_char = orig[i];
1932 erased_pos = &orig[i];
1933 orig[i] = '\0';
1934 post = &orig[i + 1];
1935 }
1936 }
1937 LOG (GNUNET_ERROR_TYPE_DEBUG,
1938 "Split into `%s' and `%s' with default %s\n",
1939 start,
1940 post,
1941 def);
1942 if (GNUNET_OK !=
1943 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", start, &prefix))
1944 {
1945 if (NULL == (env = getenv (start)))
1946 {
1947 /* try default */
1948 def = expand_dollar (cfg, def, depth + 1);
1949 env = def;
1950 }
1951 if (NULL == env)
1952 {
1953 start = GNUNET_strdup (start);
1954 if (erased_pos)
1955 *erased_pos = erased_char;
1956 LOG (GNUNET_ERROR_TYPE_WARNING,
1957 _ (
1958 "Failed to expand `%s' in `%s' as it is neither found in [PATHS] nor defined as an environmental variable\n"),
1959 start,
1960 orig);
1961 GNUNET_free (start);
1962 return orig;
1963 }
1964 prefix = GNUNET_strdup (env);
1965 }
1966 prefix = GNUNET_CONFIGURATION_expand_dollar (cfg, prefix);
1967 if ((erased_pos) && ('}' != erased_char))
1968 {
1969 len = strlen (prefix) + 1;
1970 prefix = GNUNET_realloc (prefix, len + 1);
1971 prefix[len - 1] = erased_char;
1972 prefix[len] = '\0';
1973 }
1974 result = GNUNET_malloc (strlen (prefix) + strlen (post) + 1);
1975 strcpy (result, prefix);
1976 strcat (result, post);
1977 GNUNET_free (def);
1978 GNUNET_free (prefix);
1979 GNUNET_free (orig);
1980 return result;
1981}
1982
1983
1984char *
1985GNUNET_CONFIGURATION_expand_dollar (
1986 const struct GNUNET_CONFIGURATION_Handle *cfg,
1987 char *orig)
1988{
1989 char *dup;
1990 size_t i;
1991 size_t len;
1992
1993 for (i = 0; '\0' != orig[i]; i++)
1994 {
1995 if ('$' != orig[i])
1996 continue;
1997 dup = GNUNET_strdup (orig + i);
1998 dup = expand_dollar (cfg, dup, 0);
1999 GNUNET_assert (NULL != dup); /* make compiler happy */
2000 len = strlen (dup) + 1;
2001 orig = GNUNET_realloc (orig, i + len);
2002 GNUNET_memcpy (orig + i, dup, len);
2003 GNUNET_free (dup);
2004 }
2005 return orig;
2006}
2007
2008
2009enum GNUNET_GenericReturnValue
2010GNUNET_CONFIGURATION_get_value_filename (
2011 const struct GNUNET_CONFIGURATION_Handle *cfg,
2012 const char *section,
2013 const char *option,
2014 char **value)
2015{
2016 char *tmp;
2017
2018 if (GNUNET_OK !=
2019 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
2020 {
2021 LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to retrieve filename\n");
2022 *value = NULL;
2023 return GNUNET_SYSERR;
2024 }
2025 tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
2026 *value = GNUNET_STRINGS_filename_expand (tmp);
2027 GNUNET_free (tmp);
2028 if (*value == NULL)
2029 return GNUNET_SYSERR;
2030 return GNUNET_OK;
2031}
2032
2033
2034enum GNUNET_GenericReturnValue
2035GNUNET_CONFIGURATION_get_value_yesno (
2036 const struct GNUNET_CONFIGURATION_Handle *cfg,
2037 const char *section,
2038 const char *option)
2039{
2040 static const char *yesno[] = { "YES", "NO", NULL };
2041 const char *val;
2042 int ret;
2043
2044 ret =
2045 GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val);
2046 if (ret == GNUNET_SYSERR)
2047 return ret;
2048 if (val == yesno[0])
2049 return GNUNET_YES;
2050 return GNUNET_NO;
2051}
2052
2053
2054int
2055GNUNET_CONFIGURATION_iterate_value_filenames (
2056 const struct GNUNET_CONFIGURATION_Handle *cfg,
2057 const char *section,
2058 const char *option,
2059 GNUNET_FileNameCallback cb,
2060 void *cb_cls)
2061{
2062 char *list;
2063 char *pos;
2064 char *end;
2065 char old;
2066 int ret;
2067
2068 if (GNUNET_OK !=
2069 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
2070 return 0;
2071 GNUNET_assert (list != NULL);
2072 ret = 0;
2073 pos = list;
2074 while (1)
2075 {
2076 while (pos[0] == ' ')
2077 pos++;
2078 if (strlen (pos) == 0)
2079 break;
2080 end = pos + 1;
2081 while ((end[0] != ' ') && (end[0] != '\0'))
2082 {
2083 if (end[0] == '\\')
2084 {
2085 switch (end[1])
2086 {
2087 case '\\':
2088 case ' ':
2089 memmove (end, &end[1], strlen (&end[1]) + 1);
2090
2091 case '\0':
2092 /* illegal, but just keep it */
2093 break;
2094
2095 default:
2096 /* illegal, but just ignore that there was a '/' */
2097 break;
2098 }
2099 }
2100 end++;
2101 }
2102 old = end[0];
2103 end[0] = '\0';
2104 if (strlen (pos) > 0)
2105 {
2106 ret++;
2107 if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
2108 {
2109 ret = GNUNET_SYSERR;
2110 break;
2111 }
2112 }
2113 if (old == '\0')
2114 break;
2115 pos = end + 1;
2116 }
2117 GNUNET_free (list);
2118 return ret;
2119}
2120
2121
2122/**
2123 * FIXME.
2124 *
2125 * @param value FIXME
2126 * @return FIXME
2127 */
2128static char *
2129escape_name (const char *value)
2130{
2131 char *escaped;
2132 const char *rpos;
2133 char *wpos;
2134
2135 escaped = GNUNET_malloc (strlen (value) * 2 + 1);
2136 memset (escaped, 0, strlen (value) * 2 + 1);
2137 rpos = value;
2138 wpos = escaped;
2139 while (rpos[0] != '\0')
2140 {
2141 switch (rpos[0])
2142 {
2143 case '\\':
2144 case ' ':
2145 wpos[0] = '\\';
2146 wpos[1] = rpos[0];
2147 wpos += 2;
2148 break;
2149
2150 default:
2151 wpos[0] = rpos[0];
2152 wpos++;
2153 }
2154 rpos++;
2155 }
2156 return escaped;
2157}
2158
2159
2160/**
2161 * FIXME.
2162 *
2163 * @param cls string we compare with (const char*)
2164 * @param fn filename we are currently looking at
2165 * @return #GNUNET_OK if the names do not match, #GNUNET_SYSERR if they do
2166 */
2167static enum GNUNET_GenericReturnValue
2168test_match (void *cls, const char *fn)
2169{
2170 const char *of = cls;
2171
2172 return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
2173}
2174
2175
2176enum GNUNET_GenericReturnValue
2177GNUNET_CONFIGURATION_append_value_filename (
2178 struct GNUNET_CONFIGURATION_Handle *cfg,
2179 const char *section,
2180 const char *option,
2181 const char *value)
2182{
2183 char *escaped;
2184 char *old;
2185 char *nw;
2186
2187 if (GNUNET_SYSERR ==
2188 GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
2189 section,
2190 option,
2191 &test_match,
2192 (void *) value))
2193 return GNUNET_NO; /* already exists */
2194 if (GNUNET_OK !=
2195 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
2196 old = GNUNET_strdup ("");
2197 escaped = escape_name (value);
2198 nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
2199 strcpy (nw, old);
2200 if (strlen (old) > 0)
2201 strcat (nw, " ");
2202 strcat (nw, escaped);
2203 GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
2204 GNUNET_free (old);
2205 GNUNET_free (nw);
2206 GNUNET_free (escaped);
2207 return GNUNET_OK;
2208}
2209
2210
2211enum GNUNET_GenericReturnValue
2212GNUNET_CONFIGURATION_remove_value_filename (
2213 struct GNUNET_CONFIGURATION_Handle *cfg,
2214 const char *section,
2215 const char *option,
2216 const char *value)
2217{
2218 char *list;
2219 char *pos;
2220 char *end;
2221 char *match;
2222 char old;
2223
2224 if (GNUNET_OK !=
2225 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
2226 return GNUNET_NO;
2227 match = escape_name (value);
2228 pos = list;
2229 while (1)
2230 {
2231 while (pos[0] == ' ')
2232 pos++;
2233 if (strlen (pos) == 0)
2234 break;
2235 end = pos + 1;
2236 while ((end[0] != ' ') && (end[0] != '\0'))
2237 {
2238 if (end[0] == '\\')
2239 {
2240 switch (end[1])
2241 {
2242 case '\\':
2243 case ' ':
2244 end++;
2245 break;
2246
2247 case '\0':
2248 /* illegal, but just keep it */
2249 break;
2250
2251 default:
2252 /* illegal, but just ignore that there was a '/' */
2253 break;
2254 }
2255 }
2256 end++;
2257 }
2258 old = end[0];
2259 end[0] = '\0';
2260 if (0 == strcmp (pos, match))
2261 {
2262 if (old != '\0')
2263 memmove (pos, &end[1], strlen (&end[1]) + 1);
2264 else
2265 {
2266 if (pos != list)
2267 pos[-1] = '\0';
2268 else
2269 pos[0] = '\0';
2270 }
2271 GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list);
2272 GNUNET_free (list);
2273 GNUNET_free (match);
2274 return GNUNET_OK;
2275 }
2276 if (old == '\0')
2277 break;
2278 end[0] = old;
2279 pos = end + 1;
2280 }
2281 GNUNET_free (list);
2282 GNUNET_free (match);
2283 return GNUNET_NO;
2284}
2285
2286
2287enum GNUNET_GenericReturnValue
2288GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
2289 const char *defaults_d)
2290{
2291 struct CollectFilesContext files_context = {
2292 .files = NULL,
2293 .files_length = 0,
2294 };
2295 enum GNUNET_GenericReturnValue fun_ret;
2296
2297 if (GNUNET_SYSERR ==
2298 GNUNET_DISK_directory_scan (defaults_d, &collect_files_cb,
2299 &files_context))
2300 return GNUNET_SYSERR; /* no configuration at all found */
2301 qsort (files_context.files,
2302 files_context.files_length,
2303 sizeof (char *),
2304 pstrcmp);
2305 for (unsigned int i = 0; i < files_context.files_length; i++)
2306 {
2307 char *ext;
2308 const char *filename = files_context.files[i];
2309
2310 /* Examine file extension */
2311 ext = strrchr (filename, '.');
2312 if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
2313 {
2314 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
2315 fun_ret = GNUNET_OK;
2316 goto cleanup;
2317 }
2318 fun_ret = GNUNET_CONFIGURATION_parse (cfg, filename);
2319 if (fun_ret != GNUNET_OK)
2320 break;
2321 }
2322cleanup:
2323 if (files_context.files_length > 0)
2324 {
2325 for (size_t i = 0; i < files_context.files_length; i++)
2326 GNUNET_free (files_context.files[i]);
2327 GNUNET_array_grow (files_context.files,
2328 files_context.files_length,
2329 0);
2330 }
2331 return fun_ret;
2332}
2333
2334
2335char *
2336GNUNET_CONFIGURATION_default_filename (void)
2337{
2338 char *cfg_fn;
2339 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
2340 const char *xdg = getenv ("XDG_CONFIG_HOME");
2341
2342 if (NULL != xdg)
2343 GNUNET_asprintf (&cfg_fn,
2344 "%s%s%s",
2345 xdg,
2346 DIR_SEPARATOR_STR,
2347 pd->config_file);
2348 else
2349 cfg_fn = GNUNET_strdup (pd->user_config_file);
2350
2351 if (GNUNET_OK == GNUNET_DISK_file_test_read (cfg_fn))
2352 return cfg_fn;
2353 GNUNET_free (cfg_fn);
2354
2355 /* Fall back to /etc/ for the default configuration.
2356 Should be okay to use forward slashes here. */
2357
2358 GNUNET_asprintf (&cfg_fn,
2359 "/etc/%s",
2360 pd->config_file);
2361 if (GNUNET_OK == GNUNET_DISK_file_test_read (cfg_fn))
2362 return cfg_fn;
2363 GNUNET_free (cfg_fn);
2364
2365 GNUNET_asprintf (&cfg_fn,
2366 "/etc/%s/%s",
2367 pd->project_dirname,
2368 pd->config_file);
2369 if (GNUNET_OK == GNUNET_DISK_file_test_read (cfg_fn))
2370 return cfg_fn;
2371
2372 GNUNET_free (cfg_fn);
2373 return NULL;
2374}
2375
2376
2377struct GNUNET_CONFIGURATION_Handle *
2378GNUNET_CONFIGURATION_default (void)
2379{
2380 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
2381 const struct GNUNET_OS_ProjectData *dpd = GNUNET_OS_project_data_default ();
2382 const char *xdg = getenv ("XDG_CONFIG_HOME");
2383 char *cfgname = NULL;
2384 struct GNUNET_CONFIGURATION_Handle *cfg;
2385
2386 /* Makes sure function implicitly looking at the installation directory (for
2387 example GNUNET_CONFIGURATION_load further down) use GNUnet's environment
2388 instead of the caller's. It's done at the start to make sure as many
2389 functions as possible are directed to the proper paths. */
2390 GNUNET_OS_init (dpd);
2391
2392 cfg = GNUNET_CONFIGURATION_create ();
2393
2394 /* First, try user configuration. */
2395 if (NULL != xdg)
2396 GNUNET_asprintf (&cfgname, "%s/%s", xdg, dpd->config_file);
2397 else
2398 cfgname = GNUNET_strdup (dpd->user_config_file);
2399
2400 /* If user config doesn't exist, try in
2401 /etc/<projdir>/<cfgfile> and /etc/<cfgfile> */
2402 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2403 {
2404 GNUNET_free (cfgname);
2405 GNUNET_asprintf (&cfgname, "/etc/%s", dpd->config_file);
2406 }
2407 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2408 {
2409 GNUNET_free (cfgname);
2410 GNUNET_asprintf (&cfgname,
2411 "/etc/%s/%s",
2412 dpd->project_dirname,
2413 dpd->config_file);
2414 }
2415 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2416 {
2417 LOG (GNUNET_ERROR_TYPE_ERROR,
2418 "Unable to top-level configuration file.\n");
2419 GNUNET_OS_init (pd);
2420 GNUNET_CONFIGURATION_destroy (cfg);
2421 GNUNET_free (cfgname);
2422 return NULL;
2423 }
2424
2425 /* We found a configuration file that looks good, try to load it. */
2426
2427 LOG (GNUNET_ERROR_TYPE_DEBUG,
2428 "Loading top-level configuration from '%s'\n",
2429 cfgname);
2430 if (GNUNET_OK !=
2431 GNUNET_CONFIGURATION_load (cfg, cfgname))
2432 {
2433 GNUNET_OS_init (pd);
2434 GNUNET_CONFIGURATION_destroy (cfg);
2435 GNUNET_free (cfgname);
2436 return NULL;
2437 }
2438 GNUNET_free (cfgname);
2439 GNUNET_OS_init (pd);
2440 return cfg;
2441}
2442
2443
2444/**
2445 * Load configuration (starts with defaults, then loads
2446 * system-specific configuration).
2447 *
2448 * @param cfg configuration to update
2449 * @param filename name of the configuration file, NULL to load defaults
2450 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
2451 */
2452int
2453GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
2454 const char *filename)
2455{
2456 char *baseconfig;
2457 const char *base_config_varname;
2458
2459 if (cfg->load_called)
2460 {
2461 /* FIXME: Make this a GNUNET_assert later */
2462 GNUNET_break (0);
2463 GNUNET_free (cfg->main_filename);
2464 }
2465 cfg->load_called = true;
2466 if (NULL != filename)
2467 {
2468 GNUNET_free (cfg->main_filename);
2469 cfg->main_filename = GNUNET_strdup (filename);
2470 }
2471
2472 base_config_varname = GNUNET_OS_project_data_get ()->base_config_varname;
2473
2474 if ((NULL != base_config_varname)
2475 && (NULL != (baseconfig = getenv (base_config_varname))))
2476 {
2477 baseconfig = GNUNET_strdup (baseconfig);
2478 }
2479 else
2480 {
2481 char *ipath;
2482
2483 ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
2484 if (NULL == ipath)
2485 {
2486 GNUNET_break (0);
2487 return GNUNET_SYSERR;
2488 }
2489 GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
2490 GNUNET_free (ipath);
2491 }
2492
2493 char *dname = GNUNET_STRINGS_filename_expand (baseconfig);
2494 GNUNET_free (baseconfig);
2495
2496 if ((GNUNET_YES == GNUNET_DISK_directory_test (dname, GNUNET_YES)) &&
2497 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load_from (cfg, dname)))
2498 {
2499 LOG (GNUNET_ERROR_TYPE_WARNING,
2500 "Failed to load base configuration from '%s'\n",
2501 filename);
2502 GNUNET_free (dname);
2503 return GNUNET_SYSERR; /* no configuration at all found */
2504 }
2505 GNUNET_free (dname);
2506 if ((NULL != filename) &&
2507 (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
2508 {
2509 /* specified configuration not found */
2510 LOG (GNUNET_ERROR_TYPE_WARNING,
2511 "Failed to load configuration from file '%s'\n",
2512 filename);
2513 return GNUNET_SYSERR;
2514 }
2515 if (((GNUNET_YES !=
2516 GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
2517 (filename != NULL))
2518 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
2519 filename);
2520 return GNUNET_OK;
2521}
2522
2523
2524/* end of configuration.c */
diff --git a/src/util/configuration_helper.c b/src/util/configuration_helper.c
deleted file mode 100644
index 8f995ec03..000000000
--- a/src/util/configuration_helper.c
+++ /dev/null
@@ -1,302 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2007, 2008, 2009, 2013, 2020, 2021 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 * @file src/util/configuration_helper.c
22 * @brief helper logic for gnunet-config
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28/**
29 * Print each option in a given section as a filename.
30 *
31 * @param cls closure
32 * @param section name of the section
33 * @param option name of the option
34 * @param value value of the option
35 */
36static void
37print_filename_option (void *cls,
38 const char *section,
39 const char *option,
40 const char *value)
41{
42 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
43
44 char *value_fn;
45 char *fn;
46
47 GNUNET_assert (GNUNET_OK ==
48 GNUNET_CONFIGURATION_get_value_filename (cfg,
49 section,
50 option,
51 &value_fn));
52 fn = GNUNET_STRINGS_filename_expand (value_fn);
53 if (NULL == fn)
54 fn = value_fn;
55 else
56 GNUNET_free (value_fn);
57 fprintf (stdout,
58 "%s = %s\n",
59 option,
60 fn);
61 GNUNET_free (fn);
62}
63
64
65/**
66 * Print each option in a given section.
67 *
68 * @param cls closure
69 * @param section name of the section
70 * @param option name of the option
71 * @param value value of the option
72 */
73static void
74print_option (void *cls,
75 const char *section,
76 const char *option,
77 const char *value)
78{
79 (void) cls;
80 (void) section;
81
82 fprintf (stdout,
83 "%s = %s\n",
84 option,
85 value);
86}
87
88
89/**
90 * Print out given section name.
91 *
92 * @param cls unused
93 * @param section a section in the configuration file
94 */
95static void
96print_section_name (void *cls,
97 const char *section)
98{
99 (void) cls;
100 fprintf (stdout,
101 "%s\n",
102 section);
103}
104
105
106void
107GNUNET_CONFIGURATION_config_tool_run (
108 void *cls,
109 char *const *args,
110 const char *cfgfile,
111 const struct GNUNET_CONFIGURATION_Handle *cfg)
112{
113 struct GNUNET_CONFIGURATION_ConfigSettings *cs = cls;
114 struct GNUNET_CONFIGURATION_Handle *out = NULL;
115 struct GNUNET_CONFIGURATION_Handle *ncfg = NULL;
116
117 (void) args;
118 if (cs->diagnostics)
119 {
120 /* Re-parse the configuration with diagnostics enabled. */
121 ncfg = GNUNET_CONFIGURATION_create ();
122 GNUNET_CONFIGURATION_enable_diagnostics (ncfg);
123 GNUNET_CONFIGURATION_load (ncfg,
124 cfgfile);
125 cfg = ncfg;
126 }
127
128 if (cs->full)
129 cs->rewrite = GNUNET_YES;
130 if (cs->list_sections)
131 {
132 fprintf (stderr,
133 _ ("The following sections are available:\n"));
134 GNUNET_CONFIGURATION_iterate_sections (cfg,
135 &print_section_name,
136 NULL);
137 return;
138 }
139 if ( (! cs->rewrite) &&
140 (NULL == cs->section) )
141 {
142 char *serialization;
143
144 if (! cs->diagnostics)
145 {
146 fprintf (stderr,
147 _ ("%s, %s or %s argument is required\n"),
148 "--section",
149 "--list-sections",
150 "--diagnostics");
151 cs->global_ret = EXIT_INVALIDARGUMENT;
152 return;
153 }
154 serialization = GNUNET_CONFIGURATION_serialize_diagnostics (cfg);
155 fprintf (stdout,
156 "%s",
157 serialization);
158 GNUNET_free (serialization);
159 }
160 else if ( (NULL != cs->section) &&
161 (NULL == cs->value) )
162 {
163 if (NULL == cs->option)
164 {
165 GNUNET_CONFIGURATION_iterate_section_values (
166 cfg,
167 cs->section,
168 cs->is_filename
169 ? &print_filename_option
170 : &print_option,
171 (void *) cfg);
172 }
173 else
174 {
175 char *value;
176
177 if (cs->is_filename)
178 {
179 if (GNUNET_OK !=
180 GNUNET_CONFIGURATION_get_value_filename (cfg,
181 cs->section,
182 cs->option,
183 &value))
184 {
185 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
186 cs->section,
187 cs->option);
188 cs->global_ret = EXIT_NOTCONFIGURED;
189 return;
190 }
191 }
192 else
193 {
194 if (GNUNET_OK !=
195 GNUNET_CONFIGURATION_get_value_string (cfg,
196 cs->section,
197 cs->option,
198 &value))
199 {
200 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
201 cs->section,
202 cs->option);
203 cs->global_ret = EXIT_NOTCONFIGURED;
204 return;
205 }
206 }
207 fprintf (stdout,
208 "%s\n",
209 value);
210 GNUNET_free (value);
211 }
212 }
213 else if (NULL != cs->section)
214 {
215 if (NULL == cs->option)
216 {
217 fprintf (stderr,
218 _ ("--option argument required to set value\n"));
219 cs->global_ret = EXIT_INVALIDARGUMENT;
220 return;
221 }
222 out = GNUNET_CONFIGURATION_dup (cfg);
223 GNUNET_CONFIGURATION_set_value_string (out,
224 cs->section,
225 cs->option,
226 cs->value);
227 cs->rewrite = GNUNET_YES;
228 }
229 if (cs->rewrite)
230 {
231 char *cfg_fn = NULL;
232
233 if (NULL == out)
234 out = GNUNET_CONFIGURATION_dup (cfg);
235
236 if (NULL == cfgfile)
237 {
238 const char *xdg = getenv ("XDG_CONFIG_HOME");
239
240 if (NULL != xdg)
241 GNUNET_asprintf (&cfg_fn,
242 "%s%s%s",
243 xdg,
244 DIR_SEPARATOR_STR,
245 GNUNET_OS_project_data_get ()->config_file);
246 else
247 cfg_fn = GNUNET_strdup (
248 GNUNET_OS_project_data_get ()->user_config_file);
249 cfgfile = cfg_fn;
250 }
251
252 if (! cs->full)
253 {
254 struct GNUNET_CONFIGURATION_Handle *def;
255
256 def = GNUNET_CONFIGURATION_create ();
257 if (GNUNET_OK !=
258 GNUNET_CONFIGURATION_load (def,
259 NULL))
260 {
261 fprintf (stderr,
262 _ ("failed to load configuration defaults"));
263 cs->global_ret = 1;
264 GNUNET_CONFIGURATION_destroy (def);
265 GNUNET_CONFIGURATION_destroy (out);
266 GNUNET_free (cfg_fn);
267 return;
268 }
269 if (GNUNET_OK !=
270 GNUNET_CONFIGURATION_write_diffs (def,
271 out,
272 cfgfile))
273 cs->global_ret = 2;
274 GNUNET_CONFIGURATION_destroy (def);
275 }
276 else
277 {
278 if (GNUNET_OK !=
279 GNUNET_CONFIGURATION_write (out,
280 cfgfile))
281 cs->global_ret = 2;
282 }
283 GNUNET_free (cfg_fn);
284 }
285 if (NULL != out)
286 GNUNET_CONFIGURATION_destroy (out);
287 if (NULL != ncfg)
288 GNUNET_CONFIGURATION_destroy (ncfg);
289}
290
291
292void
293GNUNET_CONFIGURATION_config_settings_free (
294 struct GNUNET_CONFIGURATION_ConfigSettings *cs)
295{
296 GNUNET_free (cs->option);
297 GNUNET_free (cs->section);
298 GNUNET_free (cs->value);
299}
300
301
302/* end of configuration_helper.c */
diff --git a/src/util/consttime_memcmp.c b/src/util/consttime_memcmp.c
deleted file mode 100644
index 5dfcb0757..000000000
--- a/src/util/consttime_memcmp.c
+++ /dev/null
@@ -1,279 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2015 Christophe Meessen
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25/* Minimally modified for libgnunetutil: added license header
26 (from https://github.com/chmike/cst_time_memcmp, LICENSE file), and
27 renamed the exported symbol: */
28#define consttime_memcmp GNUNET_memcmp_ct_
29/* Rest of the file is 'original' */
30
31
32#include <stddef.h>
33#include <inttypes.h>
34
35/*
36 * "constant time" memcmp. Time taken depends on the buffer length, of
37 * course, but not on the content of the buffers.
38 *
39 * Just like the ordinary memcmp function, the return value is
40 * tri-state: <0, 0, or >0. However, applications that need a
41 * constant-time memory comparison function usually need only a
42 * two-state result, signalling only whether the inputs were identical
43 * or different, but not signalling which of the inputs was larger.
44 * This code could be made significantly faster and simpler if the
45 * requirement for a tri-state result were removed.
46 *
47 * In order to protect against adversaries who can observe timing,
48 * cache hits or misses, page faults, etc., and who can use such
49 * observations to learn something about the relationship between the
50 * contents of the two buffers, we have to perform exactly the same
51 * instructions and memory accesses regardless of the contents of the
52 * buffers. We can't stop as soon as we find a difference, we can't
53 * take different conditional branches depending on the data, and we
54 * can't use different pointers or array indexes depending on the data.
55 *
56 * Further reading:
57 *
58 * .Rs
59 * .%A Paul C. Kocher
60 * .%T Timing Attacks on Implementations of Diffie-Hellman, RSA, DSS, and Other Systems
61 * .%D 1996
62 * .%J CRYPTO 1996
63 * .%P 104-113
64 * .%U http://www.cryptography.com/timingattack/paper.html
65 * .%U http://www.webcitation.org/query?url=http%3A%2F%2Fwww.cryptography.com%2Ftimingattack%2Fpaper.html&date=2012-10-17
66 * .Re
67 *
68 * .Rs
69 * .%A D. Boneh
70 * .%A D. Brumley
71 * .%T Remote timing attacks are practical
72 * .%D August 2003
73 * .%J Proceedings of the 12th Usenix Security Symposium, 2003
74 * .%U https://crypto.stanford.edu/~dabo/abstracts/ssl-timing.html
75 * .%U http://www.webcitation.org/query?url=https%3A%2F%2Fcrypto.stanford.edu%2F%7Edabo%2Fabstracts%2Fssl-timing.html&date=2012-10-17
76 * .%U http://www.webcitation.org/query?url=http%3A%2F%2Fcrypto.stanford.edu%2F%7Edabo%2Fpubs%2Fpapers%2Fssl-timing.pdf&date=2012-10-17
77 * .Es
78 *
79 * .Rs
80 * .%A Coda Hale
81 * .%T A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)
82 * .%D 13 Aug 2009
83 * .%U http://codahale.com/a-lesson-in-timing-attacks/
84 * .%U http://www.webcitation.org/query?url=http%3A%2F%2Fcodahale.com%2Fa-lesson-in-timing-attacks%2F&date=2012-10-17
85 * .Re
86 *
87 */
88
89/*
90 * A note on portability:
91 *
92 * We assume that char is exactly 8 bits, the same as uint8_t, and that
93 * integer types with exactly 16 bits and exactly 32 bits exist. (If
94 * there is ever a need to change this, then the actual requirement is
95 * that we need a type that is at least two bits wider than char, and
96 * another type that is at least two bits wider than that, or we need to
97 * fake it somehow.)
98 *
99 * We do not assume any particular size for the plain "int" type, except
100 * that it is at least 16 bits, as is guaranteed by the C language
101 * standard.
102 *
103 * We do not assume that signed integer overflow is harmless. We
104 * ensure that signed integer overflow does not occur, so that
105 * implementation-defined overflow behaviour is not invoked.
106 *
107 * We rely on the C standard's guarantees regarding the wraparound
108 * behaviour of unsigned integer arithmetic, and on the analogous
109 * guarantees regarding conversions from signed types to narrower
110 * unsigned types.
111 *
112 * We do not assume that the platform uses two's complement arithmetic.
113 */
114
115/*
116 * How hard do we have to try to prevent unwanted compiler optimisations?
117 *
118 * Try compiling with "#define USE_VOLATILE_TEMPORARY 0", and examine
119 * the compiler output. If the only conditional tests in the entire
120 * function are to test whether len is zero, then all is well, but try
121 * again with different optimisation flags to be sure. If the compiler
122 * emitted code with conditional tests that do anything other than
123 * testing whether len is zero, then that's a problem, so try again with
124 * "#define USE_VOLATILE_TEMPORARY 1". If it's still bad, then you are
125 * out of luck.
126 */
127#define USE_VOLATILE_TEMPORARY 0
128
129int
130consttime_memcmp (const void *b1, const void *b2, size_t len)
131{
132 const uint8_t *c1, *c2;
133 uint16_t d, r, m;
134
135#if USE_VOLATILE_TEMPORARY
136 volatile uint16_t v;
137#else
138 uint16_t v;
139#endif
140
141 c1 = b1;
142 c2 = b2;
143
144 r = 0;
145 while (len)
146 {
147 /*
148 * Take the low 8 bits of r (in the range 0x00 to 0xff,
149 * or 0 to 255);
150 * As explained elsewhere, the low 8 bits of r will be zero
151 * if and only if all bytes compared so far were identical;
152 * Zero-extend to a 16-bit type (in the range 0x0000 to
153 * 0x00ff);
154 * Add 255, yielding a result in the range 255 to 510;
155 * Save that in a volatile variable to prevent
156 * the compiler from trying any shortcuts (the
157 * use of a volatile variable depends on "#ifdef
158 * USE_VOLATILE_TEMPORARY", and most compilers won't
159 * need it);
160 * Divide by 256 yielding a result of 1 if the original
161 * value of r was non-zero, or 0 if r was zero;
162 * Subtract 1, yielding 0 if r was non-zero, or -1 if r
163 * was zero;
164 * Convert to uint16_t, yielding 0x0000 if r was
165 * non-zero, or 0xffff if r was zero;
166 * Save in m.
167 */v = ((uint16_t) (uint8_t) r) + 255;
168 m = v / 256 - 1;
169
170 /*
171 * Get the values from *c1 and *c2 as uint8_t (each will
172 * be in the range 0 to 255, or 0x00 to 0xff);
173 * Convert them to signed int values (still in the
174 * range 0 to 255);
175 * Subtract them using signed arithmetic, yielding a
176 * result in the range -255 to +255;
177 * Convert to uint16_t, yielding a result in the range
178 * 0xff01 to 0xffff (for what was previously -255 to
179 * -1), or 0, or in the range 0x0001 to 0x00ff (for what
180 * was previously +1 to +255).
181 */d = (uint16_t) ((int) *c1 - (int) *c2);
182
183 /*
184 * If the low 8 bits of r were previously 0, then m
185 * is now 0xffff, so (d & m) is the same as d, so we
186 * effectively copy d to r;
187 * Otherwise, if r was previously non-zero, then m is
188 * now 0, so (d & m) is zero, so leave r unchanged.
189 * Note that the low 8 bits of d will be zero if and
190 * only if d == 0, which happens when *c1 == *c2.
191 * The low 8 bits of r are thus zero if and only if the
192 * entirety of r is zero, which happens if and only if
193 * all bytes compared so far were equal. As soon as a
194 * non-zero value is stored in r, it remains unchanged
195 * for the remainder of the loop.
196 */r |= (d & m);
197
198 /*
199 * Increment pointers, decrement length, and loop.
200 */
201 ++c1;
202 ++c2;
203 --len;
204 }
205
206 /*
207 * At this point, r is an unsigned value, which will be 0 if the
208 * final result should be zero, or in the range 0x0001 to 0x00ff
209 * (1 to 255) if the final result should be positive, or in the
210 * range 0xff01 to 0xffff (65281 to 65535) if the final result
211 * should be negative.
212 *
213 * We want to convert the unsigned values in the range 0xff01
214 * to 0xffff to signed values in the range -255 to -1, while
215 * converting the other unsigned values to equivalent signed
216 * values (0, or +1 to +255).
217 *
218 * On a machine with two's complement arithmetic, simply copying
219 * the underlying bits (with sign extension if int is wider than
220 * 16 bits) would do the job, so something like this might work:
221 *
222 * return (int16_t)r;
223 *
224 * However, that invokes implementation-defined behaviour,
225 * because values larger than 32767 can't fit in a signed 16-bit
226 * integer without overflow.
227 *
228 * To avoid any implementation-defined behaviour, we go through
229 * these contortions:
230 *
231 * a. Calculate ((uint32_t)r + 0x8000). The cast to uint32_t
232 * it to prevent problems on platforms where int is narrower
233 * than 32 bits. If int is a larger than 32-bits, then the
234 * usual arithmetic conversions cause this addition to be
235 * done in unsigned int arithmetic. If int is 32 bits
236 * or narrower, then this addition is done in uint32_t
237 * arithmetic. In either case, no overflow or wraparound
238 * occurs, and the result from this step has a value that
239 * will be one of 0x00008000 (32768), or in the range
240 * 0x00008001 to 0x000080ff (32769 to 33023), or in the range
241 * 0x00017f01 to 0x00017fff (98049 to 98303).
242 *
243 * b. Cast the result from (a) to uint16_t. This effectively
244 * discards the high bits of the result, in a way that is
245 * well defined by the C language. The result from this step
246 * will be of type uint16_t, and its value will be one of
247 * 0x8000 (32768), or in the range 0x8001 to 0x80ff (32769 to
248 * 33023), or in the range 0x7f01 to 0x7fff (32513 to
249 * 32767).
250 *
251 * c. Cast the result from (b) to int32_t. We use int32_t
252 * instead of int because we need a type that's strictly
253 * larger than 16 bits, and the C standard allows
254 * implementations where int is only 16 bits. The result
255 * from this step will be of type int32_t, and its value will
256 * be one of 0x00008000 (32768), or in the range 0x00008001
257 * to 0x000080ff (32769 to 33023), or in the range 0x00007f01
258 * to 0x00007fff (32513 to 32767).
259 *
260 * d. Take the result from (c) and subtract 0x8000 (32768) using
261 * signed int32_t arithmetic. The result from this step will
262 * be of type int32_t and the value will be one of
263 * 0x00000000 (0), or in the range 0x00000001 to 0x000000ff
264 * (+1 to +255), or in the range 0xffffff01 to 0xffffffff
265 * (-255 to -1).
266 *
267 * e. Cast the result from (d) to int. This does nothing
268 * interesting, except to make explicit what would have been
269 * implicit in the return statement. The final result is an
270 * int in the range -255 to +255.
271 *
272 * Unfortunately, compilers don't seem to be good at figuring
273 * out that most of this can be optimised away by careful choice
274 * of register width and sign extension.
275 *
276 */return (/*e*/ int) (/*d*/
277 (/*c*/ int32_t) (/*b*/ uint16_t) (/*a*/ (uint32_t) r + 0x8000)
278 - 0x8000);
279}
diff --git a/src/util/container_bloomfilter.c b/src/util/container_bloomfilter.c
deleted file mode 100644
index d89b46252..000000000
--- a/src/util/container_bloomfilter.c
+++ /dev/null
@@ -1,896 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2004, 2006, 2008, 2011, 2012, 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 * @file util/container_bloomfilter.c
22 * @brief data structure used to reduce disk accesses.
23 *
24 * The idea basically: Create a signature for each element in the
25 * database. Add those signatures to a bit array. When doing a lookup,
26 * check if the bit array matches the signature of the requested
27 * element. If yes, address the disk, otherwise return 'not found'.
28 *
29 * A property of the bloom filter is that sometimes we will have
30 * a match even if the element is not on the disk (then we do
31 * an unnecessary disk access), but what's most important is that
32 * we never get a single "false negative".
33 *
34 * To be able to delete entries from the bloom filter, we maintain
35 * a 4 bit counter in the file on the drive (we still use only one
36 * bit in memory).
37 *
38 * @author Igor Wronsky
39 * @author Christian Grothoff
40 */
41
42#include "platform.h"
43#include "gnunet_util_lib.h"
44
45#define LOG(kind, ...) \
46 GNUNET_log_from (kind, "util-container-bloomfilter", __VA_ARGS__)
47
48#define LOG_STRERROR(kind, syscall) \
49 GNUNET_log_from_strerror (kind, "util-container-bloomfilter", syscall)
50
51#define LOG_STRERROR_FILE(kind, syscall, filename) \
52 GNUNET_log_from_strerror_file (kind, \
53 "util-container-bloomfilter", \
54 syscall, \
55 filename)
56
57struct GNUNET_CONTAINER_BloomFilter
58{
59 /**
60 * The actual bloomfilter bit array
61 */
62 char *bitArray;
63
64 /**
65 * Filename of the filter
66 */
67 char *filename;
68
69 /**
70 * The bit counter file on disk
71 */
72 struct GNUNET_DISK_FileHandle *fh;
73
74 /**
75 * How many bits we set for each stored element
76 */
77 unsigned int addressesPerElement;
78
79 /**
80 * Size of bitArray in bytes
81 */
82 size_t bitArraySize;
83};
84
85
86/**
87 * Get the number of the addresses set per element in the bloom filter.
88 *
89 * @param bf the filter
90 * @return addresses set per element in the bf
91 */
92size_t
93GNUNET_CONTAINER_bloomfilter_get_element_addresses (
94 const struct GNUNET_CONTAINER_BloomFilter *bf)
95{
96 if (bf == NULL)
97 return 0;
98 return bf->addressesPerElement;
99}
100
101
102/**
103 * Get size of the bloom filter.
104 *
105 * @param bf the filter
106 * @return number of bytes used for the data of the bloom filter
107 */
108size_t
109GNUNET_CONTAINER_bloomfilter_get_size (
110 const struct GNUNET_CONTAINER_BloomFilter *bf)
111{
112 if (bf == NULL)
113 return 0;
114 return bf->bitArraySize;
115}
116
117
118/**
119 * Copy an existing memory. Any association with a file
120 * on-disk will be lost in the process.
121 * @param bf the filter to copy
122 * @return copy of the bf
123 */
124struct GNUNET_CONTAINER_BloomFilter *
125GNUNET_CONTAINER_bloomfilter_copy (
126 const struct GNUNET_CONTAINER_BloomFilter *bf)
127{
128 return GNUNET_CONTAINER_bloomfilter_init (bf->bitArray,
129 bf->bitArraySize,
130 bf->addressesPerElement);
131}
132
133
134/**
135 * Sets a bit active in the bitArray. Increment bit-specific
136 * usage counter on disk only if below 4bit max (==15).
137 *
138 * @param bitArray memory area to set the bit in
139 * @param bitIdx which bit to set
140 */
141static void
142setBit (char *bitArray, unsigned int bitIdx)
143{
144 size_t arraySlot;
145 unsigned int targetBit;
146
147 arraySlot = bitIdx / 8;
148 targetBit = (1L << (bitIdx % 8));
149 bitArray[arraySlot] |= targetBit;
150}
151
152
153/**
154 * Clears a bit from bitArray. Bit is cleared from the array
155 * only if the respective usage counter on the disk hits/is zero.
156 *
157 * @param bitArray memory area to set the bit in
158 * @param bitIdx which bit to unset
159 */
160static void
161clearBit (char *bitArray, unsigned int bitIdx)
162{
163 size_t slot;
164 unsigned int targetBit;
165
166 slot = bitIdx / 8;
167 targetBit = (1L << (bitIdx % 8));
168 bitArray[slot] = bitArray[slot] & (~targetBit);
169}
170
171
172/**
173 * Checks if a bit is active in the bitArray
174 *
175 * @param bitArray memory area to set the bit in
176 * @param bitIdx which bit to test
177 * @return GNUNET_YES if the bit is set, GNUNET_NO if not.
178 */
179static int
180testBit (char *bitArray, unsigned int bitIdx)
181{
182 size_t slot;
183 unsigned int targetBit;
184
185 slot = bitIdx / 8;
186 targetBit = (1L << (bitIdx % 8));
187 if (bitArray[slot] & targetBit)
188 return GNUNET_YES;
189 else
190 return GNUNET_NO;
191}
192
193
194/**
195 * Sets a bit active in the bitArray and increments
196 * bit-specific usage counter on disk (but only if
197 * the counter was below 4 bit max (==15)).
198 *
199 * @param bitArray memory area to set the bit in
200 * @param bitIdx which bit to test
201 * @param fh A file to keep the 4 bit address usage counters in
202 */
203static void
204incrementBit (char *bitArray,
205 unsigned int bitIdx,
206 const struct GNUNET_DISK_FileHandle *fh)
207{
208 off_t fileSlot;
209 unsigned char value;
210 unsigned int high;
211 unsigned int low;
212 unsigned int targetLoc;
213
214 setBit (bitArray, bitIdx);
215 if (GNUNET_DISK_handle_invalid (fh))
216 return;
217 /* Update the counter file on disk */
218 fileSlot = bitIdx / 2;
219 targetLoc = bitIdx % 2;
220
221 GNUNET_assert (fileSlot ==
222 GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET));
223 if (1 != GNUNET_DISK_file_read (fh, &value, 1))
224 value = 0;
225 low = value & 0xF;
226 high = (value & (~0xF)) >> 4;
227
228 if (targetLoc == 0)
229 {
230 if (low < 0xF)
231 low++;
232 }
233 else
234 {
235 if (high < 0xF)
236 high++;
237 }
238 value = ((high << 4) | low);
239 GNUNET_assert (fileSlot ==
240 GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET));
241 GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1));
242}
243
244
245/**
246 * Clears a bit from bitArray if the respective usage
247 * counter on the disk hits/is zero.
248 *
249 * @param bitArray memory area to set the bit in
250 * @param bitIdx which bit to test
251 * @param fh A file to keep the 4bit address usage counters in
252 */
253static void
254decrementBit (char *bitArray,
255 unsigned int bitIdx,
256 const struct GNUNET_DISK_FileHandle *fh)
257{
258 off_t fileslot;
259 unsigned char value;
260 unsigned int high;
261 unsigned int low;
262 unsigned int targetLoc;
263
264 if (GNUNET_DISK_handle_invalid (fh))
265 return; /* cannot decrement! */
266 /* Each char slot in the counter file holds two 4 bit counters */
267 fileslot = bitIdx / 2;
268 targetLoc = bitIdx % 2;
269 if (GNUNET_SYSERR ==
270 GNUNET_DISK_file_seek (fh, fileslot, GNUNET_DISK_SEEK_SET))
271 {
272 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "seek");
273 return;
274 }
275 if (1 != GNUNET_DISK_file_read (fh, &value, 1))
276 value = 0;
277 low = value & 0xF;
278 high = (value & 0xF0) >> 4;
279
280 /* decrement, but once we have reached the max, never go back! */
281 if (targetLoc == 0)
282 {
283 if ((low > 0) && (low < 0xF))
284 low--;
285 if (low == 0)
286 {
287 clearBit (bitArray, bitIdx);
288 }
289 }
290 else
291 {
292 if ((high > 0) && (high < 0xF))
293 high--;
294 if (high == 0)
295 {
296 clearBit (bitArray, bitIdx);
297 }
298 }
299 value = ((high << 4) | low);
300 if (GNUNET_SYSERR ==
301 GNUNET_DISK_file_seek (fh, fileslot, GNUNET_DISK_SEEK_SET))
302 {
303 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "seek");
304 return;
305 }
306 GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1));
307}
308
309
310#define BUFFSIZE 65536
311
312/**
313 * Creates a file filled with zeroes
314 *
315 * @param fh the file handle
316 * @param size the size of the file
317 * @return GNUNET_OK if created ok, GNUNET_SYSERR otherwise
318 */
319static int
320make_empty_file (const struct GNUNET_DISK_FileHandle *fh, size_t size)
321{
322 char buffer[BUFFSIZE];
323 size_t bytesleft = size;
324 int res = 0;
325
326 if (GNUNET_DISK_handle_invalid (fh))
327 return GNUNET_SYSERR;
328 memset (buffer, 0, sizeof(buffer));
329 GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_SET);
330 while (bytesleft > 0)
331 {
332 if (bytesleft > sizeof(buffer))
333 {
334 res = GNUNET_DISK_file_write (fh, buffer, sizeof(buffer));
335 if (res >= 0)
336 bytesleft -= res;
337 }
338 else
339 {
340 res = GNUNET_DISK_file_write (fh, buffer, bytesleft);
341 if (res >= 0)
342 bytesleft -= res;
343 }
344 if (GNUNET_SYSERR == res)
345 return GNUNET_SYSERR;
346 }
347 return GNUNET_OK;
348}
349
350
351/* ************** GNUNET_CONTAINER_BloomFilter iterator ********* */
352
353/**
354 * Iterator (callback) method to be called by the
355 * bloomfilter iterator on each bit that is to be
356 * set or tested for the key.
357 *
358 * @param cls closure
359 * @param bf the filter to manipulate
360 * @param bit the current bit
361 * @return GNUNET_YES to continue, GNUNET_NO to stop early
362 */
363typedef int (*BitIterator) (void *cls,
364 const struct GNUNET_CONTAINER_BloomFilter *bf,
365 unsigned int bit);
366
367
368/**
369 * Call an iterator for each bit that the bloomfilter
370 * must test or set for this element.
371 *
372 * @param bf the filter
373 * @param callback the method to call
374 * @param arg extra argument to callback
375 * @param key the key for which we iterate over the BF bits
376 */
377static void
378iterateBits (const struct GNUNET_CONTAINER_BloomFilter *bf,
379 BitIterator callback,
380 void *arg,
381 const struct GNUNET_HashCode *key)
382{
383 struct GNUNET_HashCode tmp = *key;
384 int bitCount;
385 unsigned int slot = 0;
386
387 bitCount = bf->addressesPerElement;
388 GNUNET_assert (bf->bitArraySize > 0);
389 GNUNET_assert (bf->bitArraySize * 8LL > bf->bitArraySize);
390 while (bitCount > 0)
391 {
392 while ( (0 != bitCount) &&
393 (slot < (sizeof(struct GNUNET_HashCode) / sizeof(uint32_t))) )
394 {
395 if (GNUNET_YES !=
396 callback (arg,
397 bf,
398 ntohl ((((uint32_t *) &tmp)[slot]))
399 % ((bf->bitArraySize * 8LL))))
400 return;
401 slot++;
402 bitCount--;
403 }
404 if (0 == bitCount)
405 break;
406 GNUNET_CRYPTO_hash (&tmp,
407 sizeof(tmp),
408 &tmp);
409 slot = 0;
410 }
411}
412
413
414/**
415 * Callback: increment bit
416 *
417 * @param cls pointer to writeable form of bf
418 * @param bf the filter to manipulate
419 * @param bit the bit to increment
420 * @return GNUNET_YES
421 */
422static int
423incrementBitCallback (void *cls,
424 const struct GNUNET_CONTAINER_BloomFilter *bf,
425 unsigned int bit)
426{
427 struct GNUNET_CONTAINER_BloomFilter *b = cls;
428
429 incrementBit (b->bitArray, bit, bf->fh);
430 return GNUNET_YES;
431}
432
433
434/**
435 * Callback: decrement bit
436 *
437 * @param cls pointer to writeable form of bf
438 * @param bf the filter to manipulate
439 * @param bit the bit to decrement
440 * @return GNUNET_YES
441 */
442static int
443decrementBitCallback (void *cls,
444 const struct GNUNET_CONTAINER_BloomFilter *bf,
445 unsigned int bit)
446{
447 struct GNUNET_CONTAINER_BloomFilter *b = cls;
448
449 decrementBit (b->bitArray, bit, bf->fh);
450 return GNUNET_YES;
451}
452
453
454/**
455 * Callback: test if all bits are set
456 *
457 * @param cls pointer set to GNUNET_NO if bit is not set
458 * @param bf the filter
459 * @param bit the bit to test
460 * @return YES if the bit is set, NO if not
461 */
462static int
463testBitCallback (void *cls,
464 const struct GNUNET_CONTAINER_BloomFilter *bf,
465 unsigned int bit)
466{
467 int *arg = cls;
468
469 if (GNUNET_NO == testBit (bf->bitArray, bit))
470 {
471 *arg = GNUNET_NO;
472 return GNUNET_NO;
473 }
474 return GNUNET_YES;
475}
476
477
478/* *********************** INTERFACE **************** */
479
480/**
481 * Load a bloom-filter from a file.
482 *
483 * @param filename the name of the file (or the prefix)
484 * @param size the size of the bloom-filter (number of
485 * bytes of storage space to use); will be rounded up
486 * to next power of 2
487 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per
488 * element (number of bits set per element in the set)
489 * @return the bloomfilter
490 */
491struct GNUNET_CONTAINER_BloomFilter *
492GNUNET_CONTAINER_bloomfilter_load (const char *filename,
493 size_t size,
494 unsigned int k)
495{
496 struct GNUNET_CONTAINER_BloomFilter *bf;
497 char *rbuff;
498 off_t pos;
499 int i;
500 size_t ui;
501 off_t fsize;
502 int must_read;
503
504 GNUNET_assert (NULL != filename);
505 if ((k == 0) || (size == 0))
506 return NULL;
507 if (size < BUFFSIZE)
508 size = BUFFSIZE;
509 ui = 1;
510 while ((ui < size) && (ui * 2 > ui))
511 ui *= 2;
512 size = ui; /* make sure it's a power of 2 */
513
514 bf = GNUNET_new (struct GNUNET_CONTAINER_BloomFilter);
515 /* Try to open a bloomfilter file */
516 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
517 bf->fh = GNUNET_DISK_file_open (filename,
518 GNUNET_DISK_OPEN_READWRITE,
519 GNUNET_DISK_PERM_USER_READ
520 | GNUNET_DISK_PERM_USER_WRITE);
521 if (NULL != bf->fh)
522 {
523 /* file existed, try to read it! */
524 must_read = GNUNET_YES;
525 if (GNUNET_OK != GNUNET_DISK_file_handle_size (bf->fh, &fsize))
526 {
527 GNUNET_DISK_file_close (bf->fh);
528 GNUNET_free (bf);
529 return NULL;
530 }
531 if (0 == fsize)
532 {
533 /* found existing empty file, just overwrite */
534 if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL))
535 {
536 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
537 GNUNET_DISK_file_close (bf->fh);
538 GNUNET_free (bf);
539 return NULL;
540 }
541 }
542 else if (fsize != ((off_t) size) * 4LL)
543 {
544 GNUNET_log (
545 GNUNET_ERROR_TYPE_ERROR,
546 _ (
547 "Size of file on disk is incorrect for this Bloom filter (want %llu, have %llu)\n"),
548 (unsigned long long) (size * 4LL),
549 (unsigned long long) fsize);
550 GNUNET_DISK_file_close (bf->fh);
551 GNUNET_free (bf);
552 return NULL;
553 }
554 }
555 else
556 {
557 /* file did not exist, don't read, just create */
558 must_read = GNUNET_NO;
559 bf->fh = GNUNET_DISK_file_open (filename,
560 GNUNET_DISK_OPEN_CREATE
561 | GNUNET_DISK_OPEN_READWRITE,
562 GNUNET_DISK_PERM_USER_READ
563 | GNUNET_DISK_PERM_USER_WRITE);
564 if (NULL == bf->fh)
565 {
566 GNUNET_free (bf);
567 return NULL;
568 }
569 if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL))
570 {
571 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
572 GNUNET_DISK_file_close (bf->fh);
573 GNUNET_free (bf);
574 return NULL;
575 }
576 }
577 bf->filename = GNUNET_strdup (filename);
578 /* Alloc block */
579 bf->bitArray = GNUNET_malloc_large (size);
580 if (NULL == bf->bitArray)
581 {
582 if (NULL != bf->fh)
583 GNUNET_DISK_file_close (bf->fh);
584 GNUNET_free (bf->filename);
585 GNUNET_free (bf);
586 return NULL;
587 }
588 bf->bitArraySize = size;
589 bf->addressesPerElement = k;
590 if (GNUNET_YES != must_read)
591 return bf; /* already done! */
592 /* Read from the file what bits we can */
593 rbuff = GNUNET_malloc (BUFFSIZE);
594 pos = 0;
595 while (pos < ((off_t) size) * 8LL)
596 {
597 int res;
598
599 res = GNUNET_DISK_file_read (bf->fh, rbuff, BUFFSIZE);
600 if (res == -1)
601 {
602 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", bf->filename);
603 GNUNET_free (rbuff);
604 GNUNET_free (bf->filename);
605 GNUNET_DISK_file_close (bf->fh);
606 GNUNET_free (bf);
607 return NULL;
608 }
609 if (res == 0)
610 break; /* is ok! we just did not use that many bits yet */
611 for (i = 0; i < res; i++)
612 {
613 if ((rbuff[i] & 0x0F) != 0)
614 setBit (bf->bitArray, pos + i * 2);
615 if ((rbuff[i] & 0xF0) != 0)
616 setBit (bf->bitArray, pos + i * 2 + 1);
617 }
618 if (res < BUFFSIZE)
619 break;
620 pos += BUFFSIZE * 2; /* 2 bits per byte in the buffer */
621 }
622 GNUNET_free (rbuff);
623 return bf;
624}
625
626
627/**
628 * Create a bloom filter from raw bits.
629 *
630 * @param data the raw bits in memory (maybe NULL,
631 * in which case all bits should be considered
632 * to be zero).
633 * @param size the size of the bloom-filter (number of
634 * bytes of storage space to use); also size of data
635 * -- unless data is NULL
636 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per
637 * element (number of bits set per element in the set)
638 * @return the bloomfilter
639 */
640struct GNUNET_CONTAINER_BloomFilter *
641GNUNET_CONTAINER_bloomfilter_init (const char *data,
642 size_t size,
643 unsigned int k)
644{
645 struct GNUNET_CONTAINER_BloomFilter *bf;
646
647 if ((0 == k) || (0 == size))
648 return NULL;
649 bf = GNUNET_new (struct GNUNET_CONTAINER_BloomFilter);
650 bf->filename = NULL;
651 bf->fh = NULL;
652 bf->bitArray = GNUNET_malloc_large (size);
653 if (NULL == bf->bitArray)
654 {
655 GNUNET_free (bf);
656 return NULL;
657 }
658 bf->bitArraySize = size;
659 bf->addressesPerElement = k;
660 if (NULL != data)
661 GNUNET_memcpy (bf->bitArray, data, size);
662 return bf;
663}
664
665
666/**
667 * Copy the raw data of this bloomfilter into
668 * the given data array.
669 *
670 * @param bf bloomfilter to take the raw data from
671 * @param data where to write the data
672 * @param size the size of the given data array
673 * @return #GNUNET_SYSERR if the data array is not big enough
674 */
675int
676GNUNET_CONTAINER_bloomfilter_get_raw_data (
677 const struct GNUNET_CONTAINER_BloomFilter *bf,
678 char *data,
679 size_t size)
680{
681 if (NULL == bf)
682 return GNUNET_SYSERR;
683 if (bf->bitArraySize != size)
684 return GNUNET_SYSERR;
685 GNUNET_memcpy (data, bf->bitArray, size);
686 return GNUNET_OK;
687}
688
689
690/**
691 * Free the space associated with a filter
692 * in memory, flush to drive if needed (do not
693 * free the space on the drive)
694 *
695 * @param bf the filter
696 */
697void
698GNUNET_CONTAINER_bloomfilter_free (struct GNUNET_CONTAINER_BloomFilter *bf)
699{
700 if (NULL == bf)
701 return;
702 if (bf->fh != NULL)
703 GNUNET_DISK_file_close (bf->fh);
704 GNUNET_free (bf->filename);
705 GNUNET_free (bf->bitArray);
706 GNUNET_free (bf);
707}
708
709
710/**
711 * Reset a bloom filter to empty. Clears the file on disk.
712 *
713 * @param bf the filter
714 */
715void
716GNUNET_CONTAINER_bloomfilter_clear (struct GNUNET_CONTAINER_BloomFilter *bf)
717{
718 if (NULL == bf)
719 return;
720
721 memset (bf->bitArray, 0, bf->bitArraySize);
722 if (bf->filename != NULL)
723 make_empty_file (bf->fh, bf->bitArraySize * 4LL);
724}
725
726
727/**
728 * Test if an element is in the filter.
729 *
730 * @param e the element
731 * @param bf the filter
732 * @return #GNUNET_YES if the element is in the filter, #GNUNET_NO if not
733 */
734int
735GNUNET_CONTAINER_bloomfilter_test (
736 const struct GNUNET_CONTAINER_BloomFilter *bf,
737 const struct GNUNET_HashCode *e)
738{
739 int res;
740
741 if (NULL == bf)
742 return GNUNET_YES;
743 res = GNUNET_YES;
744 iterateBits (bf, &testBitCallback, &res, e);
745 return res;
746}
747
748
749/**
750 * Add an element to the filter
751 *
752 * @param bf the filter
753 * @param e the element
754 */
755void
756GNUNET_CONTAINER_bloomfilter_add (struct GNUNET_CONTAINER_BloomFilter *bf,
757 const struct GNUNET_HashCode *e)
758{
759 if (NULL == bf)
760 return;
761 iterateBits (bf, &incrementBitCallback, bf, e);
762}
763
764
765/**
766 * Or the entries of the given raw data array with the
767 * data of the given bloom filter. Assumes that
768 * the size of the data array and the current filter
769 * match.
770 *
771 * @param bf the filter
772 * @param data the data to or-in
773 * @param size number of bytes in data
774 */
775int
776GNUNET_CONTAINER_bloomfilter_or (struct GNUNET_CONTAINER_BloomFilter *bf,
777 const char *data,
778 size_t size)
779{
780 unsigned int i;
781 unsigned int n;
782 unsigned long long *fc;
783 const unsigned long long *dc;
784
785 if (NULL == bf)
786 return GNUNET_YES;
787 if (bf->bitArraySize != size)
788 return GNUNET_SYSERR;
789 fc = (unsigned long long *) bf->bitArray;
790 dc = (const unsigned long long *) data;
791 n = size / sizeof(unsigned long long);
792
793 for (i = 0; i < n; i++)
794 fc[i] |= dc[i];
795 for (i = n * sizeof(unsigned long long); i < size; i++)
796 bf->bitArray[i] |= data[i];
797 return GNUNET_OK;
798}
799
800
801/**
802 * Or the entries of the given raw data array with the
803 * data of the given bloom filter. Assumes that
804 * the size of the data array and the current filter
805 * match.
806 *
807 * @param bf the filter
808 * @param to_or the bloomfilter to or-in
809 * @return #GNUNET_OK on success
810 */
811int
812GNUNET_CONTAINER_bloomfilter_or2 (
813 struct GNUNET_CONTAINER_BloomFilter *bf,
814 const struct GNUNET_CONTAINER_BloomFilter *to_or)
815{
816 unsigned int i;
817 unsigned int n;
818 unsigned long long *fc;
819 const unsigned long long *dc;
820 size_t size;
821
822 if (NULL == bf)
823 return GNUNET_OK;
824 if (bf->bitArraySize != to_or->bitArraySize)
825 {
826 GNUNET_break (0);
827 return GNUNET_SYSERR;
828 }
829 size = bf->bitArraySize;
830 fc = (unsigned long long *) bf->bitArray;
831 dc = (const unsigned long long *) to_or->bitArray;
832 n = size / sizeof(unsigned long long);
833
834 for (i = 0; i < n; i++)
835 fc[i] |= dc[i];
836 for (i = n * sizeof(unsigned long long); i < size; i++)
837 bf->bitArray[i] |= to_or->bitArray[i];
838 return GNUNET_OK;
839}
840
841
842/**
843 * Remove an element from the filter.
844 *
845 * @param bf the filter
846 * @param e the element to remove
847 */
848void
849GNUNET_CONTAINER_bloomfilter_remove (struct GNUNET_CONTAINER_BloomFilter *bf,
850 const struct GNUNET_HashCode *e)
851{
852 if (NULL == bf)
853 return;
854 if (NULL == bf->filename)
855 return;
856 iterateBits (bf, &decrementBitCallback, bf, e);
857}
858
859
860/**
861 * Resize a bloom filter. Note that this operation
862 * is pretty costly. Essentially, the bloom filter
863 * needs to be completely re-build.
864 *
865 * @param bf the filter
866 * @param iterator an iterator over all elements stored in the BF
867 * @param iterator_cls argument to the iterator function
868 * @param size the new size for the filter
869 * @param k the new number of GNUNET_CRYPTO_hash-function to apply per element
870 */
871void
872GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf,
873 GNUNET_CONTAINER_HashCodeIterator iterator,
874 void *iterator_cls,
875 size_t size,
876 unsigned int k)
877{
878 struct GNUNET_HashCode hc;
879 unsigned int i;
880
881 GNUNET_free (bf->bitArray);
882 i = 1;
883 while (i < size)
884 i *= 2;
885 size = i; /* make sure it's a power of 2 */
886 bf->addressesPerElement = k;
887 bf->bitArraySize = size;
888 bf->bitArray = GNUNET_malloc (size);
889 if (NULL != bf->filename)
890 make_empty_file (bf->fh, bf->bitArraySize * 4LL);
891 while (GNUNET_YES == iterator (iterator_cls, &hc))
892 GNUNET_CONTAINER_bloomfilter_add (bf, &hc);
893}
894
895
896/* end of container_bloomfilter.c */
diff --git a/src/util/container_heap.c b/src/util/container_heap.c
deleted file mode 100644
index 35d7cd4ab..000000000
--- a/src/util/container_heap.c
+++ /dev/null
@@ -1,562 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008, 2009 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 util/container_heap.c
23 * @brief Implementation of a heap
24 * @author Nathan Evans
25 * @author Christian Grothoff
26 */
27
28#include "platform.h"
29#include "gnunet_container_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-container-heap", \
32 __VA_ARGS__)
33
34#define EXTRA_CHECKS 0
35
36/**
37 * Node in the heap.
38 */
39struct GNUNET_CONTAINER_HeapNode
40{
41 /**
42 * Heap this node belongs to.
43 */
44 struct GNUNET_CONTAINER_Heap *heap;
45
46 /**
47 * Parent node.
48 */
49 struct GNUNET_CONTAINER_HeapNode *parent;
50
51 /**
52 * Left child.
53 */
54 struct GNUNET_CONTAINER_HeapNode *left_child;
55
56 /**
57 * Right child.
58 */
59 struct GNUNET_CONTAINER_HeapNode *right_child;
60
61 /**
62 * Our element.
63 */
64 void *element;
65
66 /**
67 * Cost for this element.
68 */
69 GNUNET_CONTAINER_HeapCostType cost;
70
71 /**
72 * Number of elements below this node in the heap
73 * (excluding this node itself).
74 */
75 unsigned int tree_size;
76};
77
78/**
79 * Handle to a node in a heap.
80 */
81struct GNUNET_CONTAINER_Heap
82{
83 /**
84 * Root of the heap.
85 */
86 struct GNUNET_CONTAINER_HeapNode *root;
87
88 /**
89 * Current position of our random walk.
90 */
91 struct GNUNET_CONTAINER_HeapNode *walk_pos;
92
93 /**
94 * Number of elements in the heap.
95 */
96 unsigned int size;
97
98 /**
99 * How is the heap sorted?
100 */
101 enum GNUNET_CONTAINER_HeapOrder order;
102};
103
104
105#if EXTRA_CHECKS
106/**
107 * Check if internal invariants hold for the given node.
108 *
109 * @param node subtree to check
110 */
111static void
112check (const struct GNUNET_CONTAINER_HeapNode *node)
113{
114 if (NULL == node)
115 return;
116 GNUNET_assert (node->tree_size ==
117 ((node->left_child ==
118 NULL) ? 0 : 1 + node->left_child->tree_size)
119 + ((node->right_child ==
120 NULL) ? 0 : 1 + node->right_child->tree_size));
121 check (node->left_child);
122 check (node->right_child);
123}
124
125
126#define CHECK(n) check (n)
127#else
128#define CHECK(n) do {} while (0)
129#endif
130
131
132/**
133 * Create a new heap.
134 *
135 * @param order how should the heap be sorted?
136 * @return handle to the heap
137 */
138struct GNUNET_CONTAINER_Heap *
139GNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder order)
140{
141 struct GNUNET_CONTAINER_Heap *heap;
142
143 heap = GNUNET_new (struct GNUNET_CONTAINER_Heap);
144 heap->order = order;
145 return heap;
146}
147
148
149/**
150 * Destroys the heap. Only call on a heap that
151 * is already empty.
152 *
153 * @param heap heap to destroy
154 */
155void
156GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap)
157{
158 GNUNET_break (heap->size == 0);
159 GNUNET_free (heap);
160}
161
162
163/**
164 * Get element stored at the root of @a heap.
165 *
166 * @param heap Heap to inspect.
167 * @return Element at the root, or NULL if heap is empty.
168 */
169void *
170GNUNET_CONTAINER_heap_peek (const struct GNUNET_CONTAINER_Heap *heap)
171{
172 if (heap->root == NULL)
173 return NULL;
174 return heap->root->element;
175}
176
177
178/**
179 * Get @a element and @a cost stored at the root of @a heap.
180 *
181 * @param[in] heap Heap to inspect.
182 * @param[out] element Root element is returned here.
183 * @param[out] cost Cost of @a element is returned here.
184 * @return #GNUNET_YES if an element is returned,
185 * #GNUNET_NO if the heap is empty.
186 */
187int
188GNUNET_CONTAINER_heap_peek2 (const struct GNUNET_CONTAINER_Heap *heap,
189 void **element,
190 GNUNET_CONTAINER_HeapCostType *cost)
191{
192 if (NULL == heap->root)
193 return GNUNET_NO;
194 if (NULL != element)
195 *element = heap->root->element;
196 if (NULL != cost)
197 *cost = heap->root->cost;
198 return GNUNET_YES;
199}
200
201
202/**
203 * Get the current size of the heap
204 *
205 * @param heap the heap to get the size of
206 * @return number of elements stored
207 */
208unsigned int
209GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap)
210{
211 return heap->size;
212}
213
214
215/**
216 * Get the current cost of the node
217 *
218 * @param node the node to get the cost of
219 * @return cost of the node
220 */
221GNUNET_CONTAINER_HeapCostType
222GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode
223 *node)
224{
225 return node->cost;
226}
227
228
229/**
230 * Iterate over the children of the given node.
231 *
232 * @param heap argument to give to iterator
233 * @param node node to iterate over
234 * @param iterator function to call on each node
235 * @param iterator_cls closure for iterator
236 * @return GNUNET_YES to continue to iterate
237 */
238static int
239node_iterator (const struct GNUNET_CONTAINER_Heap *heap,
240 struct GNUNET_CONTAINER_HeapNode *node,
241 GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
242{
243 if (node == NULL)
244 return GNUNET_YES;
245 if (GNUNET_YES !=
246 node_iterator (heap, node->left_child, iterator, iterator_cls))
247 return GNUNET_NO;
248 if (GNUNET_YES !=
249 node_iterator (heap, node->right_child, iterator, iterator_cls))
250 return GNUNET_NO;
251 return iterator (iterator_cls, node, node->element, node->cost);
252}
253
254
255/**
256 * Iterate over all entries in the heap.
257 *
258 * @param heap the heap
259 * @param iterator function to call on each entry
260 * @param iterator_cls closure for iterator
261 */
262void
263GNUNET_CONTAINER_heap_iterate (const struct GNUNET_CONTAINER_Heap *heap,
264 GNUNET_CONTAINER_HeapIterator iterator,
265 void *iterator_cls)
266{
267 (void) node_iterator (heap, heap->root, iterator, iterator_cls);
268}
269
270
271/**
272 * Perform a random walk of the tree. The walk is biased
273 * towards elements closer to the root of the tree (since
274 * each walk starts at the root and ends at a random leaf).
275 * The heap internally tracks the current position of the
276 * walk.
277 *
278 * @param heap heap to walk
279 * @return data stored at the next random node in the walk;
280 * NULL if the tree is empty.
281 */
282void *
283GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap)
284{
285 struct GNUNET_CONTAINER_HeapNode *pos;
286 void *element;
287
288 if (heap->root == NULL)
289 return NULL;
290 pos = heap->walk_pos;
291 if (pos == NULL)
292 pos = heap->root;
293 element = pos->element;
294 heap->walk_pos =
295 (0 ==
296 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
297 2)) ? pos->right_child : pos->left_child;
298 return element;
299}
300
301
302/**
303 * Insert the given node 'node' into the subtree starting
304 * at 'pos' (while keeping the tree somewhat balanced).
305 *
306 * @param heap heap to modify
307 * @param pos existing tree
308 * @param node node to insert (which may be a subtree itself)
309 */
310static void
311insert_node (struct GNUNET_CONTAINER_Heap *heap,
312 struct GNUNET_CONTAINER_HeapNode *pos,
313 struct GNUNET_CONTAINER_HeapNode *node)
314{
315 struct GNUNET_CONTAINER_HeapNode *parent;
316
317 GNUNET_assert (node->parent == NULL);
318 while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >=
319 node->cost)
320 : (pos->cost <= node->cost))
321 {
322 /* node is descendent of pos */
323 pos->tree_size += (1 + node->tree_size);
324 if (pos->left_child == NULL)
325 {
326 pos->left_child = node;
327 node->parent = pos;
328 return;
329 }
330 if (pos->right_child == NULL)
331 {
332 pos->right_child = node;
333 node->parent = pos;
334 return;
335 }
336 /* keep it balanced by descending into smaller subtree */
337 if (pos->left_child->tree_size < pos->right_child->tree_size)
338 pos = pos->left_child;
339 else
340 pos = pos->right_child;
341 }
342 /* make 'node' parent of 'pos' */
343 parent = pos->parent;
344 pos->parent = NULL;
345 node->parent = parent;
346 if (NULL == parent)
347 {
348 heap->root = node;
349 }
350 else
351 {
352 if (parent->left_child == pos)
353 parent->left_child = node;
354 else
355 parent->right_child = node;
356 }
357 /* insert 'pos' below 'node' */
358 insert_node (heap, node, pos);
359 CHECK (pos);
360}
361
362
363/**
364 * Inserts a new element into the heap.
365 *
366 * @param heap heap to modify
367 * @param element element to insert
368 * @param cost cost for the element
369 * @return node for the new element
370 */
371struct GNUNET_CONTAINER_HeapNode *
372GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element,
373 GNUNET_CONTAINER_HeapCostType cost)
374{
375 struct GNUNET_CONTAINER_HeapNode *node;
376
377 node = GNUNET_new (struct GNUNET_CONTAINER_HeapNode);
378 node->heap = heap;
379 node->element = element;
380 node->cost = cost;
381 heap->size++;
382 if (NULL == heap->root)
383 heap->root = node;
384 else
385 insert_node (heap, heap->root, node);
386 GNUNET_assert (heap->size == heap->root->tree_size + 1);
387 CHECK (heap->root);
388 return node;
389}
390
391
392/**
393 * Remove root of the heap.
394 *
395 * @param heap heap to modify
396 * @return element data stored at the root node, NULL if heap is empty
397 */
398void *
399GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap)
400{
401 void *ret;
402 struct GNUNET_CONTAINER_HeapNode *root;
403
404 if (NULL == (root = heap->root))
405 return NULL;
406 heap->size--;
407 ret = root->element;
408 if (root->left_child == NULL)
409 {
410 heap->root = root->right_child;
411 if (root->right_child != NULL)
412 root->right_child->parent = NULL;
413 }
414 else if (root->right_child == NULL)
415 {
416 heap->root = root->left_child;
417 root->left_child->parent = NULL;
418 }
419 else
420 {
421 root->left_child->parent = NULL;
422 root->right_child->parent = NULL;
423 heap->root = root->left_child;
424 insert_node (heap, heap->root, root->right_child);
425 }
426 if (heap->walk_pos == root)
427 heap->walk_pos = heap->root;
428 GNUNET_free (root);
429#if EXTRA_CHECKS
430 GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
431 (heap->size == heap->root->tree_size + 1));
432 CHECK (heap->root);
433#endif
434 return ret;
435}
436
437
438/**
439 * Remove the given node 'node' from the tree and update
440 * the 'tree_size' fields accordingly. Preserves the
441 * children of 'node' and does NOT change the overall
442 * 'size' field of the tree.
443 */
444static void
445remove_node (struct GNUNET_CONTAINER_HeapNode *node)
446{
447 struct GNUNET_CONTAINER_HeapNode *ancestor;
448 struct GNUNET_CONTAINER_Heap *heap = node->heap;
449
450 /* update 'size' of the ancestors */
451 ancestor = node;
452 while (NULL != (ancestor = ancestor->parent))
453 ancestor->tree_size--;
454
455 /* update 'size' of node itself */
456 if (node->left_child != NULL)
457 node->tree_size -= (1 + node->left_child->tree_size);
458 if (node->right_child != NULL)
459 node->tree_size -= (1 + node->right_child->tree_size);
460
461 /* unlink 'node' itself and insert children in its place */
462 if (node->parent == NULL)
463 {
464 if (node->left_child != NULL)
465 {
466 heap->root = node->left_child;
467 node->left_child->parent = NULL;
468 if (node->right_child != NULL)
469 {
470 node->right_child->parent = NULL;
471 insert_node (heap, heap->root, node->right_child);
472 }
473 }
474 else
475 {
476 heap->root = node->right_child;
477 if (node->right_child != NULL)
478 node->right_child->parent = NULL;
479 }
480 }
481 else
482 {
483 if (node->parent->left_child == node)
484 node->parent->left_child = NULL;
485 else
486 node->parent->right_child = NULL;
487 if (node->left_child != NULL)
488 {
489 node->left_child->parent = NULL;
490 node->parent->tree_size -= (1 + node->left_child->tree_size);
491 insert_node (heap, node->parent, node->left_child);
492 }
493 if (node->right_child != NULL)
494 {
495 node->right_child->parent = NULL;
496 node->parent->tree_size -= (1 + node->right_child->tree_size);
497 insert_node (heap, node->parent, node->right_child);
498 }
499 }
500 node->parent = NULL;
501 node->left_child = NULL;
502 node->right_child = NULL;
503 GNUNET_assert (node->tree_size == 0);
504 CHECK (heap->root);
505}
506
507
508/**
509 * Removes a node from the heap.
510 *
511 * @param node node to remove
512 * @return element data stored at the node
513 */
514void *
515GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node)
516{
517 void *ret;
518 struct GNUNET_CONTAINER_Heap *heap;
519
520 heap = node->heap;
521 CHECK (heap->root);
522 if (heap->walk_pos == node)
523 (void) GNUNET_CONTAINER_heap_walk_get_next (heap);
524 remove_node (node);
525 heap->size--;
526 ret = node->element;
527 if (heap->walk_pos == node)
528 heap->walk_pos = NULL;
529 GNUNET_free (node);
530#if EXTRA_CHECKS
531 CHECK (heap->root);
532 GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
533 (heap->size == heap->root->tree_size + 1));
534#endif
535 return ret;
536}
537
538
539/**
540 * Updates the cost of any node in the tree
541 *
542 * @param node node for which the cost is to be changed
543 * @param new_cost new cost for the node
544 */
545void
546GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_HeapNode *node,
547 GNUNET_CONTAINER_HeapCostType new_cost)
548{
549 struct GNUNET_CONTAINER_Heap *heap = node->heap;
550
551 remove_node (node);
552 node->cost = new_cost;
553 if (NULL == heap->root)
554 heap->root = node;
555 else
556 insert_node (heap,
557 heap->root,
558 node);
559}
560
561
562/* end of heap.c */
diff --git a/src/util/container_meta_data.c b/src/util/container_meta_data.c
deleted file mode 100644
index 2c477db40..000000000
--- a/src/util/container_meta_data.c
+++ /dev/null
@@ -1,1191 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 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 util/container_meta_data.c
23 * @brief Storing of meta data
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#if HAVE_EXTRACTOR_H
30#include <extractor.h>
31#endif
32#include <zlib.h>
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "util-container-meta-data", \
35 __VA_ARGS__)
36
37
38/**
39 * Try to compress the given block of data using libz. Only returns
40 * the compressed block if compression worked and the new block is
41 * actually smaller. Decompress using #GNUNET_decompress().
42 *
43 * @param data block to compress; if compression
44 * resulted in a smaller block, the first
45 * bytes of data are updated to the compressed
46 * data
47 * @param old_size number of bytes in data
48 * @param[out] result set to the compressed data, if compression worked
49 * @param[out] new_size set to size of result, if compression worked
50 * @return #GNUNET_YES if compression reduce the size,
51 * #GNUNET_NO if compression did not help
52 */
53int
54GNUNET_try_compression (const char *data,
55 size_t old_size,
56 char **result,
57 size_t *new_size)
58{
59 char *tmp;
60 uLongf dlen;
61
62 *result = NULL;
63 *new_size = 0;
64#ifdef compressBound
65 dlen = compressBound (old_size);
66#else
67 dlen = old_size + (old_size / 100) + 20;
68 /* documentation says 100.1% oldSize + 12 bytes, but we
69 * should be able to overshoot by more to be safe */
70#endif
71 tmp = GNUNET_malloc (dlen);
72 if (Z_OK ==
73 compress2 ((Bytef *) tmp,
74 &dlen,
75 (const Bytef *) data,
76 old_size, 9))
77 {
78 if (dlen < old_size)
79 {
80 *result = tmp;
81 *new_size = dlen;
82 return GNUNET_YES;
83 }
84 }
85 GNUNET_free (tmp);
86 return GNUNET_NO;
87}
88
89
90/**
91 * Decompress input, return the decompressed data as output. Dual to
92 * #GNUNET_try_compression(). Caller must set @a output_size to the
93 * number of bytes that were originally compressed.
94 *
95 * @param input compressed data
96 * @param input_size number of bytes in input
97 * @param output_size expected size of the output
98 * @return NULL on error, buffer of @a output_size decompressed bytes otherwise
99 */
100char *
101GNUNET_decompress (const char *input,
102 size_t input_size,
103 size_t output_size)
104{
105 char *output;
106 uLongf olen;
107
108 olen = output_size;
109 output = GNUNET_malloc (olen);
110 if (Z_OK ==
111 uncompress ((Bytef *) output,
112 &olen,
113 (const Bytef *) input,
114 input_size))
115 return output;
116 GNUNET_free (output);
117 return NULL;
118}
119
120
121/**
122 * Meta data item.
123 */
124struct MetaItem
125{
126 /**
127 * This is a doubly linked list.
128 */
129 struct MetaItem *next;
130
131 /**
132 * This is a doubly linked list.
133 */
134 struct MetaItem *prev;
135
136 /**
137 * Name of the extracting plugin.
138 */
139 char *plugin_name;
140
141 /**
142 * Mime-type of data.
143 */
144 char *mime_type;
145
146 /**
147 * The actual meta data.
148 */
149 char *data;
150
151 /**
152 * Number of bytes in 'data'.
153 */
154 size_t data_size;
155
156 /**
157 * Type of the meta data.
158 */
159 enum EXTRACTOR_MetaType type;
160
161 /**
162 * Format of the meta data.
163 */
164 enum EXTRACTOR_MetaFormat format;
165};
166
167/**
168 * Meta data to associate with a file, directory or namespace.
169 */
170struct GNUNET_CONTAINER_MetaData
171{
172 /**
173 * Head of linked list of the meta data items.
174 */
175 struct MetaItem *items_head;
176
177 /**
178 * Tail of linked list of the meta data items.
179 */
180 struct MetaItem *items_tail;
181
182 /**
183 * Complete serialized and compressed buffer of the items.
184 * NULL if we have not computed that buffer yet.
185 */
186 char *sbuf;
187
188 /**
189 * Number of bytes in 'sbuf'. 0 if the buffer is stale.
190 */
191 size_t sbuf_size;
192
193 /**
194 * Number of items in the linked list.
195 */
196 unsigned int item_count;
197};
198
199
200/**
201 * Create a fresh struct CONTAINER_MetaData token.
202 *
203 * @return empty meta-data container
204 */
205struct GNUNET_CONTAINER_MetaData *
206GNUNET_CONTAINER_meta_data_create ()
207{
208 return GNUNET_new (struct GNUNET_CONTAINER_MetaData);
209}
210
211
212/**
213 * Free meta data item.
214 *
215 * @param mi item to free
216 */
217static void
218meta_item_free (struct MetaItem *mi)
219{
220 GNUNET_free (mi->plugin_name);
221 GNUNET_free (mi->mime_type);
222 GNUNET_free (mi->data);
223 GNUNET_free (mi);
224}
225
226
227/**
228 * The meta data has changed, invalidate its serialization
229 * buffer.
230 *
231 * @param md meta data that changed
232 */
233static void
234invalidate_sbuf (struct GNUNET_CONTAINER_MetaData *md)
235{
236 if (NULL == md->sbuf)
237 return;
238 GNUNET_free (md->sbuf);
239 md->sbuf = NULL;
240 md->sbuf_size = 0;
241}
242
243
244/**
245 * Free meta data.
246 *
247 * @param md what to free
248 */
249void
250GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *md)
251{
252 struct MetaItem *pos;
253
254 if (NULL == md)
255 return;
256 while (NULL != (pos = md->items_head))
257 {
258 GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, pos);
259 meta_item_free (pos);
260 }
261 GNUNET_free (md->sbuf);
262 GNUNET_free (md);
263}
264
265
266/**
267 * Remove all items in the container.
268 *
269 * @param md metadata to manipulate
270 */
271void
272GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md)
273{
274 struct MetaItem *mi;
275
276 if (NULL == md)
277 return;
278 while (NULL != (mi = md->items_head))
279 {
280 GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, mi);
281 meta_item_free (mi);
282 }
283 GNUNET_free (md->sbuf);
284 memset (md, 0, sizeof(struct GNUNET_CONTAINER_MetaData));
285}
286
287
288/**
289 * Test if two MDs are equal. We consider them equal if
290 * the meta types, formats and content match (we do not
291 * include the mime types and plugins names in this
292 * consideration).
293 *
294 * @param md1 first value to check
295 * @param md2 other value to check
296 * @return #GNUNET_YES if they are equal
297 */
298int
299GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
300 *md1,
301 const struct GNUNET_CONTAINER_MetaData
302 *md2)
303{
304 struct MetaItem *i;
305 struct MetaItem *j;
306 int found;
307
308 if (md1 == md2)
309 return GNUNET_YES;
310 if (md1->item_count != md2->item_count)
311 return GNUNET_NO;
312 for (i = md1->items_head; NULL != i; i = i->next)
313 {
314 found = GNUNET_NO;
315 for (j = md2->items_head; NULL != j; j = j->next)
316 {
317 if ((i->type == j->type) && (i->format == j->format) &&
318 (i->data_size == j->data_size) &&
319 (0 == memcmp (i->data, j->data, i->data_size)))
320 {
321 found = GNUNET_YES;
322 break;
323 }
324 if (j->data_size < i->data_size)
325 break; /* elements are sorted by (decreasing) size... */
326 }
327 if (GNUNET_NO == found)
328 return GNUNET_NO;
329 }
330 return GNUNET_YES;
331}
332
333
334/**
335 * Extend metadata. Note that the list of meta data items is
336 * sorted by size (largest first).
337 *
338 * @param md metadata to extend
339 * @param plugin_name name of the plugin that produced this value;
340 * special values can be used (e.g. '&lt;zlib&gt;' for zlib being
341 * used in the main libextractor library and yielding
342 * meta data).
343 * @param type libextractor-type describing the meta data
344 * @param format basic format information about data
345 * @param data_mime_type mime-type of data (not of the original file);
346 * can be NULL (if mime-type is not known)
347 * @param data actual meta-data found
348 * @param data_size number of bytes in @a data
349 * @return #GNUNET_OK on success, #GNUNET_SYSERR if this entry already exists
350 * data_mime_type and plugin_name are not considered for "exists" checks
351 */
352int
353GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
354 const char *plugin_name,
355 enum EXTRACTOR_MetaType type,
356 enum EXTRACTOR_MetaFormat format,
357 const char *data_mime_type, const char *data,
358 size_t data_size)
359{
360 struct MetaItem *pos;
361 struct MetaItem *mi;
362 char *p;
363
364 if ((EXTRACTOR_METAFORMAT_UTF8 == format) ||
365 (EXTRACTOR_METAFORMAT_C_STRING == format))
366 GNUNET_break ('\0' == data[data_size - 1]);
367
368 for (pos = md->items_head; NULL != pos; pos = pos->next)
369 {
370 if (pos->data_size < data_size)
371 break; /* elements are sorted by size in the list */
372 if ((pos->type == type) && (pos->data_size == data_size) &&
373 (0 == memcmp (pos->data, data, data_size)))
374 {
375 if ((NULL == pos->mime_type) && (NULL != data_mime_type))
376 {
377 pos->mime_type = GNUNET_strdup (data_mime_type);
378 invalidate_sbuf (md);
379 }
380 if ((EXTRACTOR_METAFORMAT_C_STRING == pos->format) &&
381 (EXTRACTOR_METAFORMAT_UTF8 == format))
382 {
383 pos->format = EXTRACTOR_METAFORMAT_UTF8;
384 invalidate_sbuf (md);
385 }
386 return GNUNET_SYSERR;
387 }
388 }
389 md->item_count++;
390 mi = GNUNET_new (struct MetaItem);
391 mi->type = type;
392 mi->format = format;
393 mi->data_size = data_size;
394 if (NULL == pos)
395 GNUNET_CONTAINER_DLL_insert_tail (md->items_head,
396 md->items_tail,
397 mi);
398 else
399 GNUNET_CONTAINER_DLL_insert_after (md->items_head,
400 md->items_tail,
401 pos->prev,
402 mi);
403 mi->mime_type =
404 (NULL == data_mime_type) ? NULL : GNUNET_strdup (data_mime_type);
405 mi->plugin_name = (NULL == plugin_name) ? NULL : GNUNET_strdup (plugin_name);
406 mi->data = GNUNET_malloc (data_size);
407 GNUNET_memcpy (mi->data, data, data_size);
408 /* change all dir separators to POSIX style ('/') */
409 if ((EXTRACTOR_METATYPE_FILENAME == type) ||
410 (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type))
411 {
412 p = mi->data;
413 while (('\0' != *p) && (p < mi->data + data_size))
414 {
415 if ('\\' == *p)
416 *p = '/';
417 p++;
418 }
419 }
420 invalidate_sbuf (md);
421 return GNUNET_OK;
422}
423
424
425/**
426 * Merge given meta data.
427 *
428 * @param cls the `struct GNUNET_CONTAINER_MetaData` to merge into
429 * @param plugin_name name of the plugin that produced this value;
430 * special values can be used (e.g. '&lt;zlib&gt;' for zlib being
431 * used in the main libextractor library and yielding
432 * meta data).
433 * @param type libextractor-type describing the meta data
434 * @param format basic format information about data
435 * @param data_mime_type mime-type of data (not of the original file);
436 * can be NULL (if mime-type is not known)
437 * @param data actual meta-data found
438 * @param data_size number of bytes in @a data
439 * @return 0 (to continue)
440 */
441static int
442merge_helper (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type,
443 enum EXTRACTOR_MetaFormat format, const char *data_mime_type,
444 const char *data, size_t data_size)
445{
446 struct GNUNET_CONTAINER_MetaData *md = cls;
447
448 (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format,
449 data_mime_type, data, data_size);
450 return 0;
451}
452
453
454/**
455 * Extend metadata. Merges the meta data from the second argument
456 * into the first, discarding duplicate key-value pairs.
457 *
458 * @param md metadata to extend
459 * @param in metadata to merge
460 */
461void
462GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md,
463 const struct GNUNET_CONTAINER_MetaData *in)
464{
465 GNUNET_CONTAINER_meta_data_iterate (in, &merge_helper, md);
466}
467
468
469/**
470 * Remove an item.
471 *
472 * @param md metadata to manipulate
473 * @param type type of the item to remove
474 * @param data specific value to remove, NULL to remove all
475 * entries of the given type
476 * @param data_size number of bytes in @a data
477 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the item does not exist in md
478 */
479int
480GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md,
481 enum EXTRACTOR_MetaType type,
482 const char *data, size_t data_size)
483{
484 struct MetaItem *pos;
485
486 for (pos = md->items_head; NULL != pos; pos = pos->next)
487 {
488 if (pos->data_size < data_size)
489 break; /* items are sorted by (decreasing) size */
490 if ((pos->type == type) &&
491 ((NULL == data) ||
492 ((pos->data_size == data_size) &&
493 (0 == memcmp (pos->data, data, data_size)))))
494 {
495 GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, pos);
496 meta_item_free (pos);
497 md->item_count--;
498 invalidate_sbuf (md);
499 return GNUNET_OK;
500 }
501 }
502 return GNUNET_SYSERR;
503}
504
505
506/**
507 * Add the current time as the publication date
508 * to the meta-data.
509 *
510 * @param md metadata to modify
511 */
512void
513GNUNET_CONTAINER_meta_data_add_publication_date (struct
514 GNUNET_CONTAINER_MetaData *md)
515{
516 const char *dat;
517 struct GNUNET_TIME_Absolute t;
518
519 t = GNUNET_TIME_absolute_get ();
520 GNUNET_CONTAINER_meta_data_delete (md,
521 EXTRACTOR_METATYPE_PUBLICATION_DATE,
522 NULL, 0);
523 dat = GNUNET_STRINGS_absolute_time_to_string (t);
524 GNUNET_CONTAINER_meta_data_insert (md, "<gnunet>",
525 EXTRACTOR_METATYPE_PUBLICATION_DATE,
526 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
527 dat, strlen (dat) + 1);
528}
529
530
531/**
532 * Iterate over MD entries.
533 *
534 * @param md metadata to inspect
535 * @param iter function to call on each entry
536 * @param iter_cls closure for iterator
537 * @return number of entries
538 */
539int
540GNUNET_CONTAINER_meta_data_iterate (const struct GNUNET_CONTAINER_MetaData *md,
541 EXTRACTOR_MetaDataProcessor iter,
542 void *iter_cls)
543{
544 struct MetaItem *pos;
545
546 if (NULL == md)
547 return 0;
548 if (NULL == iter)
549 return md->item_count;
550 for (pos = md->items_head; NULL != pos; pos = pos->next)
551 if (0 !=
552 iter (iter_cls, pos->plugin_name, pos->type, pos->format,
553 pos->mime_type, pos->data, pos->data_size))
554 return md->item_count;
555 return md->item_count;
556}
557
558
559/**
560 * Get the first MD entry of the given type. Caller
561 * is responsible for freeing the return value.
562 * Also, only meta data items that are strings (0-terminated)
563 * are returned by this function.
564 *
565 * @param md metadata to inspect
566 * @param type type to look for
567 * @return NULL if no entry was found
568 */
569char *
570GNUNET_CONTAINER_meta_data_get_by_type (const struct
571 GNUNET_CONTAINER_MetaData *md,
572 enum EXTRACTOR_MetaType type)
573{
574 struct MetaItem *pos;
575
576 if (NULL == md)
577 return NULL;
578 for (pos = md->items_head; NULL != pos; pos = pos->next)
579 if ((type == pos->type) &&
580 ((pos->format == EXTRACTOR_METAFORMAT_UTF8) ||
581 (pos->format == EXTRACTOR_METAFORMAT_C_STRING)))
582 return GNUNET_strdup (pos->data);
583 return NULL;
584}
585
586
587/**
588 * Get the first matching MD entry of the given types. Caller is
589 * responsible for freeing the return value. Also, only meta data
590 * items that are strings (0-terminated) are returned by this
591 * function.
592 *
593 * @param md metadata to inspect
594 * @param ... -1-terminated list of types
595 * @return NULL if we do not have any such entry,
596 * otherwise client is responsible for freeing the value!
597 */
598char *
599GNUNET_CONTAINER_meta_data_get_first_by_types (const struct
600 GNUNET_CONTAINER_MetaData *md,
601 ...)
602{
603 char *ret;
604 va_list args;
605 int type;
606
607 if (NULL == md)
608 return NULL;
609 ret = NULL;
610 va_start (args, md);
611 while (1)
612 {
613 type = va_arg (args, int);
614 if (-1 == type)
615 break;
616 if (NULL != (ret = GNUNET_CONTAINER_meta_data_get_by_type (md, type)))
617 break;
618 }
619 va_end (args);
620 return ret;
621}
622
623
624/**
625 * Get a thumbnail from the meta-data (if present).
626 *
627 * @param md metadata to get the thumbnail from
628 * @param thumb will be set to the thumbnail data. Must be
629 * freed by the caller!
630 * @return number of bytes in thumbnail, 0 if not available
631 */
632size_t
633GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData
634 *md, unsigned char **thumb)
635{
636 struct MetaItem *pos;
637 struct MetaItem *match;
638
639 if (NULL == md)
640 return 0;
641 match = NULL;
642 for (pos = md->items_head; NULL != pos; pos = pos->next)
643 {
644 if ((NULL != pos->mime_type) &&
645 (0 == strncasecmp ("image/", pos->mime_type, strlen ("image/"))) &&
646 (EXTRACTOR_METAFORMAT_BINARY == pos->format))
647 {
648 if (NULL == match)
649 match = pos;
650 else if ((match->type != EXTRACTOR_METATYPE_THUMBNAIL) &&
651 (pos->type == EXTRACTOR_METATYPE_THUMBNAIL))
652 match = pos;
653 }
654 }
655 if ((NULL == match) || (0 == match->data_size))
656 return 0;
657 *thumb = GNUNET_malloc (match->data_size);
658 GNUNET_memcpy (*thumb, match->data, match->data_size);
659 return match->data_size;
660}
661
662
663/**
664 * Duplicate a `struct GNUNET_CONTAINER_MetaData`.
665 *
666 * @param md what to duplicate
667 * @return duplicate meta-data container
668 */
669struct GNUNET_CONTAINER_MetaData *
670GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData
671 *md)
672{
673 struct GNUNET_CONTAINER_MetaData *ret;
674 struct MetaItem *pos;
675
676 if (NULL == md)
677 return NULL;
678 ret = GNUNET_CONTAINER_meta_data_create ();
679 for (pos = md->items_tail; NULL != pos; pos = pos->prev)
680 GNUNET_CONTAINER_meta_data_insert (ret, pos->plugin_name, pos->type,
681 pos->format, pos->mime_type, pos->data,
682 pos->data_size);
683 return ret;
684}
685
686
687/**
688 * Flag in 'version' that indicates compressed meta-data.
689 */
690#define HEADER_COMPRESSED 0x80000000
691
692
693/**
694 * Bits in 'version' that give the version number.
695 */
696#define HEADER_VERSION_MASK 0x7FFFFFFF
697
698
699/**
700 * Header for serialized meta data.
701 */
702struct MetaDataHeader
703{
704 /**
705 * The version of the MD serialization. The highest bit is used to
706 * indicate compression.
707 *
708 * Version 0 is traditional (pre-0.9) meta data (unsupported)
709 * Version is 1 for a NULL pointer
710 * Version 2 is for 0.9.x (and possibly higher)
711 * Other version numbers are not yet defined.
712 */
713 uint32_t version;
714
715 /**
716 * How many MD entries are there?
717 */
718 uint32_t entries;
719
720 /**
721 * Size of the decompressed meta data.
722 */
723 uint32_t size;
724
725 /**
726 * This is followed by 'entries' values of type 'struct MetaDataEntry'
727 * and then by 'entry' plugin names, mime-types and data blocks
728 * as specified in those meta data entries.
729 */
730};
731
732
733/**
734 * Entry of serialized meta data.
735 */
736struct MetaDataEntry
737{
738 /**
739 * Meta data type. Corresponds to an 'enum EXTRACTOR_MetaType'
740 */
741 uint32_t type;
742
743 /**
744 * Meta data format. Corresponds to an 'enum EXTRACTOR_MetaFormat'
745 */
746 uint32_t format;
747
748 /**
749 * Number of bytes of meta data.
750 */
751 uint32_t data_size;
752
753 /**
754 * Number of bytes in the plugin name including 0-terminator. 0 for NULL.
755 */
756 uint32_t plugin_name_len;
757
758 /**
759 * Number of bytes in the mime type including 0-terminator. 0 for NULL.
760 */
761 uint32_t mime_type_len;
762};
763
764
765/**
766 * Serialize meta-data to target.
767 *
768 * @param md metadata to serialize
769 * @param target where to write the serialized metadata;
770 * *target can be NULL, in which case memory is allocated
771 * @param max maximum number of bytes available in target
772 * @param opt is it ok to just write SOME of the
773 * meta-data to match the size constraint,
774 * possibly discarding some data?
775 * @return number of bytes written on success,
776 * #GNUNET_SYSERR on error (typically: not enough
777 * space)
778 */
779ssize_t
780GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
781 *md, char **target, size_t max,
782 enum
783 GNUNET_CONTAINER_MetaDataSerializationOptions
784 opt)
785{
786 struct GNUNET_CONTAINER_MetaData *vmd;
787 struct MetaItem *pos;
788 struct MetaDataHeader ihdr;
789 struct MetaDataHeader *hdr;
790 struct MetaDataEntry *ent;
791 char *dst;
792 unsigned int i;
793 uint64_t msize;
794 size_t off;
795 char *mdata;
796 char *cdata;
797 size_t mlen;
798 size_t plen;
799 size_t size;
800 size_t left;
801 size_t clen;
802 size_t rlen;
803 int comp;
804
805 if (max < sizeof(struct MetaDataHeader))
806 return GNUNET_SYSERR; /* far too small */
807 if (NULL == md)
808 return 0;
809
810 if (NULL != md->sbuf)
811 {
812 /* try to use serialization cache */
813 if (md->sbuf_size <= max)
814 {
815 if (NULL == *target)
816 *target = GNUNET_malloc (md->sbuf_size);
817 GNUNET_memcpy (*target, md->sbuf, md->sbuf_size);
818 return md->sbuf_size;
819 }
820 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
821 return GNUNET_SYSERR; /* can say that this will fail */
822 /* need to compute a partial serialization, sbuf useless ... */
823 }
824 dst = NULL;
825 msize = 0;
826 for (pos = md->items_tail; NULL != pos; pos = pos->prev)
827 {
828 msize += sizeof(struct MetaDataEntry);
829 msize += pos->data_size;
830 if (NULL != pos->plugin_name)
831 msize += strlen (pos->plugin_name) + 1;
832 if (NULL != pos->mime_type)
833 msize += strlen (pos->mime_type) + 1;
834 }
835 size = (size_t) msize;
836 if (size != msize)
837 {
838 GNUNET_break (0); /* integer overflow */
839 return GNUNET_SYSERR;
840 }
841 if (size >= GNUNET_MAX_MALLOC_CHECKED)
842 {
843 /* too large to be processed */
844 return GNUNET_SYSERR;
845 }
846 ent = GNUNET_malloc (size);
847 mdata = (char *) &ent[md->item_count];
848 off = size - (md->item_count * sizeof(struct MetaDataEntry));
849 i = 0;
850 for (pos = md->items_head; NULL != pos; pos = pos->next)
851 {
852 ent[i].type = htonl ((uint32_t) pos->type);
853 ent[i].format = htonl ((uint32_t) pos->format);
854 ent[i].data_size = htonl ((uint32_t) pos->data_size);
855 if (NULL == pos->plugin_name)
856 plen = 0;
857 else
858 plen = strlen (pos->plugin_name) + 1;
859 ent[i].plugin_name_len = htonl ((uint32_t) plen);
860 if (NULL == pos->mime_type)
861 mlen = 0;
862 else
863 mlen = strlen (pos->mime_type) + 1;
864 ent[i].mime_type_len = htonl ((uint32_t) mlen);
865 off -= pos->data_size;
866 if ((EXTRACTOR_METAFORMAT_UTF8 == pos->format) ||
867 (EXTRACTOR_METAFORMAT_C_STRING == pos->format))
868 GNUNET_break ('\0' == pos->data[pos->data_size - 1]);
869 GNUNET_memcpy (&mdata[off], pos->data, pos->data_size);
870 off -= plen;
871 if (NULL != pos->plugin_name)
872 GNUNET_memcpy (&mdata[off], pos->plugin_name, plen);
873 off -= mlen;
874 if (NULL != pos->mime_type)
875 GNUNET_memcpy (&mdata[off], pos->mime_type, mlen);
876 i++;
877 }
878 GNUNET_assert (0 == off);
879
880 clen = 0;
881 cdata = NULL;
882 left = size;
883 i = 0;
884 for (pos = md->items_head; NULL != pos; pos = pos->next)
885 {
886 comp = GNUNET_NO;
887 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS))
888 comp = GNUNET_try_compression ((const char *) &ent[i],
889 left,
890 &cdata,
891 &clen);
892
893 if ((NULL == md->sbuf) && (0 == i))
894 {
895 /* fill 'sbuf'; this "modifies" md, but since this is only
896 * an internal cache we will cast away the 'const' instead
897 * of making the API look strange. */
898 vmd = (struct GNUNET_CONTAINER_MetaData *) md;
899 hdr = GNUNET_malloc (left + sizeof(struct MetaDataHeader));
900 hdr->size = htonl (left);
901 hdr->entries = htonl (md->item_count);
902 if (GNUNET_YES == comp)
903 {
904 GNUNET_assert (clen < left);
905 hdr->version = htonl (2 | HEADER_COMPRESSED);
906 GNUNET_memcpy (&hdr[1], cdata, clen);
907 vmd->sbuf_size = clen + sizeof(struct MetaDataHeader);
908 }
909 else
910 {
911 hdr->version = htonl (2);
912 GNUNET_memcpy (&hdr[1], &ent[0], left);
913 vmd->sbuf_size = left + sizeof(struct MetaDataHeader);
914 }
915 vmd->sbuf = (char *) hdr;
916 }
917
918 if (((left + sizeof(struct MetaDataHeader)) <= max) ||
919 ((GNUNET_YES == comp) && (clen <= max)))
920 {
921 /* success, this now fits! */
922 if (GNUNET_YES == comp)
923 {
924 if (NULL == dst)
925 dst = GNUNET_malloc (clen + sizeof(struct MetaDataHeader));
926 hdr = (struct MetaDataHeader *) dst;
927 hdr->version = htonl (2 | HEADER_COMPRESSED);
928 hdr->size = htonl (left);
929 hdr->entries = htonl (md->item_count - i);
930 GNUNET_memcpy (&dst[sizeof(struct MetaDataHeader)], cdata, clen);
931 GNUNET_free (cdata);
932 cdata = NULL;
933 GNUNET_free (ent);
934 rlen = clen + sizeof(struct MetaDataHeader);
935 }
936 else
937 {
938 if (NULL == dst)
939 dst = GNUNET_malloc (left + sizeof(struct MetaDataHeader));
940 hdr = (struct MetaDataHeader *) dst;
941 hdr->version = htonl (2);
942 hdr->entries = htonl (md->item_count - i);
943 hdr->size = htonl (left);
944 GNUNET_memcpy (&dst[sizeof(struct MetaDataHeader)], &ent[i], left);
945 GNUNET_free (ent);
946 rlen = left + sizeof(struct MetaDataHeader);
947 }
948 if (NULL != *target)
949 {
950 if (GNUNET_YES == comp)
951 GNUNET_memcpy (*target, dst, clen + sizeof(struct MetaDataHeader));
952 else
953 GNUNET_memcpy (*target, dst, left + sizeof(struct MetaDataHeader));
954 GNUNET_free (dst);
955 }
956 else
957 {
958 *target = dst;
959 }
960 return rlen;
961 }
962
963 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
964 {
965 /* does not fit! */
966 GNUNET_free (ent);
967 if (NULL != cdata)
968 GNUNET_free (cdata);
969 cdata = NULL;
970 return GNUNET_SYSERR;
971 }
972
973 /* next iteration: ignore the corresponding meta data at the
974 * end and try again without it */
975 left -= sizeof(struct MetaDataEntry);
976 left -= pos->data_size;
977 if (NULL != pos->plugin_name)
978 left -= strlen (pos->plugin_name) + 1;
979 if (NULL != pos->mime_type)
980 left -= strlen (pos->mime_type) + 1;
981
982 if (NULL != cdata)
983 GNUNET_free (cdata);
984 cdata = NULL;
985 i++;
986 }
987 GNUNET_free (ent);
988
989 /* nothing fit, only write header! */
990 ihdr.version = htonl (2);
991 ihdr.entries = htonl (0);
992 ihdr.size = htonl (0);
993 if (NULL == *target)
994 *target = (char *) GNUNET_new (struct MetaDataHeader);
995 GNUNET_memcpy (*target, &ihdr, sizeof(struct MetaDataHeader));
996 return sizeof(struct MetaDataHeader);
997}
998
999
1000/**
1001 * Get the size of the full meta-data in serialized form.
1002 *
1003 * @param md metadata to inspect
1004 * @return number of bytes needed for serialization, -1 on error
1005 */
1006ssize_t
1007GNUNET_CONTAINER_meta_data_get_serialized_size (const struct
1008 GNUNET_CONTAINER_MetaData *md)
1009{
1010 ssize_t ret;
1011 char *ptr;
1012
1013 if (NULL != md->sbuf)
1014 return md->sbuf_size;
1015 ptr = NULL;
1016 ret =
1017 GNUNET_CONTAINER_meta_data_serialize (md, &ptr, GNUNET_MAX_MALLOC_CHECKED,
1018 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
1019 if (-1 != ret)
1020 GNUNET_free (ptr);
1021 return ret;
1022}
1023
1024
1025/**
1026 * Deserialize meta-data. Initializes md.
1027 *
1028 * @param input buffer with the serialized metadata
1029 * @param size number of bytes available in input
1030 * @return MD on success, NULL on error (i.e.
1031 * bad format)
1032 */
1033struct GNUNET_CONTAINER_MetaData *
1034GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
1035{
1036 struct GNUNET_CONTAINER_MetaData *md;
1037 struct MetaDataHeader hdr;
1038 struct MetaDataEntry ent;
1039 uint32_t ic;
1040 uint32_t i;
1041 char *data;
1042 const char *cdata;
1043 uint32_t version;
1044 uint32_t dataSize;
1045 int compressed;
1046 size_t left;
1047 uint32_t mlen;
1048 uint32_t plen;
1049 uint32_t dlen;
1050 const char *mdata;
1051 const char *meta_data;
1052 const char *plugin_name;
1053 const char *mime_type;
1054 enum EXTRACTOR_MetaFormat format;
1055
1056 if (size < sizeof(struct MetaDataHeader))
1057 return NULL;
1058 GNUNET_memcpy (&hdr, input, sizeof(struct MetaDataHeader));
1059 version = ntohl (hdr.version) & HEADER_VERSION_MASK;
1060 compressed = (ntohl (hdr.version) & HEADER_COMPRESSED) != 0;
1061
1062 if (1 == version)
1063 return NULL; /* null pointer */
1064 if (2 != version)
1065 {
1066 GNUNET_break_op (0); /* unsupported version */
1067 return NULL;
1068 }
1069
1070 ic = ntohl (hdr.entries);
1071 dataSize = ntohl (hdr.size);
1072 if (((sizeof(struct MetaDataEntry) * ic) > dataSize) ||
1073 ((0 != ic) &&
1074 (dataSize / ic < sizeof(struct MetaDataEntry))))
1075 {
1076 GNUNET_break_op (0);
1077 return NULL;
1078 }
1079
1080 if (compressed)
1081 {
1082 if (dataSize >= GNUNET_MAX_MALLOC_CHECKED)
1083 {
1084 /* make sure we don't blow our memory limit because of a mal-formed
1085 * message... */
1086 GNUNET_break_op (0);
1087 return NULL;
1088 }
1089 data =
1090 GNUNET_decompress ((const char *) &input[sizeof(struct MetaDataHeader)],
1091 size - sizeof(struct MetaDataHeader),
1092 dataSize);
1093 if (NULL == data)
1094 {
1095 GNUNET_break_op (0);
1096 return NULL;
1097 }
1098 cdata = data;
1099 }
1100 else
1101 {
1102 data = NULL;
1103 cdata = (const char *) &input[sizeof(struct MetaDataHeader)];
1104 if (dataSize != size - sizeof(struct MetaDataHeader))
1105 {
1106 GNUNET_break_op (0);
1107 return NULL;
1108 }
1109 }
1110
1111 md = GNUNET_CONTAINER_meta_data_create ();
1112 left = dataSize - ic * sizeof(struct MetaDataEntry);
1113 mdata = &cdata[ic * sizeof(struct MetaDataEntry)];
1114 for (i = 0; i < ic; i++)
1115 {
1116 GNUNET_memcpy (&ent, &cdata[i * sizeof(struct MetaDataEntry)],
1117 sizeof(struct MetaDataEntry));
1118 format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format);
1119 if ((EXTRACTOR_METAFORMAT_UTF8 != format) &&
1120 (EXTRACTOR_METAFORMAT_C_STRING != format) &&
1121 (EXTRACTOR_METAFORMAT_BINARY != format))
1122 {
1123 GNUNET_break_op (0);
1124 break;
1125 }
1126 dlen = ntohl (ent.data_size);
1127 plen = ntohl (ent.plugin_name_len);
1128 mlen = ntohl (ent.mime_type_len);
1129 if (dlen > left)
1130 {
1131 GNUNET_break_op (0);
1132 break;
1133 }
1134 left -= dlen;
1135 meta_data = &mdata[left];
1136 if ((EXTRACTOR_METAFORMAT_UTF8 == format) ||
1137 (EXTRACTOR_METAFORMAT_C_STRING == format))
1138 {
1139 if (0 == dlen)
1140 {
1141 GNUNET_break_op (0);
1142 break;
1143 }
1144 if ('\0' != meta_data[dlen - 1])
1145 {
1146 GNUNET_break_op (0);
1147 break;
1148 }
1149 }
1150 if (plen > left)
1151 {
1152 GNUNET_break_op (0);
1153 break;
1154 }
1155 left -= plen;
1156 if ((plen > 0) && ('\0' != mdata[left + plen - 1]))
1157 {
1158 GNUNET_break_op (0);
1159 break;
1160 }
1161 if (0 == plen)
1162 plugin_name = NULL;
1163 else
1164 plugin_name = &mdata[left];
1165
1166 if (mlen > left)
1167 {
1168 GNUNET_break_op (0);
1169 break;
1170 }
1171 left -= mlen;
1172 if ((mlen > 0) && ('\0' != mdata[left + mlen - 1]))
1173 {
1174 GNUNET_break_op (0);
1175 break;
1176 }
1177 if (0 == mlen)
1178 mime_type = NULL;
1179 else
1180 mime_type = &mdata[left];
1181 GNUNET_CONTAINER_meta_data_insert (md, plugin_name,
1182 (enum EXTRACTOR_MetaType)
1183 ntohl (ent.type), format, mime_type,
1184 meta_data, dlen);
1185 }
1186 GNUNET_free (data);
1187 return md;
1188}
1189
1190
1191/* end of container_meta_data.c */
diff --git a/src/util/container_multihashmap.c b/src/util/container_multihashmap.c
deleted file mode 100644
index 08893d81f..000000000
--- a/src/util/container_multihashmap.c
+++ /dev/null
@@ -1,1098 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008, 2012 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 * @file util/container_multihashmap.c
22 * @brief hash map where the same key may be present multiple times
23 * @author Christian Grothoff
24 */
25
26#include "platform.h"
27#include "gnunet_container_lib.h"
28
29#define LOG(kind, ...) \
30 GNUNET_log_from (kind, "util-container-multihashmap", __VA_ARGS__)
31
32/**
33 * Maximum recursion depth for callbacks of
34 * #GNUNET_CONTAINER_multihashmap_get_multiple() themselves s
35 * again calling #GNUNET_CONTAINER_multihashmap_get_multiple().
36 * Should be totally excessive, but if violated we die.
37 */
38#define NEXT_CACHE_SIZE 16
39
40
41/**
42 * An entry in the hash map with the full key.
43 */
44struct BigMapEntry
45{
46 /**
47 * Value of the entry.
48 */
49 void *value;
50
51 /**
52 * If there is a hash collision, we create a linked list.
53 */
54 struct BigMapEntry *next;
55
56 /**
57 * Key for the entry.
58 */
59 struct GNUNET_HashCode key;
60};
61
62
63/**
64 * An entry in the hash map with just a pointer to the key.
65 */
66struct SmallMapEntry
67{
68 /**
69 * Value of the entry.
70 */
71 void *value;
72
73 /**
74 * If there is a hash collision, we create a linked list.
75 */
76 struct SmallMapEntry *next;
77
78 /**
79 * Key for the entry.
80 */
81 const struct GNUNET_HashCode *key;
82};
83
84
85/**
86 * Entry in the map.
87 */
88union MapEntry
89{
90 /**
91 * Variant used if map entries only contain a pointer to the key.
92 */
93 struct SmallMapEntry *sme;
94
95 /**
96 * Variant used if map entries contain the full key.
97 */
98 struct BigMapEntry *bme;
99};
100
101
102/**
103 * Internal representation of the hash map.
104 */
105struct GNUNET_CONTAINER_MultiHashMap
106{
107 /**
108 * All of our buckets.
109 */
110 union MapEntry *map;
111
112 /**
113 * Number of entries in the map.
114 */
115 unsigned int size;
116
117 /**
118 * Length of the "map" array.
119 */
120 unsigned int map_length;
121
122 /**
123 * #GNUNET_NO if the map entries are of type 'struct BigMapEntry',
124 * #GNUNET_YES if the map entries are of type 'struct SmallMapEntry'.
125 */
126 int use_small_entries;
127
128 /**
129 * Counts the destructive modifications (grow, remove)
130 * to the map, so that iterators can check if they are still valid.
131 */
132 unsigned int modification_counter;
133
134 /**
135 * Map entries indicating iteration positions currently
136 * in use by #GNUNET_CONTAINER_multihashmap_get_multiple().
137 * Only used up to @e next_cache_off.
138 */
139 union MapEntry next_cache[NEXT_CACHE_SIZE];
140
141 /**
142 * Offset of @e next_cache entries in use, must be smaller
143 * than #NEXT_CACHE_SIZE.
144 */
145 unsigned int next_cache_off;
146};
147
148
149/**
150 * Cursor into a multihashmap.
151 * Allows to enumerate elements asynchronously.
152 */
153struct GNUNET_CONTAINER_MultiHashMapIterator
154{
155 /**
156 * Position in the bucket @e idx
157 */
158 union MapEntry me;
159
160 /**
161 * Current bucket index.
162 */
163 unsigned int idx;
164
165 /**
166 * Modification counter as observed on the map when the iterator
167 * was created.
168 */
169 unsigned int modification_counter;
170
171 /**
172 * Map that we are iterating over.
173 */
174 const struct GNUNET_CONTAINER_MultiHashMap *map;
175};
176
177
178/**
179 * Create a multi hash map.
180 *
181 * @param len initial size (map will grow as needed)
182 * @param do_not_copy_keys #GNUNET_NO is always safe and should be used by default;
183 * #GNUNET_YES means that on 'put', the 'key' does not have
184 * to be copied as the destination of the pointer is
185 * guaranteed to be life as long as the value is stored in
186 * the hashmap. This can significantly reduce memory
187 * consumption, but of course is also a recipe for
188 * heap corruption if the assumption is not true. Only
189 * use this if (1) memory use is important in this case and
190 * (2) you have triple-checked that the invariant holds
191 * @return NULL on error
192 */
193struct GNUNET_CONTAINER_MultiHashMap *
194GNUNET_CONTAINER_multihashmap_create (unsigned int len, int do_not_copy_keys)
195{
196 struct GNUNET_CONTAINER_MultiHashMap *hm;
197
198 GNUNET_assert (len > 0);
199 hm = GNUNET_new (struct GNUNET_CONTAINER_MultiHashMap);
200 if (len * sizeof(union MapEntry) > GNUNET_MAX_MALLOC_CHECKED)
201 {
202 size_t s;
203 /* application *explicitly* requested very large map, hopefully
204 it checks the return value... */
205 s = len * sizeof(union MapEntry);
206 if ((s / sizeof(union MapEntry)) != len)
207 return NULL; /* integer overflow on multiplication */
208 if (NULL == (hm->map = GNUNET_malloc_large (s)))
209 {
210 /* out of memory */
211 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
212 "Out of memory allocating large hash map (%u entries)\n",
213 len);
214 GNUNET_free (hm);
215 return NULL;
216 }
217 }
218 else
219 {
220 hm->map = GNUNET_new_array (len, union MapEntry);
221 }
222 hm->map_length = len;
223 hm->use_small_entries = do_not_copy_keys;
224 return hm;
225}
226
227
228/**
229 * Destroy a hash map. Will not free any values stored in the hash
230 * map!
231 *
232 * @param map the map
233 */
234void
235GNUNET_CONTAINER_multihashmap_destroy (
236 struct GNUNET_CONTAINER_MultiHashMap *map)
237{
238 GNUNET_assert (0 == map->next_cache_off);
239 for (unsigned int i = 0; i < map->map_length; i++)
240 {
241 union MapEntry me;
242
243 me = map->map[i];
244 if (map->use_small_entries)
245 {
246 struct SmallMapEntry *sme;
247 struct SmallMapEntry *nxt;
248
249 nxt = me.sme;
250 while (NULL != (sme = nxt))
251 {
252 nxt = sme->next;
253 GNUNET_free (sme);
254 }
255 me.sme = NULL;
256 }
257 else
258 {
259 struct BigMapEntry *bme;
260 struct BigMapEntry *nxt;
261
262 nxt = me.bme;
263 while (NULL != (bme = nxt))
264 {
265 nxt = bme->next;
266 GNUNET_free (bme);
267 }
268 me.bme = NULL;
269 }
270 }
271 GNUNET_free (map->map);
272 GNUNET_free (map);
273}
274
275
276/**
277 * Compute the index of the bucket for the given key.
278 *
279 * @param map hash map for which to compute the index
280 * @param key what key should the index be computed for
281 * @return offset into the "map" array of "map"
282 */
283static unsigned int
284idx_of (const struct GNUNET_CONTAINER_MultiHashMap *map,
285 const struct GNUNET_HashCode *key)
286{
287 GNUNET_assert (map != NULL);
288 return (*(unsigned int *) key) % map->map_length;
289}
290
291
292/**
293 * Get the number of key-value pairs in the map.
294 *
295 * @param map the map
296 * @return the number of key value pairs
297 */
298unsigned int
299GNUNET_CONTAINER_multihashmap_size (
300 const struct GNUNET_CONTAINER_MultiHashMap *map)
301{
302 return map->size;
303}
304
305
306/**
307 * Given a key find a value in the map matching the key.
308 *
309 * @param map the map
310 * @param key what to look for
311 * @return NULL if no value was found; note that
312 * this is indistinguishable from values that just
313 * happen to be NULL; use "contains" to test for
314 * key-value pairs with value NULL
315 */
316void *
317GNUNET_CONTAINER_multihashmap_get (
318 const struct GNUNET_CONTAINER_MultiHashMap *map,
319 const struct GNUNET_HashCode *key)
320{
321 union MapEntry me;
322
323 me = map->map[idx_of (map, key)];
324 if (map->use_small_entries)
325 {
326 struct SmallMapEntry *sme;
327
328 for (sme = me.sme; NULL != sme; sme = sme->next)
329 if (0 == GNUNET_memcmp (key, sme->key))
330 return sme->value;
331 }
332 else
333 {
334 struct BigMapEntry *bme;
335
336 for (bme = me.bme; NULL != bme; bme = bme->next)
337 if (0 == GNUNET_memcmp (key, &bme->key))
338 return bme->value;
339 }
340 return NULL;
341}
342
343
344/**
345 * Iterate over all entries in the map.
346 *
347 * @param map the map
348 * @param it function to call on each entry
349 * @param it_cls extra argument to @a it
350 * @return the number of key value pairs processed,
351 * #GNUNET_SYSERR if it aborted iteration
352 */
353int
354GNUNET_CONTAINER_multihashmap_iterate (
355 struct GNUNET_CONTAINER_MultiHashMap *map,
356 GNUNET_CONTAINER_MulitHashMapIteratorCallback it,
357 void *it_cls)
358{
359 int count;
360 union MapEntry me;
361 union MapEntry *ce;
362 struct GNUNET_HashCode kc;
363
364 GNUNET_assert (NULL != map);
365 ce = &map->next_cache[map->next_cache_off];
366 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
367 count = 0;
368 for (unsigned i = 0; i < map->map_length; i++)
369 {
370 me = map->map[i];
371 if (map->use_small_entries)
372 {
373 struct SmallMapEntry *sme;
374
375 ce->sme = me.sme;
376 while (NULL != (sme = ce->sme))
377 {
378 ce->sme = sme->next;
379 if (NULL != it)
380 {
381 if (GNUNET_OK != it (it_cls, sme->key, sme->value))
382 {
383 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
384 return GNUNET_SYSERR;
385 }
386 }
387 count++;
388 }
389 }
390 else
391 {
392 struct BigMapEntry *bme;
393
394 ce->bme = me.bme;
395 while (NULL != (bme = ce->bme))
396 {
397 ce->bme = bme->next;
398 if (NULL != it)
399 {
400 kc = bme->key;
401 if (GNUNET_OK != it (it_cls, &kc, bme->value))
402 {
403 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
404 return GNUNET_SYSERR;
405 }
406 }
407 count++;
408 }
409 }
410 }
411 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
412 return count;
413}
414
415
416/**
417 * We are about to free() the @a bme, make sure it is not in
418 * the list of next values for any iterator in the @a map's next_cache.
419 *
420 * @param map the map to check
421 * @param bme the entry that is about to be free'd
422 */
423static void
424update_next_cache_bme (struct GNUNET_CONTAINER_MultiHashMap *map,
425 const struct BigMapEntry *bme)
426{
427 for (unsigned int i = 0; i < map->next_cache_off; i++)
428 if (map->next_cache[i].bme == bme)
429 map->next_cache[i].bme = bme->next;
430}
431
432
433/**
434 * We are about to free() the @a sme, make sure it is not in
435 * the list of next values for any iterator in the @a map's next_cache.
436 *
437 * @param map the map to check
438 * @param sme the entry that is about to be free'd
439 */
440static void
441update_next_cache_sme (struct GNUNET_CONTAINER_MultiHashMap *map,
442 const struct SmallMapEntry *sme)
443{
444 for (unsigned int i = 0; i < map->next_cache_off; i++)
445 if (map->next_cache[i].sme == sme)
446 map->next_cache[i].sme = sme->next;
447}
448
449
450/**
451 * Remove the given key-value pair from the map. Note that if the
452 * key-value pair is in the map multiple times, only one of the pairs
453 * will be removed.
454 *
455 * @param map the map
456 * @param key key of the key-value pair
457 * @param value value of the key-value pair
458 * @return #GNUNET_YES on success, #GNUNET_NO if the key-value pair
459 * is not in the map
460 */
461int
462GNUNET_CONTAINER_multihashmap_remove (struct GNUNET_CONTAINER_MultiHashMap *map,
463 const struct GNUNET_HashCode *key,
464 const void *value)
465{
466 union MapEntry me;
467 unsigned int i;
468
469 map->modification_counter++;
470
471 i = idx_of (map, key);
472 me = map->map[i];
473 if (map->use_small_entries)
474 {
475 struct SmallMapEntry *p;
476
477 p = NULL;
478 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
479 {
480 if ((0 == GNUNET_memcmp (key, sme->key)) && (value == sme->value))
481 {
482 if (NULL == p)
483 map->map[i].sme = sme->next;
484 else
485 p->next = sme->next;
486 update_next_cache_sme (map, sme);
487 GNUNET_free (sme);
488 map->size--;
489 return GNUNET_YES;
490 }
491 p = sme;
492 }
493 }
494 else
495 {
496 struct BigMapEntry *p;
497
498 p = NULL;
499 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
500 {
501 if ((0 == GNUNET_memcmp (key, &bme->key)) && (value == bme->value))
502 {
503 if (NULL == p)
504 map->map[i].bme = bme->next;
505 else
506 p->next = bme->next;
507 update_next_cache_bme (map, bme);
508 GNUNET_free (bme);
509 map->size--;
510 return GNUNET_YES;
511 }
512 p = bme;
513 }
514 }
515 return GNUNET_NO;
516}
517
518
519/**
520 * Remove all entries for the given key from the map.
521 * Note that the values would not be "freed".
522 *
523 * @param map the map
524 * @param key identifies values to be removed
525 * @return number of values removed
526 */
527int
528GNUNET_CONTAINER_multihashmap_remove_all (
529 struct GNUNET_CONTAINER_MultiHashMap *map,
530 const struct GNUNET_HashCode *key)
531{
532 union MapEntry me;
533 unsigned int i;
534 int ret;
535
536 map->modification_counter++;
537
538 ret = 0;
539 i = idx_of (map, key);
540 me = map->map[i];
541 if (map->use_small_entries)
542 {
543 struct SmallMapEntry *sme;
544 struct SmallMapEntry *p;
545
546 p = NULL;
547 sme = me.sme;
548 while (NULL != sme)
549 {
550 if (0 == GNUNET_memcmp (key, sme->key))
551 {
552 if (NULL == p)
553 map->map[i].sme = sme->next;
554 else
555 p->next = sme->next;
556 update_next_cache_sme (map, sme);
557 GNUNET_free (sme);
558 map->size--;
559 if (NULL == p)
560 sme = map->map[i].sme;
561 else
562 sme = p->next;
563 ret++;
564 }
565 else
566 {
567 p = sme;
568 sme = sme->next;
569 }
570 }
571 }
572 else
573 {
574 struct BigMapEntry *bme;
575 struct BigMapEntry *p;
576
577 p = NULL;
578 bme = me.bme;
579 while (NULL != bme)
580 {
581 if (0 == GNUNET_memcmp (key, &bme->key))
582 {
583 if (NULL == p)
584 map->map[i].bme = bme->next;
585 else
586 p->next = bme->next;
587 update_next_cache_bme (map, bme);
588 GNUNET_free (bme);
589 map->size--;
590 if (NULL == p)
591 bme = map->map[i].bme;
592 else
593 bme = p->next;
594 ret++;
595 }
596 else
597 {
598 p = bme;
599 bme = bme->next;
600 }
601 }
602 }
603 return ret;
604}
605
606
607/**
608 * Callback used to remove all entries from the map.
609 *
610 * @param cls the `struct GNUNET_CONTAINER_MultiHashMap`
611 * @param key the key
612 * @param value the value
613 * @return #GNUNET_OK (continue to iterate)
614 */
615static int
616remove_all (void *cls, const struct GNUNET_HashCode *key, void *value)
617{
618 struct GNUNET_CONTAINER_MultiHashMap *map = cls;
619
620 GNUNET_assert (GNUNET_YES ==
621 GNUNET_CONTAINER_multihashmap_remove (map, key, value));
622 return GNUNET_OK;
623}
624
625
626/**
627 * @ingroup hashmap
628 * Remove all entries from the map.
629 * Note that the values would not be "freed".
630 *
631 * @param map the map
632 * @return number of values removed
633 */
634unsigned int
635GNUNET_CONTAINER_multihashmap_clear (struct GNUNET_CONTAINER_MultiHashMap *map)
636{
637 unsigned int ret;
638
639 ret = map->size;
640 GNUNET_CONTAINER_multihashmap_iterate (map, &remove_all, map);
641 return ret;
642}
643
644
645/**
646 * Check if the map contains any value under the given
647 * key (including values that are NULL).
648 *
649 * @param map the map
650 * @param key the key to test if a value exists for it
651 * @return #GNUNET_YES if such a value exists,
652 * #GNUNET_NO if not
653 */
654int
655GNUNET_CONTAINER_multihashmap_contains (
656 const struct GNUNET_CONTAINER_MultiHashMap *map,
657 const struct GNUNET_HashCode *key)
658{
659 union MapEntry me;
660
661 me = map->map[idx_of (map, key)];
662 if (map->use_small_entries)
663 {
664 struct SmallMapEntry *sme;
665
666 for (sme = me.sme; NULL != sme; sme = sme->next)
667 if (0 == GNUNET_memcmp (key, sme->key))
668 return GNUNET_YES;
669 }
670 else
671 {
672 struct BigMapEntry *bme;
673
674 for (bme = me.bme; NULL != bme; bme = bme->next)
675 if (0 == GNUNET_memcmp (key, &bme->key))
676 return GNUNET_YES;
677 }
678 return GNUNET_NO;
679}
680
681
682/**
683 * Check if the map contains the given value under the given
684 * key.
685 *
686 * @param map the map
687 * @param key the key to test if a value exists for it
688 * @param value value to test for
689 * @return #GNUNET_YES if such a value exists,
690 * #GNUNET_NO if not
691 */
692int
693GNUNET_CONTAINER_multihashmap_contains_value (
694 const struct GNUNET_CONTAINER_MultiHashMap *map,
695 const struct GNUNET_HashCode *key,
696 const void *value)
697{
698 union MapEntry me;
699
700 me = map->map[idx_of (map, key)];
701 if (map->use_small_entries)
702 {
703 struct SmallMapEntry *sme;
704
705 for (sme = me.sme; NULL != sme; sme = sme->next)
706 if ((0 == GNUNET_memcmp (key, sme->key)) && (sme->value == value))
707 return GNUNET_YES;
708 }
709 else
710 {
711 struct BigMapEntry *bme;
712
713 for (bme = me.bme; NULL != bme; bme = bme->next)
714 if ((0 == GNUNET_memcmp (key, &bme->key)) && (bme->value == value))
715 return GNUNET_YES;
716 }
717 return GNUNET_NO;
718}
719
720
721/**
722 * Grow the given map to a more appropriate size.
723 *
724 * @param map the hash map to grow
725 */
726static void
727grow (struct GNUNET_CONTAINER_MultiHashMap *map)
728{
729 union MapEntry *old_map;
730 union MapEntry *new_map;
731 unsigned int old_len;
732 unsigned int new_len;
733 unsigned int idx;
734
735 old_map = map->map;
736 old_len = map->map_length;
737 GNUNET_assert (0 != old_len);
738 new_len = old_len * 2;
739 if (0 == new_len) /* 2^31 * 2 == 0 */
740 new_len = old_len; /* never use 0 */
741 if (new_len == old_len)
742 return; /* nothing changed */
743 new_map = GNUNET_malloc_large (new_len * sizeof(union MapEntry));
744 if (NULL == new_map)
745 return; /* grow not possible */
746 map->modification_counter++;
747 map->map_length = new_len;
748 map->map = new_map;
749 for (unsigned int i = 0; i < old_len; i++)
750 {
751 if (map->use_small_entries)
752 {
753 struct SmallMapEntry *sme;
754
755 while (NULL != (sme = old_map[i].sme))
756 {
757 old_map[i].sme = sme->next;
758 idx = idx_of (map, sme->key);
759 sme->next = new_map[idx].sme;
760 new_map[idx].sme = sme;
761 }
762 }
763 else
764 {
765 struct BigMapEntry *bme;
766
767 while (NULL != (bme = old_map[i].bme))
768 {
769 old_map[i].bme = bme->next;
770 idx = idx_of (map, &bme->key);
771 bme->next = new_map[idx].bme;
772 new_map[idx].bme = bme;
773 }
774 }
775 }
776 GNUNET_free (old_map);
777}
778
779
780/**
781 * Store a key-value pair in the map.
782 *
783 * @param map the map
784 * @param key key to use
785 * @param value value to use
786 * @param opt options for put
787 * @return #GNUNET_OK on success,
788 * #GNUNET_NO if a value was replaced (with REPLACE)
789 * #GNUNET_SYSERR if UNIQUE_ONLY was the option and the
790 * value already exists
791 */
792int
793GNUNET_CONTAINER_multihashmap_put (struct GNUNET_CONTAINER_MultiHashMap *map,
794 const struct GNUNET_HashCode *key,
795 void *value,
796 enum GNUNET_CONTAINER_MultiHashMapOption opt)
797{
798 union MapEntry me;
799 unsigned int i;
800
801 i = idx_of (map, key);
802 if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
803 (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
804 {
805 me = map->map[i];
806 if (map->use_small_entries)
807 {
808 struct SmallMapEntry *sme;
809
810 for (sme = me.sme; NULL != sme; sme = sme->next)
811 if (0 == GNUNET_memcmp (key, sme->key))
812 {
813 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
814 return GNUNET_SYSERR;
815 sme->value = value;
816 return GNUNET_NO;
817 }
818 }
819 else
820 {
821 struct BigMapEntry *bme;
822
823 for (bme = me.bme; NULL != bme; bme = bme->next)
824 if (0 == GNUNET_memcmp (key, &bme->key))
825 {
826 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
827 return GNUNET_SYSERR;
828 bme->value = value;
829 return GNUNET_NO;
830 }
831 }
832 }
833 if (map->size / 3 >= map->map_length / 4)
834 {
835 grow (map);
836 i = idx_of (map, key);
837 }
838 if (map->use_small_entries)
839 {
840 struct SmallMapEntry *sme;
841
842 sme = GNUNET_new (struct SmallMapEntry);
843 sme->key = key;
844 sme->value = value;
845 sme->next = map->map[i].sme;
846 map->map[i].sme = sme;
847 }
848 else
849 {
850 struct BigMapEntry *bme;
851
852 bme = GNUNET_new (struct BigMapEntry);
853 bme->key = *key;
854 bme->value = value;
855 bme->next = map->map[i].bme;
856 map->map[i].bme = bme;
857 }
858 map->size++;
859 return GNUNET_OK;
860}
861
862
863/**
864 * Iterate over all entries in the map that match a particular key.
865 *
866 * @param map the map
867 * @param key key that the entries must correspond to
868 * @param it function to call on each entry
869 * @param it_cls extra argument to it
870 * @return the number of key value pairs processed,
871 * #GNUNET_SYSERR if it aborted iteration
872 */
873int
874GNUNET_CONTAINER_multihashmap_get_multiple (
875 struct GNUNET_CONTAINER_MultiHashMap *map,
876 const struct GNUNET_HashCode *key,
877 GNUNET_CONTAINER_MulitHashMapIteratorCallback it,
878 void *it_cls)
879{
880 int count;
881 union MapEntry *me;
882 union MapEntry *ce;
883
884 ce = &map->next_cache[map->next_cache_off];
885 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
886 count = 0;
887 me = &map->map[idx_of (map, key)];
888 if (map->use_small_entries)
889 {
890 struct SmallMapEntry *sme;
891
892 ce->sme = me->sme;
893 while (NULL != (sme = ce->sme))
894 {
895 ce->sme = sme->next;
896 if (0 != GNUNET_memcmp (key, sme->key))
897 continue;
898 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, sme->value)))
899 {
900 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
901 return GNUNET_SYSERR;
902 }
903 count++;
904 }
905 }
906 else
907 {
908 struct BigMapEntry *bme;
909
910 ce->bme = me->bme;
911 while (NULL != (bme = ce->bme))
912 {
913 ce->bme = bme->next;
914 if (0 != GNUNET_memcmp (key, &bme->key))
915 continue;
916 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, bme->value)))
917 {
918 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
919 return GNUNET_SYSERR;
920 }
921 count++;
922 }
923 }
924 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
925 return count;
926}
927
928
929/**
930 * @ingroup hashmap
931 * Call @a it on a random value from the map, or not at all
932 * if the map is empty. Note that this function has linear
933 * complexity (in the size of the map).
934 *
935 * @param map the map
936 * @param it function to call on a random entry
937 * @param it_cls extra argument to @a it
938 * @return the number of key value pairs processed, zero or one.
939 */
940unsigned int
941GNUNET_CONTAINER_multihashmap_get_random (
942 const struct GNUNET_CONTAINER_MultiHashMap *map,
943 GNUNET_CONTAINER_MulitHashMapIteratorCallback it,
944 void *it_cls)
945{
946 unsigned int off;
947 unsigned int idx;
948 union MapEntry me;
949
950 if (0 == map->size)
951 return 0;
952 if (NULL == it)
953 return 1;
954 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, map->size);
955 for (idx = 0; idx < map->map_length; idx++)
956 {
957 me = map->map[idx];
958 if (map->use_small_entries)
959 {
960 struct SmallMapEntry *sme;
961 struct SmallMapEntry *nxt;
962
963 nxt = me.sme;
964 while (NULL != (sme = nxt))
965 {
966 nxt = sme->next;
967 if (0 == off)
968 {
969 if (GNUNET_OK != it (it_cls, sme->key, sme->value))
970 return GNUNET_SYSERR;
971 return 1;
972 }
973 off--;
974 }
975 }
976 else
977 {
978 struct BigMapEntry *bme;
979 struct BigMapEntry *nxt;
980
981 nxt = me.bme;
982 while (NULL != (bme = nxt))
983 {
984 nxt = bme->next;
985 if (0 == off)
986 {
987 if (GNUNET_OK != it (it_cls, &bme->key, bme->value))
988 return GNUNET_SYSERR;
989 return 1;
990 }
991 off--;
992 }
993 }
994 }
995 GNUNET_break (0);
996 return GNUNET_SYSERR;
997}
998
999
1000/**
1001 * Create an iterator for a multihashmap.
1002 * The iterator can be used to retrieve all the elements in the multihashmap
1003 * one by one, without having to handle all elements at once (in contrast to
1004 * GNUNET_CONTAINER_multihashmap_iterate()). Note that the iterator can not be
1005 * used anymore if elements have been removed from 'map' after the creation of
1006 * the iterator, or 'map' has been destroyed. Adding elements to 'map' may
1007 * result in skipped or repeated elements.
1008 *
1009 * @param map the map to create an iterator for
1010 * @return an iterator over the given multihashmap 'map'
1011 */
1012struct GNUNET_CONTAINER_MultiHashMapIterator *
1013GNUNET_CONTAINER_multihashmap_iterator_create (
1014 const struct GNUNET_CONTAINER_MultiHashMap *map)
1015{
1016 struct GNUNET_CONTAINER_MultiHashMapIterator *iter;
1017
1018 iter = GNUNET_new (struct GNUNET_CONTAINER_MultiHashMapIterator);
1019 iter->map = map;
1020 iter->modification_counter = map->modification_counter;
1021 iter->me = map->map[0];
1022 return iter;
1023}
1024
1025
1026/**
1027 * Retrieve the next element from the hash map at the iterator's position.
1028 * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
1029 * are not modified.
1030 * This operation is only allowed if no elements have been removed from the
1031 * multihashmap since the creation of 'iter', and the map has not been destroyed.
1032 * Adding elements may result in repeating or skipping elements.
1033 *
1034 * @param iter the iterator to get the next element from
1035 * @param key pointer to store the key in, can be NULL
1036 * @param value pointer to store the value in, can be NULL
1037 * @return #GNUNET_YES we returned an element,
1038 * #GNUNET_NO if we are out of elements
1039 */
1040int
1041GNUNET_CONTAINER_multihashmap_iterator_next (
1042 struct GNUNET_CONTAINER_MultiHashMapIterator *iter,
1043 struct GNUNET_HashCode *key,
1044 const void **value)
1045{
1046 /* make sure the map has not been modified */
1047 GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
1048
1049 /* look for the next entry, skipping empty buckets */
1050 while (1)
1051 {
1052 if (iter->idx >= iter->map->map_length)
1053 return GNUNET_NO;
1054 if (GNUNET_YES == iter->map->use_small_entries)
1055 {
1056 if (NULL != iter->me.sme)
1057 {
1058 if (NULL != key)
1059 *key = *iter->me.sme->key;
1060 if (NULL != value)
1061 *value = iter->me.sme->value;
1062 iter->me.sme = iter->me.sme->next;
1063 return GNUNET_YES;
1064 }
1065 }
1066 else
1067 {
1068 if (NULL != iter->me.bme)
1069 {
1070 if (NULL != key)
1071 *key = iter->me.bme->key;
1072 if (NULL != value)
1073 *value = iter->me.bme->value;
1074 iter->me.bme = iter->me.bme->next;
1075 return GNUNET_YES;
1076 }
1077 }
1078 iter->idx += 1;
1079 if (iter->idx < iter->map->map_length)
1080 iter->me = iter->map->map[iter->idx];
1081 }
1082}
1083
1084
1085/**
1086 * Destroy a multihashmap iterator.
1087 *
1088 * @param iter the iterator to destroy
1089 */
1090void
1091GNUNET_CONTAINER_multihashmap_iterator_destroy (
1092 struct GNUNET_CONTAINER_MultiHashMapIterator *iter)
1093{
1094 GNUNET_free (iter);
1095}
1096
1097
1098/* end of container_multihashmap.c */
diff --git a/src/util/container_multihashmap32.c b/src/util/container_multihashmap32.c
deleted file mode 100644
index f349a5f80..000000000
--- a/src/util/container_multihashmap32.c
+++ /dev/null
@@ -1,678 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008 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 * @file util/container_multihashmap32.c
22 * @brief a version of hash map implemented in container_multihashmap.c but with
23 * uint32_t as keys
24 * @author Christian Grothoff
25 * @author Sree Harsha Totakura
26 */
27
28#include "platform.h"
29#include "gnunet_container_lib.h"
30
31#define LOG(kind, ...) \
32 GNUNET_log_from (kind, "util-container-multihashmap32", __VA_ARGS__)
33
34
35/**
36 * Maximum recursion depth for callbacks of
37 * #GNUNET_CONTAINER_multihashmap_get_multiple() themselves
38 * again calling #GNUNET_CONTAINER_multihashmap_get_multiple().
39 * Should be totally excessive, but if violated we die.
40 */
41#define NEXT_CACHE_SIZE 16
42
43/**
44 * An entry in the hash map.
45 */
46struct MapEntry
47{
48 /**
49 * Key for the entry.
50 */
51 uint32_t key;
52
53 /**
54 * Value of the entry.
55 */
56 void *value;
57
58 /**
59 * If there is a hash collision, we create a linked list.
60 */
61 struct MapEntry *next;
62};
63
64/**
65 * Internal representation of the hash map.
66 */
67struct GNUNET_CONTAINER_MultiHashMap32
68{
69 /**
70 * All of our buckets.
71 */
72 struct MapEntry **map;
73
74 /**
75 * Number of entries in the map.
76 */
77 unsigned int size;
78
79 /**
80 * Length of the @e map array.
81 */
82 unsigned int map_length;
83
84 /**
85 * Counts the destructive modifications (grow, remove)
86 * to the map, so that iterators can check if they are still valid.
87 */
88 unsigned int modification_counter;
89
90 /**
91 * Map entries indicating iteration positions currently
92 * in use by #GNUNET_CONTAINER_multihashmap_get_multiple().
93 * Only used up to @e next_cache_off.
94 */
95 struct MapEntry *next_cache[NEXT_CACHE_SIZE];
96
97 /**
98 * Offset of @e next_cache entries in use, must be smaller
99 * than #NEXT_CACHE_SIZE.
100 */
101 unsigned int next_cache_off;
102};
103
104
105/**
106 * Cursor into a multihashmap.
107 * Allows to enumerate elements asynchronously.
108 */
109struct GNUNET_CONTAINER_MultiHashMap32Iterator
110{
111 /**
112 * Position in the bucket @e idx
113 */
114 struct MapEntry *me;
115
116 /**
117 * Current bucket index.
118 */
119 unsigned int idx;
120
121 /**
122 * Modification counter as observed on the map when the iterator
123 * was created.
124 */
125 unsigned int modification_counter;
126
127 /**
128 * Map that we are iterating over.
129 */
130 const struct GNUNET_CONTAINER_MultiHashMap32 *map;
131};
132
133
134/**
135 * Create a multi hash map.
136 *
137 * @param len initial size (map will grow as needed)
138 * @return NULL on error
139 */
140struct GNUNET_CONTAINER_MultiHashMap32 *
141GNUNET_CONTAINER_multihashmap32_create (unsigned int len)
142{
143 struct GNUNET_CONTAINER_MultiHashMap32 *ret;
144
145 GNUNET_assert (len > 0);
146 ret = GNUNET_new (struct GNUNET_CONTAINER_MultiHashMap32);
147 ret->map = GNUNET_malloc_large (len * sizeof(struct MapEntry *));
148 if (NULL == ret->map)
149 {
150 GNUNET_free (ret);
151 return NULL;
152 }
153 ret->map_length = len;
154 return ret;
155}
156
157
158/**
159 * Destroy a hash map. Will not free any values
160 * stored in the hash map!
161 *
162 * @param map the map
163 */
164void
165GNUNET_CONTAINER_multihashmap32_destroy (
166 struct GNUNET_CONTAINER_MultiHashMap32 *map)
167{
168 struct MapEntry *e;
169
170 for (unsigned int i = 0; i < map->map_length; i++)
171 {
172 while (NULL != (e = map->map[i]))
173 {
174 map->map[i] = e->next;
175 GNUNET_free (e);
176 }
177 }
178 GNUNET_free (map->map);
179 GNUNET_free (map);
180}
181
182
183/**
184 * Compute the index of the bucket for the given key.
185 *
186 * @param m hash map for which to compute the index
187 * @param key what key should the index be computed for
188 * @return offset into the "map" array of "m"
189 */
190static unsigned int
191idx_of (const struct GNUNET_CONTAINER_MultiHashMap32 *m, const uint32_t key)
192{
193 GNUNET_assert (NULL != m);
194 return ((unsigned int) key) % m->map_length;
195}
196
197
198/**
199 * Get the number of key-value pairs in the map.
200 *
201 * @param map the map
202 * @return the number of key value pairs
203 */
204unsigned int
205GNUNET_CONTAINER_multihashmap32_size (
206 const struct GNUNET_CONTAINER_MultiHashMap32 *map)
207{
208 return map->size;
209}
210
211
212/**
213 * Given a key find a value in the map matching the key.
214 *
215 * @param map the map
216 * @param key what to look for
217 * @return NULL if no value was found; note that
218 * this is indistinguishable from values that just
219 * happen to be NULL; use "contains" to test for
220 * key-value pairs with value NULL
221 */
222void *
223GNUNET_CONTAINER_multihashmap32_get (
224 const struct GNUNET_CONTAINER_MultiHashMap32 *map,
225 uint32_t key)
226{
227 struct MapEntry *e;
228
229 e = map->map[idx_of (map, key)];
230 while (NULL != e)
231 {
232 if (key == e->key)
233 return e->value;
234 e = e->next;
235 }
236 return NULL;
237}
238
239
240/**
241 * Iterate over all entries in the map.
242 *
243 * @param map the map
244 * @param it function to call on each entry
245 * @param it_cls extra argument to @a it
246 * @return the number of key value pairs processed,
247 * #GNUNET_SYSERR if it aborted iteration
248 */
249int
250GNUNET_CONTAINER_multihashmap32_iterate (
251 struct GNUNET_CONTAINER_MultiHashMap32 *map,
252 GNUNET_CONTAINER_MulitHashMapIterator32Callback it,
253 void *it_cls)
254{
255 int count;
256 struct MapEntry **ce;
257
258 count = 0;
259 GNUNET_assert (NULL != map);
260 ce = &map->next_cache[map->next_cache_off];
261 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
262 for (unsigned int i = 0; i < map->map_length; i++)
263 {
264 struct MapEntry *e;
265
266 *ce = map->map[i];
267 while (NULL != (e = *ce))
268 {
269 *ce = e->next;
270 if (NULL != it)
271 {
272 if (GNUNET_OK != it (it_cls, e->key, e->value))
273 {
274 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
275 return GNUNET_SYSERR;
276 }
277 }
278 count++;
279 }
280 }
281 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
282 return count;
283}
284
285
286/**
287 * We are about to free() the @a bme, make sure it is not in
288 * the list of next values for any iterator in the @a map's next_cache.
289 *
290 * @param map the map to check
291 * @param bme the entry that is about to be free'd
292 */
293static void
294update_next_cache (struct GNUNET_CONTAINER_MultiHashMap32 *map,
295 const struct MapEntry *me)
296{
297 for (unsigned int i = 0; i < map->next_cache_off; i++)
298 if (map->next_cache[i] == me)
299 map->next_cache[i] = me->next;
300}
301
302
303/**
304 * Remove the given key-value pair from the map. Note that if the
305 * key-value pair is in the map multiple times, only one of the pairs
306 * will be removed.
307 *
308 * @param map the map
309 * @param key key of the key-value pair
310 * @param value value of the key-value pair
311 * @return #GNUNET_YES on success, #GNUNET_NO if the key-value pair
312 * is not in the map
313 */
314int
315GNUNET_CONTAINER_multihashmap32_remove (
316 struct GNUNET_CONTAINER_MultiHashMap32 *map,
317 uint32_t key,
318 const void *value)
319{
320 struct MapEntry *e;
321 struct MapEntry *p;
322 unsigned int i;
323
324 map->modification_counter++;
325
326 i = idx_of (map, key);
327 p = NULL;
328 e = map->map[i];
329 while (e != NULL)
330 {
331 if ((key == e->key) && (value == e->value))
332 {
333 if (p == NULL)
334 map->map[i] = e->next;
335 else
336 p->next = e->next;
337 update_next_cache (map, e);
338 GNUNET_free (e);
339 map->size--;
340 return GNUNET_YES;
341 }
342 p = e;
343 e = e->next;
344 }
345 return GNUNET_NO;
346}
347
348
349/**
350 * Remove all entries for the given key from the map.
351 * Note that the values would not be "freed".
352 *
353 * @param map the map
354 * @param key identifies values to be removed
355 * @return number of values removed
356 */
357int
358GNUNET_CONTAINER_multihashmap32_remove_all (
359 struct GNUNET_CONTAINER_MultiHashMap32 *map,
360 uint32_t key)
361{
362 struct MapEntry *e;
363 struct MapEntry *p;
364 unsigned int i;
365 int ret;
366
367 map->modification_counter++;
368
369 ret = 0;
370 i = idx_of (map, key);
371 p = NULL;
372 e = map->map[i];
373 while (e != NULL)
374 {
375 if (key == e->key)
376 {
377 if (p == NULL)
378 map->map[i] = e->next;
379 else
380 p->next = e->next;
381 update_next_cache (map, e);
382 GNUNET_free (e);
383 map->size--;
384 if (p == NULL)
385 e = map->map[i];
386 else
387 e = p->next;
388 ret++;
389 }
390 else
391 {
392 p = e;
393 e = e->next;
394 }
395 }
396 return ret;
397}
398
399
400/**
401 * Check if the map contains any value under the given
402 * key (including values that are NULL).
403 *
404 * @param map the map
405 * @param key the key to test if a value exists for it
406 * @return #GNUNET_YES if such a value exists,
407 * #GNUNET_NO if not
408 */
409int
410GNUNET_CONTAINER_multihashmap32_contains (
411 const struct GNUNET_CONTAINER_MultiHashMap32 *map,
412 uint32_t key)
413{
414 struct MapEntry *e;
415
416 e = map->map[idx_of (map, key)];
417 while (e != NULL)
418 {
419 if (key == e->key)
420 return GNUNET_YES;
421 e = e->next;
422 }
423 return GNUNET_NO;
424}
425
426
427/**
428 * Check if the map contains the given value under the given
429 * key.
430 *
431 * @param map the map
432 * @param key the key to test if a value exists for it
433 * @param value value to test for
434 * @return #GNUNET_YES if such a value exists,
435 * #GNUNET_NO if not
436 */
437int
438GNUNET_CONTAINER_multihashmap32_contains_value (
439 const struct GNUNET_CONTAINER_MultiHashMap32 *map,
440 uint32_t key,
441 const void *value)
442{
443 struct MapEntry *e;
444
445 e = map->map[idx_of (map, key)];
446 while (e != NULL)
447 {
448 if ((key == e->key) && (e->value == value))
449 return GNUNET_YES;
450 e = e->next;
451 }
452 return GNUNET_NO;
453}
454
455
456/**
457 * Grow the given map to a more appropriate size.
458 *
459 * @param map the hash map to grow
460 */
461static void
462grow (struct GNUNET_CONTAINER_MultiHashMap32 *map)
463{
464 struct MapEntry **old_map;
465 struct MapEntry **new_map;
466 struct MapEntry *e;
467 unsigned int old_len;
468 unsigned int new_len;
469 unsigned int idx;
470
471 old_map = map->map;
472 old_len = map->map_length;
473 new_len = old_len * 2;
474 if (0 == new_len) /* 2^31 * 2 == 0 */
475 new_len = old_len; /* never use 0 */
476 if (new_len == old_len)
477 return; /* nothing changed */
478 new_map = GNUNET_malloc_large (new_len * sizeof(struct MapEntry *));
479 if (NULL == new_map)
480 return; /* grow not possible */
481 map->modification_counter++;
482 map->map_length = new_len;
483 map->map = new_map;
484 for (unsigned int i = 0; i < old_len; i++)
485 {
486 while (NULL != (e = old_map[i]))
487 {
488 old_map[i] = e->next;
489 idx = idx_of (map, e->key);
490 e->next = new_map[idx];
491 new_map[idx] = e;
492 }
493 }
494 GNUNET_free (old_map);
495}
496
497
498/**
499 * Store a key-value pair in the map.
500 *
501 * @param map the map
502 * @param key key to use
503 * @param value value to use
504 * @param opt options for put
505 * @return #GNUNET_OK on success,
506 * #GNUNET_NO if a value was replaced (with REPLACE)
507 * #GNUNET_SYSERR if UNIQUE_ONLY was the option and the
508 * value already exists
509 */
510int
511GNUNET_CONTAINER_multihashmap32_put (
512 struct GNUNET_CONTAINER_MultiHashMap32 *map,
513 uint32_t key,
514 void *value,
515 enum GNUNET_CONTAINER_MultiHashMapOption opt)
516{
517 struct MapEntry *e;
518 unsigned int i;
519
520 i = idx_of (map, key);
521 if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
522 (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
523 {
524 e = map->map[i];
525 while (e != NULL)
526 {
527 if (key == e->key)
528 {
529 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
530 return GNUNET_SYSERR;
531 e->value = value;
532 return GNUNET_NO;
533 }
534 e = e->next;
535 }
536 }
537 if (map->size / 3 >= map->map_length / 4)
538 {
539 grow (map);
540 i = idx_of (map, key);
541 }
542 e = GNUNET_new (struct MapEntry);
543 e->key = key;
544 e->value = value;
545 e->next = map->map[i];
546 map->map[i] = e;
547 map->size++;
548 return GNUNET_OK;
549}
550
551
552/**
553 * Iterate over all entries in the map that match a particular key.
554 *
555 * @param map the map
556 * @param key key that the entries must correspond to
557 * @param it function to call on each entry
558 * @param it_cls extra argument to @a it
559 * @return the number of key value pairs processed,
560 * GNUNET_SYSERR if it aborted iteration
561 */
562int
563GNUNET_CONTAINER_multihashmap32_get_multiple (
564 struct GNUNET_CONTAINER_MultiHashMap32 *map,
565 uint32_t key,
566 GNUNET_CONTAINER_MulitHashMapIterator32Callback it,
567 void *it_cls)
568{
569 int count;
570 struct MapEntry *e;
571 struct MapEntry **ce;
572
573 count = 0;
574 ce = &map->next_cache[map->next_cache_off];
575 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
576
577 *ce = map->map[idx_of (map, key)];
578 while (NULL != (e = *ce))
579 {
580 *ce = e->next;
581 if (key != e->key)
582 continue;
583 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, e->value)))
584 {
585 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
586 return GNUNET_SYSERR;
587 }
588 count++;
589 }
590 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
591 return count;
592}
593
594
595/**
596 * Create an iterator for a multihashmap.
597 * The iterator can be used to retrieve all the elements in the multihashmap
598 * one by one, without having to handle all elements at once (in contrast to
599 * GNUNET_CONTAINER_multihashmap_iterate()). Note that the iterator can not be
600 * used anymore if elements have been removed from 'map' after the creation of
601 * the iterator, or 'map' has been destroyed. Adding elements to 'map' may
602 * result in skipped or repeated elements.
603 *
604 * @param map the map to create an iterator for
605 * @return an iterator over the given multihashmap @a map
606 */
607struct GNUNET_CONTAINER_MultiHashMap32Iterator *
608GNUNET_CONTAINER_multihashmap32_iterator_create (
609 const struct GNUNET_CONTAINER_MultiHashMap32 *map)
610{
611 struct GNUNET_CONTAINER_MultiHashMap32Iterator *iter;
612
613 iter = GNUNET_new (struct GNUNET_CONTAINER_MultiHashMap32Iterator);
614 iter->map = map;
615 iter->modification_counter = map->modification_counter;
616 iter->me = map->map[0];
617 return iter;
618}
619
620
621/**
622 * Retrieve the next element from the hash map at the iterator's position.
623 * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
624 * are not modified.
625 * This operation is only allowed if no elements have been removed from the
626 * multihashmap since the creation of 'iter', and the map has not been destroyed.
627 * Adding elements may result in repeating or skipping elements.
628 *
629 * @param iter the iterator to get the next element from
630 * @param key pointer to store the key in, can be NULL
631 * @param value pointer to store the value in, can be NULL
632 * @return #GNUNET_YES we returned an element,
633 * #GNUNET_NO if we are out of elements
634 */
635int
636GNUNET_CONTAINER_multihashmap32_iterator_next (
637 struct GNUNET_CONTAINER_MultiHashMap32Iterator *iter,
638 uint32_t *key,
639 const void **value)
640{
641 /* make sure the map has not been modified */
642 GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
643
644 /* look for the next entry, skipping empty buckets */
645 while (1)
646 {
647 if (iter->idx >= iter->map->map_length)
648 return GNUNET_NO;
649 if (NULL != iter->me)
650 {
651 if (NULL != key)
652 *key = iter->me->key;
653 if (NULL != value)
654 *value = iter->me->value;
655 iter->me = iter->me->next;
656 return GNUNET_YES;
657 }
658 iter->idx += 1;
659 if (iter->idx < iter->map->map_length)
660 iter->me = iter->map->map[iter->idx];
661 }
662}
663
664
665/**
666 * Destroy a multihashmap iterator.
667 *
668 * @param iter the iterator to destroy
669 */
670void
671GNUNET_CONTAINER_multihashmap32_iterator_destroy (
672 struct GNUNET_CONTAINER_MultiHashMapIterator *iter)
673{
674 GNUNET_free (iter);
675}
676
677
678/* end of container_multihashmap.c */
diff --git a/src/util/container_multipeermap.c b/src/util/container_multipeermap.c
deleted file mode 100644
index fa4d2210b..000000000
--- a/src/util/container_multipeermap.c
+++ /dev/null
@@ -1,1031 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008, 2012 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 * @file util/container_multipeermap.c
22 * @brief hash map where the same key may be present multiple times
23 * @author Christian Grothoff
24 */
25
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define LOG(kind, ...) \
30 GNUNET_log_from (kind, "util-container-multipeermap", __VA_ARGS__)
31
32/**
33 * Maximum recursion depth for callbacks of
34 * #GNUNET_CONTAINER_multihashmap_get_multiple() themselves s
35 * again calling #GNUNET_CONTAINER_multihashmap_get_multiple().
36 * Should be totally excessive, but if violated we die.
37 */
38#define NEXT_CACHE_SIZE 16
39
40/**
41 * An entry in the hash map with the full key.
42 */
43struct BigMapEntry
44{
45 /**
46 * Value of the entry.
47 */
48 void *value;
49
50 /**
51 * If there is a hash collision, we create a linked list.
52 */
53 struct BigMapEntry *next;
54
55 /**
56 * Key for the entry.
57 */
58 struct GNUNET_PeerIdentity key;
59};
60
61
62/**
63 * An entry in the hash map with just a pointer to the key.
64 */
65struct SmallMapEntry
66{
67 /**
68 * Value of the entry.
69 */
70 void *value;
71
72 /**
73 * If there is a hash collision, we create a linked list.
74 */
75 struct SmallMapEntry *next;
76
77 /**
78 * Key for the entry.
79 */
80 const struct GNUNET_PeerIdentity *key;
81};
82
83
84/**
85 * Entry in the map.
86 */
87union MapEntry
88{
89 /**
90 * Variant used if map entries only contain a pointer to the key.
91 */
92 struct SmallMapEntry *sme;
93
94 /**
95 * Variant used if map entries contain the full key.
96 */
97 struct BigMapEntry *bme;
98};
99
100
101/**
102 * Internal representation of the hash map.
103 */
104struct GNUNET_CONTAINER_MultiPeerMap
105{
106 /**
107 * All of our buckets.
108 */
109 union MapEntry *map;
110
111 /**
112 * Number of entries in the map.
113 */
114 unsigned int size;
115
116 /**
117 * Length of the "map" array.
118 */
119 unsigned int map_length;
120
121 /**
122 * #GNUNET_NO if the map entries are of type 'struct BigMapEntry',
123 * #GNUNET_YES if the map entries are of type 'struct SmallMapEntry'.
124 */
125 int use_small_entries;
126
127 /**
128 * Counts the destructive modifications (grow, remove)
129 * to the map, so that iterators can check if they are still valid.
130 */
131 unsigned int modification_counter;
132
133 /**
134 * Map entries indicating iteration positions currently
135 * in use by #GNUNET_CONTAINER_multihashmap_get_multiple().
136 * Only used up to @e next_cache_off.
137 */
138 union MapEntry next_cache[NEXT_CACHE_SIZE];
139
140 /**
141 * Offset of @e next_cache entries in use, must be smaller
142 * than #NEXT_CACHE_SIZE.
143 */
144 unsigned int next_cache_off;
145};
146
147
148/**
149 * Cursor into a multipeermap.
150 * Allows to enumerate elements asynchronously.
151 */
152struct GNUNET_CONTAINER_MultiPeerMapIterator
153{
154 /**
155 * Position in the bucket 'idx'
156 */
157 union MapEntry me;
158
159 /**
160 * Current bucket index.
161 */
162 unsigned int idx;
163
164 /**
165 * Modification counter as observed on the map when the iterator
166 * was created.
167 */
168 unsigned int modification_counter;
169
170 /**
171 * Map that we are iterating over.
172 */
173 const struct GNUNET_CONTAINER_MultiPeerMap *map;
174};
175
176
177/**
178 * Create a multi hash map.
179 *
180 * @param len initial size (map will grow as needed)
181 * @param do_not_copy_keys GNUNET_NO is always safe and should be used by default;
182 * GNUNET_YES means that on 'put', the 'key' does not have
183 * to be copied as the destination of the pointer is
184 * guaranteed to be life as long as the value is stored in
185 * the hashmap. This can significantly reduce memory
186 * consumption, but of course is also a recipe for
187 * heap corruption if the assumption is not true. Only
188 * use this if (1) memory use is important in this case and
189 * (2) you have triple-checked that the invariant holds
190 * @return NULL on error
191 */
192struct GNUNET_CONTAINER_MultiPeerMap *
193GNUNET_CONTAINER_multipeermap_create (unsigned int len,
194 int do_not_copy_keys)
195{
196 struct GNUNET_CONTAINER_MultiPeerMap *map;
197
198 GNUNET_assert (len > 0);
199 map = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMap);
200 map->map = GNUNET_malloc_large (len * sizeof(union MapEntry));
201 if (NULL == map->map)
202 {
203 GNUNET_free (map);
204 return NULL;
205 }
206 map->map_length = len;
207 map->use_small_entries = do_not_copy_keys;
208 return map;
209}
210
211
212/**
213 * Destroy a hash map. Will not free any values
214 * stored in the hash map!
215 *
216 * @param map the map
217 */
218void
219GNUNET_CONTAINER_multipeermap_destroy (
220 struct GNUNET_CONTAINER_MultiPeerMap *map)
221{
222 GNUNET_assert (0 == map->next_cache_off);
223 for (unsigned int i = 0; i < map->map_length; i++)
224 {
225 union MapEntry me;
226
227 me = map->map[i];
228 if (map->use_small_entries)
229 {
230 struct SmallMapEntry *sme;
231 struct SmallMapEntry *nxt;
232
233 nxt = me.sme;
234 while (NULL != (sme = nxt))
235 {
236 nxt = sme->next;
237 GNUNET_free (sme);
238 }
239 me.sme = NULL;
240 }
241 else
242 {
243 struct BigMapEntry *bme;
244 struct BigMapEntry *nxt;
245
246 nxt = me.bme;
247 while (NULL != (bme = nxt))
248 {
249 nxt = bme->next;
250 GNUNET_free (bme);
251 }
252 me.bme = NULL;
253 }
254 }
255 GNUNET_free (map->map);
256 GNUNET_free (map);
257}
258
259
260/**
261 * Compute the index of the bucket for the given key.
262 *
263 * @param map hash map for which to compute the index
264 * @param key what key should the index be computed for
265 * @return offset into the "map" array of "map"
266 */
267static unsigned int
268idx_of (const struct GNUNET_CONTAINER_MultiPeerMap *map,
269 const struct GNUNET_PeerIdentity *key)
270{
271 unsigned int kx;
272
273 GNUNET_assert (NULL != map);
274 GNUNET_memcpy (&kx, key, sizeof(kx));
275 return kx % map->map_length;
276}
277
278
279/**
280 * Get the number of key-value pairs in the map.
281 *
282 * @param map the map
283 * @return the number of key value pairs
284 */
285unsigned int
286GNUNET_CONTAINER_multipeermap_size (
287 const struct GNUNET_CONTAINER_MultiPeerMap *map)
288{
289 return map->size;
290}
291
292
293/**
294 * Given a key find a value in the map matching the key.
295 *
296 * @param map the map
297 * @param key what to look for
298 * @return NULL if no value was found; note that
299 * this is indistinguishable from values that just
300 * happen to be NULL; use "contains" to test for
301 * key-value pairs with value NULL
302 */
303void *
304GNUNET_CONTAINER_multipeermap_get (
305 const struct GNUNET_CONTAINER_MultiPeerMap *map,
306 const struct GNUNET_PeerIdentity *key)
307{
308 union MapEntry me;
309
310 me = map->map[idx_of (map, key)];
311 if (map->use_small_entries)
312 {
313 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
314 if (0 == GNUNET_memcmp (key, sme->key))
315 return sme->value;
316 }
317 else
318 {
319 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
320 if (0 == GNUNET_memcmp (key, &bme->key))
321 return bme->value;
322 }
323 return NULL;
324}
325
326
327/**
328 * Iterate over all entries in the map.
329 *
330 * @param map the map
331 * @param it function to call on each entry
332 * @param it_cls extra argument to @a it
333 * @return the number of key value pairs processed,
334 * #GNUNET_SYSERR if it aborted iteration
335 */
336int
337GNUNET_CONTAINER_multipeermap_iterate (
338 struct GNUNET_CONTAINER_MultiPeerMap *map,
339 GNUNET_CONTAINER_PeerMapIterator it,
340 void *it_cls)
341{
342 int count;
343 union MapEntry me;
344 union MapEntry *ce;
345 struct GNUNET_PeerIdentity kc;
346
347 count = 0;
348 GNUNET_assert (NULL != map);
349 ce = &map->next_cache[map->next_cache_off];
350 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
351 for (unsigned int i = 0; i < map->map_length; i++)
352 {
353 me = map->map[i];
354 if (map->use_small_entries)
355 {
356 struct SmallMapEntry *sme;
357
358 ce->sme = me.sme;
359 while (NULL != (sme = ce->sme))
360 {
361 ce->sme = sme->next;
362 if (NULL != it)
363 {
364 if (GNUNET_OK != it (it_cls, sme->key, sme->value))
365 {
366 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
367 return GNUNET_SYSERR;
368 }
369 }
370 count++;
371 }
372 }
373 else
374 {
375 struct BigMapEntry *bme;
376
377 ce->bme = me.bme;
378 while (NULL != (bme = ce->bme))
379 {
380 ce->bme = bme->next;
381 if (NULL != it)
382 {
383 kc = bme->key;
384 if (GNUNET_OK != it (it_cls, &kc, bme->value))
385 {
386 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
387 return GNUNET_SYSERR;
388 }
389 }
390 count++;
391 }
392 }
393 }
394 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
395 return count;
396}
397
398
399/**
400 * We are about to free() the @a bme, make sure it is not in
401 * the list of next values for any iterator in the @a map's next_cache.
402 *
403 * @param map the map to check
404 * @param bme the entry that is about to be free'd
405 */
406static void
407update_next_cache_bme (struct GNUNET_CONTAINER_MultiPeerMap *map,
408 const struct BigMapEntry *bme)
409{
410 for (unsigned int i = 0; i < map->next_cache_off; i++)
411 if (map->next_cache[i].bme == bme)
412 map->next_cache[i].bme = bme->next;
413}
414
415
416/**
417 * We are about to free() the @a sme, make sure it is not in
418 * the list of next values for any iterator in the @a map's next_cache.
419 *
420 * @param map the map to check
421 * @param sme the entry that is about to be free'd
422 */
423static void
424update_next_cache_sme (struct GNUNET_CONTAINER_MultiPeerMap *map,
425 const struct SmallMapEntry *sme)
426{
427 for (unsigned int i = 0; i < map->next_cache_off; i++)
428 if (map->next_cache[i].sme == sme)
429 map->next_cache[i].sme = sme->next;
430}
431
432
433/**
434 * Remove the given key-value pair from the map. Note that if the
435 * key-value pair is in the map multiple times, only one of the pairs
436 * will be removed.
437 *
438 * @param map the map
439 * @param key key of the key-value pair
440 * @param value value of the key-value pair
441 * @return #GNUNET_YES on success, #GNUNET_NO if the key-value pair
442 * is not in the map
443 */
444int
445GNUNET_CONTAINER_multipeermap_remove (struct GNUNET_CONTAINER_MultiPeerMap *map,
446 const struct GNUNET_PeerIdentity *key,
447 const void *value)
448{
449 union MapEntry me;
450 unsigned int i;
451
452 map->modification_counter++;
453 i = idx_of (map, key);
454 me = map->map[i];
455 if (map->use_small_entries)
456 {
457 struct SmallMapEntry *p = NULL;
458
459 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
460 {
461 if ((0 == GNUNET_memcmp (key, sme->key)) && (value == sme->value))
462 {
463 if (NULL == p)
464 map->map[i].sme = sme->next;
465 else
466 p->next = sme->next;
467 update_next_cache_sme (map, sme);
468 GNUNET_free (sme);
469 map->size--;
470 return GNUNET_YES;
471 }
472 p = sme;
473 }
474 }
475 else
476 {
477 struct BigMapEntry *p = NULL;
478
479 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
480 {
481 if ((0 == GNUNET_memcmp (key, &bme->key)) && (value == bme->value))
482 {
483 if (NULL == p)
484 map->map[i].bme = bme->next;
485 else
486 p->next = bme->next;
487 update_next_cache_bme (map, bme);
488 GNUNET_free (bme);
489 map->size--;
490 return GNUNET_YES;
491 }
492 p = bme;
493 }
494 }
495 return GNUNET_NO;
496}
497
498
499/**
500 * Remove all entries for the given key from the map.
501 * Note that the values would not be "freed".
502 *
503 * @param map the map
504 * @param key identifies values to be removed
505 * @return number of values removed
506 */
507int
508GNUNET_CONTAINER_multipeermap_remove_all (
509 struct GNUNET_CONTAINER_MultiPeerMap *map,
510 const struct GNUNET_PeerIdentity *key)
511{
512 union MapEntry me;
513 unsigned int i;
514 int ret;
515
516 map->modification_counter++;
517
518 ret = 0;
519 i = idx_of (map, key);
520 me = map->map[i];
521 if (map->use_small_entries)
522 {
523 struct SmallMapEntry *sme;
524 struct SmallMapEntry *p;
525
526 p = NULL;
527 sme = me.sme;
528 while (NULL != sme)
529 {
530 if (0 == GNUNET_memcmp (key, sme->key))
531 {
532 if (NULL == p)
533 map->map[i].sme = sme->next;
534 else
535 p->next = sme->next;
536 update_next_cache_sme (map, sme);
537 GNUNET_free (sme);
538 map->size--;
539 if (NULL == p)
540 sme = map->map[i].sme;
541 else
542 sme = p->next;
543 ret++;
544 }
545 else
546 {
547 p = sme;
548 sme = sme->next;
549 }
550 }
551 }
552 else
553 {
554 struct BigMapEntry *bme;
555 struct BigMapEntry *p;
556
557 p = NULL;
558 bme = me.bme;
559 while (NULL != bme)
560 {
561 if (0 == GNUNET_memcmp (key, &bme->key))
562 {
563 if (NULL == p)
564 map->map[i].bme = bme->next;
565 else
566 p->next = bme->next;
567 update_next_cache_bme (map, bme);
568 GNUNET_free (bme);
569 map->size--;
570 if (NULL == p)
571 bme = map->map[i].bme;
572 else
573 bme = p->next;
574 ret++;
575 }
576 else
577 {
578 p = bme;
579 bme = bme->next;
580 }
581 }
582 }
583 return ret;
584}
585
586
587/**
588 * Check if the map contains any value under the given
589 * key (including values that are NULL).
590 *
591 * @param map the map
592 * @param key the key to test if a value exists for it
593 * @return #GNUNET_YES if such a value exists,
594 * #GNUNET_NO if not
595 */
596int
597GNUNET_CONTAINER_multipeermap_contains (
598 const struct GNUNET_CONTAINER_MultiPeerMap *map,
599 const struct GNUNET_PeerIdentity *key)
600{
601 union MapEntry me;
602
603 me = map->map[idx_of (map, key)];
604 if (map->use_small_entries)
605 {
606 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
607 if (0 == GNUNET_memcmp (key, sme->key))
608 return GNUNET_YES;
609 }
610 else
611 {
612 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
613 if (0 == GNUNET_memcmp (key, &bme->key))
614 return GNUNET_YES;
615 }
616 return GNUNET_NO;
617}
618
619
620/**
621 * Check if the map contains the given value under the given
622 * key.
623 *
624 * @param map the map
625 * @param key the key to test if a value exists for it
626 * @param value value to test for
627 * @return #GNUNET_YES if such a value exists,
628 * #GNUNET_NO if not
629 */
630int
631GNUNET_CONTAINER_multipeermap_contains_value (
632 const struct GNUNET_CONTAINER_MultiPeerMap *map,
633 const struct GNUNET_PeerIdentity *key,
634 const void *value)
635{
636 union MapEntry me;
637
638 me = map->map[idx_of (map, key)];
639 if (map->use_small_entries)
640 {
641 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
642 if ((0 == GNUNET_memcmp (key, sme->key)) && (sme->value == value))
643 return GNUNET_YES;
644 }
645 else
646 {
647 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
648 if ((0 == GNUNET_memcmp (key, &bme->key)) && (bme->value == value))
649 return GNUNET_YES;
650 }
651 return GNUNET_NO;
652}
653
654
655/**
656 * Grow the given map to a more appropriate size.
657 *
658 * @param map the hash map to grow
659 */
660static void
661grow (struct GNUNET_CONTAINER_MultiPeerMap *map)
662{
663 union MapEntry *old_map;
664 union MapEntry *new_map;
665 unsigned int old_len;
666 unsigned int new_len;
667 unsigned int idx;
668
669 old_map = map->map;
670 old_len = map->map_length;
671 GNUNET_assert (0 != old_len);
672 new_len = old_len * 2;
673 if (0 == new_len) /* 2^31 * 2 == 0 */
674 new_len = old_len; /* never use 0 */
675 if (new_len == old_len)
676 return; /* nothing changed */
677 new_map = GNUNET_malloc_large (new_len * sizeof(union MapEntry));
678 if (NULL == new_map)
679 return; /* grow not possible */
680 map->modification_counter++;
681 map->map_length = new_len;
682 map->map = new_map;
683 for (unsigned int i = 0; i < old_len; i++)
684 {
685 if (map->use_small_entries)
686 {
687 struct SmallMapEntry *sme;
688
689 while (NULL != (sme = old_map[i].sme))
690 {
691 old_map[i].sme = sme->next;
692 idx = idx_of (map, sme->key);
693 sme->next = new_map[idx].sme;
694 new_map[idx].sme = sme;
695 }
696 }
697 else
698 {
699 struct BigMapEntry *bme;
700
701 while (NULL != (bme = old_map[i].bme))
702 {
703 old_map[i].bme = bme->next;
704 idx = idx_of (map, &bme->key);
705 bme->next = new_map[idx].bme;
706 new_map[idx].bme = bme;
707 }
708 }
709 }
710 GNUNET_free (old_map);
711}
712
713
714/**
715 * Store a key-value pair in the map.
716 *
717 * @param map the map
718 * @param key key to use
719 * @param value value to use
720 * @param opt options for put
721 * @return #GNUNET_OK on success,
722 * #GNUNET_NO if a value was replaced (with REPLACE)
723 * #GNUNET_SYSERR if #GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
724 * value already exists
725 */
726int
727GNUNET_CONTAINER_multipeermap_put (struct GNUNET_CONTAINER_MultiPeerMap *map,
728 const struct GNUNET_PeerIdentity *key,
729 void *value,
730 enum GNUNET_CONTAINER_MultiHashMapOption opt)
731{
732 union MapEntry me;
733 unsigned int i;
734
735 i = idx_of (map, key);
736 if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
737 (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
738 {
739 me = map->map[i];
740 if (map->use_small_entries)
741 {
742 struct SmallMapEntry *sme;
743
744 for (sme = me.sme; NULL != sme; sme = sme->next)
745 if (0 == GNUNET_memcmp (key, sme->key))
746 {
747 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
748 return GNUNET_SYSERR;
749 sme->value = value;
750 return GNUNET_NO;
751 }
752 }
753 else
754 {
755 struct BigMapEntry *bme;
756
757 for (bme = me.bme; NULL != bme; bme = bme->next)
758 if (0 == GNUNET_memcmp (key, &bme->key))
759 {
760 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
761 return GNUNET_SYSERR;
762 bme->value = value;
763 return GNUNET_NO;
764 }
765 }
766 }
767 if (map->size / 3 >= map->map_length / 4)
768 {
769 grow (map);
770 i = idx_of (map, key);
771 }
772 if (map->use_small_entries)
773 {
774 struct SmallMapEntry *sme;
775
776 sme = GNUNET_new (struct SmallMapEntry);
777 sme->key = key;
778 sme->value = value;
779 sme->next = map->map[i].sme;
780 map->map[i].sme = sme;
781 }
782 else
783 {
784 struct BigMapEntry *bme;
785
786 bme = GNUNET_new (struct BigMapEntry);
787 bme->key = *key;
788 bme->value = value;
789 bme->next = map->map[i].bme;
790 map->map[i].bme = bme;
791 }
792 map->size++;
793 return GNUNET_OK;
794}
795
796
797/**
798 * Iterate over all entries in the map that match a particular key.
799 *
800 * @param map the map
801 * @param key key that the entries must correspond to
802 * @param it function to call on each entry
803 * @param it_cls extra argument to @a it
804 * @return the number of key value pairs processed,
805 * #GNUNET_SYSERR if it aborted iteration
806 */
807int
808GNUNET_CONTAINER_multipeermap_get_multiple (
809 struct GNUNET_CONTAINER_MultiPeerMap *map,
810 const struct GNUNET_PeerIdentity *key,
811 GNUNET_CONTAINER_PeerMapIterator it,
812 void *it_cls)
813{
814 int count;
815 union MapEntry me;
816 union MapEntry *ce;
817
818 ce = &map->next_cache[map->next_cache_off];
819 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
820 count = 0;
821 me = map->map[idx_of (map, key)];
822 if (map->use_small_entries)
823 {
824 struct SmallMapEntry *sme;
825
826 ce->sme = me.sme;
827 while (NULL != (sme = ce->sme))
828 {
829 ce->sme = sme->next;
830 if (0 != GNUNET_memcmp (key, sme->key))
831 continue;
832 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, sme->value)))
833 {
834 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
835 return GNUNET_SYSERR;
836 }
837 count++;
838 }
839 }
840 else
841 {
842 struct BigMapEntry *bme;
843
844 ce->bme = me.bme;
845 while (NULL != (bme = ce->bme))
846 {
847 ce->bme = bme->next;
848 if (0 != GNUNET_memcmp (key, &bme->key))
849 continue;
850 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, bme->value)))
851 {
852 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
853 return GNUNET_SYSERR;
854 }
855 count++;
856 }
857 }
858 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
859 return count;
860}
861
862
863/**
864 * @ingroup hashmap
865 * Call @a it on a random value from the map, or not at all
866 * if the map is empty. Note that this function has linear
867 * complexity (in the size of the map).
868 *
869 * @param map the map
870 * @param it function to call on a random entry
871 * @param it_cls extra argument to @a it
872 * @return the number of key value pairs processed, zero or one.
873 */
874unsigned int
875GNUNET_CONTAINER_multipeermap_get_random (
876 const struct GNUNET_CONTAINER_MultiPeerMap *map,
877 GNUNET_CONTAINER_PeerMapIterator it,
878 void *it_cls)
879{
880 unsigned int off;
881 union MapEntry me;
882
883 if (0 == map->size)
884 return 0;
885 if (NULL == it)
886 return 1;
887 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, map->size);
888 for (unsigned int idx = 0; idx < map->map_length; idx++)
889 {
890 me = map->map[idx];
891 if (map->use_small_entries)
892 {
893 struct SmallMapEntry *sme;
894 struct SmallMapEntry *nxt;
895
896 nxt = me.sme;
897 while (NULL != (sme = nxt))
898 {
899 nxt = sme->next;
900 if (0 == off)
901 {
902 if (GNUNET_OK != it (it_cls, sme->key, sme->value))
903 return GNUNET_SYSERR;
904 return 1;
905 }
906 off--;
907 }
908 }
909 else
910 {
911 struct BigMapEntry *bme;
912 struct BigMapEntry *nxt;
913
914 nxt = me.bme;
915 while (NULL != (bme = nxt))
916 {
917 nxt = bme->next;
918 if (0 == off)
919 {
920 if (GNUNET_OK != it (it_cls, &bme->key, bme->value))
921 return GNUNET_SYSERR;
922 return 1;
923 }
924 off--;
925 }
926 }
927 }
928 GNUNET_break (0);
929 return GNUNET_SYSERR;
930}
931
932
933/**
934 * Create an iterator for a multipeermap.
935 * The iterator can be used to retrieve all the elements in the multipeermap
936 * one by one, without having to handle all elements at once (in contrast to
937 * #GNUNET_CONTAINER_multipeermap_iterate). Note that the iterator can not be
938 * used anymore if elements have been removed from 'map' after the creation of
939 * the iterator, or 'map' has been destroyed. Adding elements to 'map' may
940 * result in skipped or repeated elements.
941 *
942 * @param map the map to create an iterator for
943 * @return an iterator over the given multipeermap 'map'
944 */
945struct GNUNET_CONTAINER_MultiPeerMapIterator *
946GNUNET_CONTAINER_multipeermap_iterator_create (
947 const struct GNUNET_CONTAINER_MultiPeerMap *map)
948{
949 struct GNUNET_CONTAINER_MultiPeerMapIterator *iter;
950
951 iter = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMapIterator);
952 iter->map = map;
953 iter->modification_counter = map->modification_counter;
954 iter->me = map->map[0];
955 return iter;
956}
957
958
959/**
960 * Retrieve the next element from the hash map at the iterator's position.
961 * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
962 * are not modified.
963 * This operation is only allowed if no elements have been removed from the
964 * multipeermap since the creation of 'iter', and the map has not been destroyed.
965 * Adding elements may result in repeating or skipping elements.
966 *
967 * @param iter the iterator to get the next element from
968 * @param key pointer to store the key in, can be NULL
969 * @param value pointer to store the value in, can be NULL
970 * @return #GNUNET_YES we returned an element,
971 * #GNUNET_NO if we are out of elements
972 */
973int
974GNUNET_CONTAINER_multipeermap_iterator_next (
975 struct GNUNET_CONTAINER_MultiPeerMapIterator *iter,
976 struct GNUNET_PeerIdentity *key,
977 const void **value)
978{
979 /* make sure the map has not been modified */
980 GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
981
982 /* look for the next entry, skipping empty buckets */
983 while (1)
984 {
985 if (iter->idx >= iter->map->map_length)
986 return GNUNET_NO;
987 if (GNUNET_YES == iter->map->use_small_entries)
988 {
989 if (NULL != iter->me.sme)
990 {
991 if (NULL != key)
992 *key = *iter->me.sme->key;
993 if (NULL != value)
994 *value = iter->me.sme->value;
995 iter->me.sme = iter->me.sme->next;
996 return GNUNET_YES;
997 }
998 }
999 else
1000 {
1001 if (NULL != iter->me.bme)
1002 {
1003 if (NULL != key)
1004 *key = iter->me.bme->key;
1005 if (NULL != value)
1006 *value = iter->me.bme->value;
1007 iter->me.bme = iter->me.bme->next;
1008 return GNUNET_YES;
1009 }
1010 }
1011 iter->idx += 1;
1012 if (iter->idx < iter->map->map_length)
1013 iter->me = iter->map->map[iter->idx];
1014 }
1015}
1016
1017
1018/**
1019 * Destroy a multipeermap iterator.
1020 *
1021 * @param iter the iterator to destroy
1022 */
1023void
1024GNUNET_CONTAINER_multipeermap_iterator_destroy (
1025 struct GNUNET_CONTAINER_MultiPeerMapIterator *iter)
1026{
1027 GNUNET_free (iter);
1028}
1029
1030
1031/* end of container_multipeermap.c */
diff --git a/src/util/container_multishortmap.c b/src/util/container_multishortmap.c
deleted file mode 100644
index 77e5ca139..000000000
--- a/src/util/container_multishortmap.c
+++ /dev/null
@@ -1,1015 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008, 2012 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 * @file util/container_multishortmap.c
22 * @brief hash map where the same key may be present multiple times
23 * @author Christian Grothoff
24 */
25
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define LOG(kind, ...) \
30 GNUNET_log_from (kind, "util-container-multishortmap", __VA_ARGS__)
31
32/**
33 * Maximum recursion depth for callbacks of
34 * #GNUNET_CONTAINER_multihashmap_get_multiple() themselves s
35 * again calling #GNUNET_CONTAINER_multihashmap_get_multiple().
36 * Should be totally excessive, but if violated we die.
37 */
38#define NEXT_CACHE_SIZE 16
39
40
41/**
42 * An entry in the hash map with the full key.
43 */
44struct BigMapEntry
45{
46 /**
47 * Value of the entry.
48 */
49 void *value;
50
51 /**
52 * If there is a hash collision, we create a linked list.
53 */
54 struct BigMapEntry *next;
55
56 /**
57 * Key for the entry.
58 */
59 struct GNUNET_ShortHashCode key;
60};
61
62
63/**
64 * An entry in the hash map with just a pointer to the key.
65 */
66struct SmallMapEntry
67{
68 /**
69 * Value of the entry.
70 */
71 void *value;
72
73 /**
74 * If there is a hash collision, we create a linked list.
75 */
76 struct SmallMapEntry *next;
77
78 /**
79 * Key for the entry.
80 */
81 const struct GNUNET_ShortHashCode *key;
82};
83
84
85/**
86 * Entry in the map.
87 */
88union MapEntry
89{
90 /**
91 * Variant used if map entries only contain a pointer to the key.
92 */
93 struct SmallMapEntry *sme;
94
95 /**
96 * Variant used if map entries contain the full key.
97 */
98 struct BigMapEntry *bme;
99};
100
101
102/**
103 * Internal representation of the hash map.
104 */
105struct GNUNET_CONTAINER_MultiShortmap
106{
107 /**
108 * All of our buckets.
109 */
110 union MapEntry *map;
111
112 /**
113 * Number of entries in the map.
114 */
115 unsigned int size;
116
117 /**
118 * Length of the "map" array.
119 */
120 unsigned int map_length;
121
122 /**
123 * #GNUNET_NO if the map entries are of type 'struct BigMapEntry',
124 * #GNUNET_YES if the map entries are of type 'struct SmallMapEntry'.
125 */
126 int use_small_entries;
127
128 /**
129 * Counts the destructive modifications (grow, remove)
130 * to the map, so that iterators can check if they are still valid.
131 */
132 unsigned int modification_counter;
133
134 /**
135 * Map entries indicating iteration positions currently
136 * in use by #GNUNET_CONTAINER_multihashmap_get_multiple().
137 * Only used up to @e next_cache_off.
138 */
139 union MapEntry next_cache[NEXT_CACHE_SIZE];
140
141 /**
142 * Offset of @e next_cache entries in use, must be smaller
143 * than #NEXT_CACHE_SIZE.
144 */
145 unsigned int next_cache_off;
146};
147
148
149/**
150 * Cursor into a multishortmap.
151 * Allows to enumerate elements asynchronously.
152 */
153struct GNUNET_CONTAINER_MultiShortmapIterator
154{
155 /**
156 * Position in the bucket 'idx'
157 */
158 union MapEntry me;
159
160 /**
161 * Current bucket index.
162 */
163 unsigned int idx;
164
165 /**
166 * Modification counter as observed on the map when the iterator
167 * was created.
168 */
169 unsigned int modification_counter;
170
171 /**
172 * Map that we are iterating over.
173 */
174 const struct GNUNET_CONTAINER_MultiShortmap *map;
175};
176
177
178/**
179 * Create a multi hash map.
180 *
181 * @param len initial size (map will grow as needed)
182 * @param do_not_copy_keys #GNUNET_NO is always safe and should be used by default;
183 * #GNUNET_YES means that on 'put', the 'key' does not have
184 * to be copied as the destination of the pointer is
185 * guaranteed to be life as long as the value is stored in
186 * the hashmap. This can significantly reduce memory
187 * consumption, but of course is also a recipe for
188 * heap corruption if the assumption is not true. Only
189 * use this if (1) memory use is important in this case and
190 * (2) you have triple-checked that the invariant holds
191 * @return NULL on error
192 */
193struct GNUNET_CONTAINER_MultiShortmap *
194GNUNET_CONTAINER_multishortmap_create (unsigned int len, int do_not_copy_keys)
195{
196 struct GNUNET_CONTAINER_MultiShortmap *map;
197
198 GNUNET_assert (len > 0);
199 map = GNUNET_new (struct GNUNET_CONTAINER_MultiShortmap);
200 map->map = GNUNET_malloc_large (len * sizeof(union MapEntry));
201 if (NULL == map->map)
202 {
203 GNUNET_free (map);
204 return NULL;
205 }
206 map->map_length = len;
207 map->use_small_entries = do_not_copy_keys;
208 return map;
209}
210
211
212/**
213 * Destroy a hash map. Will not free any values
214 * stored in the hash map!
215 *
216 * @param map the map
217 */
218void
219GNUNET_CONTAINER_multishortmap_destroy (
220 struct GNUNET_CONTAINER_MultiShortmap *map)
221{
222 GNUNET_assert (0 == map->next_cache_off);
223 for (unsigned int i = 0; i < map->map_length; i++)
224 {
225 union MapEntry me;
226
227 me = map->map[i];
228 if (map->use_small_entries)
229 {
230 struct SmallMapEntry *sme;
231 struct SmallMapEntry *nxt;
232
233 nxt = me.sme;
234 while (NULL != (sme = nxt))
235 {
236 nxt = sme->next;
237 GNUNET_free (sme);
238 }
239 me.sme = NULL;
240 }
241 else
242 {
243 struct BigMapEntry *bme;
244 struct BigMapEntry *nxt;
245
246 nxt = me.bme;
247 while (NULL != (bme = nxt))
248 {
249 nxt = bme->next;
250 GNUNET_free (bme);
251 }
252 me.bme = NULL;
253 }
254 }
255 GNUNET_free (map->map);
256 GNUNET_free (map);
257}
258
259
260/**
261 * Compute the index of the bucket for the given key.
262 *
263 * @param map hash map for which to compute the index
264 * @param key what key should the index be computed for
265 * @return offset into the "map" array of "map"
266 */
267static unsigned int
268idx_of (const struct GNUNET_CONTAINER_MultiShortmap *map,
269 const struct GNUNET_ShortHashCode *key)
270{
271 unsigned int kx;
272
273 GNUNET_assert (NULL != map);
274 GNUNET_memcpy (&kx, key, sizeof(kx));
275 return kx % map->map_length;
276}
277
278
279/**
280 * Get the number of key-value pairs in the map.
281 *
282 * @param map the map
283 * @return the number of key value pairs
284 */
285unsigned int
286GNUNET_CONTAINER_multishortmap_size (
287 const struct GNUNET_CONTAINER_MultiShortmap *map)
288{
289 return map->size;
290}
291
292
293/**
294 * Given a key find a value in the map matching the key.
295 *
296 * @param map the map
297 * @param key what to look for
298 * @return NULL if no value was found; note that
299 * this is indistinguishable from values that just
300 * happen to be NULL; use "contains" to test for
301 * key-value pairs with value NULL
302 */
303void *
304GNUNET_CONTAINER_multishortmap_get (
305 const struct GNUNET_CONTAINER_MultiShortmap *map,
306 const struct GNUNET_ShortHashCode *key)
307{
308 union MapEntry me;
309
310 me = map->map[idx_of (map, key)];
311 if (map->use_small_entries)
312 {
313 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
314 if (0 == GNUNET_memcmp (key, sme->key))
315 return sme->value;
316 }
317 else
318 {
319 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
320 if (0 == GNUNET_memcmp (key, &bme->key))
321 return bme->value;
322 }
323 return NULL;
324}
325
326
327/**
328 * Iterate over all entries in the map.
329 *
330 * @param map the map
331 * @param it function to call on each entry
332 * @param it_cls extra argument to @a it
333 * @return the number of key value pairs processed,
334 * #GNUNET_SYSERR if it aborted iteration
335 */
336int
337GNUNET_CONTAINER_multishortmap_iterate (
338 struct GNUNET_CONTAINER_MultiShortmap *map,
339 GNUNET_CONTAINER_ShortmapIterator it,
340 void *it_cls)
341{
342 int count;
343 union MapEntry me;
344 union MapEntry *ce;
345 struct GNUNET_ShortHashCode kc;
346
347 count = 0;
348 GNUNET_assert (NULL != map);
349 ce = &map->next_cache[map->next_cache_off];
350 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
351 for (unsigned int i = 0; i < map->map_length; i++)
352 {
353 me = map->map[i];
354 if (map->use_small_entries)
355 {
356 struct SmallMapEntry *sme;
357
358 ce->sme = me.sme;
359 while (NULL != (sme = ce->sme))
360 {
361 ce->sme = sme->next;
362 if ((NULL != it) && (GNUNET_OK != it (it_cls, sme->key, sme->value)))
363 {
364 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
365 return GNUNET_SYSERR;
366 }
367 count++;
368 }
369 }
370 else
371 {
372 struct BigMapEntry *bme;
373
374 ce->bme = me.bme;
375 while (NULL != (bme = ce->bme))
376 {
377 ce->bme = bme->next;
378 if (NULL != it)
379 {
380 kc = bme->key;
381 if (GNUNET_OK != it (it_cls, &kc, bme->value))
382 {
383 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
384 return GNUNET_SYSERR;
385 }
386 }
387 count++;
388 }
389 }
390 }
391 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
392 return count;
393}
394
395
396/**
397 * We are about to free() the @a bme, make sure it is not in
398 * the list of next values for any iterator in the @a map's next_cache.
399 *
400 * @param map the map to check
401 * @param bme the entry that is about to be free'd
402 */
403static void
404update_next_cache_bme (struct GNUNET_CONTAINER_MultiShortmap *map,
405 const struct BigMapEntry *bme)
406{
407 for (unsigned int i = 0; i < map->next_cache_off; i++)
408 if (map->next_cache[i].bme == bme)
409 map->next_cache[i].bme = bme->next;
410}
411
412
413/**
414 * We are about to free() the @a sme, make sure it is not in
415 * the list of next values for any iterator in the @a map's next_cache.
416 *
417 * @param map the map to check
418 * @param sme the entry that is about to be free'd
419 */
420static void
421update_next_cache_sme (struct GNUNET_CONTAINER_MultiShortmap *map,
422 const struct SmallMapEntry *sme)
423{
424 for (unsigned int i = 0; i < map->next_cache_off; i++)
425 if (map->next_cache[i].sme == sme)
426 map->next_cache[i].sme = sme->next;
427}
428
429
430/**
431 * Remove the given key-value pair from the map. Note that if the
432 * key-value pair is in the map multiple times, only one of the pairs
433 * will be removed.
434 *
435 * @param map the map
436 * @param key key of the key-value pair
437 * @param value value of the key-value pair
438 * @return #GNUNET_YES on success, #GNUNET_NO if the key-value pair
439 * is not in the map
440 */
441int
442GNUNET_CONTAINER_multishortmap_remove (
443 struct GNUNET_CONTAINER_MultiShortmap *map,
444 const struct GNUNET_ShortHashCode *key,
445 const void *value)
446{
447 union MapEntry me;
448 unsigned int i;
449
450 map->modification_counter++;
451 i = idx_of (map, key);
452 me = map->map[i];
453 if (map->use_small_entries)
454 {
455 struct SmallMapEntry *p = NULL;
456
457 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
458 {
459 if ((0 == GNUNET_memcmp (key, sme->key)) && (value == sme->value))
460 {
461 if (NULL == p)
462 map->map[i].sme = sme->next;
463 else
464 p->next = sme->next;
465 update_next_cache_sme (map, sme);
466 GNUNET_free (sme);
467 map->size--;
468 return GNUNET_YES;
469 }
470 p = sme;
471 }
472 }
473 else
474 {
475 struct BigMapEntry *p = NULL;
476
477 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
478 {
479 if ((0 == GNUNET_memcmp (key, &bme->key)) && (value == bme->value))
480 {
481 if (NULL == p)
482 map->map[i].bme = bme->next;
483 else
484 p->next = bme->next;
485 update_next_cache_bme (map, bme);
486 GNUNET_free (bme);
487 map->size--;
488 return GNUNET_YES;
489 }
490 p = bme;
491 }
492 }
493 return GNUNET_NO;
494}
495
496
497/**
498 * Remove all entries for the given key from the map.
499 * Note that the values would not be "freed".
500 *
501 * @param map the map
502 * @param key identifies values to be removed
503 * @return number of values removed
504 */
505int
506GNUNET_CONTAINER_multishortmap_remove_all (
507 struct GNUNET_CONTAINER_MultiShortmap *map,
508 const struct GNUNET_ShortHashCode *key)
509{
510 union MapEntry me;
511 unsigned int i;
512 int ret;
513
514 map->modification_counter++;
515
516 ret = 0;
517 i = idx_of (map, key);
518 me = map->map[i];
519 if (map->use_small_entries)
520 {
521 struct SmallMapEntry *sme;
522 struct SmallMapEntry *p;
523
524 p = NULL;
525 sme = me.sme;
526 while (NULL != sme)
527 {
528 if (0 == GNUNET_memcmp (key, sme->key))
529 {
530 if (NULL == p)
531 map->map[i].sme = sme->next;
532 else
533 p->next = sme->next;
534 update_next_cache_sme (map, sme);
535 GNUNET_free (sme);
536 map->size--;
537 if (NULL == p)
538 sme = map->map[i].sme;
539 else
540 sme = p->next;
541 ret++;
542 }
543 else
544 {
545 p = sme;
546 sme = sme->next;
547 }
548 }
549 }
550 else
551 {
552 struct BigMapEntry *bme;
553 struct BigMapEntry *p;
554
555 p = NULL;
556 bme = me.bme;
557 while (NULL != bme)
558 {
559 if (0 == GNUNET_memcmp (key, &bme->key))
560 {
561 if (NULL == p)
562 map->map[i].bme = bme->next;
563 else
564 p->next = bme->next;
565 update_next_cache_bme (map, bme);
566 GNUNET_free (bme);
567 map->size--;
568 if (NULL == p)
569 bme = map->map[i].bme;
570 else
571 bme = p->next;
572 ret++;
573 }
574 else
575 {
576 p = bme;
577 bme = bme->next;
578 }
579 }
580 }
581 return ret;
582}
583
584
585/**
586 * Check if the map contains any value under the given
587 * key (including values that are NULL).
588 *
589 * @param map the map
590 * @param key the key to test if a value exists for it
591 * @return #GNUNET_YES if such a value exists,
592 * #GNUNET_NO if not
593 */
594int
595GNUNET_CONTAINER_multishortmap_contains (
596 const struct GNUNET_CONTAINER_MultiShortmap *map,
597 const struct GNUNET_ShortHashCode *key)
598{
599 union MapEntry me;
600
601 me = map->map[idx_of (map, key)];
602 if (map->use_small_entries)
603 {
604 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
605 if (0 == GNUNET_memcmp (key, sme->key))
606 return GNUNET_YES;
607 }
608 else
609 {
610 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
611 if (0 == GNUNET_memcmp (key, &bme->key))
612 return GNUNET_YES;
613 }
614 return GNUNET_NO;
615}
616
617
618/**
619 * Check if the map contains the given value under the given
620 * key.
621 *
622 * @param map the map
623 * @param key the key to test if a value exists for it
624 * @param value value to test for
625 * @return #GNUNET_YES if such a value exists,
626 * #GNUNET_NO if not
627 */
628int
629GNUNET_CONTAINER_multishortmap_contains_value (
630 const struct GNUNET_CONTAINER_MultiShortmap *map,
631 const struct GNUNET_ShortHashCode *key,
632 const void *value)
633{
634 union MapEntry me;
635
636 me = map->map[idx_of (map, key)];
637 if (map->use_small_entries)
638 {
639 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
640 if ((0 == GNUNET_memcmp (key, sme->key)) && (sme->value == value))
641 return GNUNET_YES;
642 }
643 else
644 {
645 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
646 if ((0 == GNUNET_memcmp (key, &bme->key)) && (bme->value == value))
647 return GNUNET_YES;
648 }
649 return GNUNET_NO;
650}
651
652
653/**
654 * Grow the given map to a more appropriate size.
655 *
656 * @param map the hash map to grow
657 */
658static void
659grow (struct GNUNET_CONTAINER_MultiShortmap *map)
660{
661 union MapEntry *old_map;
662 union MapEntry *new_map;
663 unsigned int old_len;
664 unsigned int new_len;
665 unsigned int idx;
666
667 old_map = map->map;
668 old_len = map->map_length;
669 new_len = old_len * 2;
670 if (0 == new_len) /* 2^31 * 2 == 0 */
671 new_len = old_len; /* never use 0 */
672 if (new_len == old_len)
673 return; /* nothing changed */
674 new_map = GNUNET_malloc_large (new_len * sizeof(union MapEntry));
675 if (NULL == new_map)
676 return; /* grow not possible */
677 map->modification_counter++;
678 map->map_length = new_len;
679 map->map = new_map;
680 for (unsigned int i = 0; i < old_len; i++)
681 {
682 if (map->use_small_entries)
683 {
684 struct SmallMapEntry *sme;
685
686 while (NULL != (sme = old_map[i].sme))
687 {
688 old_map[i].sme = sme->next;
689 idx = idx_of (map, sme->key);
690 sme->next = new_map[idx].sme;
691 new_map[idx].sme = sme;
692 }
693 }
694 else
695 {
696 struct BigMapEntry *bme;
697
698 while (NULL != (bme = old_map[i].bme))
699 {
700 old_map[i].bme = bme->next;
701 idx = idx_of (map, &bme->key);
702 bme->next = new_map[idx].bme;
703 new_map[idx].bme = bme;
704 }
705 }
706 }
707 GNUNET_free (old_map);
708}
709
710
711/**
712 * Store a key-value pair in the map.
713 *
714 * @param map the map
715 * @param key key to use
716 * @param value value to use
717 * @param opt options for put
718 * @return #GNUNET_OK on success,
719 * #GNUNET_NO if a value was replaced (with REPLACE)
720 * #GNUNET_SYSERR if #GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
721 * value already exists
722 */
723int
724GNUNET_CONTAINER_multishortmap_put (
725 struct GNUNET_CONTAINER_MultiShortmap *map,
726 const struct GNUNET_ShortHashCode *key,
727 void *value,
728 enum GNUNET_CONTAINER_MultiHashMapOption opt)
729{
730 union MapEntry me;
731 unsigned int i;
732
733 i = idx_of (map, key);
734 if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
735 (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
736 {
737 me = map->map[i];
738 if (map->use_small_entries)
739 {
740 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
741 if (0 == GNUNET_memcmp (key, sme->key))
742 {
743 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
744 return GNUNET_SYSERR;
745 sme->value = value;
746 return GNUNET_NO;
747 }
748 }
749 else
750 {
751 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
752 if (0 == GNUNET_memcmp (key, &bme->key))
753 {
754 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
755 return GNUNET_SYSERR;
756 bme->value = value;
757 return GNUNET_NO;
758 }
759 }
760 }
761 if (map->size / 3 >= map->map_length / 4)
762 {
763 grow (map);
764 i = idx_of (map, key);
765 }
766 if (map->use_small_entries)
767 {
768 struct SmallMapEntry *sme;
769
770 sme = GNUNET_new (struct SmallMapEntry);
771 sme->key = key;
772 sme->value = value;
773 sme->next = map->map[i].sme;
774 map->map[i].sme = sme;
775 }
776 else
777 {
778 struct BigMapEntry *bme;
779
780 bme = GNUNET_new (struct BigMapEntry);
781 bme->key = *key;
782 bme->value = value;
783 bme->next = map->map[i].bme;
784 map->map[i].bme = bme;
785 }
786 map->size++;
787 return GNUNET_OK;
788}
789
790
791/**
792 * Iterate over all entries in the map that match a particular key.
793 *
794 * @param map the map
795 * @param key key that the entries must correspond to
796 * @param it function to call on each entry
797 * @param it_cls extra argument to @a it
798 * @return the number of key value pairs processed,
799 * #GNUNET_SYSERR if it aborted iteration
800 */
801int
802GNUNET_CONTAINER_multishortmap_get_multiple (
803 struct GNUNET_CONTAINER_MultiShortmap *map,
804 const struct GNUNET_ShortHashCode *key,
805 GNUNET_CONTAINER_ShortmapIterator it,
806 void *it_cls)
807{
808 int count;
809 union MapEntry me;
810 union MapEntry *ce;
811
812 ce = &map->next_cache[map->next_cache_off];
813 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
814 count = 0;
815 me = map->map[idx_of (map, key)];
816 if (map->use_small_entries)
817 {
818 struct SmallMapEntry *sme;
819
820 ce->sme = me.sme;
821 while (NULL != (sme = ce->sme))
822 {
823 ce->sme = sme->next;
824 if (0 != GNUNET_memcmp (key, sme->key))
825 continue;
826 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, sme->value)))
827 {
828 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
829 return GNUNET_SYSERR;
830 }
831 count++;
832 }
833 }
834 else
835 {
836 struct BigMapEntry *bme;
837
838 ce->bme = me.bme;
839 while (NULL != (bme = ce->bme))
840 {
841 ce->bme = bme->next;
842 if (0 != GNUNET_memcmp (key, &bme->key))
843 continue;
844 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, bme->value)))
845 {
846 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
847 return GNUNET_SYSERR;
848 }
849 count++;
850 }
851 }
852 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
853 return count;
854}
855
856
857/**
858 * @ingroup hashmap
859 * Call @a it on a random value from the map, or not at all
860 * if the map is empty. Note that this function has linear
861 * complexity (in the size of the map).
862 *
863 * @param map the map
864 * @param it function to call on a random entry
865 * @param it_cls extra argument to @a it
866 * @return the number of key value pairs processed, zero or one.
867 */
868unsigned int
869GNUNET_CONTAINER_multishortmap_get_random (
870 const struct GNUNET_CONTAINER_MultiShortmap *map,
871 GNUNET_CONTAINER_ShortmapIterator it,
872 void *it_cls)
873{
874 unsigned int off;
875 union MapEntry me;
876
877 if (0 == map->size)
878 return 0;
879 if (NULL == it)
880 return 1;
881 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, map->size);
882 for (unsigned int idx = 0; idx < map->map_length; idx++)
883 {
884 me = map->map[idx];
885 if (map->use_small_entries)
886 {
887 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
888 {
889 if (0 == off)
890 {
891 if (GNUNET_OK != it (it_cls, sme->key, sme->value))
892 return GNUNET_SYSERR;
893 return 1;
894 }
895 off--;
896 }
897 }
898 else
899 {
900 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
901 {
902 if (0 == off)
903 {
904 if (GNUNET_OK != it (it_cls, &bme->key, bme->value))
905 return GNUNET_SYSERR;
906 return 1;
907 }
908 off--;
909 }
910 }
911 }
912 GNUNET_break (0);
913 return GNUNET_SYSERR;
914}
915
916
917/**
918 * Create an iterator for a multishortmap.
919 * The iterator can be used to retrieve all the elements in the multishortmap
920 * one by one, without having to handle all elements at once (in contrast to
921 * #GNUNET_CONTAINER_multishortmap_iterate). Note that the iterator can not be
922 * used anymore if elements have been removed from 'map' after the creation of
923 * the iterator, or 'map' has been destroyed. Adding elements to 'map' may
924 * result in skipped or repeated elements.
925 *
926 * @param map the map to create an iterator for
927 * @return an iterator over the given multishortmap 'map'
928 */
929struct GNUNET_CONTAINER_MultiShortmapIterator *
930GNUNET_CONTAINER_multishortmap_iterator_create (
931 const struct GNUNET_CONTAINER_MultiShortmap *map)
932{
933 struct GNUNET_CONTAINER_MultiShortmapIterator *iter;
934
935 iter = GNUNET_new (struct GNUNET_CONTAINER_MultiShortmapIterator);
936 iter->map = map;
937 iter->modification_counter = map->modification_counter;
938 iter->me = map->map[0];
939 return iter;
940}
941
942
943/**
944 * Retrieve the next element from the hash map at the iterator's position.
945 * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
946 * are not modified.
947 * This operation is only allowed if no elements have been removed from the
948 * multishortmap since the creation of 'iter', and the map has not been destroyed.
949 * Adding elements may result in repeating or skipping elements.
950 *
951 * @param iter the iterator to get the next element from
952 * @param key pointer to store the key in, can be NULL
953 * @param value pointer to store the value in, can be NULL
954 * @return #GNUNET_YES we returned an element,
955 * #GNUNET_NO if we are out of elements
956 */
957int
958GNUNET_CONTAINER_multishortmap_iterator_next (
959 struct GNUNET_CONTAINER_MultiShortmapIterator *iter,
960 struct GNUNET_ShortHashCode *key,
961 const void **value)
962{
963 /* make sure the map has not been modified */
964 GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
965
966 /* look for the next entry, skipping empty buckets */
967 while (1)
968 {
969 if (iter->idx >= iter->map->map_length)
970 return GNUNET_NO;
971 if (GNUNET_YES == iter->map->use_small_entries)
972 {
973 if (NULL != iter->me.sme)
974 {
975 if (NULL != key)
976 *key = *iter->me.sme->key;
977 if (NULL != value)
978 *value = iter->me.sme->value;
979 iter->me.sme = iter->me.sme->next;
980 return GNUNET_YES;
981 }
982 }
983 else
984 {
985 if (NULL != iter->me.bme)
986 {
987 if (NULL != key)
988 *key = iter->me.bme->key;
989 if (NULL != value)
990 *value = iter->me.bme->value;
991 iter->me.bme = iter->me.bme->next;
992 return GNUNET_YES;
993 }
994 }
995 iter->idx += 1;
996 if (iter->idx < iter->map->map_length)
997 iter->me = iter->map->map[iter->idx];
998 }
999}
1000
1001
1002/**
1003 * Destroy a multishortmap iterator.
1004 *
1005 * @param iter the iterator to destroy
1006 */
1007void
1008GNUNET_CONTAINER_multishortmap_iterator_destroy (
1009 struct GNUNET_CONTAINER_MultiShortmapIterator *iter)
1010{
1011 GNUNET_free (iter);
1012}
1013
1014
1015/* end of container_multishortmap.c */
diff --git a/src/util/container_multiuuidmap.c b/src/util/container_multiuuidmap.c
deleted file mode 100644
index f2ed304b3..000000000
--- a/src/util/container_multiuuidmap.c
+++ /dev/null
@@ -1,1013 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008, 2012 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 * @file util/container_multiuuidmap.c
22 * @brief hash map for UUIDs where the same key may be present multiple times
23 * @author Christian Grothoff
24 */
25
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define LOG(kind, ...) \
30 GNUNET_log_from (kind, "util-container-multiuuidmap", __VA_ARGS__)
31
32/**
33 * Maximum recursion depth for callbacks of
34 * #GNUNET_CONTAINER_multihashmap_get_multiple() themselves s
35 * again calling #GNUNET_CONTAINER_multihashmap_get_multiple().
36 * Should be totally excessive, but if violated we die.
37 */
38#define NEXT_CACHE_SIZE 16
39
40
41/**
42 * An entry in the hash map with the full key.
43 */
44struct BigMapEntry
45{
46 /**
47 * Value of the entry.
48 */
49 void *value;
50
51 /**
52 * If there is a hash collision, we create a linked list.
53 */
54 struct BigMapEntry *next;
55
56 /**
57 * Key for the entry.
58 */
59 struct GNUNET_Uuid key;
60};
61
62
63/**
64 * An entry in the hash map with just a pointer to the key.
65 */
66struct SmallMapEntry
67{
68 /**
69 * Value of the entry.
70 */
71 void *value;
72
73 /**
74 * If there is a hash collision, we create a linked list.
75 */
76 struct SmallMapEntry *next;
77
78 /**
79 * Key for the entry.
80 */
81 const struct GNUNET_Uuid *key;
82};
83
84
85/**
86 * Entry in the map.
87 */
88union MapEntry
89{
90 /**
91 * Variant used if map entries only contain a pointer to the key.
92 */
93 struct SmallMapEntry *sme;
94
95 /**
96 * Variant used if map entries contain the full key.
97 */
98 struct BigMapEntry *bme;
99};
100
101
102/**
103 * Internal representation of the hash map.
104 */
105struct GNUNET_CONTAINER_MultiUuidmap
106{
107 /**
108 * All of our buckets.
109 */
110 union MapEntry *map;
111
112 /**
113 * Number of entries in the map.
114 */
115 unsigned int size;
116
117 /**
118 * Length of the "map" array.
119 */
120 unsigned int map_length;
121
122 /**
123 * #GNUNET_NO if the map entries are of type 'struct BigMapEntry',
124 * #GNUNET_YES if the map entries are of type 'struct SmallMapEntry'.
125 */
126 int use_small_entries;
127
128 /**
129 * Counts the destructive modifications (grow, remove)
130 * to the map, so that iterators can check if they are still valid.
131 */
132 unsigned int modification_counter;
133
134 /**
135 * Map entries indicating iteration positions currently
136 * in use by #GNUNET_CONTAINER_multihashmap_get_multiple().
137 * Only used up to @e next_cache_off.
138 */
139 union MapEntry next_cache[NEXT_CACHE_SIZE];
140
141 /**
142 * Offset of @e next_cache entries in use, must be smaller
143 * than #NEXT_CACHE_SIZE.
144 */
145 unsigned int next_cache_off;
146};
147
148
149/**
150 * Cursor into a multiuuidmap.
151 * Allows to enumerate elements asynchronously.
152 */
153struct GNUNET_CONTAINER_MultiUuidmapIterator
154{
155 /**
156 * Position in the bucket 'idx'
157 */
158 union MapEntry me;
159
160 /**
161 * Current bucket index.
162 */
163 unsigned int idx;
164
165 /**
166 * Modification counter as observed on the map when the iterator
167 * was created.
168 */
169 unsigned int modification_counter;
170
171 /**
172 * Map that we are iterating over.
173 */
174 const struct GNUNET_CONTAINER_MultiUuidmap *map;
175};
176
177
178/**
179 * Create a multi hash map.
180 *
181 * @param len initial size (map will grow as needed)
182 * @param do_not_copy_keys #GNUNET_NO is always safe and should be used by default;
183 * #GNUNET_YES means that on 'put', the 'key' does not have
184 * to be copied as the destination of the pointer is
185 * guaranteed to be life as long as the value is stored in
186 * the hashmap. This can significantly reduce memory
187 * consumption, but of course is also a recipe for
188 * heap corruption if the assumption is not true. Only
189 * use this if (1) memory use is important in this case and
190 * (2) you have triple-checked that the invariant holds
191 * @return NULL on error
192 */
193struct GNUNET_CONTAINER_MultiUuidmap *
194GNUNET_CONTAINER_multiuuidmap_create (unsigned int len, int do_not_copy_keys)
195{
196 struct GNUNET_CONTAINER_MultiUuidmap *map;
197
198 GNUNET_assert (len > 0);
199 map = GNUNET_new (struct GNUNET_CONTAINER_MultiUuidmap);
200 map->map = GNUNET_malloc_large (len * sizeof(union MapEntry));
201 if (NULL == map->map)
202 {
203 GNUNET_free (map);
204 return NULL;
205 }
206 map->map_length = len;
207 map->use_small_entries = do_not_copy_keys;
208 return map;
209}
210
211
212/**
213 * Destroy a hash map. Will not free any values
214 * stored in the hash map!
215 *
216 * @param map the map
217 */
218void
219GNUNET_CONTAINER_multiuuidmap_destroy (
220 struct GNUNET_CONTAINER_MultiUuidmap *map)
221{
222 GNUNET_assert (0 == map->next_cache_off);
223 for (unsigned int i = 0; i < map->map_length; i++)
224 {
225 union MapEntry me;
226
227 me = map->map[i];
228 if (map->use_small_entries)
229 {
230 struct SmallMapEntry *sme;
231 struct SmallMapEntry *nxt;
232
233 nxt = me.sme;
234 while (NULL != (sme = nxt))
235 {
236 nxt = sme->next;
237 GNUNET_free (sme);
238 }
239 me.sme = NULL;
240 }
241 else
242 {
243 struct BigMapEntry *bme;
244 struct BigMapEntry *nxt;
245
246 nxt = me.bme;
247 while (NULL != (bme = nxt))
248 {
249 nxt = bme->next;
250 GNUNET_free (bme);
251 }
252 me.bme = NULL;
253 }
254 }
255 GNUNET_free (map->map);
256 GNUNET_free (map);
257}
258
259
260/**
261 * Compute the index of the bucket for the given key.
262 *
263 * @param map hash map for which to compute the index
264 * @param key what key should the index be computed for
265 * @return offset into the "map" array of "map"
266 */
267static unsigned int
268idx_of (const struct GNUNET_CONTAINER_MultiUuidmap *map,
269 const struct GNUNET_Uuid *key)
270{
271 unsigned int kx;
272
273 GNUNET_assert (NULL != map);
274 GNUNET_memcpy (&kx, key, sizeof(kx));
275 return kx % map->map_length;
276}
277
278
279/**
280 * Get the number of key-value pairs in the map.
281 *
282 * @param map the map
283 * @return the number of key value pairs
284 */
285unsigned int
286GNUNET_CONTAINER_multiuuidmap_size (
287 const struct GNUNET_CONTAINER_MultiUuidmap *map)
288{
289 return map->size;
290}
291
292
293/**
294 * Given a key find a value in the map matching the key.
295 *
296 * @param map the map
297 * @param key what to look for
298 * @return NULL if no value was found; note that
299 * this is indistinguishable from values that just
300 * happen to be NULL; use "contains" to test for
301 * key-value pairs with value NULL
302 */
303void *
304GNUNET_CONTAINER_multiuuidmap_get (
305 const struct GNUNET_CONTAINER_MultiUuidmap *map,
306 const struct GNUNET_Uuid *key)
307{
308 union MapEntry me;
309
310 me = map->map[idx_of (map, key)];
311 if (map->use_small_entries)
312 {
313 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
314 if (0 == GNUNET_memcmp (key, sme->key))
315 return sme->value;
316 }
317 else
318 {
319 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
320 if (0 == GNUNET_memcmp (key, &bme->key))
321 return bme->value;
322 }
323 return NULL;
324}
325
326
327/**
328 * Iterate over all entries in the map.
329 *
330 * @param map the map
331 * @param it function to call on each entry
332 * @param it_cls extra argument to @a it
333 * @return the number of key value pairs processed,
334 * #GNUNET_SYSERR if it aborted iteration
335 */
336int
337GNUNET_CONTAINER_multiuuidmap_iterate (
338 struct GNUNET_CONTAINER_MultiUuidmap *map,
339 GNUNET_CONTAINER_MultiUuidmapIteratorCallback it,
340 void *it_cls)
341{
342 int count;
343 union MapEntry me;
344 union MapEntry *ce;
345 struct GNUNET_Uuid kc;
346
347 count = 0;
348 GNUNET_assert (NULL != map);
349 ce = &map->next_cache[map->next_cache_off];
350 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
351 for (unsigned int i = 0; i < map->map_length; i++)
352 {
353 me = map->map[i];
354 if (map->use_small_entries)
355 {
356 struct SmallMapEntry *sme;
357
358 ce->sme = me.sme;
359 while (NULL != (sme = ce->sme))
360 {
361 ce->sme = sme->next;
362 if ((NULL != it) && (GNUNET_OK != it (it_cls, sme->key, sme->value)))
363 {
364 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
365 return GNUNET_SYSERR;
366 }
367 count++;
368 }
369 }
370 else
371 {
372 struct BigMapEntry *bme;
373
374 ce->bme = me.bme;
375 while (NULL != (bme = ce->bme))
376 {
377 ce->bme = bme->next;
378 if (NULL != it)
379 {
380 kc = bme->key;
381 if (GNUNET_OK != it (it_cls, &kc, bme->value))
382 {
383 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
384 return GNUNET_SYSERR;
385 }
386 }
387 count++;
388 }
389 }
390 }
391 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
392 return count;
393}
394
395
396/**
397 * We are about to free() the @a bme, make sure it is not in
398 * the list of next values for any iterator in the @a map's next_cache.
399 *
400 * @param map the map to check
401 * @param bme the entry that is about to be free'd
402 */
403static void
404update_next_cache_bme (struct GNUNET_CONTAINER_MultiUuidmap *map,
405 const struct BigMapEntry *bme)
406{
407 for (unsigned int i = 0; i < map->next_cache_off; i++)
408 if (map->next_cache[i].bme == bme)
409 map->next_cache[i].bme = bme->next;
410}
411
412
413/**
414 * We are about to free() the @a sme, make sure it is not in
415 * the list of next values for any iterator in the @a map's next_cache.
416 *
417 * @param map the map to check
418 * @param sme the entry that is about to be free'd
419 */
420static void
421update_next_cache_sme (struct GNUNET_CONTAINER_MultiUuidmap *map,
422 const struct SmallMapEntry *sme)
423{
424 for (unsigned int i = 0; i < map->next_cache_off; i++)
425 if (map->next_cache[i].sme == sme)
426 map->next_cache[i].sme = sme->next;
427}
428
429
430/**
431 * Remove the given key-value pair from the map. Note that if the
432 * key-value pair is in the map multiple times, only one of the pairs
433 * will be removed.
434 *
435 * @param map the map
436 * @param key key of the key-value pair
437 * @param value value of the key-value pair
438 * @return #GNUNET_YES on success, #GNUNET_NO if the key-value pair
439 * is not in the map
440 */
441int
442GNUNET_CONTAINER_multiuuidmap_remove (struct GNUNET_CONTAINER_MultiUuidmap *map,
443 const struct GNUNET_Uuid *key,
444 const void *value)
445{
446 union MapEntry me;
447 unsigned int i;
448
449 map->modification_counter++;
450 i = idx_of (map, key);
451 me = map->map[i];
452 if (map->use_small_entries)
453 {
454 struct SmallMapEntry *p = NULL;
455
456 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
457 {
458 if ((0 == GNUNET_memcmp (key, sme->key)) && (value == sme->value))
459 {
460 if (NULL == p)
461 map->map[i].sme = sme->next;
462 else
463 p->next = sme->next;
464 update_next_cache_sme (map, sme);
465 GNUNET_free (sme);
466 map->size--;
467 return GNUNET_YES;
468 }
469 p = sme;
470 }
471 }
472 else
473 {
474 struct BigMapEntry *p = NULL;
475
476 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
477 {
478 if ((0 == GNUNET_memcmp (key, &bme->key)) && (value == bme->value))
479 {
480 if (NULL == p)
481 map->map[i].bme = bme->next;
482 else
483 p->next = bme->next;
484 update_next_cache_bme (map, bme);
485 GNUNET_free (bme);
486 map->size--;
487 return GNUNET_YES;
488 }
489 p = bme;
490 }
491 }
492 return GNUNET_NO;
493}
494
495
496/**
497 * Remove all entries for the given key from the map.
498 * Note that the values would not be "freed".
499 *
500 * @param map the map
501 * @param key identifies values to be removed
502 * @return number of values removed
503 */
504int
505GNUNET_CONTAINER_multiuuidmap_remove_all (
506 struct GNUNET_CONTAINER_MultiUuidmap *map,
507 const struct GNUNET_Uuid *key)
508{
509 union MapEntry me;
510 unsigned int i;
511 int ret;
512
513 map->modification_counter++;
514
515 ret = 0;
516 i = idx_of (map, key);
517 me = map->map[i];
518 if (map->use_small_entries)
519 {
520 struct SmallMapEntry *sme;
521 struct SmallMapEntry *p;
522
523 p = NULL;
524 sme = me.sme;
525 while (NULL != sme)
526 {
527 if (0 == GNUNET_memcmp (key, sme->key))
528 {
529 if (NULL == p)
530 map->map[i].sme = sme->next;
531 else
532 p->next = sme->next;
533 update_next_cache_sme (map, sme);
534 GNUNET_free (sme);
535 map->size--;
536 if (NULL == p)
537 sme = map->map[i].sme;
538 else
539 sme = p->next;
540 ret++;
541 }
542 else
543 {
544 p = sme;
545 sme = sme->next;
546 }
547 }
548 }
549 else
550 {
551 struct BigMapEntry *bme;
552 struct BigMapEntry *p;
553
554 p = NULL;
555 bme = me.bme;
556 while (NULL != bme)
557 {
558 if (0 == GNUNET_memcmp (key, &bme->key))
559 {
560 if (NULL == p)
561 map->map[i].bme = bme->next;
562 else
563 p->next = bme->next;
564 update_next_cache_bme (map, bme);
565 GNUNET_free (bme);
566 map->size--;
567 if (NULL == p)
568 bme = map->map[i].bme;
569 else
570 bme = p->next;
571 ret++;
572 }
573 else
574 {
575 p = bme;
576 bme = bme->next;
577 }
578 }
579 }
580 return ret;
581}
582
583
584/**
585 * Check if the map contains any value under the given
586 * key (including values that are NULL).
587 *
588 * @param map the map
589 * @param key the key to test if a value exists for it
590 * @return #GNUNET_YES if such a value exists,
591 * #GNUNET_NO if not
592 */
593int
594GNUNET_CONTAINER_multiuuidmap_contains (
595 const struct GNUNET_CONTAINER_MultiUuidmap *map,
596 const struct GNUNET_Uuid *key)
597{
598 union MapEntry me;
599
600 me = map->map[idx_of (map, key)];
601 if (map->use_small_entries)
602 {
603 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
604 if (0 == GNUNET_memcmp (key, sme->key))
605 return GNUNET_YES;
606 }
607 else
608 {
609 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
610 if (0 == GNUNET_memcmp (key, &bme->key))
611 return GNUNET_YES;
612 }
613 return GNUNET_NO;
614}
615
616
617/**
618 * Check if the map contains the given value under the given
619 * key.
620 *
621 * @param map the map
622 * @param key the key to test if a value exists for it
623 * @param value value to test for
624 * @return #GNUNET_YES if such a value exists,
625 * #GNUNET_NO if not
626 */
627int
628GNUNET_CONTAINER_multiuuidmap_contains_value (
629 const struct GNUNET_CONTAINER_MultiUuidmap *map,
630 const struct GNUNET_Uuid *key,
631 const void *value)
632{
633 union MapEntry me;
634
635 me = map->map[idx_of (map, key)];
636 if (map->use_small_entries)
637 {
638 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
639 if ((0 == GNUNET_memcmp (key, sme->key)) && (sme->value == value))
640 return GNUNET_YES;
641 }
642 else
643 {
644 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
645 if ((0 == GNUNET_memcmp (key, &bme->key)) && (bme->value == value))
646 return GNUNET_YES;
647 }
648 return GNUNET_NO;
649}
650
651
652/**
653 * Grow the given map to a more appropriate size.
654 *
655 * @param map the hash map to grow
656 */
657static void
658grow (struct GNUNET_CONTAINER_MultiUuidmap *map)
659{
660 union MapEntry *old_map;
661 union MapEntry *new_map;
662 unsigned int old_len;
663 unsigned int new_len;
664 unsigned int idx;
665
666 old_map = map->map;
667 old_len = map->map_length;
668 new_len = old_len * 2;
669 if (0 == new_len) /* 2^31 * 2 == 0 */
670 new_len = old_len; /* never use 0 */
671 if (new_len == old_len)
672 return; /* nothing changed */
673 new_map = GNUNET_malloc_large (new_len * sizeof(union MapEntry));
674 if (NULL == new_map)
675 return; /* grow not possible */
676 map->modification_counter++;
677 map->map_length = new_len;
678 map->map = new_map;
679 for (unsigned int i = 0; i < old_len; i++)
680 {
681 if (map->use_small_entries)
682 {
683 struct SmallMapEntry *sme;
684
685 while (NULL != (sme = old_map[i].sme))
686 {
687 old_map[i].sme = sme->next;
688 idx = idx_of (map, sme->key);
689 sme->next = new_map[idx].sme;
690 new_map[idx].sme = sme;
691 }
692 }
693 else
694 {
695 struct BigMapEntry *bme;
696
697 while (NULL != (bme = old_map[i].bme))
698 {
699 old_map[i].bme = bme->next;
700 idx = idx_of (map, &bme->key);
701 bme->next = new_map[idx].bme;
702 new_map[idx].bme = bme;
703 }
704 }
705 }
706 GNUNET_free (old_map);
707}
708
709
710/**
711 * Store a key-value pair in the map.
712 *
713 * @param map the map
714 * @param key key to use
715 * @param value value to use
716 * @param opt options for put
717 * @return #GNUNET_OK on success,
718 * #GNUNET_NO if a value was replaced (with REPLACE)
719 * #GNUNET_SYSERR if #GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
720 * value already exists
721 */
722int
723GNUNET_CONTAINER_multiuuidmap_put (struct GNUNET_CONTAINER_MultiUuidmap *map,
724 const struct GNUNET_Uuid *key,
725 void *value,
726 enum GNUNET_CONTAINER_MultiHashMapOption opt)
727{
728 union MapEntry me;
729 unsigned int i;
730
731 i = idx_of (map, key);
732 if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
733 (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
734 {
735 me = map->map[i];
736 if (map->use_small_entries)
737 {
738 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
739 if (0 == GNUNET_memcmp (key, sme->key))
740 {
741 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
742 return GNUNET_SYSERR;
743 sme->value = value;
744 return GNUNET_NO;
745 }
746 }
747 else
748 {
749 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
750 if (0 == GNUNET_memcmp (key, &bme->key))
751 {
752 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
753 return GNUNET_SYSERR;
754 bme->value = value;
755 return GNUNET_NO;
756 }
757 }
758 }
759 if (map->size / 3 >= map->map_length / 4)
760 {
761 grow (map);
762 i = idx_of (map, key);
763 }
764 if (map->use_small_entries)
765 {
766 struct SmallMapEntry *sme;
767
768 sme = GNUNET_new (struct SmallMapEntry);
769 sme->key = key;
770 sme->value = value;
771 sme->next = map->map[i].sme;
772 map->map[i].sme = sme;
773 }
774 else
775 {
776 struct BigMapEntry *bme;
777
778 bme = GNUNET_new (struct BigMapEntry);
779 bme->key = *key;
780 bme->value = value;
781 bme->next = map->map[i].bme;
782 map->map[i].bme = bme;
783 }
784 map->size++;
785 return GNUNET_OK;
786}
787
788
789/**
790 * Iterate over all entries in the map that match a particular key.
791 *
792 * @param map the map
793 * @param key key that the entries must correspond to
794 * @param it function to call on each entry
795 * @param it_cls extra argument to @a it
796 * @return the number of key value pairs processed,
797 * #GNUNET_SYSERR if it aborted iteration
798 */
799int
800GNUNET_CONTAINER_multiuuidmap_get_multiple (
801 struct GNUNET_CONTAINER_MultiUuidmap *map,
802 const struct GNUNET_Uuid *key,
803 GNUNET_CONTAINER_MultiUuidmapIteratorCallback it,
804 void *it_cls)
805{
806 int count;
807 union MapEntry me;
808 union MapEntry *ce;
809
810 ce = &map->next_cache[map->next_cache_off];
811 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
812 count = 0;
813 me = map->map[idx_of (map, key)];
814 if (map->use_small_entries)
815 {
816 struct SmallMapEntry *sme;
817
818 ce->sme = me.sme;
819 while (NULL != (sme = ce->sme))
820 {
821 ce->sme = sme->next;
822 if (0 != GNUNET_memcmp (key, sme->key))
823 continue;
824 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, sme->value)))
825 {
826 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
827 return GNUNET_SYSERR;
828 }
829 count++;
830 }
831 }
832 else
833 {
834 struct BigMapEntry *bme;
835
836 ce->bme = me.bme;
837 while (NULL != (bme = ce->bme))
838 {
839 ce->bme = bme->next;
840 if (0 != GNUNET_memcmp (key, &bme->key))
841 continue;
842 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, bme->value)))
843 {
844 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
845 return GNUNET_SYSERR;
846 }
847 count++;
848 }
849 }
850 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
851 return count;
852}
853
854
855/**
856 * @ingroup hashmap
857 * Call @a it on a random value from the map, or not at all
858 * if the map is empty. Note that this function has linear
859 * complexity (in the size of the map).
860 *
861 * @param map the map
862 * @param it function to call on a random entry
863 * @param it_cls extra argument to @a it
864 * @return the number of key value pairs processed, zero or one.
865 */
866unsigned int
867GNUNET_CONTAINER_multiuuidmap_get_random (
868 const struct GNUNET_CONTAINER_MultiUuidmap *map,
869 GNUNET_CONTAINER_MultiUuidmapIteratorCallback it,
870 void *it_cls)
871{
872 unsigned int off;
873 union MapEntry me;
874
875 if (0 == map->size)
876 return 0;
877 if (NULL == it)
878 return 1;
879 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, map->size);
880 for (unsigned int idx = 0; idx < map->map_length; idx++)
881 {
882 me = map->map[idx];
883 if (map->use_small_entries)
884 {
885 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
886 {
887 if (0 == off)
888 {
889 if (GNUNET_OK != it (it_cls, sme->key, sme->value))
890 return GNUNET_SYSERR;
891 return 1;
892 }
893 off--;
894 }
895 }
896 else
897 {
898 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
899 {
900 if (0 == off)
901 {
902 if (GNUNET_OK != it (it_cls, &bme->key, bme->value))
903 return GNUNET_SYSERR;
904 return 1;
905 }
906 off--;
907 }
908 }
909 }
910 GNUNET_break (0);
911 return GNUNET_SYSERR;
912}
913
914
915/**
916 * Create an iterator for a multiuuidmap.
917 * The iterator can be used to retrieve all the elements in the multiuuidmap
918 * one by one, without having to handle all elements at once (in contrast to
919 * #GNUNET_CONTAINER_multiuuidmap_iterate). Note that the iterator can not be
920 * used anymore if elements have been removed from 'map' after the creation of
921 * the iterator, or 'map' has been destroyed. Adding elements to 'map' may
922 * result in skipped or repeated elements.
923 *
924 * @param map the map to create an iterator for
925 * @return an iterator over the given multiuuidmap 'map'
926 */
927struct GNUNET_CONTAINER_MultiUuidmapIterator *
928GNUNET_CONTAINER_multiuuidmap_iterator_create (
929 const struct GNUNET_CONTAINER_MultiUuidmap *map)
930{
931 struct GNUNET_CONTAINER_MultiUuidmapIterator *iter;
932
933 iter = GNUNET_new (struct GNUNET_CONTAINER_MultiUuidmapIterator);
934 iter->map = map;
935 iter->modification_counter = map->modification_counter;
936 iter->me = map->map[0];
937 return iter;
938}
939
940
941/**
942 * Retrieve the next element from the hash map at the iterator's position.
943 * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
944 * are not modified.
945 * This operation is only allowed if no elements have been removed from the
946 * multiuuidmap since the creation of 'iter', and the map has not been destroyed.
947 * Adding elements may result in repeating or skipping elements.
948 *
949 * @param iter the iterator to get the next element from
950 * @param key pointer to store the key in, can be NULL
951 * @param value pointer to store the value in, can be NULL
952 * @return #GNUNET_YES we returned an element,
953 * #GNUNET_NO if we are out of elements
954 */
955int
956GNUNET_CONTAINER_multiuuidmap_iterator_next (
957 struct GNUNET_CONTAINER_MultiUuidmapIterator *iter,
958 struct GNUNET_Uuid *key,
959 const void **value)
960{
961 /* make sure the map has not been modified */
962 GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
963
964 /* look for the next entry, skipping empty buckets */
965 while (1)
966 {
967 if (iter->idx >= iter->map->map_length)
968 return GNUNET_NO;
969 if (GNUNET_YES == iter->map->use_small_entries)
970 {
971 if (NULL != iter->me.sme)
972 {
973 if (NULL != key)
974 *key = *iter->me.sme->key;
975 if (NULL != value)
976 *value = iter->me.sme->value;
977 iter->me.sme = iter->me.sme->next;
978 return GNUNET_YES;
979 }
980 }
981 else
982 {
983 if (NULL != iter->me.bme)
984 {
985 if (NULL != key)
986 *key = iter->me.bme->key;
987 if (NULL != value)
988 *value = iter->me.bme->value;
989 iter->me.bme = iter->me.bme->next;
990 return GNUNET_YES;
991 }
992 }
993 iter->idx += 1;
994 if (iter->idx < iter->map->map_length)
995 iter->me = iter->map->map[iter->idx];
996 }
997}
998
999
1000/**
1001 * Destroy a multiuuidmap iterator.
1002 *
1003 * @param iter the iterator to destroy
1004 */
1005void
1006GNUNET_CONTAINER_multiuuidmap_iterator_destroy (
1007 struct GNUNET_CONTAINER_MultiUuidmapIterator *iter)
1008{
1009 GNUNET_free (iter);
1010}
1011
1012
1013/* end of container_multiuuidmap.c */
diff --git a/src/util/crypto-test-vectors.json b/src/util/crypto-test-vectors.json
deleted file mode 100644
index 972b62c3e..000000000
--- a/src/util/crypto-test-vectors.json
+++ /dev/null
@@ -1,56 +0,0 @@
1{
2 "encoding": "base32crockford",
3 "producer": "GNUnet 0.14.0 git-64ad3b0a1",
4 "vectors": [
5 {
6 "operation": "hash",
7 "input": "91JPRV3F5GG4EKJNDSJQ8",
8 "output": "D0R24RZ1TPASVQ2NY56CT8AJDYZE9ZGDB0GVZ05E9D4YGZQW2RC5YFPQ0Q86EPW836DY7VYQTNFFJT3ZR2K508F4JVS5JNJKYN2MMFR"
9 },
10 {
11 "operation": "ecc_ecdh",
12 "priv1": "TFA439C75RT2JK9V6GTRRXH3QR3QC4SVJ1KBQ4MNY3S338GT6T50",
13 "pub1": "E19WJDA83485BC8EC8RV7FTAK86BESJG1YNYRENEC0JV7XEZ7M80",
14 "priv2": "2DT3B0TMY6VVP56YZKG5ASRSQAEV0GB4QMT9N6CTPDARNJ905APG",
15 "skm": "GY63DCHR6BGV2AKDM44V7A4H4DA0WJC7D5C2R7DXTWC9D83H7XM0PEQKKZ1K2HWMWBSBNPDWXDN7PA1R1WJKVQ2RDTNF1PBXCFHM9QR"
16 },
17 {
18 "operation": "eddsa_key_derivation",
19 "priv": "8QC2VNF8443S5KPNKMB4XMV58BTHWAKZ7SVW5WG3KRB37567XS90",
20 "pub": "3M9KK1WSNM1RTY5P72HKFA264V4B7MVHVJ08Y90CV06DYHV8XPP0"
21 },
22 {
23 "operation": "eddsa_signing",
24 "priv": "5077XJR9AMH4T97ACKFBVBJD0KFENHPV66B2Y1JBSKXBJKNZJ4E0",
25 "pub": "6E2F03JJ8AEDANTTZZ4SBZDFEEZSF8A9DVGTS6VFBCVZQYQ46RRG",
26 "data": "00000300000000000000",
27 "sig": "XCNJGJ96WPDH60YVMH6C74NGQSGJE3BC1TYMGX6BHY5DMZZZKTB373QTXJ507K5EBSG9YS2EYKHCX3ATRQ6P5MY9MXC4ZB1XSZ2X23G"
28 },
29 {
30 "operation": "kdf",
31 "salt": "94KPT83PCNS7J83KC5P78Y8",
32 "ikm": "94KPT83MD1JJ0WV5CDS6AX10D5Q70XBM41NPAY90DNGQ8SBJD5GPR",
33 "ctx": "94KPT83141HPYVKMCNW78833D1TPWTSC41GPRWVF41NPWVVQDRG62WS04XMPWSKF4WG6JVH0EHM6A82J8S1G",
34 "out_len %u\n": 64,
35 "out": "GTMR4QT05Z9WF5HKVG0WK9RPXGHSMHJNW377G9GJXCA8B0FEKPF4D27RJMSJZYWSQNTBJ5EYVV7ZW18B48Z0JVJJ80RHB706Y96Q358"
36 },
37 {
38 "operation": "eddsa_ecdh",
39 "priv_ecdhe": "5FBRFZY942H2PD96NFNYWZKYXCRFY11JWQ59V7G9B4M8EX1KE100",
40 "pub_ecdhe": "GDX7FC01AZYMG0BY0AMHR6E7KCGX9F6SWES16WZ1QWZ2VSYXKH00",
41 "priv_eddsa": "3HYHM9DZQ3D61APDQNBCSKJE452YEP6JK01DWR1J3VZAASFEA570",
42 "pub_eddsa": "87N7PFAHBX97HRE8XYW8KYN64YZDF4FCBR2BZ5SZN3QE3D2BF0R0",
43 "key_material": "QH0RAXXC9RYDEAXKNTAWM0WXJS25RS67H5T252EGA22RA6JTYRFDAEK8CJY85QSYWGYHQXK5Y1SWSRB3P0NXNXYP237EXMXQ3P2WE00"
44 },
45 {
46 "operation": "rsa_blind_signing",
47 "message_hash": "XKQMJ4CNTXBFE1V2WR6JS063J7PZQE4XMB5JH3RS5X0THQ1JQSQ69Y7KDBC9TYRJEZH48MEPY2SF4QHQ4VHXC0YQX5935MQEGP0AX6R",
48 "rsa_public_key": "040000YRN1NVJ68RS6RJF52PGRCQG19ZKWQPSTJX2G7ZDCKSZFE2VW3HHA81YF5C639JHJF5TX8YTEE2FW2WQCG1PTKNBSPPJEJGA032CN3E8QZ27VWY0K6JFT8ZSYWRH2SKDMXW56A4QKY46JJBWJ6T0ZRVBW6S1HTHXVE2RW8MXRW5T801077MDY13N5F8Z1JZVKBJ06TK3S0YPEDBXK0VEHRHEQJ5X5XYKR4KQTFAZNBMKXY8836VCHBXTK4YNX6AJ1CK29SMJH3Z3QRM16A2TNQGFR0HSMV446BF7FMT2E379ZAT5ST4G3BM2NWZYW545S2SW5MG5S6M88XZZ7SKFD48YVXNZ205GGSEYJPVBMR76WG4ZG30WBCPC1N54XE12RMAG81D8C09WG22PKGGDHYXX68N04002",
49 "rsa_private_key": "50W3MTV5F4PP8RBMC4520A1H60X70XB2DHMP6BBBCNWGM81050SKMWKKC452081050RKMVHJ6MVKM06RN1NVJ68RS6RJF52PGRCQG19ZKWQPSTJX2G7ZDCKSZFE2VW3HHA81YF5C639JHJF5TX8YTEE2FW2WQCG1PTKNBSPPJEJGA032CN3E8QZ27VWY0K6JFT8ZSYWRH2SKDMXW56A4QKY46JJBWJ6T0ZRVBW6S1HTHXVE2RW8MXRW5T801077MDY13N5F8Z1JZVKBJ06TK3S0YPEDBXK0VEHRHEQJ5X5XYKR4KQTFAZNBMKXY8836VCHBXTK4YNX6AJ1CK29SMJH3Z3QRM16A2TNQGFR0HSMV446BF7FMT2E379ZAT5ST4G3BM2NWZYW545S2SW5MG5S6M88XZZ7SKFD48YVXNZ205GGSEYJPVBMR76WG4ZG30WBCPC1N54XE12RMAG81D8C09WG22PKGGDHYXX68N5452081050RKMS9K780G009918G2081918G20A8A40M32C9TE1S6JXK1EHJJTTV5F45208186CX74WV118G2081864X6WCHN6WX01P58DEWHJ669P4KS8NM635W0AFWZ5XPEMQ8M1ZVB4YFVVGPZ0WCAJ0FKSB1GTCMCKSEQA7PKKGKZ0Q5V40DPMXAYDNMKMM2G0RK58VJ5ZRHYZ7G4SMKYJ7YFQ648PCVD7F19JH5WZH1MMJZ4HPG7Y6TZ1P8CEMFEVGP7257E71EJ0081SX3FG8X9BT7RCQYWTWG1PMRY87NKKAZCR6VME4BNWHF9FFMY14XYKTQXAX4ZFJ20SPV4AZEMS7NF9JMGB4RJED4M8ZRXY509JGPNDW3Y04ED6S11JVSVX6GKGSTFTPHEEH40TX0NF7ZQ191E8PF1D41E9N227FZSYCVV927PZDFRG1C46BQMNPTX61SQ417W0R72V5K0D997BG8P52M20BA302F40GNMW43CFQF9J59918G2081864X6ACST04002A8A40G20A1H79J34D9P78SBPDS45EQZVX2D6R1GZ6FHKHDG4ABYZ6FCPSMMGZ29ZY5NS8B304D0QBD800A5SM3D8S92WKS3KFWFXE8X597TNJBR94BGNCFHY8TV63KQZ0RFMRTPHFA2XNFX2V4KECZNTHGKZNJTWH8051XP6FJJ6700A5KWMH24CK1KF9XVH2ATQJ4F1ZJZQM00A00ESTVKM5N58K5FN5TW34B1H1Q1CWRZXJ9QMBG0QKHXHZMFYZSN9ERV59935716NGSX9GBB3R9BY32TBTAJ7K0N391ATSE5263X5NKVDH7XCF1PF0WRTTJYBAJBQWVGJ8P7RGVWB27Q3S4AJJ55FS2T9K341EHATHJZQQTR0JWP5E4NQHR4GN60QMK2SY0VJM56N0NHJXRGAGJW3S9ABJ7M4TAV6YRJJ2H040G2GC9TE0RK4E9T03CET00DAJDXJ1NF511J69JMDDSVARPSFSS6AJTRMVXD10NVA4Z162ER74WNH0J6H2RTA9C9MZM4TEBP8P7AF0NANBH4XZJCNDZV7BEAMJ6R363GHZKGBR0HH1SATGWNJWGW2961MRFPX7S0RJK7CWYE7EX1XQ2683TENRPDKV29D1F1RNDD6P04MZTKSH5YMEZPKGEDRJZXXM9918G2081864X72C9J74X01ZXF256C681JDWRRG7T4AC9JRHP54YM65X9AT17YGC3G4569ZKBQEZ219Y7JG4V10F4AW7Q1XKGPTW3Y3X0WCTB06HM249Q094VHEYD4BTEQ2DF334W8G3VEB7N1CHCMPZEVVTR0XWQSNV6MBJRF5MBY6Z148YA36YA61EXA28PHE3KSN1M4HVF7B06JD736TSK9GC9CAG8F0MMGM81040M32EKN64S3JEG0YCC3PHPNBZAGQ2WE8HJHM28B049N2MQ94G8VPXNHG43C6ADB44DE1DK8ASMYTSXZWMAYKN1SS2GVFTVH8Q4N3TTJ3BKA61Y93QE17XNRF3S0CSSQTY3SVVAFHDA9APFFSMRYD67N4DXQ1X42NA270VF6H0MCRQ87JKVBQAB0CH2WH7RHYMCQ4KN50M2NEFE1YA6F2N2DG7Z9JA8A40G20A8A40G2J2H054500",
50 "blinding_key_secret": "3SWF49XZPHQMENTSBZQR7Z0B8ZSZ2JRARE79Q4VXZMQ7W6QABXMG",
51 "blinded_message": "3KHKZJZ30ABB4E56MA2V0EQWGCWH0QQG9P2ZHYHR186C5HZXJMM4N9WXAQTKS94QSV9Y17GGNXN5MB1PZZFG7Q0FY88QPKKRG4MYCPSMTZK5W59R0MJVNJ4P4AQM96TDG5W7RV8GSNR1QQZ1GNHW3CX6D6ZRTMXB2NKB5SSYTDJS79F5ZFBRZ4HVED9JBBPWSR79KVV5QQ4APBGHBCKGMF9NJJS53A1BVYHDEVYAGFYF2SNEP827ZP50FKJ5GKGV8NQ15ESEZ69AT7GJG0T3TZVENY2YN9CVR98W3BKEZ53J7VTANARG8SJS8AMJQ7S23P5HRJ7XE9KTNRNXKH49MXV9JHHYE5535N7AGWEKR47SBCGNF44Z7XJ9RV5BQV12ZRJKN4HBZQHDNCMH3QKX9Z6G64",
52 "blinded_sig": "ND1V807BK0G73SDXN582BP3Q21MWF4A76EGWD0KA3XGJAWPSVHNHKA44931ZRB9M76SYAFD8ZPTG3A7FH5G2CWGX76VXTCDX5XNRW7EEBNMPDAQ0ZEKF6AHP872SKCGRH89SK4NGC57M8BRA3ZRPDDT9XCBG3XY02VQH4Z0F39DPBS48K0EBMK7B9S3X6QDNR5ND5MV0G7G7T3VPKZRW94MQBKPY1T6K53MQGG4PV81D9YEWNRM3WE04NNQREYDA5ETVDWQ5ZCYV9HF4ZCMWVVGWDBDH732JA3NKZ2B8QK0E6XS0Y4GGGQJS6HFQ4PATGK3TS5GHJEPDF3A6XAFNJQV99CSJW7V1NC504NTQ5NJ8KAVC1758MBBV3SS2BND4YHF0Y4NWJNVH3STV166YWFKR8W",
53 "sig": "EC5MVSPGQMM96N2VT4R2G5104E61V8RY4PR6AK9F614TVVEN7D152T0DP97CDTRDDSQGBV4GZWXQPM90SW30R2RAKKHNDCXHQFAMRSW1XCBEKVKBGC6FP0AQY9S37NVR01VJ2WVX8PN29H2ZFFQBQ9JK96GTJZ3B7DD583S8Y93GH5KWEM41CZJ73QCRT1A2AGVXX5ACFR0T448MC81QB4EGCKP5Z96VCX6RPDD5S9A4295M0E9PPQJCN5G5JKWKG17HWEDF4A26ZMD8YW27EQBZ69GSEZX4PWEV7AXFGG5X0RPKCQEPCX7XDY6NXJ1E2FZBX259RDRCFNDAZS80T0DHD9NVE73QDDESZYEZTM1TM669GHPN8AF4QV8DNW7SFZZKJ67FWR8CZC0PWTEN4ZPTRM"
54 }
55 ]
56}
diff --git a/src/util/crypto_abe.c b/src/util/crypto_abe.c
deleted file mode 100644
index c089b29db..000000000
--- a/src/util/crypto_abe.c
+++ /dev/null
@@ -1,438 +0,0 @@
1/*
2 This file is part of GNUnet. Copyright (C) 2001-2014 Christian Grothoff
3 (and other contributing authors)
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/**
23 * @file util/crypto_random.c
24 * @brief functions to gather random numbers
25 * @author Christian Grothoff
26 */
27
28
29#include "platform.h"
30#include <pbc/pbc.h>
31#include <gabe.h>
32
33#include "gnunet_crypto_lib.h"
34
35struct GNUNET_CRYPTO_AbeMasterKey
36{
37 gabe_pub_t*pub;
38 gabe_msk_t*msk;
39};
40
41struct GNUNET_CRYPTO_AbeKey
42{
43 gabe_pub_t*pub;
44 gabe_prv_t*prv;
45};
46
47static int
48init_aes (element_t k, int enc,
49 gcry_cipher_hd_t*handle,
50 struct GNUNET_CRYPTO_SymmetricSessionKey *key,
51 unsigned char*iv)
52{
53 int rc;
54 int key_len;
55 unsigned char*key_buf;
56
57 key_len = element_length_in_bytes (k) < 33 ? 3 : element_length_in_bytes (k);
58 key_buf = (unsigned char *) malloc (key_len);
59 element_to_bytes (key_buf, k);
60
61 GNUNET_memcpy (key->aes_key,
62 key_buf,
63 GNUNET_CRYPTO_AES_KEY_LENGTH);
64 GNUNET_assert (0 ==
65 gcry_cipher_open (handle, GCRY_CIPHER_AES256,
66 GCRY_CIPHER_MODE_CFB, 0));
67 rc = gcry_cipher_setkey (*handle,
68 key->aes_key,
69 sizeof(key->aes_key));
70 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
71 memset (iv, 0, 16); // TODO make reasonable
72 rc = gcry_cipher_setiv (*handle,
73 iv,
74 16);
75 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
76
77 free (key_buf);
78 return rc;
79}
80
81
82static int
83aes_128_cbc_encrypt (char*pt,
84 int size,
85 element_t k,
86 char **ct)
87{
88 gcry_cipher_hd_t handle;
89 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
90 unsigned char iv[16];
91 char*buf;
92 int padding;
93 int buf_size;
94 uint8_t len[4];
95
96 init_aes (k, 1, &handle, &skey, iv);
97
98 /* TODO make less crufty */
99
100 /* stuff in real length (big endian) before padding */
101 len[0] = (size & 0xff000000) >> 24;
102 len[1] = (size & 0xff0000) >> 16;
103 len[2] = (size & 0xff00) >> 8;
104 len[3] = (size & 0xff) >> 0;
105 padding = 16 - ((4 + size) % 16);
106 buf_size = 4 + size + padding;
107 buf = GNUNET_malloc (buf_size);
108 GNUNET_memcpy (buf, len, 4);
109 GNUNET_memcpy (buf + 4, pt, size);
110 *ct = GNUNET_malloc (buf_size);
111
112 GNUNET_assert (0 == gcry_cipher_encrypt (handle, *ct, buf_size, buf,
113 buf_size));
114 gcry_cipher_close (handle);
115 // AES_cbc_encrypt(pt->data, ct->data, pt->len, &key, iv, AES_ENCRYPT);
116 GNUNET_free (buf);
117 return buf_size;
118}
119
120
121static int
122aes_128_cbc_decrypt (char*ct,
123 int size,
124 element_t k,
125 char **pt)
126{
127 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
128 gcry_cipher_hd_t handle;
129 unsigned char iv[16];
130 char*tmp;
131 uint32_t len;
132
133 init_aes (k, 1, &handle, &skey, iv);
134
135 tmp = GNUNET_malloc (size);
136
137 // AES_cbc_encrypt(ct->data, pt->data, ct->len, &key, iv, AES_DECRYPT);
138 GNUNET_assert (0 == gcry_cipher_decrypt (handle, tmp, size, ct, size));
139 gcry_cipher_close (handle);
140 /* TODO make less crufty */
141
142 /* get real length */
143 len = 0;
144 len = len
145 | ((tmp[0]) << 24) | ((tmp[1]) << 16)
146 | ((tmp[2]) << 8) | ((tmp[3]) << 0);
147 /* truncate any garbage from the padding */
148 *pt = GNUNET_malloc (len);
149 GNUNET_memcpy (*pt, tmp + 4, len);
150 GNUNET_free (tmp);
151 return len;
152}
153
154
155struct GNUNET_CRYPTO_AbeMasterKey*
156GNUNET_CRYPTO_cpabe_create_master_key (void)
157{
158 struct GNUNET_CRYPTO_AbeMasterKey*key;
159
160 key = GNUNET_new (struct GNUNET_CRYPTO_AbeMasterKey);
161 gabe_setup (&key->pub, &key->msk);
162 GNUNET_assert (NULL != key->pub);
163 GNUNET_assert (NULL != key->msk);
164 return key;
165}
166
167
168void
169GNUNET_CRYPTO_cpabe_delete_master_key (struct GNUNET_CRYPTO_AbeMasterKey *key)
170{
171 gabe_msk_free (key->msk);
172 gabe_pub_free (key->pub);
173 // GNUNET_free (key->msk);
174 // gabe_msk_free (key->msk); //For some reason free of pub implicit?
175 GNUNET_free (key);
176}
177
178
179struct GNUNET_CRYPTO_AbeKey*
180GNUNET_CRYPTO_cpabe_create_key (struct GNUNET_CRYPTO_AbeMasterKey *key,
181 char **attrs)
182{
183 struct GNUNET_CRYPTO_AbeKey *prv_key;
184 int size;
185 char *tmp;
186
187 prv_key = GNUNET_new (struct GNUNET_CRYPTO_AbeKey);
188 prv_key->prv = gabe_keygen (key->pub, key->msk, attrs);
189 size = gabe_pub_serialize (key->pub, &tmp);
190 prv_key->pub = gabe_pub_unserialize (tmp, size);
191 GNUNET_free (tmp);
192 GNUNET_assert (NULL != prv_key->prv);
193 return prv_key;
194}
195
196
197void
198GNUNET_CRYPTO_cpabe_delete_key (struct GNUNET_CRYPTO_AbeKey *key,
199 int delete_pub)
200{
201 // Memory management in gabe is buggy
202 gabe_prv_free (key->prv);
203 if (GNUNET_YES == delete_pub)
204 gabe_pub_free (key->pub);
205 GNUNET_free (key);
206}
207
208
209ssize_t
210write_cpabe (void **result,
211 uint32_t file_len,
212 char*cph_buf,
213 int cph_buf_len,
214 char*aes_buf,
215 int aes_buf_len)
216{
217 char *ptr;
218 uint32_t *len;
219
220 *result = GNUNET_malloc (12 + cph_buf_len + aes_buf_len);
221 ptr = *result;
222 len = (uint32_t *) ptr;
223 *len = htonl (file_len);
224 ptr += 4;
225 len = (uint32_t *) ptr;
226 *len = htonl (aes_buf_len);
227 ptr += 4;
228 GNUNET_memcpy (ptr, aes_buf, aes_buf_len);
229 ptr += aes_buf_len;
230 len = (uint32_t *) ptr;
231 *len = htonl (cph_buf_len);
232 ptr += 4;
233 GNUNET_memcpy (ptr, cph_buf, cph_buf_len);
234 return 12 + cph_buf_len + aes_buf_len;
235}
236
237
238ssize_t
239read_cpabe (const void *data,
240 char**cph_buf,
241 int *cph_buf_len,
242 char**aes_buf,
243 int *aes_buf_len)
244{
245 int buf_len;
246 char *ptr;
247 uint32_t *len;
248
249 ptr = (char *) data;
250 len = (uint32_t *) ptr;
251 buf_len = ntohl (*len);
252 ptr += 4;
253 len = (uint32_t *) ptr;
254 *aes_buf_len = ntohl (*len);
255 ptr += 4;
256 *aes_buf = GNUNET_malloc (*aes_buf_len);
257 GNUNET_memcpy (*aes_buf, ptr, *aes_buf_len);
258 ptr += *aes_buf_len;
259 len = (uint32_t *) ptr;
260 *cph_buf_len = ntohl (*len);
261 ptr += 4;
262 *cph_buf = GNUNET_malloc (*cph_buf_len);
263 GNUNET_memcpy (*cph_buf, ptr, *cph_buf_len);
264
265 return buf_len;
266}
267
268
269ssize_t
270GNUNET_CRYPTO_cpabe_encrypt (const void *block,
271 size_t size,
272 const char *policy,
273 const struct GNUNET_CRYPTO_AbeMasterKey *key,
274 void **result)
275{
276 gabe_cph_t*cph;
277 char*plt;
278 char*cph_buf;
279 char*aes_buf;
280 element_t m;
281 int cph_buf_len;
282 int aes_buf_len;
283 ssize_t result_len;
284
285 if (! (cph = gabe_enc (key->pub, m, (char *) policy)))
286 return GNUNET_SYSERR;
287 cph_buf_len = gabe_cph_serialize (cph,
288 &cph_buf);
289 gabe_cph_free (cph);
290 GNUNET_free (cph);
291 plt = GNUNET_memdup (block, size);
292 aes_buf_len = aes_128_cbc_encrypt (plt, size, m, &aes_buf);
293 GNUNET_free (plt);
294 element_clear (m);
295 result_len = write_cpabe (result, size, cph_buf, cph_buf_len, aes_buf,
296 aes_buf_len);
297 GNUNET_free (cph_buf);
298 GNUNET_free (aes_buf);
299 return result_len;
300}
301
302
303ssize_t
304GNUNET_CRYPTO_cpabe_decrypt (const void *block,
305 size_t size,
306 const struct GNUNET_CRYPTO_AbeKey *key,
307 void **result)
308{
309 char*aes_buf;
310 char*cph_buf;
311 gabe_cph_t*cph;
312 element_t m;
313 int cph_buf_size;
314 int aes_buf_size;
315 int plt_len;
316
317 read_cpabe (block, &cph_buf, &cph_buf_size, &aes_buf, &aes_buf_size);
318 cph = gabe_cph_unserialize (key->pub, cph_buf, cph_buf_size);
319 if (! gabe_dec (key->pub, key->prv, cph, m))
320 {
321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
322 "%s\n", gabe_error ());
323 GNUNET_free (aes_buf);
324 GNUNET_free (cph_buf);
325 gabe_cph_free (cph);
326 GNUNET_free (cph);
327 element_clear (m);
328 return GNUNET_SYSERR;
329 }
330 gabe_cph_free (cph);
331 GNUNET_free (cph);
332 plt_len = aes_128_cbc_decrypt (aes_buf, aes_buf_size, m, (char **) result);
333 GNUNET_free (cph_buf);
334 GNUNET_free (aes_buf);
335 element_clear (m);
336 // freeing is buggy in gabe
337 // gabe_prv_free (prv);
338 // gabe_pub_free (pub);
339 return plt_len;
340}
341
342
343ssize_t
344GNUNET_CRYPTO_cpabe_serialize_key (const struct GNUNET_CRYPTO_AbeKey *key,
345 void **result)
346{
347 ssize_t len;
348 char *pub;
349 char *prv;
350 int pub_len;
351 int prv_len;
352
353 pub_len = gabe_pub_serialize (key->pub, &pub);
354 prv_len = gabe_prv_serialize (key->prv, &prv);
355
356 len = pub_len + prv_len + 12;
357 write_cpabe (result, len, pub, pub_len, prv, prv_len);
358
359 GNUNET_free (pub);
360 GNUNET_free (prv);
361
362 return len;
363}
364
365
366struct GNUNET_CRYPTO_AbeKey*
367GNUNET_CRYPTO_cpabe_deserialize_key (const void *data,
368 size_t len)
369{
370 struct GNUNET_CRYPTO_AbeKey *key;
371 char *pub;
372 char *prv;
373 int prv_len;
374 int pub_len;
375
376 key = GNUNET_new (struct GNUNET_CRYPTO_AbeKey);
377 read_cpabe (data,
378 &pub,
379 &pub_len,
380 &prv,
381 &prv_len);
382 key->pub = gabe_pub_unserialize (pub, pub_len);
383 key->prv = gabe_prv_unserialize (key->pub, prv, prv_len);
384
385 GNUNET_free (pub);
386 GNUNET_free (prv);
387 return key;
388}
389
390
391ssize_t
392GNUNET_CRYPTO_cpabe_serialize_master_key (const struct
393 GNUNET_CRYPTO_AbeMasterKey *key,
394 void **result)
395{
396 ssize_t len;
397 char *pub;
398 char *msk;
399 int pub_len;
400 int msk_len;
401
402 pub_len = gabe_pub_serialize (key->pub, &pub);
403 msk_len = gabe_msk_serialize (key->msk, &msk);
404
405 len = pub_len + msk_len + 12;
406 write_cpabe (result, len, pub, pub_len, msk, msk_len);
407
408 GNUNET_free (pub);
409 GNUNET_free (msk);
410
411 return len;
412}
413
414
415struct GNUNET_CRYPTO_AbeMasterKey*
416GNUNET_CRYPTO_cpabe_deserialize_master_key (const void *data,
417 size_t len)
418{
419 struct GNUNET_CRYPTO_AbeMasterKey *key;
420 char *msk;
421 char *pub;
422 int msk_len;
423 int pub_len;
424
425 key = GNUNET_new (struct GNUNET_CRYPTO_AbeMasterKey);
426 read_cpabe (data,
427 &pub,
428 &pub_len,
429 &msk,
430 &msk_len);
431 key->pub = gabe_pub_unserialize (pub, pub_len);
432 key->msk = gabe_msk_unserialize (key->pub, msk, msk_len);
433
434 GNUNET_free (pub);
435 GNUNET_free (msk);
436
437 return key;
438}
diff --git a/src/util/crypto_crc.c b/src/util/crypto_crc.c
deleted file mode 100644
index 804d3eba8..000000000
--- a/src/util/crypto_crc.c
+++ /dev/null
@@ -1,201 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2004, 2006 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 For the actual CRC-32 code:
21 Copyright abandoned; this code is in the public domain.
22 Provided to GNUnet by peter@horizon.com
23 */
24
25/**
26 * @file util/crypto_crc.c
27 * @brief implementation of CRC16 and CRC32
28 * @author Christian Grothoff
29 */
30#include "platform.h"
31#include "gnunet_crypto_lib.h"
32
33#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-crc", __VA_ARGS__)
34
35/* Avoid wasting space on 8-byte longs. */
36#if UINT_MAX >= 0xffffffff
37typedef unsigned int GNUNET_uLong;
38#elif ULONG_MAX >= 0xffffffff
39typedef unsigned long GNUNET_uLong;
40#else
41#error This compiler is not ANSI-compliant!
42#endif
43
44#define Z_NULL 0
45
46
47#define POLYNOMIAL (GNUNET_uLong) 0xedb88320
48static GNUNET_uLong crc_table[256];
49
50/*
51 * This routine writes each crc_table entry exactly once,
52 * with the correct final value. Thus, it is safe to call
53 * even on a table that someone else is using concurrently.
54 */
55static void
56crc_init ()
57{
58 static int once;
59 unsigned int i, j;
60 GNUNET_uLong h = 1;
61
62 if (once)
63 return;
64 once = 1;
65 crc_table[0] = 0;
66 for (i = 128; i; i >>= 1)
67 {
68 h = (h >> 1) ^ ((h & 1) ? POLYNOMIAL : 0);
69 /* h is now crc_table[i] */
70 for (j = 0; j < 256; j += 2 * i)
71 crc_table[i + j] = crc_table[j] ^ h;
72 }
73}
74
75
76/*
77 * This computes the standard preset and inverted CRC, as used
78 * by most networking standards. Start by passing in an initial
79 * chaining value of 0, and then pass in the return value from the
80 * previous crc32() call. The final return value is the CRC.
81 * Note that this is a little-endian CRC, which is best used with
82 * data transmitted lsbit-first, and it should, itself, be appended
83 * to data in little-endian byte and bit order to preserve the
84 * property of detecting all burst errors of length 32 bits or less.
85 */
86static GNUNET_uLong
87crc32 (GNUNET_uLong crc, const char *buf, size_t len)
88{
89 crc_init ();
90 GNUNET_assert (crc_table[255] != 0);
91 crc ^= 0xffffffff;
92 while (len--)
93 crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
94 return crc ^ 0xffffffff;
95}
96
97
98/**
99 * Compute the CRC32 checksum for the first len bytes of the buffer.
100 *
101 * @param buf the data over which we're taking the CRC
102 * @param len the length of the buffer
103 * @return the resulting CRC32 checksum
104 */
105int32_t
106GNUNET_CRYPTO_crc32_n (const void *buf, size_t len)
107{
108 GNUNET_uLong crc;
109
110 crc = crc32 (0L, Z_NULL, 0);
111 crc = crc32 (crc, (char *) buf, len);
112 return crc;
113}
114
115
116/**
117 * Perform an incremental step in a CRC16 (for TCP/IP) calculation.
118 *
119 * @param sum current sum, initially 0
120 * @param buf buffer to calculate CRC over (must be 16-bit aligned)
121 * @param len number of bytes in hdr, must be multiple of 2
122 * @return updated crc sum (must be subjected to #GNUNET_CRYPTO_crc16_finish() to get actual crc16)
123 */
124uint32_t
125GNUNET_CRYPTO_crc16_step (uint32_t sum, const void *buf, size_t len)
126{
127 const uint16_t *hdr = buf;
128
129 for (; len >= 2; len -= 2)
130 sum += *(hdr++);
131 if (len == 1)
132 sum += (*hdr) & ntohs (0xFF00);
133 return sum;
134}
135
136
137/**
138 * Convert results from #GNUNET_CRYPTO_crc16_step() to final crc16.
139 *
140 * @param sum cumulative sum
141 * @return crc16 value
142 */
143uint16_t
144GNUNET_CRYPTO_crc16_finish (uint32_t sum)
145{
146 sum = (sum >> 16) + (sum & 0xFFFF);
147 sum += (sum >> 16);
148
149 return ~sum;
150}
151
152
153/**
154 * Calculate the checksum of a buffer in one step.
155 *
156 * @param buf buffer to calculate CRC over (must be 16-bit aligned)
157 * @param len number of bytes in hdr, must be multiple of 2
158 * @return crc16 value
159 */
160uint16_t
161GNUNET_CRYPTO_crc16_n (const void *buf, size_t len)
162{
163 const uint16_t *hdr = buf;
164 uint32_t sum = GNUNET_CRYPTO_crc16_step (0, hdr, len);
165
166 return GNUNET_CRYPTO_crc16_finish (sum);
167}
168
169
170/**
171 * @ingroup hash
172 * Calculate the checksum of a buffer in one step.
173 *
174 * @param buf buffer to calculate CRC over
175 * @param len number of bytes in @a buf
176 * @return crc8 value
177 */
178uint8_t
179GNUNET_CRYPTO_crc8_n (const void *buf,
180 size_t len)
181{
182 const uint8_t *data = buf;
183 unsigned int crc = 0;
184 int i;
185 int j;
186
187 for (j = len; 0 != j; j--)
188 {
189 crc ^= (*data++ << 8);
190 for (i = 8; 0 != i; i--)
191 {
192 if (0 != (crc & 0x8000))
193 crc ^= (0x1070 << 3);
194 crc <<= 1;
195 }
196 }
197 return (uint8_t) (crc >> 8);
198}
199
200
201/* end of crypto_crc.c */
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c
deleted file mode 100644
index 5b1b579ec..000000000
--- a/src/util/crypto_ecc.c
+++ /dev/null
@@ -1,791 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015 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 util/crypto_ecc.c
23 * @brief public key cryptography (ECC) with libgcrypt
24 * @author Christian Grothoff
25 * @author Florian Dold
26 */
27#include "platform.h"
28#include <gcrypt.h>
29#include <sodium.h>
30#include "gnunet_crypto_lib.h"
31#include "gnunet_strings_lib.h"
32#include "benchmark.h"
33
34#define EXTRA_CHECKS 0
35
36/**
37 * IMPLEMENTATION NOTICE:
38 *
39 * ECDSA: We use a non-standard curve for ECDSA: Ed25519.
40 * For performance reasons, we use cryptographic operations from
41 * libsodium wherever we can get away with it, even though libsodium
42 * itself does not support ECDSA.
43 * This is why the sign and verifiy functionality from libgcrypt is
44 * required and used.
45 *
46 * EdDSA: We use a standard EdDSA construction.
47 * (We still use libgcrypt for hashing and RNG, but not EC)
48 *
49 * ECDHE: For both EdDSA and ECDSA keys, we use libsodium for
50 * ECDHE due to performance benefits over libgcrypt.
51 */
52
53/**
54 * Name of the curve we are using. Note that we have hard-coded
55 * structs that use 256 bits, so using a bigger curve will require
56 * changes that break stuff badly. The name of the curve given here
57 * must be agreed by all peers and be supported by libgcrypt.
58 */
59#define CURVE "Ed25519"
60
61#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
62
63#define LOG_STRERROR(kind, syscall) \
64 GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
65
66#define LOG_STRERROR_FILE(kind, syscall, filename) \
67 GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
68
69/**
70 * Log an error message at log-level 'level' that indicates
71 * a failure of the command 'cmd' with the message given
72 * by gcry_strerror(rc).
73 */
74#define LOG_GCRY(level, cmd, rc) \
75 do \
76 { \
77 LOG (level, \
78 _ ("`%s' failed at %s:%d with error: %s\n"), \
79 cmd, \
80 __FILE__, \
81 __LINE__, \
82 gcry_strerror (rc)); \
83 } while (0)
84
85
86/**
87 * Extract values from an S-expression.
88 *
89 * @param array where to store the result(s)
90 * @param sexp S-expression to parse
91 * @param topname top-level name in the S-expression that is of interest
92 * @param elems names of the elements to extract
93 * @return 0 on success
94 */
95static int
96key_from_sexp (gcry_mpi_t *array,
97 gcry_sexp_t sexp,
98 const char *topname,
99 const char *elems)
100{
101 gcry_sexp_t list;
102 gcry_sexp_t l2;
103 unsigned int idx;
104
105 list = gcry_sexp_find_token (sexp, topname, 0);
106 if (! list)
107 return 1;
108 l2 = gcry_sexp_cadr (list);
109 gcry_sexp_release (list);
110 list = l2;
111 if (! list)
112 return 2;
113
114 idx = 0;
115 for (const char *s = elems; *s; s++, idx++)
116 {
117 l2 = gcry_sexp_find_token (list, s, 1);
118 if (! l2)
119 {
120 for (unsigned int i = 0; i < idx; i++)
121 {
122 gcry_free (array[i]);
123 array[i] = NULL;
124 }
125 gcry_sexp_release (list);
126 return 3; /* required parameter not found */
127 }
128 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
129 gcry_sexp_release (l2);
130 if (! array[idx])
131 {
132 for (unsigned int i = 0; i < idx; i++)
133 {
134 gcry_free (array[i]);
135 array[i] = NULL;
136 }
137 gcry_sexp_release (list);
138 return 4; /* required parameter is invalid */
139 }
140 }
141 gcry_sexp_release (list);
142 return 0;
143}
144
145
146/**
147 * Convert the given private key from the network format to the
148 * S-expression that can be used by libgcrypt.
149 *
150 * @param priv private key to decode
151 * @return NULL on error
152 */
153static gcry_sexp_t
154decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
155{
156 gcry_sexp_t result;
157 int rc;
158 uint8_t d[32];
159
160 for (size_t i = 0; i<32; i++)
161 d[i] = priv->d[31 - i];
162
163 rc = gcry_sexp_build (&result,
164 NULL,
165 "(private-key(ecc(curve \"" CURVE "\")"
166 "(d %b)))",
167 32,
168 d);
169 if (0 != rc)
170 {
171 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
172 GNUNET_assert (0);
173 }
174#if EXTRA_CHECKS
175 if (0 != (rc = gcry_pk_testkey (result)))
176 {
177 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
178 GNUNET_assert (0);
179 }
180#endif
181 return result;
182}
183
184
185void
186GNUNET_CRYPTO_ecdsa_key_get_public (
187 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
188 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
189{
190 BENCHMARK_START (ecdsa_key_get_public);
191 crypto_scalarmult_ed25519_base_noclamp (pub->q_y, priv->d);
192 BENCHMARK_END (ecdsa_key_get_public);
193}
194
195
196void
197GNUNET_CRYPTO_eddsa_key_get_public (
198 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
199 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
200{
201 unsigned char pk[crypto_sign_PUBLICKEYBYTES];
202 unsigned char sk[crypto_sign_SECRETKEYBYTES];
203
204 BENCHMARK_START (eddsa_key_get_public);
205 GNUNET_assert (0 == crypto_sign_seed_keypair (pk, sk, priv->d));
206 GNUNET_memcpy (pub->q_y, pk, crypto_sign_PUBLICKEYBYTES);
207 sodium_memzero (sk, crypto_sign_SECRETKEYBYTES);
208 BENCHMARK_END (eddsa_key_get_public);
209}
210
211
212void
213GNUNET_CRYPTO_ecdhe_key_get_public (
214 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
215 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
216{
217 BENCHMARK_START (ecdhe_key_get_public);
218 GNUNET_assert (0 == crypto_scalarmult_base (pub->q_y, priv->d));
219 BENCHMARK_END (ecdhe_key_get_public);
220}
221
222
223char *
224GNUNET_CRYPTO_ecdsa_public_key_to_string (
225 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
226{
227 char *pubkeybuf;
228 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
229 char *end;
230
231 if (keylen % 5 > 0)
232 keylen += 5 - keylen % 5;
233 keylen /= 5;
234 pubkeybuf = GNUNET_malloc (keylen + 1);
235 end =
236 GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
237 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
238 pubkeybuf,
239 keylen);
240 if (NULL == end)
241 {
242 GNUNET_free (pubkeybuf);
243 return NULL;
244 }
245 *end = '\0';
246 return pubkeybuf;
247}
248
249
250char *
251GNUNET_CRYPTO_eddsa_public_key_to_string (
252 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
253{
254 char *pubkeybuf;
255 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
256 char *end;
257
258 if (keylen % 5 > 0)
259 keylen += 5 - keylen % 5;
260 keylen /= 5;
261 pubkeybuf = GNUNET_malloc (keylen + 1);
262 end =
263 GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
264 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
265 pubkeybuf,
266 keylen);
267 if (NULL == end)
268 {
269 GNUNET_free (pubkeybuf);
270 return NULL;
271 }
272 *end = '\0';
273 return pubkeybuf;
274}
275
276
277char *
278GNUNET_CRYPTO_eddsa_private_key_to_string (
279 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
280{
281 char *privkeybuf;
282 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
283 char *end;
284
285 if (keylen % 5 > 0)
286 keylen += 5 - keylen % 5;
287 keylen /= 5;
288 privkeybuf = GNUNET_malloc (keylen + 1);
289 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
290 sizeof(
291 struct GNUNET_CRYPTO_EddsaPrivateKey),
292 privkeybuf,
293 keylen);
294 if (NULL == end)
295 {
296 GNUNET_free (privkeybuf);
297 return NULL;
298 }
299 *end = '\0';
300 return privkeybuf;
301}
302
303
304char *
305GNUNET_CRYPTO_ecdsa_private_key_to_string (
306 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
307{
308 char *privkeybuf;
309 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey)) * 8;
310 char *end;
311
312 if (keylen % 5 > 0)
313 keylen += 5 - keylen % 5;
314 keylen /= 5;
315 privkeybuf = GNUNET_malloc (keylen + 1);
316 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
317 sizeof(
318 struct GNUNET_CRYPTO_EcdsaPrivateKey),
319 privkeybuf,
320 keylen);
321 if (NULL == end)
322 {
323 GNUNET_free (privkeybuf);
324 return NULL;
325 }
326 *end = '\0';
327 return privkeybuf;
328}
329
330
331enum GNUNET_GenericReturnValue
332GNUNET_CRYPTO_ecdsa_public_key_from_string (
333 const char *enc,
334 size_t enclen,
335 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
336{
337 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
338
339 if (keylen % 5 > 0)
340 keylen += 5 - keylen % 5;
341 keylen /= 5;
342 if (enclen != keylen)
343 return GNUNET_SYSERR;
344
345 if (GNUNET_OK !=
346 GNUNET_STRINGS_string_to_data (enc,
347 enclen,
348 pub,
349 sizeof(
350 struct GNUNET_CRYPTO_EcdsaPublicKey)))
351 return GNUNET_SYSERR;
352 return GNUNET_OK;
353}
354
355
356enum GNUNET_GenericReturnValue
357GNUNET_CRYPTO_eddsa_public_key_from_string (
358 const char *enc,
359 size_t enclen,
360 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
361{
362 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
363
364 if (keylen % 5 > 0)
365 keylen += 5 - keylen % 5;
366 keylen /= 5;
367 if (enclen != keylen)
368 return GNUNET_SYSERR;
369
370 if (GNUNET_OK !=
371 GNUNET_STRINGS_string_to_data (enc,
372 enclen,
373 pub,
374 sizeof(
375 struct GNUNET_CRYPTO_EddsaPublicKey)))
376 return GNUNET_SYSERR;
377 return GNUNET_OK;
378}
379
380
381enum GNUNET_GenericReturnValue
382GNUNET_CRYPTO_eddsa_private_key_from_string (
383 const char *enc,
384 size_t enclen,
385 struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
386{
387 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
388
389 if (keylen % 5 > 0)
390 keylen += 5 - keylen % 5;
391 keylen /= 5;
392 if (enclen != keylen)
393 return GNUNET_SYSERR;
394
395 if (GNUNET_OK !=
396 GNUNET_STRINGS_string_to_data (enc,
397 enclen,
398 priv,
399 sizeof(
400 struct GNUNET_CRYPTO_EddsaPrivateKey)))
401 return GNUNET_SYSERR;
402#if CRYPTO_BUG
403 if (GNUNET_OK != check_eddsa_key (priv))
404 {
405 GNUNET_break (0);
406 return GNUNET_OK;
407 }
408#endif
409 return GNUNET_OK;
410}
411
412
413void
414GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
415{
416 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
417}
418
419
420void
421GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
422{
423 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey));
424}
425
426
427void
428GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
429{
430 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey));
431}
432
433
434void
435GNUNET_CRYPTO_ecdhe_key_create (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
436{
437 BENCHMARK_START (ecdhe_key_create);
438 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
439 pk,
440 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
441 BENCHMARK_END (ecdhe_key_create);
442}
443
444
445void
446GNUNET_CRYPTO_ecdsa_key_create (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
447{
448 BENCHMARK_START (ecdsa_key_create);
449 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
450 pk,
451 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
452 pk->d[0] &= 248;
453 pk->d[31] &= 127;
454 pk->d[31] |= 64;
455
456 BENCHMARK_END (ecdsa_key_create);
457}
458
459
460void
461GNUNET_CRYPTO_eddsa_key_create (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
462{
463 BENCHMARK_START (eddsa_key_create);
464 /*
465 * We do not clamp for EdDSA, since all functions that use the private key do
466 * their own clamping (just like in libsodium). What we call "private key"
467 * here, actually corresponds to the seed in libsodium.
468 *
469 * (Contrast this to ECDSA, where functions using the private key can't clamp
470 * due to properties needed for GNS. That is a worse/unsafer API, but
471 * required for the GNS constructions to work.)
472 */
473 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
474 pk,
475 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
476 BENCHMARK_END (eddsa_key_create);
477}
478
479
480const struct GNUNET_CRYPTO_EcdsaPrivateKey *
481GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
482{
483 /**
484 * 'anonymous' pseudonym (global static, d=1, public key = G
485 * (generator).
486 */
487 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
488 static int once;
489
490 if (once)
491 return &anonymous;
492 GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
493 sizeof(anonymous.d),
494 GCRYMPI_CONST_ONE);
495 anonymous.d[0] &= 248;
496 anonymous.d[31] &= 127;
497 anonymous.d[31] |= 64;
498
499 once = 1;
500 return &anonymous;
501}
502
503
504/**
505 * Convert the data specified in the given purpose argument to an
506 * S-expression suitable for signature operations.
507 *
508 * @param purpose data to convert
509 * @return converted s-expression
510 */
511static gcry_sexp_t
512data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
513{
514 gcry_sexp_t data;
515 int rc;
516
517/* See #5398 */
518#if 1
519 struct GNUNET_HashCode hc;
520
521 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
522 if (0 != (rc = gcry_sexp_build (&data,
523 NULL,
524 "(data(flags rfc6979)(hash %s %b))",
525 "sha512",
526 (int) sizeof(hc),
527 &hc)))
528 {
529 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
530 return NULL;
531 }
532#else
533 if (0 != (rc = gcry_sexp_build (&data,
534 NULL,
535 "(data(flags rfc6979)(hash %s %b))",
536 "sha512",
537 ntohl (purpose->size),
538 purpose)))
539 {
540 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
541 return NULL;
542 }
543#endif
544 return data;
545}
546
547
548enum GNUNET_GenericReturnValue
549GNUNET_CRYPTO_ecdsa_sign_ (
550 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
551 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
552 struct GNUNET_CRYPTO_EcdsaSignature *sig)
553{
554 gcry_sexp_t priv_sexp;
555 gcry_sexp_t sig_sexp;
556 gcry_sexp_t data;
557 int rc;
558 gcry_mpi_t rs[2];
559
560 BENCHMARK_START (ecdsa_sign);
561
562 priv_sexp = decode_private_ecdsa_key (priv);
563 data = data_to_ecdsa_value (purpose);
564 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
565 {
566 LOG (GNUNET_ERROR_TYPE_WARNING,
567 _ ("ECC signing failed at %s:%d: %s\n"),
568 __FILE__,
569 __LINE__,
570 gcry_strerror (rc));
571 gcry_sexp_release (data);
572 gcry_sexp_release (priv_sexp);
573 return GNUNET_SYSERR;
574 }
575 gcry_sexp_release (priv_sexp);
576 gcry_sexp_release (data);
577
578 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
579 'signature' */
580 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
581 {
582 GNUNET_break (0);
583 gcry_sexp_release (sig_sexp);
584 return GNUNET_SYSERR;
585 }
586 gcry_sexp_release (sig_sexp);
587 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof(sig->r), rs[0]);
588 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof(sig->s), rs[1]);
589 gcry_mpi_release (rs[0]);
590 gcry_mpi_release (rs[1]);
591
592 BENCHMARK_END (ecdsa_sign);
593
594 return GNUNET_OK;
595}
596
597
598enum GNUNET_GenericReturnValue
599GNUNET_CRYPTO_eddsa_sign_ (
600 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
601 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
602 struct GNUNET_CRYPTO_EddsaSignature *sig)
603{
604
605 size_t mlen = ntohl (purpose->size);
606 unsigned char sk[crypto_sign_SECRETKEYBYTES];
607 unsigned char pk[crypto_sign_PUBLICKEYBYTES];
608 int res;
609
610 BENCHMARK_START (eddsa_sign);
611 GNUNET_assert (0 == crypto_sign_seed_keypair (pk, sk, priv->d));
612 res = crypto_sign_detached ((uint8_t *) sig,
613 NULL,
614 (uint8_t *) purpose,
615 mlen,
616 sk);
617 BENCHMARK_END (eddsa_sign);
618 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
619}
620
621
622enum GNUNET_GenericReturnValue
623GNUNET_CRYPTO_ecdsa_verify_ (
624 uint32_t purpose,
625 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
626 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
627 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
628{
629 gcry_sexp_t data;
630 gcry_sexp_t sig_sexpr;
631 gcry_sexp_t pub_sexpr;
632 int rc;
633
634 BENCHMARK_START (ecdsa_verify);
635
636 if (purpose != ntohl (validate->purpose))
637 return GNUNET_SYSERR; /* purpose mismatch */
638
639 /* build s-expression for signature */
640 if (0 != (rc = gcry_sexp_build (&sig_sexpr,
641 NULL,
642 "(sig-val(ecdsa(r %b)(s %b)))",
643 (int) sizeof(sig->r),
644 sig->r,
645 (int) sizeof(sig->s),
646 sig->s)))
647 {
648 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
649 return GNUNET_SYSERR;
650 }
651 data = data_to_ecdsa_value (validate);
652 if (0 != (rc = gcry_sexp_build (&pub_sexpr,
653 NULL,
654 "(public-key(ecc(curve " CURVE ")(q %b)))",
655 (int) sizeof(pub->q_y),
656 pub->q_y)))
657 {
658 gcry_sexp_release (data);
659 gcry_sexp_release (sig_sexpr);
660 return GNUNET_SYSERR;
661 }
662 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
663 gcry_sexp_release (pub_sexpr);
664 gcry_sexp_release (data);
665 gcry_sexp_release (sig_sexpr);
666 if (0 != rc)
667 {
668 LOG (GNUNET_ERROR_TYPE_INFO,
669 _ ("ECDSA signature verification failed at %s:%d: %s\n"),
670 __FILE__,
671 __LINE__,
672 gcry_strerror (rc));
673 BENCHMARK_END (ecdsa_verify);
674 return GNUNET_SYSERR;
675 }
676 BENCHMARK_END (ecdsa_verify);
677 return GNUNET_OK;
678}
679
680
681enum GNUNET_GenericReturnValue
682GNUNET_CRYPTO_eddsa_verify_ (
683 uint32_t purpose,
684 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
685 const struct GNUNET_CRYPTO_EddsaSignature *sig,
686 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
687{
688 const unsigned char *m = (const void *) validate;
689 size_t mlen = ntohl (validate->size);
690 const unsigned char *s = (const void *) sig;
691
692 int res;
693
694 if (purpose != ntohl (validate->purpose))
695 return GNUNET_SYSERR; /* purpose mismatch */
696
697 BENCHMARK_START (eddsa_verify);
698 res = crypto_sign_verify_detached (s, m, mlen, pub->q_y);
699 BENCHMARK_END (eddsa_verify);
700 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
701}
702
703
704enum GNUNET_GenericReturnValue
705GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
706 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
707 struct GNUNET_HashCode *key_material)
708{
709 uint8_t p[crypto_scalarmult_BYTES];
710 if (0 != crypto_scalarmult (p, priv->d, pub->q_y))
711 return GNUNET_SYSERR;
712 GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
713 return GNUNET_OK;
714}
715
716
717enum GNUNET_GenericReturnValue
718GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
719 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
720 struct GNUNET_HashCode *key_material)
721{
722 struct GNUNET_HashCode hc;
723 uint8_t a[crypto_scalarmult_SCALARBYTES];
724 uint8_t p[crypto_scalarmult_BYTES];
725
726 GNUNET_CRYPTO_hash (priv,
727 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
728 &hc);
729 memcpy (a, &hc, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
730 if (0 != crypto_scalarmult (p, a, pub->q_y))
731 return GNUNET_SYSERR;
732 GNUNET_CRYPTO_hash (p,
733 crypto_scalarmult_BYTES,
734 key_material);
735 return GNUNET_OK;
736}
737
738
739enum GNUNET_GenericReturnValue
740GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
741 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
742 struct GNUNET_HashCode *key_material)
743{
744 uint8_t p[crypto_scalarmult_BYTES];
745
746 BENCHMARK_START (ecdsa_ecdh);
747 if (0 != crypto_scalarmult (p, priv->d, pub->q_y))
748 return GNUNET_SYSERR;
749 GNUNET_CRYPTO_hash (p,
750 crypto_scalarmult_BYTES,
751 key_material);
752 BENCHMARK_END (ecdsa_ecdh);
753 return GNUNET_OK;
754}
755
756
757enum GNUNET_GenericReturnValue
758GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
759 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
760 struct GNUNET_HashCode *key_material)
761{
762 uint8_t p[crypto_scalarmult_BYTES];
763 uint8_t curve25510_pk[crypto_scalarmult_BYTES];
764
765 if (0 != crypto_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y))
766 return GNUNET_SYSERR;
767 if (0 != crypto_scalarmult (p, priv->d, curve25510_pk))
768 return GNUNET_SYSERR;
769 GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
770 return GNUNET_OK;
771}
772
773
774enum GNUNET_GenericReturnValue
775GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
776 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
777 struct GNUNET_HashCode *key_material)
778{
779 uint8_t p[crypto_scalarmult_BYTES];
780 uint8_t curve25510_pk[crypto_scalarmult_BYTES];
781
782 if (0 != crypto_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y))
783 return GNUNET_SYSERR;
784 if (0 != crypto_scalarmult (p, priv->d, curve25510_pk))
785 return GNUNET_SYSERR;
786 GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
787 return GNUNET_OK;
788}
789
790
791/* end of crypto_ecc.c */
diff --git a/src/util/crypto_ecc_dlog.c b/src/util/crypto_ecc_dlog.c
deleted file mode 100644
index 916acd9dd..000000000
--- a/src/util/crypto_ecc_dlog.c
+++ /dev/null
@@ -1,336 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015 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 util/crypto_ecc_dlog.c
23 * @brief ECC addition and discreate logarithm for small values.
24 * Allows us to use ECC for computations as long as the
25 * result is relativey small.
26 * @author Christian Grothoff
27 */
28#include "platform.h"
29#include <gcrypt.h>
30#include "gnunet_crypto_lib.h"
31#include "gnunet_container_lib.h"
32
33
34/**
35 * Internal structure used to cache pre-calculated values for DLOG calculation.
36 */
37struct GNUNET_CRYPTO_EccDlogContext
38{
39 /**
40 * Maximum absolute value the calculation supports.
41 */
42 unsigned int max;
43
44 /**
45 * How much memory should we use (relates to the number of entries in the map).
46 */
47 unsigned int mem;
48
49 /**
50 * Map mapping points (here "interpreted" as EdDSA public keys) to
51 * a "void * = long" which corresponds to the numeric value of the
52 * point. As NULL is used to represent "unknown", the actual value
53 * represented by the entry in the map is the "long" minus @e max.
54 */
55 struct GNUNET_CONTAINER_MultiPeerMap *map;
56
57 /**
58 * Context to use for operations on the elliptic curve.
59 */
60 gcry_ctx_t ctx;
61};
62
63
64struct GNUNET_CRYPTO_EccDlogContext *
65GNUNET_CRYPTO_ecc_dlog_prepare (unsigned int max,
66 unsigned int mem)
67{
68 struct GNUNET_CRYPTO_EccDlogContext *edc;
69 int K = ((max + (mem - 1)) / mem);
70
71 GNUNET_assert (max < INT32_MAX);
72 edc = GNUNET_new (struct GNUNET_CRYPTO_EccDlogContext);
73 edc->max = max;
74 edc->mem = mem;
75 edc->map = GNUNET_CONTAINER_multipeermap_create (mem * 2,
76 GNUNET_NO);
77 for (int i = -(int) mem; i <= (int) mem; i++)
78 {
79 struct GNUNET_CRYPTO_EccScalar Ki;
80 struct GNUNET_PeerIdentity key;
81
82 GNUNET_CRYPTO_ecc_scalar_from_int (K * i,
83 &Ki);
84 if (0 == i) /* libsodium does not like to multiply with zero */
85 GNUNET_assert (
86 0 ==
87 crypto_core_ed25519_sub ((unsigned char *) &key,
88 (unsigned char *) &key,
89 (unsigned char *) &key));
90 else
91 GNUNET_assert (
92 0 ==
93 crypto_scalarmult_ed25519_base_noclamp ((unsigned char*) &key,
94 Ki.v));
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96 "K*i: %d (mem=%u, i=%d) => %s\n",
97 K * i,
98 mem,
99 i,
100 GNUNET_i2s (&key));
101 GNUNET_assert (GNUNET_OK ==
102 GNUNET_CONTAINER_multipeermap_put (edc->map,
103 &key,
104 (void *) (long) i + max,
105 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
106 }
107 return edc;
108}
109
110
111int
112GNUNET_CRYPTO_ecc_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc,
113 const struct GNUNET_CRYPTO_EccPoint *input)
114{
115 unsigned int K = ((edc->max + (edc->mem - 1)) / edc->mem);
116 int res;
117 struct GNUNET_CRYPTO_EccPoint g;
118 struct GNUNET_CRYPTO_EccPoint q;
119 struct GNUNET_CRYPTO_EccPoint nq;
120
121 {
122 struct GNUNET_CRYPTO_EccScalar fact;
123
124 memset (&fact,
125 0,
126 sizeof (fact));
127 sodium_increment (fact.v,
128 sizeof (fact.v));
129 GNUNET_assert (0 ==
130 crypto_scalarmult_ed25519_base_noclamp (g.v,
131 fact.v));
132 }
133 /* make compiler happy: initialize q and nq, technically not needed! */
134 memset (&q,
135 0,
136 sizeof (q));
137 memset (&nq,
138 0,
139 sizeof (nq));
140 res = INT_MAX;
141 for (unsigned int i = 0; i <= edc->max / edc->mem; i++)
142 {
143 struct GNUNET_PeerIdentity key;
144 void *retp;
145
146 GNUNET_assert (sizeof (key) == crypto_scalarmult_BYTES);
147 if (0 == i)
148 {
149 memcpy (&key,
150 input,
151 sizeof (key));
152 }
153 else
154 {
155 memcpy (&key,
156 &q,
157 sizeof (key));
158 }
159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
160 "Trying offset i=%u): %s\n",
161 i,
162 GNUNET_i2s (&key));
163 retp = GNUNET_CONTAINER_multipeermap_get (edc->map,
164 &key);
165 if (NULL != retp)
166 {
167 res = (((long) retp) - edc->max) * K - i;
168 /* we continue the loop here to make the implementation
169 "constant-time". If we do not care about this, we could just
170 'break' here and do fewer operations... */
171 }
172 if (i == edc->max / edc->mem)
173 break;
174 /* q = q + g */
175 if (0 == i)
176 {
177 GNUNET_assert (0 ==
178 crypto_core_ed25519_add (q.v,
179 input->v,
180 g.v));
181 }
182 else
183 {
184 GNUNET_assert (0 ==
185 crypto_core_ed25519_add (q.v,
186 q.v,
187 g.v));
188 }
189 }
190 return res;
191}
192
193
194void
195GNUNET_CRYPTO_ecc_random_mod_n (struct GNUNET_CRYPTO_EccScalar *r)
196{
197 crypto_core_ed25519_scalar_random (r->v);
198}
199
200
201void
202GNUNET_CRYPTO_ecc_dlog_release (struct GNUNET_CRYPTO_EccDlogContext *edc)
203{
204 GNUNET_CONTAINER_multipeermap_destroy (edc->map);
205 GNUNET_free (edc);
206}
207
208
209void
210GNUNET_CRYPTO_ecc_dexp (int val,
211 struct GNUNET_CRYPTO_EccPoint *r)
212{
213 struct GNUNET_CRYPTO_EccScalar fact;
214
215 GNUNET_CRYPTO_ecc_scalar_from_int (val,
216 &fact);
217 crypto_scalarmult_ed25519_base_noclamp (r->v,
218 fact.v);
219}
220
221
222enum GNUNET_GenericReturnValue
223GNUNET_CRYPTO_ecc_dexp_mpi (const struct GNUNET_CRYPTO_EccScalar *val,
224 struct GNUNET_CRYPTO_EccPoint *r)
225{
226 if (0 ==
227 crypto_scalarmult_ed25519_base_noclamp (r->v,
228 val->v))
229 return GNUNET_OK;
230 return GNUNET_SYSERR;
231}
232
233
234enum GNUNET_GenericReturnValue
235GNUNET_CRYPTO_ecc_add (const struct GNUNET_CRYPTO_EccPoint *a,
236 const struct GNUNET_CRYPTO_EccPoint *b,
237 struct GNUNET_CRYPTO_EccPoint *r)
238{
239 if (0 ==
240 crypto_core_ed25519_add (r->v,
241 a->v,
242 b->v))
243 return GNUNET_OK;
244 return GNUNET_SYSERR;
245}
246
247
248enum GNUNET_GenericReturnValue
249GNUNET_CRYPTO_ecc_pmul_mpi (const struct GNUNET_CRYPTO_EccPoint *p,
250 const struct GNUNET_CRYPTO_EccScalar *val,
251 struct GNUNET_CRYPTO_EccPoint *r)
252{
253 if (0 ==
254 crypto_scalarmult_ed25519_noclamp (r->v,
255 val->v,
256 p->v))
257 return GNUNET_OK;
258 return GNUNET_SYSERR;
259}
260
261
262enum GNUNET_GenericReturnValue
263GNUNET_CRYPTO_ecc_rnd (struct GNUNET_CRYPTO_EccPoint *r,
264 struct GNUNET_CRYPTO_EccPoint *r_inv)
265{
266 struct GNUNET_CRYPTO_EccScalar s;
267 unsigned char inv_s[crypto_scalarmult_ed25519_SCALARBYTES];
268
269 GNUNET_CRYPTO_ecc_random_mod_n (&s);
270 if (0 !=
271 crypto_scalarmult_ed25519_base_noclamp (r->v,
272 s.v))
273 return GNUNET_SYSERR;
274 crypto_core_ed25519_scalar_negate (inv_s,
275 s.v);
276 if (0 !=
277 crypto_scalarmult_ed25519_base_noclamp (r_inv->v,
278 inv_s))
279 return GNUNET_SYSERR;
280 return GNUNET_OK;
281}
282
283
284void
285GNUNET_CRYPTO_ecc_rnd_mpi (struct GNUNET_CRYPTO_EccScalar *r,
286 struct GNUNET_CRYPTO_EccScalar *r_neg)
287{
288 GNUNET_CRYPTO_ecc_random_mod_n (r);
289 crypto_core_ed25519_scalar_negate (r_neg->v,
290 r->v);
291}
292
293
294void
295GNUNET_CRYPTO_ecc_scalar_from_int (int64_t val,
296 struct GNUNET_CRYPTO_EccScalar *r)
297{
298 unsigned char fact[crypto_scalarmult_ed25519_SCALARBYTES];
299 uint64_t valBe;
300
301 GNUNET_assert (sizeof (*r) == sizeof (fact));
302 if (val < 0)
303 {
304 if (INT64_MIN == val)
305 valBe = GNUNET_htonll ((uint64_t) INT64_MAX);
306 else
307 valBe = GNUNET_htonll ((uint64_t) (-val));
308 }
309 else
310 {
311 valBe = GNUNET_htonll ((uint64_t) val);
312 }
313 memset (fact,
314 0,
315 sizeof (fact));
316 for (unsigned int i = 0; i < sizeof (val); i++)
317 fact[i] = ((unsigned char*) &valBe)[sizeof (val) - 1 - i];
318 if (val < 0)
319 {
320 if (INT64_MIN == val)
321 /* See above: fact is one too small, increment now that we can */
322 sodium_increment (fact,
323 sizeof (fact));
324 crypto_core_ed25519_scalar_negate (r->v,
325 fact);
326 }
327 else
328 {
329 memcpy (r,
330 fact,
331 sizeof (fact));
332 }
333}
334
335
336/* end of crypto_ecc_dlog.c */
diff --git a/src/util/crypto_ecc_gnsrecord.c b/src/util/crypto_ecc_gnsrecord.c
deleted file mode 100644
index ce41a4699..000000000
--- a/src/util/crypto_ecc_gnsrecord.c
+++ /dev/null
@@ -1,445 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015 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 util/crypto_ecc_gnsrecord.c
23 * @brief public key cryptography (ECC) for GNS records (LSD0001)
24 * @author Christian Grothoff
25 * @author Florian Dold
26 * @author Martin Schanzenbach
27 */
28#include "platform.h"
29#include <gcrypt.h>
30#include <sodium.h>
31#include "gnunet_crypto_lib.h"
32#include "gnunet_strings_lib.h"
33
34#define CURVE "Ed25519"
35
36/**
37 * Derive the 'h' value for key derivation, where
38 * 'h = H(l,P)'.
39 *
40 * @param pub public key for deriviation
41 * @param pubsize the size of the public key
42 * @param label label for deriviation
43 * @param context additional context to use for HKDF of 'h';
44 * typically the name of the subsystem/application
45 * @param hc where to write the result
46 */
47void
48derive_h (const void *pub,
49 size_t pubsize,
50 const char *label,
51 const char *context,
52 struct GNUNET_HashCode *hc)
53{
54 static const char *const salt = "key-derivation";
55
56 GNUNET_CRYPTO_kdf (hc,
57 sizeof(*hc),
58 salt,
59 strlen (salt),
60 pub,
61 pubsize,
62 label,
63 strlen (label),
64 context,
65 strlen (context),
66 NULL,
67 0);
68}
69
70
71/**
72 * This is a signature function for EdDSA which takes the
73 * secret scalar sk instead of the private seed which is
74 * usually the case for crypto APIs. We require this functionality
75 * in order to use derived private keys for signatures we
76 * cannot calculate the inverse of a sk to find the seed
77 * efficiently.
78 *
79 * The resulting signature is a standard EdDSA signature
80 * which can be verified using the usual APIs.
81 *
82 * @param sk the secret scalar
83 * @param purp the signature purpose
84 * @param sig the resulting signature
85 */
86void
87GNUNET_CRYPTO_eddsa_sign_with_scalar (
88 const struct GNUNET_CRYPTO_EddsaPrivateScalar *priv,
89 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
90 struct GNUNET_CRYPTO_EddsaSignature *sig)
91{
92
93 crypto_hash_sha512_state hs;
94 unsigned char sk[64];
95 unsigned char r[64];
96 unsigned char hram[64];
97 unsigned char R[32];
98 unsigned char zk[32];
99 unsigned char tmp[32];
100
101 crypto_hash_sha512_init (&hs);
102
103 /**
104 * Instead of expanding the private here, we already
105 * have the secret scalar as input. Use it.
106 * Note that sk is not plain SHA512 (d).
107 * sk[0..31] contains the derived private scalar
108 * sk[0..31] = h * SHA512 (d)[0..31]
109 * sk[32..63] = SHA512 (d)[32..63]
110 */
111 memcpy (sk, priv->s, 64);
112
113 /**
114 * Calculate the derived zone key zk' from the
115 * derived private scalar.
116 */
117 crypto_scalarmult_ed25519_base_noclamp (zk,
118 sk);
119
120 /**
121 * Calculate r:
122 * r = SHA512 (sk[32..63] | M)
123 * where M is our message (purpose).
124 * Note that sk[32..63] is the other half of the
125 * expansion from the original, non-derived private key
126 * "d".
127 */
128 crypto_hash_sha512_update (&hs, sk + 32, 32);
129 crypto_hash_sha512_update (&hs, (uint8_t*) purpose, ntohl (purpose->size));
130 crypto_hash_sha512_final (&hs, r);
131
132 /**
133 * Temporarily put zk into S
134 */
135 memcpy (sig->s, zk, 32);
136
137 /**
138 * Reduce the scalar value r
139 */
140 unsigned char r_mod[64];
141 crypto_core_ed25519_scalar_reduce (r_mod, r);
142
143 /**
144 * Calculate R := r * G of the signature
145 */
146 crypto_scalarmult_ed25519_base_noclamp (R, r_mod);
147 memcpy (sig->r, R, sizeof (R));
148
149 /**
150 * Calculate
151 * hram := SHA512 (R | zk' | M)
152 */
153 crypto_hash_sha512_init (&hs);
154 crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64);
155 crypto_hash_sha512_update (&hs, (uint8_t*) purpose,
156 ntohl (purpose->size));
157 crypto_hash_sha512_final (&hs, hram);
158
159 /**
160 * Reduce the resulting scalar value
161 */
162 unsigned char hram_mod[64];
163 crypto_core_ed25519_scalar_reduce (hram_mod, hram);
164
165 /**
166 * Calculate
167 * S := r + hram * s mod L
168 */
169 crypto_core_ed25519_scalar_mul (tmp, hram_mod, sk);
170 crypto_core_ed25519_scalar_add (sig->s, tmp, r_mod);
171
172 sodium_memzero (sk, sizeof (sk));
173 sodium_memzero (r, sizeof (r));
174 sodium_memzero (r_mod, sizeof (r_mod));
175}
176
177
178struct GNUNET_CRYPTO_EcdsaPrivateKey *
179GNUNET_CRYPTO_ecdsa_private_key_derive (
180 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
181 const char *label,
182 const char *context)
183{
184 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
185 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
186 struct GNUNET_HashCode hc;
187 uint8_t dc[32];
188 gcry_mpi_t h;
189 gcry_mpi_t x;
190 gcry_mpi_t d;
191 gcry_mpi_t n;
192 gcry_ctx_t ctx;
193
194 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
195
196 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
197 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
198
199 derive_h (&pub, sizeof (pub), label, context, &hc);
200 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
201
202 /* Convert to big endian for libgcrypt */
203 for (size_t i = 0; i < 32; i++)
204 dc[i] = priv->d[31 - i];
205 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));
206 d = gcry_mpi_new (256);
207 gcry_mpi_mulm (d, h, x, n);
208 gcry_mpi_release (h);
209 gcry_mpi_release (x);
210 gcry_mpi_release (n);
211 gcry_ctx_release (ctx);
212 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
213 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
214 /* Convert to big endian for libgcrypt */
215 for (size_t i = 0; i < 32; i++)
216 ret->d[i] = dc[31 - i];
217 sodium_memzero (dc, sizeof(dc));
218 gcry_mpi_release (d);
219 return ret;
220}
221
222
223void
224GNUNET_CRYPTO_ecdsa_public_key_derive (
225 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
226 const char *label,
227 const char *context,
228 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
229{
230 struct GNUNET_HashCode hc;
231 gcry_ctx_t ctx;
232 gcry_mpi_t q_y;
233 gcry_mpi_t h;
234 gcry_mpi_t n;
235 gcry_mpi_t h_mod_n;
236 gcry_mpi_point_t q;
237 gcry_mpi_point_t v;
238
239 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
240
241 /* obtain point 'q' from original public key. The provided 'q' is
242 compressed thus we first store it in the context and then get it
243 back as a (decompresssed) point. */
244 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
245 GNUNET_assert (NULL != q_y);
246 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
247 gcry_mpi_release (q_y);
248 q = gcry_mpi_ec_get_point ("q", ctx, 0);
249 GNUNET_assert (q);
250
251 /* calculate h_mod_n = h % n */
252 derive_h (pub, sizeof (*pub), label, context, &hc);
253 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
254 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
255 h_mod_n = gcry_mpi_new (256);
256 gcry_mpi_mod (h_mod_n, h, n);
257 /* calculate v = h_mod_n * q */
258 v = gcry_mpi_point_new (0);
259 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
260 gcry_mpi_release (h_mod_n);
261 gcry_mpi_release (h);
262 gcry_mpi_release (n);
263 gcry_mpi_point_release (q);
264
265 /* convert point 'v' to public key that we return */
266 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
267 gcry_mpi_point_release (v);
268 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
269 GNUNET_assert (q_y);
270 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
271 gcry_mpi_release (q_y);
272 gcry_ctx_release (ctx);
273}
274
275
276void
277GNUNET_CRYPTO_eddsa_private_key_derive (
278 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
279 const char *label,
280 const char *context,
281 struct GNUNET_CRYPTO_EddsaPrivateScalar *result)
282{
283 struct GNUNET_CRYPTO_EddsaPublicKey pub;
284 struct GNUNET_HashCode hc;
285 uint8_t dc[32];
286 unsigned char sk[64];
287 gcry_mpi_t h;
288 gcry_mpi_t h_mod_n;
289 gcry_mpi_t x;
290 gcry_mpi_t d;
291 gcry_mpi_t n;
292 gcry_mpi_t a1;
293 gcry_mpi_t a2;
294 gcry_ctx_t ctx;
295
296 /**
297 * Libsodium does not offer an API with arbitrary arithmetic.
298 * Hence we have to use libgcrypt here.
299 */
300 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
301
302 /**
303 * Get our modulo
304 */
305 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
306 GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub);
307
308 /**
309 * This is the standard private key expansion in Ed25519.
310 * The first 32 octets are used as a little-endian private
311 * scalar.
312 * We derive this scalar using our "h".
313 */
314 crypto_hash_sha512 (sk, priv->d, 32);
315 sk[0] &= 248;
316 sk[31] &= 127;
317 sk[31] |= 64;
318
319 /**
320 * Get h mod n
321 */
322 derive_h (&pub, sizeof (pub), label, context, &hc);
323 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
324 h_mod_n = gcry_mpi_new (256);
325 gcry_mpi_mod (h_mod_n, h, n);
326 /* Convert scalar to big endian for libgcrypt */
327 for (size_t i = 0; i < 32; i++)
328 dc[i] = sk[31 - i];
329
330 /**
331 * dc now contains the private scalar "a".
332 * We carefully remove the clamping and derive a'.
333 * Calculate:
334 * a1 := a / 8
335 * a2 := h * a1 mod n
336 * a' := a2 * 8 mod n
337 */
338 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc)); // a
339 a1 = gcry_mpi_new (256);
340 gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8);
341 gcry_mpi_div (a1, NULL, x, eight, 0); // a1 := a / 8
342 a2 = gcry_mpi_new (256);
343 gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n
344 d = gcry_mpi_new (256);
345 gcry_mpi_mul (d, a2, eight); // a' := a2 * 8
346 gcry_mpi_release (h);
347 gcry_mpi_release (x);
348 gcry_mpi_release (n);
349 gcry_mpi_release (a1);
350 gcry_mpi_release (a2);
351 gcry_ctx_release (ctx);
352 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
353 /**
354 * We hash the derived "h" parameter with the
355 * other half of the expanded private key. This ensures
356 * that for signature generation, the "R" is derived from
357 * the same derivation path as "h" and is not reused.
358 */
359 crypto_hash_sha256_state hs;
360 crypto_hash_sha256_init (&hs);
361 crypto_hash_sha256_update (&hs, sk + 32, 32);
362 crypto_hash_sha256_update (&hs, (unsigned char*) &hc, sizeof (hc));
363 crypto_hash_sha256_final (&hs, result->s + 32);
364 //memcpy (result->s, sk, sizeof (sk));
365 /* Convert to little endian for libsodium */
366 for (size_t i = 0; i < 32; i++)
367 result->s[i] = dc[31 - i];
368
369 sodium_memzero (dc, sizeof(dc));
370 gcry_mpi_release (d);
371}
372
373
374void
375GNUNET_CRYPTO_eddsa_public_key_derive (
376 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
377 const char *label,
378 const char *context,
379 struct GNUNET_CRYPTO_EddsaPublicKey *result)
380{
381 struct GNUNET_HashCode hc;
382 gcry_ctx_t ctx;
383 gcry_mpi_t q_y;
384 gcry_mpi_t h;
385 gcry_mpi_t n;
386 gcry_mpi_t h_mod_n;
387 gcry_mpi_point_t q;
388 gcry_mpi_point_t v;
389
390 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
391
392 /* obtain point 'q' from original public key. The provided 'q' is
393 compressed thus we first store it in the context and then get it
394 back as a (decompresssed) point. */
395 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
396 GNUNET_assert (NULL != q_y);
397 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
398 gcry_mpi_release (q_y);
399 q = gcry_mpi_ec_get_point ("q", ctx, 0);
400 GNUNET_assert (q);
401
402 /* calculate h_mod_n = h % n */
403 derive_h (pub, sizeof (*pub), label, context, &hc);
404 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
405
406 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
407 h_mod_n = gcry_mpi_new (256);
408 gcry_mpi_mod (h_mod_n, h, n);
409
410 /* calculate v = h_mod_n * q */
411 v = gcry_mpi_point_new (0);
412 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
413 gcry_mpi_release (h_mod_n);
414 gcry_mpi_release (h);
415 gcry_mpi_release (n);
416 gcry_mpi_point_release (q);
417
418 /* convert point 'v' to public key that we return */
419 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
420 gcry_mpi_point_release (v);
421 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
422 GNUNET_assert (q_y);
423 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
424 gcry_mpi_release (q_y);
425 gcry_ctx_release (ctx);
426
427}
428
429
430void
431GNUNET_CRYPTO_eddsa_key_get_public_from_scalar (
432 const struct GNUNET_CRYPTO_EddsaPrivateScalar *priv,
433 struct GNUNET_CRYPTO_EddsaPublicKey *pkey)
434{
435 unsigned char sk[32];
436
437 memcpy (sk, priv->s, 32);
438
439 /**
440 * Calculate the derived zone key zk' from the
441 * derived private scalar.
442 */
443 crypto_scalarmult_ed25519_base_noclamp (pkey->q_y,
444 sk);
445}
diff --git a/src/util/crypto_ecc_setup.c b/src/util/crypto_ecc_setup.c
deleted file mode 100644
index f7cd8c6d9..000000000
--- a/src/util/crypto_ecc_setup.c
+++ /dev/null
@@ -1,306 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015, 2020 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 util/crypto_ecc_setup.c
23 * @brief helper function for easy EdDSA key setup
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include <gcrypt.h>
28#include "gnunet_util_lib.h"
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
31
32#define LOG_STRERROR(kind, syscall) \
33 GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
34
35#define LOG_STRERROR_FILE(kind, syscall, filename) \
36 GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
37
38/**
39 * Log an error message at log-level 'level' that indicates
40 * a failure of the command 'cmd' with the message given
41 * by gcry_strerror(rc).
42 */
43#define LOG_GCRY(level, cmd, rc) \
44 do \
45 { \
46 LOG (level, \
47 _ ("`%s' failed at %s:%d with error: %s\n"), \
48 cmd, \
49 __FILE__, \
50 __LINE__, \
51 gcry_strerror (rc)); \
52 } while (0)
53
54
55/**
56 * Read file to @a buf. Fails if the file does not exist or
57 * does not have precisely @a buf_size bytes.
58 *
59 * @param filename file to read
60 * @param[out] buf where to write the file contents
61 * @param buf_size number of bytes in @a buf
62 * @return #GNUNET_OK on success
63 */
64static enum GNUNET_GenericReturnValue
65read_from_file (const char *filename,
66 void *buf,
67 size_t buf_size)
68{
69 int fd;
70 struct stat sb;
71
72 fd = open (filename,
73 O_RDONLY);
74 if (-1 == fd)
75 {
76 memset (buf,
77 0,
78 buf_size);
79 return GNUNET_SYSERR;
80 }
81 if (0 != fstat (fd,
82 &sb))
83 {
84 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
85 "stat",
86 filename);
87 GNUNET_assert (0 == close (fd));
88 memset (buf,
89 0,
90 buf_size);
91 return GNUNET_SYSERR;
92 }
93 if (sb.st_size != buf_size)
94 {
95 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
96 "File `%s' has wrong size (%llu), expected %llu bytes\n",
97 filename,
98 (unsigned long long) sb.st_size,
99 (unsigned long long) buf_size);
100 GNUNET_assert (0 == close (fd));
101 memset (buf,
102 0,
103 buf_size);
104 return GNUNET_SYSERR;
105 }
106 if (buf_size !=
107 read (fd,
108 buf,
109 buf_size))
110 {
111 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
112 "read",
113 filename);
114 GNUNET_assert (0 == close (fd));
115 memset (buf,
116 0,
117 buf_size);
118 return GNUNET_SYSERR;
119 }
120 GNUNET_assert (0 == close (fd));
121 return GNUNET_OK;
122}
123
124
125/**
126 * @ingroup crypto
127 * @brief Create a new private key by reading it from a file.
128 *
129 * If the files does not exist and @a do_create is set, creates a new key and
130 * write it to the file.
131 *
132 * If the contents of the file are invalid, an error is returned.
133 *
134 * @param filename name of file to use to store the key
135 * @param do_create should a file be created?
136 * @param[out] pkey set to the private key from @a filename on success
137 * @return #GNUNET_OK on success, #GNUNET_NO if @a do_create was set but
138 * we found an existing file, #GNUNET_SYSERR on failure
139 */
140enum GNUNET_GenericReturnValue
141GNUNET_CRYPTO_eddsa_key_from_file (const char *filename,
142 int do_create,
143 struct GNUNET_CRYPTO_EddsaPrivateKey *pkey)
144{
145 enum GNUNET_GenericReturnValue ret;
146
147 if (GNUNET_OK ==
148 read_from_file (filename,
149 pkey,
150 sizeof (*pkey)))
151 {
152 /* file existed, report that we didn't create it... */
153 return (do_create) ? GNUNET_NO : GNUNET_OK;
154 }
155 GNUNET_CRYPTO_eddsa_key_create (pkey);
156 ret = GNUNET_DISK_fn_write (filename,
157 pkey,
158 sizeof (*pkey),
159 GNUNET_DISK_PERM_USER_READ);
160 if ( (GNUNET_OK == ret) ||
161 (GNUNET_SYSERR == ret) )
162 return ret;
163 /* maybe another process succeeded in the meantime, try reading one more time */
164 if (GNUNET_OK ==
165 read_from_file (filename,
166 pkey,
167 sizeof (*pkey)))
168 {
169 /* file existed, report that *we* didn't create it... */
170 return (do_create) ? GNUNET_NO : GNUNET_OK;
171 }
172 /* give up */
173 return GNUNET_SYSERR;
174}
175
176
177/**
178 * @ingroup crypto
179 * @brief Create a new private key by reading it from a file.
180 *
181 * If the files does not exist and @a do_create is set, creates a new key and
182 * write it to the file.
183 *
184 * If the contents of the file are invalid, an error is returned.
185 *
186 * @param filename name of file to use to store the key
187 * @param do_create should a file be created?
188 * @param[out] pkey set to the private key from @a filename on success
189 * @return #GNUNET_OK on success, #GNUNET_NO if @a do_create was set but
190 * we found an existing file, #GNUNET_SYSERR on failure
191 */
192enum GNUNET_GenericReturnValue
193GNUNET_CRYPTO_ecdsa_key_from_file (const char *filename,
194 int do_create,
195 struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey)
196{
197 if (GNUNET_OK ==
198 read_from_file (filename,
199 pkey,
200 sizeof (*pkey)))
201 {
202 /* file existed, report that we didn't create it... */
203 return (do_create) ? GNUNET_NO : GNUNET_OK;
204 }
205 GNUNET_CRYPTO_ecdsa_key_create (pkey);
206 if (GNUNET_OK ==
207 GNUNET_DISK_fn_write (filename,
208 pkey,
209 sizeof (*pkey),
210 GNUNET_DISK_PERM_USER_READ))
211 return GNUNET_OK;
212 /* maybe another process succeeded in the meantime, try reading one more time */
213 if (GNUNET_OK ==
214 read_from_file (filename,
215 pkey,
216 sizeof (*pkey)))
217 {
218 /* file existed, report that *we* didn't create it... */
219 return (do_create) ? GNUNET_NO : GNUNET_OK;
220 }
221 /* give up */
222 return GNUNET_SYSERR;
223}
224
225
226/**
227 * Create a new private key by reading our peer's key from
228 * the file specified in the configuration.
229 *
230 * @param cfg the configuration to use
231 * @return new private key, NULL on error (for example,
232 * permission denied)
233 */
234struct GNUNET_CRYPTO_EddsaPrivateKey *
235GNUNET_CRYPTO_eddsa_key_create_from_configuration (
236 const struct GNUNET_CONFIGURATION_Handle *cfg)
237{
238 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
239 char *fn;
240
241 if (GNUNET_OK !=
242 GNUNET_CONFIGURATION_get_value_filename (cfg,
243 "PEER",
244 "PRIVATE_KEY",
245 &fn))
246 return NULL;
247 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
248 GNUNET_CRYPTO_eddsa_key_from_file (fn,
249 GNUNET_YES,
250 priv);
251 GNUNET_free (fn);
252 return priv;
253}
254
255
256/**
257 * Retrieve the identity of the host's peer.
258 *
259 * @param cfg configuration to use
260 * @param dst pointer to where to write the peer identity
261 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
262 * could not be retrieved
263 */
264enum GNUNET_GenericReturnValue
265GNUNET_CRYPTO_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
266 struct GNUNET_PeerIdentity *dst)
267{
268 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
269
270 if (NULL == (priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg)))
271 {
272 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
273 _ ("Could not load peer's private key\n"));
274 return GNUNET_SYSERR;
275 }
276 GNUNET_CRYPTO_eddsa_key_get_public (priv,
277 &dst->public_key);
278 GNUNET_free (priv);
279 return GNUNET_OK;
280}
281
282
283/**
284 * Setup a key file for a peer given the name of the
285 * configuration file (!). This function is used so that
286 * at a later point code can be certain that reading a
287 * key is fast (for example in time-dependent testcases).
288 *
289 * @param cfg_name name of the configuration file to use
290 */
291void
292GNUNET_CRYPTO_eddsa_setup_key (const char *cfg_name)
293{
294 struct GNUNET_CONFIGURATION_Handle *cfg;
295 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
296
297 cfg = GNUNET_CONFIGURATION_create ();
298 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
299 priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
300 if (NULL != priv)
301 GNUNET_free (priv);
302 GNUNET_CONFIGURATION_destroy (cfg);
303}
304
305
306/* end of crypto_ecc_setup.c */
diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c
deleted file mode 100644
index d62ec8012..000000000
--- a/src/util/crypto_hash.c
+++ /dev/null
@@ -1,389 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013 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 util/crypto_hash.c
23 * @brief SHA-512 #GNUNET_CRYPTO_hash() related functions
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_crypto_lib.h"
28#include "gnunet_strings_lib.h"
29#include "benchmark.h"
30#include <gcrypt.h>
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-hash", __VA_ARGS__)
33
34#define LOG_STRERROR_FILE(kind, syscall, \
35 filename) GNUNET_log_from_strerror_file (kind, \
36 "util-crypto-hash", \
37 syscall, \
38 filename)
39
40void
41GNUNET_CRYPTO_hash (const void *block,
42 size_t size,
43 struct GNUNET_HashCode *ret)
44{
45 BENCHMARK_START (hash);
46 gcry_md_hash_buffer (GCRY_MD_SHA512, ret, block, size);
47 BENCHMARK_END (hash);
48}
49
50
51/* ***************** binary-ASCII encoding *************** */
52
53
54void
55GNUNET_CRYPTO_hash_to_enc (const struct GNUNET_HashCode *block,
56 struct GNUNET_CRYPTO_HashAsciiEncoded *result)
57{
58 char *np;
59
60 np = GNUNET_STRINGS_data_to_string ((const unsigned char *) block,
61 sizeof(struct GNUNET_HashCode),
62 (char *) result,
63 sizeof(struct
64 GNUNET_CRYPTO_HashAsciiEncoded)
65 - 1);
66 GNUNET_assert (NULL != np);
67 *np = '\0';
68}
69
70
71enum GNUNET_GenericReturnValue
72GNUNET_CRYPTO_hash_from_string2 (const char *enc,
73 size_t enclen,
74 struct GNUNET_HashCode *result)
75{
76 char upper_enc[enclen];
77 char *up_ptr = upper_enc;
78
79 GNUNET_STRINGS_utf8_toupper (enc, up_ptr);
80
81 return GNUNET_STRINGS_string_to_data (upper_enc, enclen,
82 (unsigned char *) result,
83 sizeof(struct GNUNET_HashCode));
84}
85
86
87unsigned int
88GNUNET_CRYPTO_hash_distance_u32 (const struct GNUNET_HashCode *a,
89 const struct GNUNET_HashCode *b)
90{
91 unsigned int x1 = (a->bits[1] - b->bits[1]) >> 16;
92 unsigned int x2 = (b->bits[1] - a->bits[1]) >> 16;
93
94 return(x1 * x2);
95}
96
97
98void
99GNUNET_CRYPTO_hash_create_random (enum GNUNET_CRYPTO_Quality mode,
100 struct GNUNET_HashCode *result)
101{
102 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(uint32_t)) - 1;
103 i >= 0;
104 i--)
105 result->bits[i] = GNUNET_CRYPTO_random_u32 (mode, UINT32_MAX);
106}
107
108
109void
110GNUNET_CRYPTO_hash_difference (const struct GNUNET_HashCode *a,
111 const struct GNUNET_HashCode *b,
112 struct GNUNET_HashCode *result)
113{
114 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(unsigned int)) - 1;
115 i >= 0;
116 i--)
117 result->bits[i] = b->bits[i] - a->bits[i];
118}
119
120
121void
122GNUNET_CRYPTO_hash_sum (const struct GNUNET_HashCode *a,
123 const struct GNUNET_HashCode *delta, struct
124 GNUNET_HashCode *result)
125{
126 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(unsigned int)) - 1;
127 i >= 0;
128 i--)
129 result->bits[i] = delta->bits[i] + a->bits[i];
130}
131
132
133void
134GNUNET_CRYPTO_hash_xor (const struct GNUNET_HashCode *a,
135 const struct GNUNET_HashCode *b,
136 struct GNUNET_HashCode *result)
137{
138 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(unsigned int)) - 1;
139 i >= 0;
140 i--)
141 result->bits[i] = a->bits[i] ^ b->bits[i];
142}
143
144
145void
146GNUNET_CRYPTO_hash_to_aes_key (const struct GNUNET_HashCode *hc,
147 struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
148 struct
149 GNUNET_CRYPTO_SymmetricInitializationVector *iv)
150{
151 GNUNET_assert (GNUNET_YES ==
152 GNUNET_CRYPTO_kdf (
153 skey,
154 sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
155 "Hash key derivation",
156 strlen ("Hash key derivation"),
157 hc, sizeof(struct GNUNET_HashCode),
158 NULL, 0));
159 GNUNET_assert (GNUNET_YES ==
160 GNUNET_CRYPTO_kdf (
161 iv,
162 sizeof(struct GNUNET_CRYPTO_SymmetricInitializationVector),
163 "Initialization vector derivation",
164 strlen ("Initialization vector derivation"),
165 hc, sizeof(struct GNUNET_HashCode),
166 NULL, 0));
167}
168
169
170int
171GNUNET_CRYPTO_hash_get_bit_ltr (const struct GNUNET_HashCode *code,
172 unsigned int bit)
173{
174 GNUNET_assert (bit < 8 * sizeof(struct GNUNET_HashCode));
175 return (((unsigned char *) code)[bit >> 3] & (128 >> (bit & 7))) > 0;
176}
177
178
179int
180GNUNET_CRYPTO_hash_get_bit_rtl (const struct GNUNET_HashCode *code,
181 unsigned int bit)
182{
183 GNUNET_assert (bit < 8 * sizeof(struct GNUNET_HashCode));
184 return (((unsigned char *) code)[bit >> 3] & (1 << (bit & 7))) > 0;
185}
186
187
188unsigned int
189GNUNET_CRYPTO_hash_matching_bits (const struct GNUNET_HashCode *first,
190 const struct GNUNET_HashCode *second)
191{
192 for (unsigned int i = 0; i < sizeof(struct GNUNET_HashCode) * 8; i++)
193 if (GNUNET_CRYPTO_hash_get_bit_rtl (first, i) !=
194 GNUNET_CRYPTO_hash_get_bit_rtl (second, i))
195 return i;
196 return sizeof(struct GNUNET_HashCode) * 8;
197}
198
199
200int
201GNUNET_CRYPTO_hash_cmp (const struct GNUNET_HashCode *h1,
202 const struct GNUNET_HashCode *h2)
203{
204 unsigned int *i1;
205 unsigned int *i2;
206
207 i1 = (unsigned int *) h1;
208 i2 = (unsigned int *) h2;
209 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(unsigned int)) - 1;
210 i >= 0;
211 i--)
212 {
213 if (i1[i] > i2[i])
214 return 1;
215 if (i1[i] < i2[i])
216 return -1;
217 }
218 return 0;
219}
220
221
222int
223GNUNET_CRYPTO_hash_xorcmp (const struct GNUNET_HashCode *h1,
224 const struct GNUNET_HashCode *h2,
225 const struct GNUNET_HashCode *target)
226{
227 unsigned int d1;
228 unsigned int d2;
229
230 for (ssize_t i = sizeof(struct GNUNET_HashCode) / sizeof(unsigned int) - 1;
231 i >= 0;
232 i--)
233 {
234 d1 = ((unsigned int *) h1)[i] ^ ((unsigned int *) target)[i];
235 d2 = ((unsigned int *) h2)[i] ^ ((unsigned int *) target)[i];
236 if (d1 > d2)
237 return 1;
238 else if (d1 < d2)
239 return -1;
240 }
241 return 0;
242}
243
244
245void
246GNUNET_CRYPTO_hmac_derive_key (struct GNUNET_CRYPTO_AuthKey *key,
247 const struct
248 GNUNET_CRYPTO_SymmetricSessionKey *rkey,
249 const void *salt, size_t salt_len, ...)
250{
251 va_list argp;
252
253 va_start (argp, salt_len);
254 GNUNET_CRYPTO_hmac_derive_key_v (key, rkey, salt, salt_len, argp);
255 va_end (argp);
256}
257
258
259void
260GNUNET_CRYPTO_hmac_derive_key_v (struct GNUNET_CRYPTO_AuthKey *key,
261 const struct
262 GNUNET_CRYPTO_SymmetricSessionKey *rkey,
263 const void *salt, size_t salt_len,
264 va_list argp)
265{
266 GNUNET_CRYPTO_kdf_v (key->key, sizeof(key->key),
267 salt, salt_len,
268 rkey, sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
269 argp);
270}
271
272
273void
274GNUNET_CRYPTO_hmac_raw (const void *key, size_t key_len,
275 const void *plaintext, size_t plaintext_len,
276 struct GNUNET_HashCode *hmac)
277{
278 static int once;
279 static gcry_md_hd_t md;
280 const unsigned char *mc;
281
282 if (! once)
283 {
284 once = 1;
285 GNUNET_assert (GPG_ERR_NO_ERROR ==
286 gcry_md_open (&md, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC));
287 }
288 else
289 {
290 gcry_md_reset (md);
291 }
292 gcry_md_setkey (md, key, key_len);
293 gcry_md_write (md, plaintext, plaintext_len);
294 mc = gcry_md_read (md, GCRY_MD_SHA512);
295 GNUNET_assert (NULL != mc);
296 GNUNET_memcpy (hmac->bits, mc, sizeof(hmac->bits));
297}
298
299
300void
301GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key,
302 const void *plaintext, size_t plaintext_len,
303 struct GNUNET_HashCode *hmac)
304{
305 GNUNET_CRYPTO_hmac_raw ((void *) key->key, sizeof(key->key),
306 plaintext, plaintext_len,
307 hmac);
308}
309
310
311struct GNUNET_HashContext
312{
313 /**
314 * Internal state of the hash function.
315 */
316 gcry_md_hd_t hd;
317};
318
319
320struct GNUNET_HashContext *
321GNUNET_CRYPTO_hash_context_start ()
322{
323 struct GNUNET_HashContext *hc;
324
325 BENCHMARK_START (hash_context_start);
326
327 hc = GNUNET_new (struct GNUNET_HashContext);
328 GNUNET_assert (0 ==
329 gcry_md_open (&hc->hd,
330 GCRY_MD_SHA512,
331 0));
332
333 BENCHMARK_END (hash_context_start);
334
335 return hc;
336}
337
338
339void
340GNUNET_CRYPTO_hash_context_read (struct GNUNET_HashContext *hc,
341 const void *buf,
342 size_t size)
343{
344 BENCHMARK_START (hash_context_read);
345 gcry_md_write (hc->hd, buf, size);
346 BENCHMARK_END (hash_context_read);
347}
348
349
350struct GNUNET_HashContext *
351GNUNET_CRYPTO_hash_context_copy (const struct GNUNET_HashContext *hc)
352{
353 struct GNUNET_HashContext *cp;
354
355 cp = GNUNET_new (struct GNUNET_HashContext);
356 GNUNET_assert (0 ==
357 gcry_md_copy (&cp->hd,
358 hc->hd));
359 return cp;
360}
361
362
363void
364GNUNET_CRYPTO_hash_context_finish (struct GNUNET_HashContext *hc,
365 struct GNUNET_HashCode *r_hash)
366{
367 const void *res = gcry_md_read (hc->hd, 0);
368
369 BENCHMARK_START (hash_context_finish);
370
371 GNUNET_assert (NULL != res);
372 if (NULL != r_hash)
373 GNUNET_memcpy (r_hash,
374 res,
375 sizeof(struct GNUNET_HashCode));
376 GNUNET_CRYPTO_hash_context_abort (hc);
377 BENCHMARK_END (hash_context_finish);
378}
379
380
381void
382GNUNET_CRYPTO_hash_context_abort (struct GNUNET_HashContext *hc)
383{
384 gcry_md_close (hc->hd);
385 GNUNET_free (hc);
386}
387
388
389/* end of crypto_hash.c */
diff --git a/src/util/crypto_hash_file.c b/src/util/crypto_hash_file.c
deleted file mode 100644
index 8e46d71fd..000000000
--- a/src/util/crypto_hash_file.c
+++ /dev/null
@@ -1,243 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013 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 util/crypto_hash_file.c
23 * @brief incremental hashing of files
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gcrypt.h>
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-hash-file", \
31 __VA_ARGS__)
32
33#define LOG_STRERROR_FILE(kind, syscall, \
34 filename) GNUNET_log_from_strerror_file (kind, \
35 "util-crypto-hash-file", \
36 syscall, \
37 filename)
38
39
40/**
41 * Context used when hashing a file.
42 */
43struct GNUNET_CRYPTO_FileHashContext
44{
45 /**
46 * Function to call upon completion.
47 */
48 GNUNET_CRYPTO_HashCompletedCallback callback;
49
50 /**
51 * Closure for callback.
52 */
53 void *callback_cls;
54
55 /**
56 * IO buffer.
57 */
58 unsigned char *buffer;
59
60 /**
61 * Name of the file we are hashing.
62 */
63 char *filename;
64
65 /**
66 * File descriptor.
67 */
68 struct GNUNET_DISK_FileHandle *fh;
69
70 /**
71 * Cummulated hash.
72 */
73 gcry_md_hd_t md;
74
75 /**
76 * Size of the file.
77 */
78 uint64_t fsize;
79
80 /**
81 * Current offset.
82 */
83 uint64_t offset;
84
85 /**
86 * Current task for hashing.
87 */
88 struct GNUNET_SCHEDULER_Task *task;
89
90 /**
91 * Priority we use.
92 */
93 enum GNUNET_SCHEDULER_Priority priority;
94
95 /**
96 * Blocksize.
97 */
98 size_t bsize;
99};
100
101
102/**
103 * Report result of hash computation to callback
104 * and free associated resources.
105 */
106static void
107file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc,
108 const struct GNUNET_HashCode *res)
109{
110 fhc->callback (fhc->callback_cls, res);
111 GNUNET_free (fhc->filename);
112 if (! GNUNET_DISK_handle_invalid (fhc->fh))
113 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
114 gcry_md_close (fhc->md);
115 GNUNET_free (fhc); /* also frees fhc->buffer */
116}
117
118
119/**
120 * File hashing task.
121 *
122 * @param cls closure
123 */
124static void
125file_hash_task (void *cls)
126{
127 struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
128 struct GNUNET_HashCode *res;
129 size_t delta;
130 ssize_t sret;
131
132 fhc->task = NULL;
133 GNUNET_assert (fhc->offset <= fhc->fsize);
134 delta = fhc->bsize;
135 if (fhc->fsize - fhc->offset < delta)
136 delta = fhc->fsize - fhc->offset;
137 sret = GNUNET_DISK_file_read (fhc->fh,
138 fhc->buffer,
139 delta);
140 if ((sret < 0) ||
141 (delta != (size_t) sret))
142 {
143 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
144 "read",
145 fhc->filename);
146 file_hash_finish (fhc,
147 NULL);
148 return;
149 }
150 gcry_md_write (fhc->md,
151 fhc->buffer,
152 delta);
153 fhc->offset += delta;
154 if (fhc->offset == fhc->fsize)
155 {
156 res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md,
157 GCRY_MD_SHA512);
158 file_hash_finish (fhc, res);
159 return;
160 }
161 fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority,
162 &file_hash_task,
163 fhc);
164}
165
166
167/**
168 * Compute the hash of an entire file.
169 *
170 * @param priority scheduling priority to use
171 * @param filename name of file to hash
172 * @param blocksize number of bytes to process in one task
173 * @param callback function to call upon completion
174 * @param callback_cls closure for @a callback
175 * @return NULL on (immediate) error
176 */
177struct GNUNET_CRYPTO_FileHashContext *
178GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority,
179 const char *filename,
180 size_t blocksize,
181 GNUNET_CRYPTO_HashCompletedCallback callback,
182 void *callback_cls)
183{
184 struct GNUNET_CRYPTO_FileHashContext *fhc;
185
186 GNUNET_assert (blocksize > 0);
187 fhc =
188 GNUNET_malloc (sizeof(struct GNUNET_CRYPTO_FileHashContext) + blocksize);
189 fhc->callback = callback;
190 fhc->callback_cls = callback_cls;
191 fhc->buffer = (unsigned char *) &fhc[1];
192 fhc->filename = GNUNET_strdup (filename);
193 if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0))
194 {
195 GNUNET_break (0);
196 GNUNET_free (fhc);
197 return NULL;
198 }
199 fhc->bsize = blocksize;
200 if (GNUNET_OK !=
201 GNUNET_DISK_file_size (filename,
202 &fhc->fsize,
203 GNUNET_NO,
204 GNUNET_YES))
205 {
206 GNUNET_free (fhc->filename);
207 GNUNET_free (fhc);
208 return NULL;
209 }
210 fhc->fh = GNUNET_DISK_file_open (filename,
211 GNUNET_DISK_OPEN_READ,
212 GNUNET_DISK_PERM_NONE);
213 if (! fhc->fh)
214 {
215 GNUNET_free (fhc->filename);
216 GNUNET_free (fhc);
217 return NULL;
218 }
219 fhc->priority = priority;
220 fhc->task = GNUNET_SCHEDULER_add_with_priority (priority,
221 &file_hash_task,
222 fhc);
223 return fhc;
224}
225
226
227/**
228 * Cancel a file hashing operation.
229 *
230 * @param fhc operation to cancel (callback must not yet have been invoked)
231 */
232void
233GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc)
234{
235 GNUNET_SCHEDULER_cancel (fhc->task);
236 GNUNET_free (fhc->filename);
237 GNUNET_break (GNUNET_OK ==
238 GNUNET_DISK_file_close (fhc->fh));
239 GNUNET_free (fhc);
240}
241
242
243/* end of crypto_hash_file.c */
diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c
deleted file mode 100644
index 4e4496819..000000000
--- a/src/util/crypto_hkdf.c
+++ /dev/null
@@ -1,360 +0,0 @@
1/*
2 Copyright (c) 2010 Nils Durner
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23/**
24 * @file src/util/crypto_hkdf.c
25 * @brief Hash-based KDF as defined in RFC 5869
26 * @see http://www.rfc-editor.org/rfc/rfc5869.txt
27 * @todo remove GNUNET references
28 * @author Nils Durner
29 *
30 * The following list of people have reviewed this code and considered
31 * it correct on the date given (if you reviewed it, please
32 * have your name added to the list):
33 *
34 * - Christian Grothoff (08.10.2010)
35 * - Nathan Evans (08.10.2010)
36 * - Matthias Wachs (08.10.2010)
37 */
38
39#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-hkdf", __VA_ARGS__)
40
41/**
42 * Set this to 0 if you compile this code outside of GNUnet.
43 */
44#define GNUNET_BUILD 1
45
46/**
47 * Enable debugging.
48 */
49#define DEBUG_HKDF 0
50
51
52#if GNUNET_BUILD
53#include "platform.h"
54#include "gnunet_crypto_lib.h"
55#include "benchmark.h"
56#else
57#define GNUNET_NO 0
58#define GNUNET_YES 1
59#define GNUNET_SYSERR -1
60#include <stdlib.h>
61#endif
62
63#include <gcrypt.h>
64
65
66/**
67 * @brief Compute the HMAC
68 * @todo use chunked buffers
69 * @param mac gcrypt MAC handle
70 * @param key HMAC key
71 * @param key_len length of key
72 * @param buf message to be processed
73 * @param buf_len length of buf
74 * @return HMAC, freed by caller via gcry_md_close/_reset
75 */
76static const void *
77doHMAC (gcry_md_hd_t mac, const void *key, size_t key_len, const void *buf,
78 size_t buf_len)
79{
80 if (GPG_ERR_NO_ERROR != gcry_md_setkey (mac, key, key_len))
81 {
82 GNUNET_break (0);
83 return NULL;
84 }
85 gcry_md_write (mac, buf, buf_len);
86
87 return (const void *) gcry_md_read (mac, 0);
88}
89
90
91/**
92 * @brief Generate pseudo-random key
93 * @param mac gcrypt HMAC handle
94 * @param xts salt
95 * @param xts_len length of the @a xts salt
96 * @param skm source key material
97 * @param skm_len length of @a skm
98 * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes)
99 * @return #GNUNET_YES on success
100 */
101static int
102getPRK (gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm,
103 size_t skm_len, void *prk)
104{
105 const void *ret;
106 size_t dlen;
107
108 dlen = gcry_md_get_algo_dlen (gcry_md_get_algo (mac));
109
110 /* sanity check to bound stack allocation */
111 GNUNET_assert (dlen <= 512);
112
113 /* From RFC 5869:
114 * salt - optional salt value (a non-secret random value);
115 * if not provided, it is set to a string of HashLen zeros. */
116
117 if (xts_len == 0)
118 {
119 char zero_salt[dlen];
120 memset (zero_salt, 0, dlen);
121 ret = doHMAC (mac, zero_salt, dlen, skm, skm_len);
122 }
123 else
124 {
125 ret = doHMAC (mac, xts, xts_len, skm, skm_len);
126 }
127 if (ret == NULL)
128 return GNUNET_SYSERR;
129 GNUNET_memcpy (prk, ret, dlen);
130
131 return GNUNET_YES;
132}
133
134
135#if DEBUG_HKDF
136static void
137dump (const char *src, const void *p, unsigned int l)
138{
139 unsigned int i;
140
141 printf ("\n%s: ", src);
142 for (i = 0; i < l; i++)
143 {
144 printf ("%2x", (int) ((const unsigned char *) p)[i]);
145 }
146 printf ("\n");
147}
148
149
150#endif
151
152
153/**
154 * @brief Derive key
155 * @param result buffer for the derived key, allocated by caller
156 * @param out_len desired length of the derived key
157 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_...
158 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_...
159 * @param xts salt
160 * @param xts_len length of @a xts
161 * @param skm source key material
162 * @param skm_len length of @a skm
163 * @param argp va_list of void * & size_t pairs for context chunks
164 * @return #GNUNET_YES on success
165 */
166int
167GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
168 const void *xts, size_t xts_len, const void *skm,
169 size_t skm_len, va_list argp)
170{
171 gcry_md_hd_t xtr;
172 gcry_md_hd_t prf;
173 const void *hc;
174 unsigned long i;
175 unsigned long t;
176 unsigned long d;
177 unsigned int k = gcry_md_get_algo_dlen (prf_algo);
178 unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo);
179 char prk[xtr_len];
180 int ret;
181 size_t ctx_len;
182 va_list args;
183
184 BENCHMARK_START (hkdf);
185
186 if (0 == k)
187 return GNUNET_SYSERR;
188 if (GPG_ERR_NO_ERROR !=
189 gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC))
190 return GNUNET_SYSERR;
191 if (GPG_ERR_NO_ERROR !=
192 gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC))
193 {
194 gcry_md_close (xtr);
195 return GNUNET_SYSERR;
196 }
197 va_copy (args, argp);
198
199 ctx_len = 0;
200 while (NULL != va_arg (args, void *))
201 {
202 size_t nxt = va_arg (args, size_t);
203 if (nxt + ctx_len < nxt)
204 {
205 /* integer overflow */
206 GNUNET_break (0);
207 va_end (args);
208 goto hkdf_error;
209 }
210 ctx_len += nxt;
211 }
212
213 va_end (args);
214
215 if ( (k + ctx_len < ctx_len) ||
216 (k + ctx_len + 1 < ctx_len) )
217 {
218 /* integer overflow */
219 GNUNET_break (0);
220 goto hkdf_error;
221 }
222
223 memset (result, 0, out_len);
224 if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES)
225 goto hkdf_error;
226#if DEBUG_HKDF
227 dump ("PRK", prk, xtr_len);
228#endif
229
230 t = out_len / k;
231 d = out_len % k;
232
233 /* K(1) */
234 {
235 size_t plain_len = k + ctx_len + 1;
236 char *plain;
237 const void *ctx;
238 char *dst;
239
240 plain = GNUNET_malloc (plain_len);
241 dst = plain + k;
242 va_copy (args, argp);
243 while ((ctx = va_arg (args, void *)))
244 {
245 size_t len;
246
247 len = va_arg (args, size_t);
248 GNUNET_memcpy (dst, ctx, len);
249 dst += len;
250 }
251 va_end (args);
252
253 if (t > 0)
254 {
255 plain[k + ctx_len] = (char) 1;
256#if DEBUG_HKDF
257 dump ("K(1)", plain, plain_len);
258#endif
259 hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
260 if (hc == NULL)
261 {
262 GNUNET_free (plain);
263 goto hkdf_error;
264 }
265 GNUNET_memcpy (result, hc, k);
266 result += k;
267 }
268
269 /* K(i+1) */
270 for (i = 1; i < t; i++)
271 {
272 GNUNET_memcpy (plain, result - k, k);
273 plain[k + ctx_len] = (char) (i + 1);
274 gcry_md_reset (prf);
275#if DEBUG_HKDF
276 dump ("K(i+1)", plain, plain_len);
277#endif
278 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
279 if (hc == NULL)
280 {
281 GNUNET_free (plain);
282 goto hkdf_error;
283 }
284 GNUNET_memcpy (result, hc, k);
285 result += k;
286 }
287
288 /* K(t):d */
289 if (d > 0)
290 {
291 if (t > 0)
292 {
293 GNUNET_memcpy (plain, result - k, k);
294 i++;
295 }
296 plain[k + ctx_len] = (char) i;
297 gcry_md_reset (prf);
298#if DEBUG_HKDF
299 dump ("K(t):d", plain, plain_len);
300#endif
301 if (t > 0)
302 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
303 else
304 hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
305 if (hc == NULL)
306 {
307 GNUNET_free (plain);
308 goto hkdf_error;
309 }
310 GNUNET_memcpy (result, hc, d);
311 }
312#if DEBUG_HKDF
313 dump ("result", result - k, out_len);
314#endif
315
316 ret = GNUNET_YES;
317 GNUNET_free (plain);
318 goto hkdf_ok;
319 }
320hkdf_error:
321 ret = GNUNET_SYSERR;
322hkdf_ok:
323 gcry_md_close (xtr);
324 gcry_md_close (prf);
325 BENCHMARK_END (hkdf);
326 return ret;
327}
328
329
330/**
331 * @brief Derive key
332 * @param result buffer for the derived key, allocated by caller
333 * @param out_len desired length of the derived key
334 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_...
335 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_...
336 * @param xts salt
337 * @param xts_len length of @a xts
338 * @param skm source key material
339 * @param skm_len length of @a skm
340 * @return #GNUNET_YES on success
341 */
342int
343GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo,
344 const void *xts, size_t xts_len, const void *skm,
345 size_t skm_len, ...)
346{
347 va_list argp;
348 int ret;
349
350 va_start (argp, skm_len);
351 ret =
352 GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len,
353 skm, skm_len, argp);
354 va_end (argp);
355
356 return ret;
357}
358
359
360/* end of crypto_hkdf.c */
diff --git a/src/util/crypto_kdf.c b/src/util/crypto_kdf.c
deleted file mode 100644
index 0dc734549..000000000
--- a/src/util/crypto_kdf.c
+++ /dev/null
@@ -1,175 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010 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 src/util/crypto_kdf.c
23 * @brief Key derivation
24 * @author Nils Durner
25 * @author Jeffrey Burdges <burdges@gnunet.org>
26 */
27
28#include <gcrypt.h>
29
30#include "platform.h"
31#include "gnunet_crypto_lib.h"
32
33#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-kdf", __VA_ARGS__)
34
35/**
36 * @brief Derive key
37 * @param result buffer for the derived key, allocated by caller
38 * @param out_len desired length of the derived key
39 * @param xts salt
40 * @param xts_len length of @a xts
41 * @param skm source key material
42 * @param skm_len length of @a skm
43 * @param argp va_list of void * & size_t pairs for context chunks
44 * @return #GNUNET_YES on success
45 */
46int
47GNUNET_CRYPTO_kdf_v (void *result,
48 size_t out_len,
49 const void *xts,
50 size_t xts_len,
51 const void *skm,
52 size_t skm_len,
53 va_list argp)
54{
55 /*
56 * "Finally, we point out to a particularly advantageous instantiation using
57 * HMAC-SHA512 as XTR and HMAC-SHA256 in PRF* (in which case the output from SHA-512 is
58 * truncated to 256 bits). This makes sense in two ways: First, the extraction part is where we need a
59 * stronger hash function due to the unconventional demand from the hash function in the extraction
60 * setting. Second, as shown in Section 6, using HMAC with a truncated output as an extractor
61 * allows to prove the security of HKDF under considerably weaker assumptions on the underlying
62 * hash function."
63 *
64 * http://eprint.iacr.org/2010/264
65 *///
66 return GNUNET_CRYPTO_hkdf_v (result,
67 out_len,
68 GCRY_MD_SHA512,
69 GCRY_MD_SHA256,
70 xts,
71 xts_len,
72 skm,
73 skm_len,
74 argp);
75}
76
77
78/**
79 * @brief Derive key
80 * @param result buffer for the derived key, allocated by caller
81 * @param out_len desired length of the derived key
82 * @param xts salt
83 * @param xts_len length of @a xts
84 * @param skm source key material
85 * @param skm_len length of @a skm
86 * @param ... void * & size_t pairs for context chunks
87 * @return #GNUNET_YES on success
88 */
89int
90GNUNET_CRYPTO_kdf (void *result,
91 size_t out_len,
92 const void *xts,
93 size_t xts_len,
94 const void *skm,
95 size_t skm_len, ...)
96{
97 va_list argp;
98 int ret;
99
100 va_start (argp, skm_len);
101 ret = GNUNET_CRYPTO_kdf_v (result,
102 out_len,
103 xts,
104 xts_len,
105 skm,
106 skm_len,
107 argp);
108 va_end (argp);
109
110 return ret;
111}
112
113
114/**
115 * Deterministically generate a pseudo-random number uniformly from the
116 * integers modulo a libgcrypt mpi.
117 *
118 * @param[out] r MPI value set to the FDH
119 * @param n MPI to work modulo
120 * @param xts salt
121 * @param xts_len length of @a xts
122 * @param skm source key material
123 * @param skm_len length of @a skm
124 * @param ctx context string
125 */
126void
127GNUNET_CRYPTO_kdf_mod_mpi (gcry_mpi_t *r,
128 gcry_mpi_t n,
129 const void *xts, size_t xts_len,
130 const void *skm, size_t skm_len,
131 const char *ctx)
132{
133 gcry_error_t rc;
134 unsigned int nbits;
135 size_t rsize;
136 uint16_t ctr;
137
138 nbits = gcry_mpi_get_nbits (n);
139 /* GNUNET_assert (nbits > 512); */
140
141 ctr = 0;
142 while (1)
143 {
144 /* Ain't clear if n is always divisible by 8 */
145 uint8_t buf[ (nbits - 1) / 8 + 1 ];
146 uint16_t ctr_nbo = htons (ctr);
147
148 rc = GNUNET_CRYPTO_kdf (buf,
149 sizeof(buf),
150 xts, xts_len,
151 skm, skm_len,
152 ctx, strlen (ctx),
153 &ctr_nbo, sizeof(ctr_nbo),
154 NULL, 0);
155 GNUNET_assert (GNUNET_YES == rc);
156
157 rc = gcry_mpi_scan (r,
158 GCRYMPI_FMT_USG,
159 (const unsigned char *) buf,
160 sizeof(buf),
161 &rsize);
162 GNUNET_assert (0 == rc); /* Allocation error? */
163
164 gcry_mpi_clear_highbit (*r, nbits);
165 GNUNET_assert (0 == gcry_mpi_test_bit (*r, nbits));
166 ++ctr;
167 /* We reject this FDH if either *r > n and retry with another ctr */
168 if (0 > gcry_mpi_cmp (*r, n))
169 break;
170 gcry_mpi_release (*r);
171 }
172}
173
174
175/* end of crypto_kdf.c */
diff --git a/src/util/crypto_mpi.c b/src/util/crypto_mpi.c
deleted file mode 100644
index 6df47c7e1..000000000
--- a/src/util/crypto_mpi.c
+++ /dev/null
@@ -1,177 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 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 util/crypto_mpi.c
23 * @brief Helper functions for libgcrypt MPIs
24 * @author Christian Grothoff
25 * @author Florian Dold
26 */
27#include "platform.h"
28#include <gcrypt.h>
29#include "gnunet_crypto_lib.h"
30
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-mpi", __VA_ARGS__)
33
34/**
35 * Log an error message at log-level 'level' that indicates
36 * a failure of the command 'cmd' with the message given
37 * by gcry_strerror(rc).
38 */
39#define LOG_GCRY(level, cmd, rc) do { LOG (level, _ ( \
40 "`%s' failed at %s:%d with error: %s\n"), \
41 cmd, __FILE__, __LINE__, \
42 gcry_strerror (rc)); } while (0)
43
44
45/**
46 * If target != size, move @a target bytes to the end of the size-sized
47 * buffer and zero out the first @a target - @a size bytes.
48 *
49 * @param buf original buffer
50 * @param size number of bytes in @a buf
51 * @param target target size of the buffer
52 */
53static void
54adjust (void *buf,
55 size_t size,
56 size_t target)
57{
58 char *p = buf;
59
60 if (size < target)
61 {
62 memmove (&p[target - size], buf, size);
63 memset (buf, 0, target - size);
64 }
65}
66
67
68/**
69 * Output the given MPI value to the given buffer in
70 * network byte order.
71 * The MPI @a val may not be negative.
72 *
73 * @param buf where to output to
74 * @param size number of bytes in @a buf
75 * @param val value to write to @a buf
76 */
77void
78GNUNET_CRYPTO_mpi_print_unsigned (void *buf,
79 size_t size,
80 gcry_mpi_t val)
81{
82 size_t rsize;
83 int rc;
84
85 if (gcry_mpi_get_flag (val, GCRYMPI_FLAG_OPAQUE))
86 {
87 /* Store opaque MPIs left aligned into the buffer. */
88 unsigned int nbits;
89 const void *p;
90
91 p = gcry_mpi_get_opaque (val, &nbits);
92 GNUNET_assert (p);
93 rsize = (nbits + 7) / 8;
94 if (rsize > size)
95 rsize = size;
96 GNUNET_memcpy (buf, p, rsize);
97 if (rsize < size)
98 memset (buf + rsize, 0, size - rsize);
99 }
100 else
101 {
102 /* Store regular MPIs as unsigned integers right aligned into
103 the buffer. */
104 rsize = size;
105 if (0 !=
106 (rc = gcry_mpi_print (GCRYMPI_FMT_USG,
107 buf,
108 rsize, &rsize,
109 val)))
110 {
111 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
112 "gcry_mpi_print",
113 rc);
114 GNUNET_assert (0);
115 }
116 adjust (buf, rsize, size);
117 }
118}
119
120
121/**
122 * Convert data buffer into MPI value.
123 * The buffer is interpreted as network
124 * byte order, unsigned integer.
125 *
126 * @param result where to store MPI value (allocated)
127 * @param data raw data (GCRYMPI_FMT_USG)
128 * @param size number of bytes in @a data
129 */
130void
131GNUNET_CRYPTO_mpi_scan_unsigned (gcry_mpi_t *result,
132 const void *data,
133 size_t size)
134{
135 int rc;
136
137 if (0 != (rc = gcry_mpi_scan (result,
138 GCRYMPI_FMT_USG,
139 data, size, &size)))
140 {
141 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
142 "gcry_mpi_scan",
143 rc);
144 GNUNET_assert (0);
145 }
146}
147
148
149/**
150 * Convert little endian data buffer into MPI value.
151 * The buffer is interpreted as network
152 * byte order, unsigned integer.
153 *
154 * @param result where to store MPI value (allocated)
155 * @param data raw data (GCRYMPI_FMT_USG)
156 * @param size number of bytes in @a data
157 */
158void
159GNUNET_CRYPTO_mpi_scan_unsigned_le (gcry_mpi_t *result,
160 const void *data,
161 size_t size)
162{
163 int rc;
164
165 if (0 != (rc = gcry_mpi_scan (result,
166 GCRYMPI_FMT_USG,
167 data, size, &size)))
168 {
169 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
170 "gcry_mpi_scan",
171 rc);
172 GNUNET_assert (0);
173 }
174}
175
176
177/* end of crypto_mpi.c */
diff --git a/src/util/crypto_paillier.c b/src/util/crypto_paillier.c
deleted file mode 100644
index 97dfad630..000000000
--- a/src/util/crypto_paillier.c
+++ /dev/null
@@ -1,484 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014 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 util/crypto_paillier.c
23 * @brief implementation of the paillier crypto system with libgcrypt
24 * @author Florian Dold
25 * @author Christian Fuchs
26 */
27#include "platform.h"
28#include <gcrypt.h>
29#include "gnunet_util_lib.h"
30
31
32/**
33 * Create a freshly generated paillier public key.
34 *
35 * @param[out] public_key Where to store the public key?
36 * @param[out] private_key Where to store the private key?
37 */
38void
39GNUNET_CRYPTO_paillier_create (struct
40 GNUNET_CRYPTO_PaillierPublicKey *public_key,
41 struct GNUNET_CRYPTO_PaillierPrivateKey *
42 private_key)
43{
44 gcry_mpi_t p;
45 gcry_mpi_t q;
46 gcry_mpi_t phi;
47 gcry_mpi_t mu;
48 gcry_mpi_t n;
49
50 /* Generate two distinct primes. The probability that the loop body
51 is executed more than once is very very low... */
52 p = NULL;
53 q = NULL;
54 do
55 {
56 if (NULL != p)
57 gcry_mpi_release (p);
58 if (NULL != q)
59 gcry_mpi_release (q);
60 GNUNET_assert (0 ==
61 gcry_prime_generate (&p,
62 GNUNET_CRYPTO_PAILLIER_BITS / 2,
63 0, NULL, NULL, NULL,
64 GCRY_STRONG_RANDOM, 0));
65 GNUNET_assert (0 ==
66 gcry_prime_generate (&q,
67 GNUNET_CRYPTO_PAILLIER_BITS / 2,
68 0, NULL, NULL, NULL,
69 GCRY_STRONG_RANDOM, 0));
70 }
71 while (0 == gcry_mpi_cmp (p, q));
72 /* n = p * q */
73 GNUNET_assert (NULL != (n = gcry_mpi_new (0)));
74 gcry_mpi_mul (n,
75 p,
76 q);
77 GNUNET_CRYPTO_mpi_print_unsigned (public_key,
78 sizeof(struct
79 GNUNET_CRYPTO_PaillierPublicKey),
80 n);
81
82 /* compute phi(n) = (p-1)(q-1) */
83 GNUNET_assert (NULL != (phi = gcry_mpi_new (0)));
84 gcry_mpi_sub_ui (p, p, 1);
85 gcry_mpi_sub_ui (q, q, 1);
86 gcry_mpi_mul (phi, p, q);
87 gcry_mpi_release (p);
88 gcry_mpi_release (q);
89
90 /* lambda equals phi(n) in the simplified key generation */
91 GNUNET_CRYPTO_mpi_print_unsigned (private_key->lambda,
92 GNUNET_CRYPTO_PAILLIER_BITS / 8,
93 phi);
94 /* mu = phi^{-1} mod n, as we use g = n + 1 */
95 GNUNET_assert (NULL != (mu = gcry_mpi_new (0)));
96 GNUNET_assert (0 != gcry_mpi_invm (mu,
97 phi,
98 n));
99 gcry_mpi_release (phi);
100 gcry_mpi_release (n);
101 GNUNET_CRYPTO_mpi_print_unsigned (private_key->mu,
102 GNUNET_CRYPTO_PAILLIER_BITS / 8,
103 mu);
104 gcry_mpi_release (mu);
105}
106
107
108/**
109 * Encrypt a plaintext with a paillier public key.
110 *
111 * @param public_key Public key to use.
112 * @param m Plaintext to encrypt.
113 * @param desired_ops How many homomorphic ops the caller intends to use
114 * @param[out] ciphertext Encryption of @a plaintext with @a public_key.
115 * @return guaranteed number of supported homomorphic operations >= 1,
116 * or desired_ops, in case that is lower,
117 * or -1 if less than one homomorphic operation is possible
118 */
119int
120GNUNET_CRYPTO_paillier_encrypt1 (const struct
121 GNUNET_CRYPTO_PaillierPublicKey *public_key,
122 const gcry_mpi_t m,
123 int desired_ops,
124 struct GNUNET_CRYPTO_PaillierCiphertext *
125 ciphertext)
126{
127 int possible_opts;
128 gcry_mpi_t n_square;
129 gcry_mpi_t r;
130 gcry_mpi_t c;
131 gcry_mpi_t n;
132 gcry_mpi_t tmp1;
133 gcry_mpi_t tmp2;
134 unsigned int highbit;
135
136 /* determine how many operations we could allow, if the other number
137 has the same length. */
138 GNUNET_assert (NULL != (tmp1 = gcry_mpi_set_ui (NULL, 1)));
139 GNUNET_assert (NULL != (tmp2 = gcry_mpi_set_ui (NULL, 2)));
140 gcry_mpi_mul_2exp (tmp1, tmp1, GNUNET_CRYPTO_PAILLIER_BITS);
141
142 /* count number of possible operations
143 this would be nicer with gcry_mpi_get_nbits, however it does not return
144 the BITLENGTH of the given MPI's value, but the bits required
145 to represent the number as MPI. */
146 for (possible_opts = -2; gcry_mpi_cmp (tmp1, m) > 0; possible_opts++)
147 gcry_mpi_div (tmp1, NULL, tmp1, tmp2, 0);
148 gcry_mpi_release (tmp1);
149 gcry_mpi_release (tmp2);
150
151 if (possible_opts < 1)
152 possible_opts = 0;
153 /* soft-cap by caller */
154 possible_opts = (desired_ops < possible_opts) ? desired_ops : possible_opts;
155
156 ciphertext->remaining_ops = htonl (possible_opts);
157
158 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
159 public_key,
160 sizeof(struct
161 GNUNET_CRYPTO_PaillierPublicKey));
162 highbit = GNUNET_CRYPTO_PAILLIER_BITS - 1;
163 while ((! gcry_mpi_test_bit (n, highbit)) &&
164 (0 != highbit))
165 highbit--;
166 if (0 == highbit)
167 {
168 /* invalid public key */
169 GNUNET_break_op (0);
170 gcry_mpi_release (n);
171 return GNUNET_SYSERR;
172 }
173 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
174 GNUNET_assert (0 != (r = gcry_mpi_new (0)));
175 GNUNET_assert (0 != (c = gcry_mpi_new (0)));
176 gcry_mpi_mul (n_square, n, n);
177
178 /* generate r < n (without bias) */
179 do
180 {
181 gcry_mpi_randomize (r, highbit + 1, GCRY_STRONG_RANDOM);
182 }
183 while (gcry_mpi_cmp (r, n) >= 0);
184
185 /* c = (n+1)^m mod n^2 */
186 /* c = n + 1 */
187 gcry_mpi_add_ui (c, n, 1);
188 /* c = (n+1)^m mod n^2 */
189 gcry_mpi_powm (c, c, m, n_square);
190 /* r <- r^n mod n^2 */
191 gcry_mpi_powm (r, r, n, n_square);
192 /* c <- r*c mod n^2 */
193 gcry_mpi_mulm (c, r, c, n_square);
194
195 GNUNET_CRYPTO_mpi_print_unsigned (ciphertext->bits,
196 sizeof ciphertext->bits,
197 c);
198
199 gcry_mpi_release (n_square);
200 gcry_mpi_release (n);
201 gcry_mpi_release (r);
202 gcry_mpi_release (c);
203
204 return possible_opts;
205}
206
207
208/**
209 * Encrypt a plaintext with a paillier public key.
210 *
211 * @param public_key Public key to use.
212 * @param m Plaintext to encrypt.
213 * @param desired_ops How many homomorphic ops the caller intends to use
214 * @param[out] ciphertext Encryption of @a plaintext with @a public_key.
215 * @return guaranteed number of supported homomorphic operations >= 1,
216 * or desired_ops, in case that is lower,
217 * or -1 if less than one homomorphic operation is possible
218 */
219int
220GNUNET_CRYPTO_paillier_encrypt (const struct
221 GNUNET_CRYPTO_PaillierPublicKey *public_key,
222 const gcry_mpi_t m,
223 int desired_ops,
224 struct GNUNET_CRYPTO_PaillierCiphertext *
225 ciphertext)
226{
227 int possible_opts;
228 gcry_mpi_t n_square;
229 gcry_mpi_t r;
230 gcry_mpi_t rn;
231 gcry_mpi_t g;
232 gcry_mpi_t gm;
233 gcry_mpi_t c;
234 gcry_mpi_t n;
235 gcry_mpi_t max_num;
236 unsigned int highbit;
237
238 /* set max_num = 2^{GNUNET_CRYPTO_PAILLIER_BITS}, the largest
239 number we can have as a result */
240 GNUNET_assert (NULL != (max_num = gcry_mpi_set_ui (NULL, 1)));
241 gcry_mpi_mul_2exp (max_num,
242 max_num,
243 GNUNET_CRYPTO_PAILLIER_BITS);
244
245 /* Determine how many operations we could allow, assuming the other
246 number has the same length (or is smaller), by counting the
247 number of possible operations. We essentially divide max_num by
248 2 until the result is no longer larger than 'm', incrementing the
249 maximum number of operations in each round, starting at -2 */for (possible_opts = -2; gcry_mpi_cmp (max_num, m) > 0; possible_opts++)
250 gcry_mpi_div (max_num,
251 NULL,
252 max_num,
253 GCRYMPI_CONST_TWO,
254 0);
255 gcry_mpi_release (max_num);
256
257 if (possible_opts < 1)
258 possible_opts = 0;
259 /* Enforce soft-cap by caller */
260 possible_opts = GNUNET_MIN (desired_ops, possible_opts);
261 ciphertext->remaining_ops = htonl (possible_opts);
262
263 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
264 public_key,
265 sizeof(struct
266 GNUNET_CRYPTO_PaillierPublicKey));
267
268 /* check public key for number of bits, bail out if key is all zeros */
269 highbit = GNUNET_CRYPTO_PAILLIER_BITS - 1;
270 while ((! gcry_mpi_test_bit (n, highbit)) &&
271 (0 != highbit))
272 highbit--;
273 if (0 == highbit)
274 {
275 /* invalid public key */
276 GNUNET_break_op (0);
277 gcry_mpi_release (n);
278 return GNUNET_SYSERR;
279 }
280
281 /* generate r < n (without bias) */
282 GNUNET_assert (NULL != (r = gcry_mpi_new (0)));
283 do
284 {
285 gcry_mpi_randomize (r, highbit + 1, GCRY_STRONG_RANDOM);
286 }
287 while (gcry_mpi_cmp (r, n) >= 0);
288
289 /* g = n + 1 */
290 GNUNET_assert (0 != (g = gcry_mpi_new (0)));
291 gcry_mpi_add_ui (g, n, 1);
292
293 /* n_square = n^2 */
294 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
295 gcry_mpi_mul (n_square,
296 n,
297 n);
298
299 /* gm = g^m mod n^2 */
300 GNUNET_assert (0 != (gm = gcry_mpi_new (0)));
301 gcry_mpi_powm (gm, g, m, n_square);
302 gcry_mpi_release (g);
303
304 /* rn <- r^n mod n^2 */
305 GNUNET_assert (0 != (rn = gcry_mpi_new (0)));
306 gcry_mpi_powm (rn, r, n, n_square);
307 gcry_mpi_release (r);
308 gcry_mpi_release (n);
309
310 /* c <- rn * gm mod n^2 */
311 GNUNET_assert (0 != (c = gcry_mpi_new (0)));
312 gcry_mpi_mulm (c, rn, gm, n_square);
313 gcry_mpi_release (n_square);
314 gcry_mpi_release (gm);
315 gcry_mpi_release (rn);
316
317 GNUNET_CRYPTO_mpi_print_unsigned (ciphertext->bits,
318 sizeof(ciphertext->bits),
319 c);
320 gcry_mpi_release (c);
321
322 return possible_opts;
323}
324
325
326/**
327 * Decrypt a paillier ciphertext with a private key.
328 *
329 * @param private_key Private key to use for decryption.
330 * @param public_key Public key to use for encryption.
331 * @param ciphertext Ciphertext to decrypt.
332 * @param[out] m Decryption of @a ciphertext with @private_key.
333 */
334void
335GNUNET_CRYPTO_paillier_decrypt (const struct
336 GNUNET_CRYPTO_PaillierPrivateKey *private_key,
337 const struct
338 GNUNET_CRYPTO_PaillierPublicKey *public_key,
339 const struct
340 GNUNET_CRYPTO_PaillierCiphertext *ciphertext,
341 gcry_mpi_t m)
342{
343 gcry_mpi_t mu;
344 gcry_mpi_t lambda;
345 gcry_mpi_t n;
346 gcry_mpi_t n_square;
347 gcry_mpi_t c;
348 gcry_mpi_t cmu;
349 gcry_mpi_t cmum1;
350 gcry_mpi_t mod;
351
352 GNUNET_CRYPTO_mpi_scan_unsigned (&lambda,
353 private_key->lambda,
354 sizeof(private_key->lambda));
355 GNUNET_CRYPTO_mpi_scan_unsigned (&mu,
356 private_key->mu,
357 sizeof(private_key->mu));
358 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
359 public_key,
360 sizeof(struct
361 GNUNET_CRYPTO_PaillierPublicKey));
362 GNUNET_CRYPTO_mpi_scan_unsigned (&c,
363 ciphertext->bits,
364 sizeof(ciphertext->bits));
365
366 /* n_square = n * n */
367 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
368 gcry_mpi_mul (n_square, n, n);
369
370 /* cmu = c^lambda mod n^2 */
371 GNUNET_assert (0 != (cmu = gcry_mpi_new (0)));
372 gcry_mpi_powm (cmu,
373 c,
374 lambda,
375 n_square);
376 gcry_mpi_release (n_square);
377 gcry_mpi_release (lambda);
378 gcry_mpi_release (c);
379
380 /* cmum1 = cmu - 1 */
381 GNUNET_assert (0 != (cmum1 = gcry_mpi_new (0)));
382 gcry_mpi_sub_ui (cmum1, cmu, 1);
383 gcry_mpi_release (cmu);
384
385 /* mod = cmum1 / n (mod n) */
386 GNUNET_assert (0 != (mod = gcry_mpi_new (0)));
387 gcry_mpi_div (mod, NULL, cmum1, n, 0);
388 gcry_mpi_release (cmum1);
389
390 /* m = mod * mu mod n */
391 gcry_mpi_mulm (m, mod, mu, n);
392 gcry_mpi_release (mod);
393 gcry_mpi_release (mu);
394 gcry_mpi_release (n);
395}
396
397
398/**
399 * Compute a ciphertext that represents the sum of the plaintext in @a
400 * c1 and @a c2.
401 *
402 * Note that this operation can only be done a finite number of times
403 * before an overflow occurs.
404 *
405 * @param public_key Public key to use for encryption.
406 * @param c1 Paillier cipher text.
407 * @param c2 Paillier cipher text.
408 * @param[out] result Result of the homomorphic operation.
409 * @return #GNUNET_OK if the result could be computed,
410 * #GNUNET_SYSERR if no more homomorphic operations are remaining.
411 */
412int
413GNUNET_CRYPTO_paillier_hom_add (const struct
414 GNUNET_CRYPTO_PaillierPublicKey *public_key,
415 const struct
416 GNUNET_CRYPTO_PaillierCiphertext *c1,
417 const struct
418 GNUNET_CRYPTO_PaillierCiphertext *c2,
419 struct GNUNET_CRYPTO_PaillierCiphertext *result)
420{
421 gcry_mpi_t a;
422 gcry_mpi_t b;
423 gcry_mpi_t c;
424 gcry_mpi_t n;
425 gcry_mpi_t n_square;
426 int32_t o1;
427 int32_t o2;
428
429 o1 = (int32_t) ntohl (c1->remaining_ops);
430 o2 = (int32_t) ntohl (c2->remaining_ops);
431 if ((0 >= o1) || (0 >= o2))
432 {
433 GNUNET_break_op (0);
434 return GNUNET_SYSERR;
435 }
436
437 GNUNET_CRYPTO_mpi_scan_unsigned (&a,
438 c1->bits,
439 sizeof(c1->bits));
440 GNUNET_CRYPTO_mpi_scan_unsigned (&b,
441 c2->bits,
442 sizeof(c2->bits));
443 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
444 public_key,
445 sizeof(struct
446 GNUNET_CRYPTO_PaillierPublicKey));
447
448 /* n_square = n * n */
449 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
450 gcry_mpi_mul (n_square, n, n);
451 gcry_mpi_release (n);
452
453 /* c = a * b mod n_square */
454 GNUNET_assert (0 != (c = gcry_mpi_new (0)));
455 gcry_mpi_mulm (c, a, b, n_square);
456 gcry_mpi_release (n_square);
457 gcry_mpi_release (a);
458 gcry_mpi_release (b);
459
460 result->remaining_ops = htonl (GNUNET_MIN (o1, o2) - 1);
461 GNUNET_CRYPTO_mpi_print_unsigned (result->bits,
462 sizeof(result->bits),
463 c);
464 gcry_mpi_release (c);
465 return ntohl (result->remaining_ops);
466}
467
468
469/**
470 * Get the number of remaining supported homomorphic operations.
471 *
472 * @param c Paillier cipher text.
473 * @return the number of remaining homomorphic operations
474 */
475int
476GNUNET_CRYPTO_paillier_hom_get_remaining (const struct
477 GNUNET_CRYPTO_PaillierCiphertext *c)
478{
479 GNUNET_assert (NULL != c);
480 return ntohl (c->remaining_ops);
481}
482
483
484/* end of crypto_paillier.c */
diff --git a/src/util/crypto_pow.c b/src/util/crypto_pow.c
deleted file mode 100644
index 051a0c209..000000000
--- a/src/util/crypto_pow.c
+++ /dev/null
@@ -1,59 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2019 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 * @file util/crypto_pow.c
22 * @brief proof-of-work hashing
23 * @author Christian Grothoff
24 * @author Bart Polot
25 */
26#include "platform.h"
27#include "gnunet_crypto_lib.h"
28#include <sodium.h>
29
30/**
31 * Calculate the 'proof-of-work' hash (an expensive hash).
32 * We're using a non-standard formula to avoid issues with
33 * ASICs appearing (see #3795).
34 *
35 * @param salt salt for the hash. Must be crypto_pwhash_argon2id_SALTBYTES long.
36 * @param buf data to hash
37 * @param buf_len number of bytes in @a buf
38 * @param result where to write the resulting hash
39 */
40void
41GNUNET_CRYPTO_pow_hash (const struct GNUNET_CRYPTO_PowSalt *salt,
42 const void *buf,
43 size_t buf_len,
44 struct GNUNET_HashCode *result)
45{
46 /* Threads hardcoded at 1 in libsodium */
47 GNUNET_break (0 ==
48 crypto_pwhash_argon2id ((unsigned char *) result,
49 sizeof (struct GNUNET_HashCode),
50 buf,
51 buf_len,
52 (unsigned char*) salt,
53 3, /* iterations */
54 1024 * 1024, /* memory (1 MiB) */
55 crypto_pwhash_argon2id_ALG_ARGON2ID13));
56}
57
58
59/* end of crypto_pow.c */
diff --git a/src/util/crypto_random.c b/src/util/crypto_random.c
deleted file mode 100644
index 0c5d6fe7e..000000000
--- a/src/util/crypto_random.c
+++ /dev/null
@@ -1,421 +0,0 @@
1/*
2 This file is part of GNUnet. Copyright (C) 2001-2014 Christian Grothoff
3 (and other contributing authors)
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/**
23 * @file util/crypto_random.c
24 * @brief functions to gather random numbers
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_crypto_lib.h"
29#include "gnunet_time_lib.h"
30#include <gcrypt.h>
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-random", __VA_ARGS__)
33
34#define LOG_STRERROR(kind, syscall) \
35 GNUNET_log_from_strerror (kind, "util-crypto-random", syscall)
36
37
38/* TODO: ndurner, move this to plibc? */
39/* The code is derived from glibc, obviously */
40#if ! HAVE_RANDOM || ! HAVE_SRANDOM
41#ifdef RANDOM
42#undef RANDOM
43#endif
44#ifdef SRANDOM
45#undef SRANDOM
46#endif
47#define RANDOM() glibc_weak_rand32 ()
48#define SRANDOM(s) glibc_weak_srand32 (s)
49#if defined(RAND_MAX)
50#undef RAND_MAX
51#endif
52#define RAND_MAX 0x7fffffff /* Hopefully this is correct */
53
54
55static int32_t glibc_weak_rand32_state = 1;
56
57
58void
59glibc_weak_srand32 (int32_t s)
60{
61 glibc_weak_rand32_state = s;
62}
63
64
65int32_t
66glibc_weak_rand32 ()
67{
68 int32_t val = glibc_weak_rand32_state;
69
70 val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff;
71 glibc_weak_rand32_state = val;
72 return val;
73}
74
75
76#endif
77
78/**
79 * Create a cryptographically weak pseudo-random number in the interval of 0 to 1.
80 *
81 * @return number between 0 and 1.
82 */
83static double
84get_weak_random (void)
85{
86 return((double) random () / RAND_MAX);
87}
88
89
90/**
91 * Seed a weak random generator. Only #GNUNET_CRYPTO_QUALITY_WEAK-mode generator
92 * can be seeded.
93 *
94 * @param seed the seed to use
95 */
96void
97GNUNET_CRYPTO_seed_weak_random (int32_t seed)
98{
99 srandom (seed);
100}
101
102
103/**
104 * @ingroup crypto
105 * Zero out @a buffer, securely against compiler optimizations.
106 * Used to delete key material.
107 *
108 * @param buffer the buffer to zap
109 * @param length buffer length
110 */
111void
112GNUNET_CRYPTO_zero_keys (void *buffer, size_t length)
113{
114#if HAVE_MEMSET_S
115 memset_s (buffer, length, 0, length);
116#elif HAVE_EXPLICIT_BZERO
117 explicit_bzero (buffer, length);
118#else
119 volatile unsigned char *p = buffer;
120 while (length--)
121 *p++ = 0;
122#endif
123}
124
125
126/**
127 * @ingroup crypto
128 * Fill block with a random values.
129 *
130 * @param mode desired quality of the random number
131 * @param buffer the buffer to fill
132 * @param length buffer length
133 */
134void
135GNUNET_CRYPTO_random_block (enum GNUNET_CRYPTO_Quality mode,
136 void *buffer,
137 size_t length)
138{
139#ifdef gcry_fast_random_poll
140 static unsigned int invokeCount;
141#endif
142 switch (mode)
143 {
144 case GNUNET_CRYPTO_QUALITY_STRONG:
145 /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
146#ifdef gcry_fast_random_poll
147 if ((invokeCount++ % 256) == 0)
148 gcry_fast_random_poll ();
149#endif
150 gcry_randomize (buffer, length, GCRY_STRONG_RANDOM);
151 return;
152
153 case GNUNET_CRYPTO_QUALITY_NONCE:
154 gcry_create_nonce (buffer, length);
155 return;
156
157 case GNUNET_CRYPTO_QUALITY_WEAK:
158 /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
159#ifdef gcry_fast_random_poll
160 if ((invokeCount++ % 256) == 0)
161 gcry_fast_random_poll ();
162#endif
163 gcry_randomize (buffer, length, GCRY_WEAK_RANDOM);
164 return;
165
166 default:
167 GNUNET_assert (0);
168 }
169}
170
171
172/**
173 * Produce a random unsigned 32-bit number modulo @a i.
174 *
175 * @param mode desired quality of the random number
176 * @param i the upper limit (exclusive) for the random number
177 * @return a random value in the interval [0,i[.
178 */
179uint32_t
180GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode,
181 uint32_t i)
182{
183#ifdef gcry_fast_random_poll
184 static unsigned int invokeCount;
185#endif
186 uint32_t ret;
187 uint32_t ul;
188
189 GNUNET_assert (i > 0);
190
191 switch (mode)
192 {
193 case GNUNET_CRYPTO_QUALITY_STRONG:
194 /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
195#ifdef gcry_fast_random_poll
196 if ((invokeCount++ % 256) == 0)
197 gcry_fast_random_poll ();
198#endif
199 ul = UINT32_MAX - (UINT32_MAX % i);
200 do
201 {
202 gcry_randomize ((unsigned char *) &ret,
203 sizeof(uint32_t),
204 GCRY_STRONG_RANDOM);
205 }
206 while (ret >= ul);
207 return ret % i;
208
209 case GNUNET_CRYPTO_QUALITY_NONCE:
210 ul = UINT32_MAX - (UINT32_MAX % i);
211 do
212 {
213 gcry_create_nonce (&ret, sizeof(ret));
214 }
215 while (ret >= ul);
216 return ret % i;
217
218 case GNUNET_CRYPTO_QUALITY_WEAK:
219 ret = i * get_weak_random ();
220 if (ret >= i)
221 ret = i - 1;
222 return ret;
223
224 default:
225 GNUNET_assert (0);
226 }
227 return 0;
228}
229
230
231/**
232 * Get an array with a random permutation of the
233 * numbers 0...n-1.
234 * @param mode #GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive)
235 * PRNG should be used, #GNUNET_RANDOM_QUALITY_WEAK otherwise
236 * @param n the size of the array
237 * @return the permutation array (allocated from heap)
238 */
239unsigned int *
240GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode,
241 unsigned int n)
242{
243 unsigned int *ret;
244 unsigned int i;
245 unsigned int tmp;
246 uint32_t x;
247
248 GNUNET_assert (n > 0);
249 ret = GNUNET_malloc (n * sizeof(unsigned int));
250 for (i = 0; i < n; i++)
251 ret[i] = i;
252 for (i = n - 1; i > 0; i--)
253 {
254 x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
255 tmp = ret[x];
256 ret[x] = ret[i];
257 ret[i] = tmp;
258 }
259 return ret;
260}
261
262
263/**
264 * Generate random unsigned 64-bit value.
265 *
266 * @param mode desired quality of the random number
267 * @param max value returned will be in range [0,max) (exclusive)
268 * @return random 64-bit number
269 */
270uint64_t
271GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode,
272 uint64_t max)
273{
274 uint64_t ret;
275 uint64_t ul;
276
277 GNUNET_assert (max > 0);
278 switch (mode)
279 {
280 case GNUNET_CRYPTO_QUALITY_STRONG:
281 ul = UINT64_MAX - (UINT64_MAX % max);
282 do
283 {
284 gcry_randomize ((unsigned char *) &ret,
285 sizeof(uint64_t),
286 GCRY_STRONG_RANDOM);
287 }
288 while (ret >= ul);
289 return ret % max;
290
291 case GNUNET_CRYPTO_QUALITY_NONCE:
292 ul = UINT64_MAX - (UINT64_MAX % max);
293 do
294 {
295 gcry_create_nonce (&ret, sizeof(ret));
296 }
297 while (ret >= ul);
298
299 return ret % max;
300
301 case GNUNET_CRYPTO_QUALITY_WEAK:
302 ret = max * get_weak_random ();
303 if (ret >= max)
304 ret = max - 1;
305 return ret;
306
307 default:
308 GNUNET_assert (0);
309 }
310 return 0;
311}
312
313
314/**
315 * @ingroup crypto
316 * Fill UUID with a timeflake pseudo-random value. Note that
317 * timeflakes use only 80 bits of randomness and 48 bits
318 * to encode a timestamp in milliseconds. So what we return
319 * here is not a completely random number.
320 *
321 * @param mode desired quality of the random number
322 * @param uuid the value to fill
323 */
324void
325GNUNET_CRYPTO_random_timeflake (enum GNUNET_CRYPTO_Quality mode,
326 struct GNUNET_Uuid *uuid)
327{
328 struct GNUNET_TIME_Absolute now;
329 uint64_t ms;
330 uint64_t be;
331 char *base;
332
333 GNUNET_CRYPTO_random_block (mode,
334 uuid,
335 sizeof (struct GNUNET_Uuid));
336 now = GNUNET_TIME_absolute_get ();
337 ms = now.abs_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
338 be = GNUNET_htonll (ms);
339 base = (char *) &be;
340 memcpy (uuid,
341 base + 2,
342 sizeof (be) - 2);
343}
344
345
346/**
347 * Allocation wrapper for libgcrypt, used to avoid bad locking
348 * strategy of libgcrypt implementation.
349 */
350static void *
351w_malloc (size_t n)
352{
353 return calloc (n, 1);
354}
355
356
357/**
358 * Allocation wrapper for libgcrypt, used to avoid bad locking
359 * strategy of libgcrypt implementation.
360 */
361static int
362w_check (const void *p)
363{
364 (void) p;
365 return 0; /* not secure memory */
366}
367
368
369/**
370 * Initialize libgcrypt.
371 */
372void __attribute__ ((constructor))
373GNUNET_CRYPTO_random_init ()
374{
375 gcry_error_t rc;
376
377 if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
378 {
379 fprintf (
380 stderr,
381 _ ("libgcrypt has not the expected version (version %s is required).\n"),
382 NEED_LIBGCRYPT_VERSION);
383 GNUNET_assert (0);
384 }
385 /* set custom allocators */
386 gcry_set_allocation_handler (&w_malloc, &w_malloc, &w_check, &realloc, &free);
387 /* Disable use of secure memory */
388 if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
389 fprintf (stderr,
390 "Failed to set libgcrypt option %s: %s\n",
391 "DISABLE_SECMEM",
392 gcry_strerror (rc));
393 /* Otherwise gnunet-ecc takes forever to complete, besides
394 we are fine with "just" using GCRY_STRONG_RANDOM */
395 if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0)))
396 fprintf (stderr,
397 "Failed to set libgcrypt option %s: %s\n",
398 "ENABLE_QUICK_RANDOM",
399 gcry_strerror (rc));
400 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
401 gcry_fast_random_poll ();
402 GNUNET_CRYPTO_seed_weak_random (
403 time (NULL)
404 ^ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
405}
406
407
408/**
409 * Nicely shut down libgcrypt.
410 */
411void __attribute__ ((destructor))
412GNUNET_CRYPTO_random_fini ()
413{
414 gcry_set_progress_handler (NULL, NULL);
415#ifdef GCRYCTL_CLOSE_RANDOM_DEVICE
416 (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
417#endif
418}
419
420
421/* end of crypto_random.c */
diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c
deleted file mode 100644
index 43e6eedac..000000000
--- a/src/util/crypto_rsa.c
+++ /dev/null
@@ -1,1256 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014,2016,2019 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 util/crypto_rsa.c
23 * @brief Chaum-style Blind signatures based on RSA
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 * @author Christian Grothoff
26 * @author Jeffrey Burdges <burdges@gnunet.org>
27 */
28#include "platform.h"
29#include <gcrypt.h>
30#include "gnunet_crypto_lib.h"
31#include "benchmark.h"
32
33#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-rsa", __VA_ARGS__)
34
35
36/**
37 * The private information of an RSA key pair.
38 */
39struct GNUNET_CRYPTO_RsaPrivateKey
40{
41 /**
42 * Libgcrypt S-expression for the RSA private key.
43 */
44 gcry_sexp_t sexp;
45};
46
47
48/**
49 * The public information of an RSA key pair.
50 */
51struct GNUNET_CRYPTO_RsaPublicKey
52{
53 /**
54 * Libgcrypt S-expression for the RSA public key.
55 */
56 gcry_sexp_t sexp;
57};
58
59
60/**
61 * @brief an RSA signature
62 */
63struct GNUNET_CRYPTO_RsaSignature
64{
65 /**
66 * Libgcrypt S-expression for the RSA signature.
67 */
68 gcry_sexp_t sexp;
69};
70
71
72/**
73 * @brief RSA blinding key
74 */
75struct RsaBlindingKey
76{
77 /**
78 * Random value used for blinding.
79 */
80 gcry_mpi_t r;
81};
82
83
84/**
85 * Extract values from an S-expression.
86 *
87 * @param array where to store the result(s)
88 * @param sexp S-expression to parse
89 * @param topname top-level name in the S-expression that is of interest
90 * @param elems names of the elements to extract
91 * @return 0 on success
92 */
93static int
94key_from_sexp (gcry_mpi_t *array,
95 gcry_sexp_t sexp,
96 const char *topname,
97 const char *elems)
98{
99 gcry_sexp_t list;
100 gcry_sexp_t l2;
101 const char *s;
102 unsigned int idx;
103
104 if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
105 return 1;
106 l2 = gcry_sexp_cadr (list);
107 gcry_sexp_release (list);
108 list = l2;
109 if (! list)
110 return 2;
111 idx = 0;
112 for (s = elems; *s; s++, idx++)
113 {
114 if (! (l2 = gcry_sexp_find_token (list, s, 1)))
115 {
116 for (unsigned int i = 0; i < idx; i++)
117 {
118 gcry_free (array[i]);
119 array[i] = NULL;
120 }
121 gcry_sexp_release (list);
122 return 3; /* required parameter not found */
123 }
124 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
125 gcry_sexp_release (l2);
126 if (! array[idx])
127 {
128 for (unsigned int i = 0; i < idx; i++)
129 {
130 gcry_free (array[i]);
131 array[i] = NULL;
132 }
133 gcry_sexp_release (list);
134 return 4; /* required parameter is invalid */
135 }
136 }
137 gcry_sexp_release (list);
138 return 0;
139}
140
141
142struct GNUNET_CRYPTO_RsaPrivateKey *
143GNUNET_CRYPTO_rsa_private_key_create (unsigned int len)
144{
145 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
146 gcry_sexp_t s_key;
147 gcry_sexp_t s_keyparam;
148
149 BENCHMARK_START (rsa_private_key_create);
150
151 GNUNET_assert (0 ==
152 gcry_sexp_build (&s_keyparam,
153 NULL,
154 "(genkey(rsa(nbits %d)))",
155 len));
156 GNUNET_assert (0 ==
157 gcry_pk_genkey (&s_key,
158 s_keyparam));
159 gcry_sexp_release (s_keyparam);
160#if EXTRA_CHECKS
161 GNUNET_assert (0 ==
162 gcry_pk_testkey (s_key));
163#endif
164 ret = GNUNET_new (struct GNUNET_CRYPTO_RsaPrivateKey);
165 ret->sexp = s_key;
166 BENCHMARK_END (rsa_private_key_create);
167 return ret;
168}
169
170
171void
172GNUNET_CRYPTO_rsa_private_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *key)
173{
174 gcry_sexp_release (key->sexp);
175 GNUNET_free (key);
176}
177
178
179size_t
180GNUNET_CRYPTO_rsa_private_key_encode (const struct
181 GNUNET_CRYPTO_RsaPrivateKey *key,
182 void **buffer)
183{
184 size_t n;
185 char *b;
186
187 n = gcry_sexp_sprint (key->sexp,
188 GCRYSEXP_FMT_DEFAULT,
189 NULL,
190 0);
191 b = GNUNET_malloc (n);
192 GNUNET_assert ((n - 1) == /* since the last byte is \0 */
193 gcry_sexp_sprint (key->sexp,
194 GCRYSEXP_FMT_DEFAULT,
195 b,
196 n));
197 *buffer = b;
198 return n;
199}
200
201
202struct GNUNET_CRYPTO_RsaPrivateKey *
203GNUNET_CRYPTO_rsa_private_key_decode (const void *buf,
204 size_t buf_size)
205{
206 struct GNUNET_CRYPTO_RsaPrivateKey *key;
207
208 key = GNUNET_new (struct GNUNET_CRYPTO_RsaPrivateKey);
209 if (0 !=
210 gcry_sexp_new (&key->sexp,
211 buf,
212 buf_size,
213 0))
214 {
215 LOG (GNUNET_ERROR_TYPE_WARNING,
216 "Decoded private key is not valid\n");
217 GNUNET_free (key);
218 return NULL;
219 }
220 if (0 != gcry_pk_testkey (key->sexp))
221 {
222 LOG (GNUNET_ERROR_TYPE_WARNING,
223 "Decoded private key is not valid\n");
224 GNUNET_CRYPTO_rsa_private_key_free (key);
225 return NULL;
226 }
227 return key;
228}
229
230
231struct GNUNET_CRYPTO_RsaPublicKey *
232GNUNET_CRYPTO_rsa_private_key_get_public (
233 const struct GNUNET_CRYPTO_RsaPrivateKey *priv)
234{
235 struct GNUNET_CRYPTO_RsaPublicKey *pub;
236 gcry_mpi_t ne[2];
237 int rc;
238 gcry_sexp_t result;
239
240 BENCHMARK_START (rsa_private_key_get_public);
241
242 rc = key_from_sexp (ne, priv->sexp, "public-key", "ne");
243 if (0 != rc)
244 rc = key_from_sexp (ne, priv->sexp, "private-key", "ne");
245 if (0 != rc)
246 rc = key_from_sexp (ne, priv->sexp, "rsa", "ne");
247 if (0 != rc)
248 {
249 GNUNET_break_op (0);
250 return NULL;
251 }
252 rc = gcry_sexp_build (&result,
253 NULL,
254 "(public-key(rsa(n %m)(e %m)))",
255 ne[0],
256 ne[1]);
257 gcry_mpi_release (ne[0]);
258 gcry_mpi_release (ne[1]);
259 pub = GNUNET_new (struct GNUNET_CRYPTO_RsaPublicKey);
260 pub->sexp = result;
261 BENCHMARK_END (rsa_private_key_get_public);
262 return pub;
263}
264
265
266void
267GNUNET_CRYPTO_rsa_public_key_free (struct GNUNET_CRYPTO_RsaPublicKey *key)
268{
269 gcry_sexp_release (key->sexp);
270 GNUNET_free (key);
271}
272
273
274GNUNET_NETWORK_STRUCT_BEGIN
275
276/**
277 * Format of the header of a serialized RSA public key.
278 */
279struct GNUNET_CRYPTO_RsaPublicKeyHeaderP
280{
281 /**
282 * length of modulus 'n' in bytes, in NBO
283 */
284 uint16_t modulus_length GNUNET_PACKED;
285
286 /**
287 * length of exponent in bytes, in NBO
288 */
289 uint16_t public_exponent_length GNUNET_PACKED;
290
291 /* followed by variable-size modulus and
292 public exponent follows as big-endian encoded
293 integers */
294};
295
296GNUNET_NETWORK_STRUCT_END
297
298
299bool
300GNUNET_CRYPTO_rsa_public_key_check (
301 const struct GNUNET_CRYPTO_RsaPublicKey *key)
302{
303 gcry_mpi_t ne[2];
304 int ret;
305
306 ret = key_from_sexp (ne,
307 key->sexp,
308 "public-key",
309 "ne");
310 if (0 != ret)
311 ret = key_from_sexp (ne,
312 key->sexp,
313 "rsa",
314 "ne");
315 if (0 != ret)
316 return false;
317 gcry_mpi_release (ne[0]);
318 gcry_mpi_release (ne[1]);
319 return true;
320}
321
322
323size_t
324GNUNET_CRYPTO_rsa_public_key_encode (
325 const struct GNUNET_CRYPTO_RsaPublicKey *key,
326 void **buffer)
327{
328 gcry_mpi_t ne[2];
329 size_t n_size;
330 size_t e_size;
331 size_t rsize;
332 size_t buf_size;
333 char *buf;
334 struct GNUNET_CRYPTO_RsaPublicKeyHeaderP hdr;
335 int ret;
336
337 ret = key_from_sexp (ne,
338 key->sexp,
339 "public-key",
340 "ne");
341 if (0 != ret)
342 ret = key_from_sexp (ne,
343 key->sexp,
344 "rsa",
345 "ne");
346 if (0 != ret)
347 {
348 GNUNET_break (0);
349 *buffer = NULL;
350 return 0;
351 }
352 gcry_mpi_print (GCRYMPI_FMT_USG,
353 NULL,
354 0,
355 &n_size,
356 ne[0]);
357 gcry_mpi_print (GCRYMPI_FMT_USG,
358 NULL,
359 0,
360 &e_size,
361 ne[1]);
362 if ( (e_size > UINT16_MAX) ||
363 (n_size > UINT16_MAX) )
364 {
365 GNUNET_break (0);
366 if (NULL != buffer)
367 *buffer = NULL;
368 gcry_mpi_release (ne[0]);
369 gcry_mpi_release (ne[1]);
370 return 0;
371 }
372 buf_size = n_size + e_size + sizeof (hdr);
373 if (NULL == buffer)
374 {
375 gcry_mpi_release (ne[0]);
376 gcry_mpi_release (ne[1]);
377 return buf_size;
378 }
379 buf = GNUNET_malloc (buf_size);
380 hdr.modulus_length = htons ((uint16_t) n_size);
381 hdr.public_exponent_length = htons ((uint16_t) e_size);
382 memcpy (buf,
383 &hdr,
384 sizeof (hdr));
385 GNUNET_assert (0 ==
386 gcry_mpi_print (GCRYMPI_FMT_USG,
387 (unsigned char *) &buf[sizeof (hdr)],
388 n_size,
389 &rsize,
390 ne[0]));
391
392 GNUNET_assert (0 ==
393 gcry_mpi_print (GCRYMPI_FMT_USG,
394 (unsigned char *) &buf[sizeof (hdr) + n_size],
395 e_size,
396 &rsize,
397 ne[1]));
398 *buffer = buf;
399 gcry_mpi_release (ne[0]);
400 gcry_mpi_release (ne[1]);
401 return buf_size;
402}
403
404
405void
406GNUNET_CRYPTO_rsa_public_key_hash (const struct GNUNET_CRYPTO_RsaPublicKey *key,
407 struct GNUNET_HashCode *hc)
408{
409 void *buf;
410 size_t buf_size;
411
412 buf_size = GNUNET_CRYPTO_rsa_public_key_encode (key,
413 &buf);
414 GNUNET_CRYPTO_hash (buf,
415 buf_size,
416 hc);
417 GNUNET_free (buf);
418}
419
420
421struct GNUNET_CRYPTO_RsaPublicKey *
422GNUNET_CRYPTO_rsa_public_key_decode (const char *buf,
423 size_t len)
424{
425 struct GNUNET_CRYPTO_RsaPublicKey *key;
426 struct GNUNET_CRYPTO_RsaPublicKeyHeaderP hdr;
427 size_t e_size;
428 size_t n_size;
429 gcry_mpi_t n;
430 gcry_mpi_t e;
431 gcry_sexp_t data;
432
433 if (len < sizeof (hdr))
434 {
435 GNUNET_break_op (0);
436 return NULL;
437 }
438 memcpy (&hdr, buf, sizeof (hdr));
439 n_size = ntohs (hdr.modulus_length);
440 e_size = ntohs (hdr.public_exponent_length);
441 if (len != sizeof (hdr) + e_size + n_size)
442 {
443 GNUNET_break_op (0);
444 return NULL;
445 }
446 if (0 !=
447 gcry_mpi_scan (&n,
448 GCRYMPI_FMT_USG,
449 &buf[sizeof (hdr)],
450 n_size,
451 NULL))
452 {
453 GNUNET_break_op (0);
454 return NULL;
455 }
456 if (0 !=
457 gcry_mpi_scan (&e,
458 GCRYMPI_FMT_USG,
459 &buf[sizeof (hdr) + n_size],
460 e_size,
461 NULL))
462 {
463 GNUNET_break_op (0);
464 gcry_mpi_release (n);
465 return NULL;
466 }
467
468 if (0 !=
469 gcry_sexp_build (&data,
470 NULL,
471 "(public-key(rsa(n %m)(e %m)))",
472 n,
473 e))
474 {
475 GNUNET_break (0);
476 gcry_mpi_release (n);
477 gcry_mpi_release (e);
478 return NULL;
479 }
480 gcry_mpi_release (n);
481 gcry_mpi_release (e);
482 key = GNUNET_new (struct GNUNET_CRYPTO_RsaPublicKey);
483 key->sexp = data;
484 return key;
485}
486
487
488/**
489 * Test for malicious RSA key.
490 *
491 * Assuming n is an RSA modulous and r is generated using a call to
492 * GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a
493 * malicious RSA key designed to deanomize the user.
494 *
495 * @param r KDF result
496 * @param n RSA modulus
497 * @return True if gcd(r,n) = 1, False means RSA key is malicious
498 */
499static int
500rsa_gcd_validate (gcry_mpi_t r, gcry_mpi_t n)
501{
502 gcry_mpi_t g;
503 int t;
504
505 g = gcry_mpi_new (0);
506 t = gcry_mpi_gcd (g, r, n);
507 gcry_mpi_release (g);
508 return t;
509}
510
511
512/**
513 * Create a blinding key
514 *
515 * @param len length of the key in bits (e.g. 2048)
516 * @param bks pre-secret to use to derive the blinding key
517 * @return the newly created blinding key, NULL if RSA key is malicious
518 */
519static struct RsaBlindingKey *
520rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
521 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks)
522{
523 char *xts = "Blinding KDF extractor HMAC key"; /* Trusts bks' randomness more */
524 struct RsaBlindingKey *blind;
525 gcry_mpi_t n;
526
527 blind = GNUNET_new (struct RsaBlindingKey);
528 GNUNET_assert (NULL != blind);
529
530 /* Extract the composite n from the RSA public key */
531 GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n"));
532 /* Assert that it at least looks like an RSA key */
533 GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE));
534
535 GNUNET_CRYPTO_kdf_mod_mpi (&blind->r,
536 n,
537 xts, strlen (xts),
538 bks, sizeof(*bks),
539 "Blinding KDF");
540 if (0 == rsa_gcd_validate (blind->r, n))
541 {
542 GNUNET_free (blind);
543 blind = NULL;
544 }
545
546 gcry_mpi_release (n);
547 return blind;
548}
549
550
551/*
552 We originally added GNUNET_CRYPTO_kdf_mod_mpi for the benefit of the
553 previous routine.
554
555 There was previously a call to GNUNET_CRYPTO_kdf in
556 bkey = rsa_blinding_key_derive (len, bks);
557 that gives exactly len bits where
558 len = GNUNET_CRYPTO_rsa_public_key_len (pkey);
559
560 Now r = 2^(len-1)/pkey.n is the probability that a set high bit being
561 okay, meaning bkey < pkey.n. It follows that (1-r)/2 of the time bkey >
562 pkey.n making the effective bkey be
563 bkey mod pkey.n = bkey - pkey.n
564 so the effective bkey has its high bit set with probability r/2.
565
566 We expect r to be close to 1/2 if the exchange is honest, but the
567 exchange can choose r otherwise.
568
569 In blind signing, the exchange sees
570 B = bkey * S mod pkey.n
571 On deposit, the exchange sees S so they can compute bkey' = B/S mod
572 pkey.n for all B they recorded to see if bkey' has it's high bit set.
573 Also, note the exchange can compute 1/S efficiently since they know the
574 factors of pkey.n.
575
576 I suppose that happens with probability r/(1+r) if its the wrong B, not
577 completely sure. If otoh we've the right B, then we've the probability
578 r/2 of a set high bit in the effective bkey.
579
580 Interestingly, r^2-r has a maximum at the default r=1/2 anyways, giving
581 the wrong and right probabilities 1/3 and 1/4, respectively.
582
583 I feared this gives the exchange a meaningful fraction of a bit of
584 information per coin involved in the transaction. It sounds damaging if
585 numerous coins were involved. And it could run across transactions in
586 some scenarios.
587
588 We fixed this by using a more uniform deterministic pseudo-random number
589 generator for blinding factors. I do not believe this to be a problem
590 for the rsa_full_domain_hash routine, but better safe than sorry.
591 */
592
593
594int
595GNUNET_CRYPTO_rsa_signature_cmp (const struct GNUNET_CRYPTO_RsaSignature *s1,
596 const struct GNUNET_CRYPTO_RsaSignature *s2)
597{
598 void *b1;
599 void *b2;
600 size_t z1;
601 size_t z2;
602 int ret;
603
604 z1 = GNUNET_CRYPTO_rsa_signature_encode (s1,
605 &b1);
606 z2 = GNUNET_CRYPTO_rsa_signature_encode (s2,
607 &b2);
608 if (z1 != z2)
609 ret = 1;
610 else
611 ret = memcmp (b1,
612 b2,
613 z1);
614 GNUNET_free (b1);
615 GNUNET_free (b2);
616 return ret;
617}
618
619
620int
621GNUNET_CRYPTO_rsa_public_key_cmp (const struct GNUNET_CRYPTO_RsaPublicKey *p1,
622 const struct GNUNET_CRYPTO_RsaPublicKey *p2)
623{
624 void *b1;
625 void *b2;
626 size_t z1;
627 size_t z2;
628 int ret;
629
630 z1 = GNUNET_CRYPTO_rsa_public_key_encode (p1,
631 &b1);
632 z2 = GNUNET_CRYPTO_rsa_public_key_encode (p2,
633 &b2);
634 if (z1 != z2)
635 ret = 1;
636 else
637 ret = memcmp (b1,
638 b2,
639 z1);
640 GNUNET_free (b1);
641 GNUNET_free (b2);
642 return ret;
643}
644
645
646int
647GNUNET_CRYPTO_rsa_private_key_cmp (const struct GNUNET_CRYPTO_RsaPrivateKey *p1,
648 const struct GNUNET_CRYPTO_RsaPrivateKey *p2)
649{
650 void *b1;
651 void *b2;
652 size_t z1;
653 size_t z2;
654 int ret;
655
656 z1 = GNUNET_CRYPTO_rsa_private_key_encode (p1,
657 &b1);
658 z2 = GNUNET_CRYPTO_rsa_private_key_encode (p2,
659 &b2);
660 if (z1 != z2)
661 ret = 1;
662 else
663 ret = memcmp (b1,
664 b2,
665 z1);
666 GNUNET_free (b1);
667 GNUNET_free (b2);
668 return ret;
669}
670
671
672unsigned int
673GNUNET_CRYPTO_rsa_public_key_len (const struct GNUNET_CRYPTO_RsaPublicKey *key)
674{
675 gcry_mpi_t n;
676 unsigned int rval;
677
678 if (0 != key_from_sexp (&n, key->sexp, "rsa", "n"))
679 { /* Not an RSA public key */
680 GNUNET_break (0);
681 return 0;
682 }
683 rval = gcry_mpi_get_nbits (n);
684 gcry_mpi_release (n);
685 return rval;
686}
687
688
689/**
690 * Destroy a blinding key
691 *
692 * @param bkey the blinding key to destroy
693 */
694static void
695rsa_blinding_key_free (struct RsaBlindingKey *bkey)
696{
697 gcry_mpi_release (bkey->r);
698 GNUNET_free (bkey);
699}
700
701
702/**
703 * Print an MPI to a newly created buffer
704 *
705 * @param v MPI to print.
706 * @param[out] newly allocated buffer containing the result
707 * @return number of bytes stored in @a buffer
708 */
709static size_t
710numeric_mpi_alloc_n_print (gcry_mpi_t v,
711 char **buffer)
712{
713 size_t n;
714 char *b;
715 size_t rsize;
716
717 gcry_mpi_print (GCRYMPI_FMT_USG,
718 NULL,
719 0,
720 &n,
721 v);
722 b = GNUNET_malloc (n);
723 GNUNET_assert (0 ==
724 gcry_mpi_print (GCRYMPI_FMT_USG,
725 (unsigned char *) b,
726 n,
727 &rsize,
728 v));
729 *buffer = b;
730 return n;
731}
732
733
734/**
735 * Computes a full domain hash seeded by the given public key.
736 * This gives a measure of provable security to the Taler exchange
737 * against one-more forgery attacks. See:
738 * https://eprint.iacr.org/2001/002.pdf
739 * http://www.di.ens.fr/~pointche/Documents/Papers/2001_fcA.pdf
740 *
741 * @param hash initial hash of the message to sign
742 * @param pkey the public key of the signer
743 * @param rsize If not NULL, the number of bytes actually stored in buffer
744 * @return MPI value set to the FDH, NULL if RSA key is malicious
745 */
746static gcry_mpi_t
747rsa_full_domain_hash (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
748 const struct GNUNET_HashCode *hash)
749{
750 gcry_mpi_t r, n;
751 void *xts;
752 size_t xts_len;
753 int ok;
754
755 /* Extract the composite n from the RSA public key */
756 GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n"));
757 /* Assert that it at least looks like an RSA key */
758 GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE));
759
760 /* We key with the public denomination key as a homage to RSA-PSS by *
761 * Mihir Bellare and Phillip Rogaway. Doing this lowers the degree *
762 * of the hypothetical polyomial-time attack on RSA-KTI created by a *
763 * polynomial-time one-more forgary attack. Yey seeding! */
764 xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &xts);
765
766 GNUNET_CRYPTO_kdf_mod_mpi (&r,
767 n,
768 xts, xts_len,
769 hash, sizeof(*hash),
770 "RSA-FDA FTpsW!");
771 GNUNET_free (xts);
772
773 ok = rsa_gcd_validate (r, n);
774 gcry_mpi_release (n);
775 if (ok)
776 return r;
777 gcry_mpi_release (r);
778 return NULL;
779}
780
781
782enum GNUNET_GenericReturnValue
783GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash,
784 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
785 struct GNUNET_CRYPTO_RsaPublicKey *pkey,
786 void **buf,
787 size_t *buf_size)
788{
789 struct RsaBlindingKey *bkey;
790 gcry_mpi_t data;
791 gcry_mpi_t ne[2];
792 gcry_mpi_t r_e;
793 gcry_mpi_t data_r_e;
794 int ret;
795
796 BENCHMARK_START (rsa_blind);
797
798 GNUNET_assert (buf != NULL);
799 GNUNET_assert (buf_size != NULL);
800 ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne");
801 if (0 != ret)
802 ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne");
803 if (0 != ret)
804 {
805 GNUNET_break (0);
806 *buf = NULL;
807 *buf_size = 0;
808 return GNUNET_NO;
809 }
810
811 data = rsa_full_domain_hash (pkey, hash);
812 if (NULL == data)
813 goto rsa_gcd_validate_failure;
814
815 bkey = rsa_blinding_key_derive (pkey, bks);
816 if (NULL == bkey)
817 {
818 gcry_mpi_release (data);
819 goto rsa_gcd_validate_failure;
820 }
821
822 r_e = gcry_mpi_new (0);
823 gcry_mpi_powm (r_e,
824 bkey->r,
825 ne[1],
826 ne[0]);
827 data_r_e = gcry_mpi_new (0);
828 gcry_mpi_mulm (data_r_e,
829 data,
830 r_e,
831 ne[0]);
832 gcry_mpi_release (data);
833 gcry_mpi_release (ne[0]);
834 gcry_mpi_release (ne[1]);
835 gcry_mpi_release (r_e);
836 rsa_blinding_key_free (bkey);
837
838 *buf_size = numeric_mpi_alloc_n_print (data_r_e,
839 (char **) buf);
840 gcry_mpi_release (data_r_e);
841
842 BENCHMARK_END (rsa_blind);
843
844 return GNUNET_YES;
845
846rsa_gcd_validate_failure:
847 /* We know the RSA key is malicious here, so warn the wallet. */
848 /* GNUNET_break_op (0); */
849 gcry_mpi_release (ne[0]);
850 gcry_mpi_release (ne[1]);
851 *buf = NULL;
852 *buf_size = 0;
853 return GNUNET_NO;
854}
855
856
857/**
858 * Convert an MPI to an S-expression suitable for signature operations.
859 *
860 * @param value pointer to the data to convert
861 * @return converted s-expression
862 */
863static gcry_sexp_t
864mpi_to_sexp (gcry_mpi_t value)
865{
866 gcry_sexp_t data = NULL;
867
868 GNUNET_assert (0 ==
869 gcry_sexp_build (&data,
870 NULL,
871 "(data (flags raw) (value %M))",
872 value));
873 return data;
874}
875
876
877/**
878 * Sign the given MPI.
879 *
880 * @param key private key to use for the signing
881 * @param value the MPI to sign
882 * @return NULL on error, signature on success
883 */
884static struct GNUNET_CRYPTO_RsaSignature *
885rsa_sign_mpi (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
886 gcry_mpi_t value)
887{
888 struct GNUNET_CRYPTO_RsaSignature *sig;
889 gcry_sexp_t data;
890 gcry_sexp_t result;
891 int rc;
892
893 data = mpi_to_sexp (value);
894
895 if (0 !=
896 (rc = gcry_pk_sign (&result,
897 data,
898 key->sexp)))
899 {
900 LOG (GNUNET_ERROR_TYPE_WARNING,
901 _ ("RSA signing failed at %s:%d: %s\n"),
902 __FILE__,
903 __LINE__,
904 gcry_strerror (rc));
905 gcry_sexp_release (data);
906 GNUNET_break (0);
907 return NULL;
908 }
909
910 /* Lenstra protection was first added to libgcrypt 1.6.4
911 * with commit c17f84bd02d7ee93845e92e20f6ddba814961588.
912 */
913#if GCRYPT_VERSION_NUMBER < 0x010604
914 /* verify signature (guards against Lenstra's attack with fault injection...) */
915 struct GNUNET_CRYPTO_RsaPublicKey *public_key =
916 GNUNET_CRYPTO_rsa_private_key_get_public (key);
917 if (0 !=
918 gcry_pk_verify (result,
919 data,
920 public_key->sexp))
921 {
922 GNUNET_break (0);
923 GNUNET_CRYPTO_rsa_public_key_free (public_key);
924 gcry_sexp_release (data);
925 gcry_sexp_release (result);
926 return NULL;
927 }
928 GNUNET_CRYPTO_rsa_public_key_free (public_key);
929#endif
930
931 /* return signature */
932 gcry_sexp_release (data);
933 sig = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
934 sig->sexp = result;
935 return sig;
936}
937
938
939struct GNUNET_CRYPTO_RsaSignature *
940GNUNET_CRYPTO_rsa_sign_blinded (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
941 const void *msg,
942 size_t msg_len)
943{
944 gcry_mpi_t v = NULL;
945 struct GNUNET_CRYPTO_RsaSignature *sig;
946
947 BENCHMARK_START (rsa_sign_blinded);
948
949 GNUNET_assert (0 ==
950 gcry_mpi_scan (&v,
951 GCRYMPI_FMT_USG,
952 msg,
953 msg_len,
954 NULL));
955
956 sig = rsa_sign_mpi (key, v);
957 gcry_mpi_release (v);
958 BENCHMARK_END (rsa_sign_blinded);
959 return sig;
960}
961
962
963struct GNUNET_CRYPTO_RsaSignature *
964GNUNET_CRYPTO_rsa_sign_fdh (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
965 const struct GNUNET_HashCode *hash)
966{
967 struct GNUNET_CRYPTO_RsaPublicKey *pkey;
968 gcry_mpi_t v = NULL;
969 struct GNUNET_CRYPTO_RsaSignature *sig;
970
971 pkey = GNUNET_CRYPTO_rsa_private_key_get_public (key);
972 v = rsa_full_domain_hash (pkey, hash);
973 GNUNET_CRYPTO_rsa_public_key_free (pkey);
974 if (NULL == v) /* rsa_gcd_validate failed meaning */
975 return NULL; /* our *own* RSA key is malicious. */
976
977 sig = rsa_sign_mpi (key, v);
978 gcry_mpi_release (v);
979 return sig;
980}
981
982
983void
984GNUNET_CRYPTO_rsa_signature_free (struct GNUNET_CRYPTO_RsaSignature *sig)
985{
986 gcry_sexp_release (sig->sexp);
987 GNUNET_free (sig);
988}
989
990
991size_t
992GNUNET_CRYPTO_rsa_signature_encode (
993 const struct GNUNET_CRYPTO_RsaSignature *sig,
994 void **buffer)
995{
996 gcry_mpi_t s;
997 size_t buf_size;
998 size_t rsize;
999 unsigned char *buf;
1000 int ret;
1001
1002 ret = key_from_sexp (&s,
1003 sig->sexp,
1004 "sig-val",
1005 "s");
1006 if (0 != ret)
1007 ret = key_from_sexp (&s,
1008 sig->sexp,
1009 "rsa",
1010 "s");
1011 GNUNET_assert (0 == ret);
1012 gcry_mpi_print (GCRYMPI_FMT_USG,
1013 NULL,
1014 0,
1015 &buf_size,
1016 s);
1017 buf = GNUNET_malloc (buf_size);
1018 GNUNET_assert (0 ==
1019 gcry_mpi_print (GCRYMPI_FMT_USG,
1020 buf,
1021 buf_size,
1022 &rsize,
1023 s));
1024 GNUNET_assert (rsize == buf_size);
1025 *buffer = (void *) buf;
1026 gcry_mpi_release (s);
1027 return buf_size;
1028}
1029
1030
1031struct GNUNET_CRYPTO_RsaSignature *
1032GNUNET_CRYPTO_rsa_signature_decode (const void *buf,
1033 size_t buf_size)
1034{
1035 struct GNUNET_CRYPTO_RsaSignature *sig;
1036 gcry_mpi_t s;
1037 gcry_sexp_t data;
1038
1039 if (0 !=
1040 gcry_mpi_scan (&s,
1041 GCRYMPI_FMT_USG,
1042 buf,
1043 buf_size,
1044 NULL))
1045 {
1046 GNUNET_break_op (0);
1047 return NULL;
1048 }
1049
1050 if (0 !=
1051 gcry_sexp_build (&data,
1052 NULL,
1053 "(sig-val(rsa(s %M)))",
1054 s))
1055 {
1056 GNUNET_break (0);
1057 gcry_mpi_release (s);
1058 return NULL;
1059 }
1060 gcry_mpi_release (s);
1061 sig = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1062 sig->sexp = data;
1063 return sig;
1064}
1065
1066
1067struct GNUNET_CRYPTO_RsaPublicKey *
1068GNUNET_CRYPTO_rsa_public_key_dup (const struct GNUNET_CRYPTO_RsaPublicKey *key)
1069{
1070 struct GNUNET_CRYPTO_RsaPublicKey *dup;
1071 gcry_sexp_t dup_sexp;
1072 size_t erroff;
1073
1074 /* check if we really are exporting a public key */
1075 dup_sexp = gcry_sexp_find_token (key->sexp, "public-key", 0);
1076 GNUNET_assert (NULL != dup_sexp);
1077 gcry_sexp_release (dup_sexp);
1078 /* copy the sexp */
1079 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", key->sexp));
1080 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaPublicKey);
1081 dup->sexp = dup_sexp;
1082 return dup;
1083}
1084
1085
1086struct GNUNET_CRYPTO_RsaSignature *
1087GNUNET_CRYPTO_rsa_unblind (const struct GNUNET_CRYPTO_RsaSignature *sig,
1088 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
1089 struct GNUNET_CRYPTO_RsaPublicKey *pkey)
1090{
1091 struct RsaBlindingKey *bkey;
1092 gcry_mpi_t n;
1093 gcry_mpi_t s;
1094 gcry_mpi_t r_inv;
1095 gcry_mpi_t ubsig;
1096 int ret;
1097 struct GNUNET_CRYPTO_RsaSignature *sret;
1098
1099 BENCHMARK_START (rsa_unblind);
1100
1101 ret = key_from_sexp (&n, pkey->sexp, "public-key", "n");
1102 if (0 != ret)
1103 ret = key_from_sexp (&n, pkey->sexp, "rsa", "n");
1104 if (0 != ret)
1105 {
1106 GNUNET_break_op (0);
1107 return NULL;
1108 }
1109 ret = key_from_sexp (&s, sig->sexp, "sig-val", "s");
1110 if (0 != ret)
1111 ret = key_from_sexp (&s, sig->sexp, "rsa", "s");
1112 if (0 != ret)
1113 {
1114 gcry_mpi_release (n);
1115 GNUNET_break_op (0);
1116 return NULL;
1117 }
1118
1119 bkey = rsa_blinding_key_derive (pkey, bks);
1120 if (NULL == bkey)
1121 {
1122 /* RSA key is malicious since rsa_gcd_validate failed here.
1123 * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
1124 * so the exchange is being malicious in an unfamilair way, maybe
1125 * just trying to crash us. */
1126 GNUNET_break_op (0);
1127 gcry_mpi_release (n);
1128 gcry_mpi_release (s);
1129 return NULL;
1130 }
1131
1132 r_inv = gcry_mpi_new (0);
1133 if (1 !=
1134 gcry_mpi_invm (r_inv,
1135 bkey->r,
1136 n))
1137 {
1138 /* We cannot find r mod n, so gcd(r,n) != 1, which should get *
1139 * caught above, but we handle it the same here. */
1140 GNUNET_break_op (0);
1141 gcry_mpi_release (r_inv);
1142 rsa_blinding_key_free (bkey);
1143 gcry_mpi_release (n);
1144 gcry_mpi_release (s);
1145 return NULL;
1146 }
1147
1148 ubsig = gcry_mpi_new (0);
1149 gcry_mpi_mulm (ubsig, s, r_inv, n);
1150 gcry_mpi_release (n);
1151 gcry_mpi_release (r_inv);
1152 gcry_mpi_release (s);
1153 rsa_blinding_key_free (bkey);
1154
1155 sret = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1156 GNUNET_assert (0 ==
1157 gcry_sexp_build (&sret->sexp,
1158 NULL,
1159 "(sig-val (rsa (s %M)))",
1160 ubsig));
1161 gcry_mpi_release (ubsig);
1162 BENCHMARK_END (rsa_unblind);
1163 return sret;
1164}
1165
1166
1167enum GNUNET_GenericReturnValue
1168GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash,
1169 const struct GNUNET_CRYPTO_RsaSignature *sig,
1170 const struct GNUNET_CRYPTO_RsaPublicKey *pkey)
1171{
1172 gcry_sexp_t data;
1173 gcry_mpi_t r;
1174 int rc;
1175
1176 BENCHMARK_START (rsa_verify);
1177
1178 r = rsa_full_domain_hash (pkey, hash);
1179 if (NULL == r)
1180 {
1181 GNUNET_break_op (0);
1182 /* RSA key is malicious since rsa_gcd_validate failed here.
1183 * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
1184 * so the exchange is being malicious in an unfamilair way, maybe
1185 * just trying to crash us. Arguably, we've only an internal error
1186 * though because we should've detected this in our previous call
1187 * to GNUNET_CRYPTO_rsa_unblind. *///
1188 return GNUNET_NO;
1189 }
1190
1191 data = mpi_to_sexp (r);
1192 gcry_mpi_release (r);
1193
1194 rc = gcry_pk_verify (sig->sexp,
1195 data,
1196 pkey->sexp);
1197 gcry_sexp_release (data);
1198 if (0 != rc)
1199 {
1200 LOG (GNUNET_ERROR_TYPE_WARNING,
1201 _ ("RSA signature verification failed at %s:%d: %s\n"),
1202 __FILE__,
1203 __LINE__,
1204 gcry_strerror (rc));
1205 BENCHMARK_END (rsa_verify);
1206 return GNUNET_SYSERR;
1207 }
1208 BENCHMARK_END (rsa_verify);
1209 return GNUNET_OK;
1210}
1211
1212
1213struct GNUNET_CRYPTO_RsaPrivateKey *
1214GNUNET_CRYPTO_rsa_private_key_dup (
1215 const struct GNUNET_CRYPTO_RsaPrivateKey *key)
1216{
1217 struct GNUNET_CRYPTO_RsaPrivateKey *dup;
1218 gcry_sexp_t dup_sexp;
1219 size_t erroff;
1220
1221 /* check if we really are exporting a private key */
1222 dup_sexp = gcry_sexp_find_token (key->sexp, "private-key", 0);
1223 GNUNET_assert (NULL != dup_sexp);
1224 gcry_sexp_release (dup_sexp);
1225 /* copy the sexp */
1226 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", key->sexp));
1227 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaPrivateKey);
1228 dup->sexp = dup_sexp;
1229 return dup;
1230}
1231
1232
1233struct GNUNET_CRYPTO_RsaSignature *
1234GNUNET_CRYPTO_rsa_signature_dup (const struct GNUNET_CRYPTO_RsaSignature *sig)
1235{
1236 struct GNUNET_CRYPTO_RsaSignature *dup;
1237 gcry_sexp_t dup_sexp;
1238 size_t erroff;
1239 gcry_mpi_t s;
1240 int ret;
1241
1242 /* verify that this is an RSA signature */
1243 ret = key_from_sexp (&s, sig->sexp, "sig-val", "s");
1244 if (0 != ret)
1245 ret = key_from_sexp (&s, sig->sexp, "rsa", "s");
1246 GNUNET_assert (0 == ret);
1247 gcry_mpi_release (s);
1248 /* copy the sexp */
1249 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", sig->sexp));
1250 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1251 dup->sexp = dup_sexp;
1252 return dup;
1253}
1254
1255
1256/* end of util/rsa.c */
diff --git a/src/util/crypto_symmetric.c b/src/util/crypto_symmetric.c
deleted file mode 100644
index 51414b00e..000000000
--- a/src/util/crypto_symmetric.c
+++ /dev/null
@@ -1,262 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2013 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 util/crypto_symmetric.c
23 * @brief Symmetric encryption services; combined cipher AES+TWOFISH (256-bit each)
24 * @author Christian Grothoff
25 * @author Ioana Patrascu
26 */
27
28#include "platform.h"
29#include "gnunet_crypto_lib.h"
30#include <gcrypt.h>
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-symmetric", \
33 __VA_ARGS__)
34
35/**
36 * Create a new SessionKey (for symmetric encryption).
37 *
38 * @param key session key to initialize
39 */
40void
41GNUNET_CRYPTO_symmetric_create_session_key (struct
42 GNUNET_CRYPTO_SymmetricSessionKey *
43 key)
44{
45 gcry_randomize (key->aes_key,
46 GNUNET_CRYPTO_AES_KEY_LENGTH,
47 GCRY_STRONG_RANDOM);
48 gcry_randomize (key->twofish_key,
49 GNUNET_CRYPTO_AES_KEY_LENGTH,
50 GCRY_STRONG_RANDOM);
51}
52
53
54/**
55 * Initialize AES cipher.
56 *
57 * @param handle handle to initialize
58 * @param sessionkey session key to use
59 * @param iv initialization vector to use
60 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
61 */
62static int
63setup_cipher_aes (gcry_cipher_hd_t *handle,
64 const struct GNUNET_CRYPTO_SymmetricSessionKey *sessionkey,
65 const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
66{
67 int rc;
68
69 GNUNET_assert (0 ==
70 gcry_cipher_open (handle, GCRY_CIPHER_AES256,
71 GCRY_CIPHER_MODE_CFB, 0));
72 rc = gcry_cipher_setkey (*handle,
73 sessionkey->aes_key,
74 sizeof(sessionkey->aes_key));
75 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
76 rc = gcry_cipher_setiv (*handle,
77 iv->aes_iv,
78 sizeof(iv->aes_iv));
79 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
80 return GNUNET_OK;
81}
82
83
84/**
85 * Initialize TWOFISH cipher.
86 *
87 * @param handle handle to initialize
88 * @param sessionkey session key to use
89 * @param iv initialization vector to use
90 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
91 */
92static int
93setup_cipher_twofish (gcry_cipher_hd_t *handle,
94 const struct
95 GNUNET_CRYPTO_SymmetricSessionKey *sessionkey,
96 const struct
97 GNUNET_CRYPTO_SymmetricInitializationVector *iv)
98{
99 int rc;
100
101 GNUNET_assert (0 ==
102 gcry_cipher_open (handle, GCRY_CIPHER_TWOFISH,
103 GCRY_CIPHER_MODE_CFB, 0));
104 rc = gcry_cipher_setkey (*handle,
105 sessionkey->twofish_key,
106 sizeof(sessionkey->twofish_key));
107 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
108 rc = gcry_cipher_setiv (*handle,
109 iv->twofish_iv,
110 sizeof(iv->twofish_iv));
111 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
112 return GNUNET_OK;
113}
114
115
116/**
117 * Encrypt a block with a symmetric session key.
118 *
119 * @param block the block to encrypt
120 * @param size the size of the @a block
121 * @param sessionkey the key used to encrypt
122 * @param iv the initialization vector to use, use INITVALUE for streams
123 * @param result the output parameter in which to store the encrypted result
124 * can be the same or overlap with @c block
125 * @returns the size of the encrypted block, -1 for errors.
126 * Due to the use of CFB and therefore an effective stream cipher,
127 * this size should be the same as @c len.
128 */
129ssize_t
130GNUNET_CRYPTO_symmetric_encrypt (const void *block,
131 size_t size,
132 const struct
133 GNUNET_CRYPTO_SymmetricSessionKey *sessionkey,
134 const struct
135 GNUNET_CRYPTO_SymmetricInitializationVector *iv,
136 void *result)
137{
138 gcry_cipher_hd_t handle;
139 char tmp[size];
140
141 if (GNUNET_OK != setup_cipher_aes (&handle, sessionkey, iv))
142 return -1;
143 GNUNET_assert (0 == gcry_cipher_encrypt (handle, tmp, size, block, size));
144 gcry_cipher_close (handle);
145 if (GNUNET_OK != setup_cipher_twofish (&handle, sessionkey, iv))
146 return -1;
147 GNUNET_assert (0 == gcry_cipher_encrypt (handle, result, size, tmp, size));
148 gcry_cipher_close (handle);
149 memset (tmp, 0, sizeof(tmp));
150 return size;
151}
152
153
154/**
155 * Decrypt a given block with the session key.
156 *
157 * @param block the data to decrypt, encoded as returned by encrypt
158 * @param size the size of the @a block to decrypt
159 * @param sessionkey the key used to decrypt
160 * @param iv the initialization vector to use, use INITVALUE for streams
161 * @param result address to store the result at
162 * can be the same or overlap with @c block
163 * @return -1 on failure, size of decrypted block on success.
164 * Due to the use of CFB and therefore an effective stream cipher,
165 * this size should be the same as @c size.
166 */
167ssize_t
168GNUNET_CRYPTO_symmetric_decrypt (const void *block,
169 size_t size,
170 const struct
171 GNUNET_CRYPTO_SymmetricSessionKey *sessionkey,
172 const struct
173 GNUNET_CRYPTO_SymmetricInitializationVector *iv,
174 void *result)
175{
176 gcry_cipher_hd_t handle;
177 char tmp[size];
178
179 if (GNUNET_OK != setup_cipher_twofish (&handle, sessionkey, iv))
180 return -1;
181 GNUNET_assert (0 == gcry_cipher_decrypt (handle, tmp, size, block, size));
182 gcry_cipher_close (handle);
183 if (GNUNET_OK != setup_cipher_aes (&handle, sessionkey, iv))
184 return -1;
185 GNUNET_assert (0 == gcry_cipher_decrypt (handle, result, size, tmp, size));
186 gcry_cipher_close (handle);
187 memset (tmp, 0, sizeof(tmp));
188 return size;
189}
190
191
192/**
193 * @brief Derive an IV
194 *
195 * @param iv initialization vector
196 * @param skey session key
197 * @param salt salt for the derivation
198 * @param salt_len size of the @a salt
199 * @param ... pairs of void * & size_t for context chunks, terminated by NULL
200 */
201void
202GNUNET_CRYPTO_symmetric_derive_iv (struct
203 GNUNET_CRYPTO_SymmetricInitializationVector *
204 iv,
205 const struct
206 GNUNET_CRYPTO_SymmetricSessionKey *skey,
207 const void *salt,
208 size_t salt_len,
209 ...)
210{
211 va_list argp;
212
213 va_start (argp, salt_len);
214 GNUNET_CRYPTO_symmetric_derive_iv_v (iv, skey, salt, salt_len, argp);
215 va_end (argp);
216}
217
218
219/**
220 * @brief Derive an IV
221 *
222 * @param iv initialization vector
223 * @param skey session key
224 * @param salt salt for the derivation
225 * @param salt_len size of the salt
226 * @param argp pairs of void * & size_t for context chunks, terminated by NULL
227 */
228void
229GNUNET_CRYPTO_symmetric_derive_iv_v (struct
230 GNUNET_CRYPTO_SymmetricInitializationVector
231 *iv,
232 const struct
233 GNUNET_CRYPTO_SymmetricSessionKey *skey,
234 const void *salt,
235 size_t salt_len,
236 va_list argp)
237{
238 char aes_salt[salt_len + 4];
239 char twofish_salt[salt_len + 4];
240
241 GNUNET_memcpy (aes_salt, salt, salt_len);
242 GNUNET_memcpy (&aes_salt[salt_len], "AES!", 4);
243 GNUNET_memcpy (twofish_salt, salt, salt_len);
244 GNUNET_memcpy (&twofish_salt[salt_len], "FISH", 4);
245 GNUNET_CRYPTO_kdf_v (iv->aes_iv,
246 sizeof(iv->aes_iv),
247 aes_salt,
248 salt_len + 4,
249 skey->aes_key,
250 sizeof(skey->aes_key),
251 argp);
252 GNUNET_CRYPTO_kdf_v (iv->twofish_iv,
253 sizeof(iv->twofish_iv),
254 twofish_salt,
255 salt_len + 4,
256 skey->twofish_key,
257 sizeof(skey->twofish_key),
258 argp);
259}
260
261
262/* end of crypto_symmetric.c */
diff --git a/src/util/disk.c b/src/util/disk.c
deleted file mode 100644
index 2efb52d46..000000000
--- a/src/util/disk.c
+++ /dev/null
@@ -1,1688 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001--2013, 2016, 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 * @file util/disk.c
22 * @brief disk IO convenience methods
23 * @author Christian Grothoff
24 * @author Nils Durner
25 */
26#include "platform.h"
27#include "disk.h"
28#include "gnunet_strings_lib.h"
29#include "gnunet_disk_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-disk", __VA_ARGS__)
32
33#define LOG_STRERROR(kind, syscall) \
34 GNUNET_log_from_strerror (kind, "util-disk", syscall)
35
36#define LOG_STRERROR_FILE(kind, syscall, filename) \
37 GNUNET_log_from_strerror_file (kind, "util-disk", syscall, filename)
38
39/**
40 * Block size for IO for copying files.
41 */
42#define COPY_BLK_SIZE 65536
43
44#include <sys/types.h>
45#if HAVE_SYS_VFS_H
46#include <sys/vfs.h>
47#endif
48#if HAVE_SYS_PARAM_H
49#include <sys/param.h>
50#endif
51#if HAVE_SYS_MOUNT_H
52#include <sys/mount.h>
53#endif
54#if HAVE_SYS_STATVFS_H
55#include <sys/statvfs.h>
56#endif
57
58#ifndef S_ISLNK
59#define _IFMT 0170000 /* type of file */
60#define _IFLNK 0120000 /* symbolic link */
61#define S_ISLNK(m) (((m) & _IFMT) == _IFLNK)
62#endif
63
64
65/**
66 * Handle used to manage a pipe.
67 */
68struct GNUNET_DISK_PipeHandle
69{
70 /**
71 * File descriptors for the pipe.
72 * One or both of them could be NULL.
73 */
74 struct GNUNET_DISK_FileHandle *fd[2];
75};
76
77
78/**
79 * Closure for the recursion to determine the file size
80 * of a directory.
81 */
82struct GetFileSizeData
83{
84 /**
85 * Set to the total file size.
86 */
87 uint64_t total;
88
89 /**
90 * GNUNET_YES if symbolic links should be included.
91 */
92 int include_sym_links;
93
94 /**
95 * #GNUNET_YES if mode is file-only (return total == -1 for directories).
96 */
97 int single_file_mode;
98};
99
100
101/**
102 * Translate GNUnet-internal permission bitmap to UNIX file
103 * access permission bitmap.
104 *
105 * @param perm file permissions, GNUnet style
106 * @return file permissions, UNIX style
107 */
108static int
109translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm)
110{
111 int mode;
112
113 mode = 0;
114 if (perm & GNUNET_DISK_PERM_USER_READ)
115 mode |= S_IRUSR;
116 if (perm & GNUNET_DISK_PERM_USER_WRITE)
117 mode |= S_IWUSR;
118 if (perm & GNUNET_DISK_PERM_USER_EXEC)
119 mode |= S_IXUSR;
120 if (perm & GNUNET_DISK_PERM_GROUP_READ)
121 mode |= S_IRGRP;
122 if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
123 mode |= S_IWGRP;
124 if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
125 mode |= S_IXGRP;
126 if (perm & GNUNET_DISK_PERM_OTHER_READ)
127 mode |= S_IROTH;
128 if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
129 mode |= S_IWOTH;
130 if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
131 mode |= S_IXOTH;
132
133 return mode;
134}
135
136
137/**
138 * Iterate over all files in the given directory and
139 * accumulate their size.
140 *
141 * @param cls closure of type `struct GetFileSizeData`
142 * @param fn current filename we are looking at
143 * @return #GNUNET_SYSERR on serious errors, otherwise #GNUNET_OK
144 */
145static enum GNUNET_GenericReturnValue
146get_size_rec (void *cls, const char *fn)
147{
148 struct GetFileSizeData *gfsd = cls;
149
150#if defined(HAVE_STAT64) && \
151 ! (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
152 struct stat64 buf;
153
154 if (0 != stat64 (fn, &buf))
155 {
156 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat64", fn);
157 return GNUNET_SYSERR;
158 }
159#else
160 struct stat buf;
161
162 if (0 != stat (fn, &buf))
163 {
164 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", fn);
165 return GNUNET_SYSERR;
166 }
167#endif
168 if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES))
169 {
170 errno = EISDIR;
171 return GNUNET_SYSERR;
172 }
173 if ((! S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
174 gfsd->total += buf.st_size;
175 if ((S_ISDIR (buf.st_mode)) && (0 == access (fn, X_OK)) &&
176 ((! S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
177 {
178 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &get_size_rec, gfsd))
179 return GNUNET_SYSERR;
180 }
181 return GNUNET_OK;
182}
183
184
185enum GNUNET_GenericReturnValue
186GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
187{
188 return ((! h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
189}
190
191
192enum GNUNET_GenericReturnValue
193GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
194 off_t *size)
195{
196 struct stat sbuf;
197
198 if (0 != fstat (fh->fd, &sbuf))
199 return GNUNET_SYSERR;
200 *size = sbuf.st_size;
201 return GNUNET_OK;
202}
203
204
205off_t
206GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h,
207 off_t offset,
208 enum GNUNET_DISK_Seek whence)
209{
210 static int t[] = { SEEK_SET, SEEK_CUR, SEEK_END };
211
212 if (h == NULL)
213 {
214 errno = EINVAL;
215 return GNUNET_SYSERR;
216 }
217 return lseek (h->fd, offset, t[whence]);
218}
219
220
221enum GNUNET_GenericReturnValue
222GNUNET_DISK_file_size (const char *filename,
223 uint64_t *size,
224 int include_symbolic_links,
225 int single_file_mode)
226{
227 struct GetFileSizeData gfsd;
228 enum GNUNET_GenericReturnValue ret;
229
230 GNUNET_assert (size != NULL);
231 gfsd.total = 0;
232 gfsd.include_sym_links = include_symbolic_links;
233 gfsd.single_file_mode = single_file_mode;
234 ret = get_size_rec (&gfsd, filename);
235 *size = gfsd.total;
236 return ret;
237}
238
239
240enum GNUNET_GenericReturnValue
241GNUNET_DISK_file_get_identifiers (const char *filename,
242 uint64_t *dev,
243 uint64_t *ino)
244{
245#if HAVE_STAT
246 {
247 struct stat sbuf;
248
249 if (0 != stat (filename, &sbuf))
250 {
251 return GNUNET_SYSERR;
252 }
253 *ino = (uint64_t) sbuf.st_ino;
254 }
255#else
256 *ino = 0;
257#endif
258#if HAVE_STATVFS
259 {
260 struct statvfs fbuf;
261
262 if (0 != statvfs (filename, &fbuf))
263 {
264 return GNUNET_SYSERR;
265 }
266 *dev = (uint64_t) fbuf.f_fsid;
267 }
268#elif HAVE_STATFS
269 {
270 struct statfs fbuf;
271
272 if (0 != statfs (filename, &fbuf))
273 {
274 return GNUNET_SYSERR;
275 }
276 *dev =
277 ((uint64_t) fbuf.f_fsid.val[0]) << 32 || ((uint64_t) fbuf.f_fsid.val[1]);
278 }
279#else
280 *dev = 0;
281#endif
282 return GNUNET_OK;
283}
284
285
286/**
287 * Create the name for a temporary file or directory from a template.
288 *
289 * @param t template (without XXXXX or "/tmp/")
290 * @return name ready for passing to 'mktemp' or 'mkdtemp', NULL on error
291 */
292static char *
293mktemp_name (const char *t)
294{
295 const char *tmpdir;
296 char *tmpl;
297 char *fn;
298
299 if ((t[0] != '/') && (t[0] != '\\'))
300 {
301 /* FIXME: This uses system codepage on W32, not UTF-8 */
302 tmpdir = getenv ("TMPDIR");
303 if (NULL == tmpdir)
304 tmpdir = getenv ("TMP");
305 if (NULL == tmpdir)
306 tmpdir = getenv ("TEMP");
307 if (NULL == tmpdir)
308 tmpdir = "/tmp";
309 GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
310 }
311 else
312 {
313 GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
314 }
315 fn = tmpl;
316 return fn;
317}
318
319
320void
321GNUNET_DISK_fix_permissions (const char *fn,
322 int require_uid_match,
323 int require_gid_match)
324{
325 mode_t mode;
326
327 if (GNUNET_YES == require_uid_match)
328 mode = S_IRUSR | S_IWUSR | S_IXUSR;
329 else if (GNUNET_YES == require_gid_match)
330 mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP;
331 else
332 mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH
333 | S_IWOTH | S_IXOTH;
334 if (0 != chmod (fn, mode))
335 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "chmod", fn);
336}
337
338
339char *
340GNUNET_DISK_mkdtemp (const char *t)
341{
342 char *fn;
343 mode_t omask;
344
345 omask = umask (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH);
346 fn = mktemp_name (t);
347 if (fn != mkdtemp (fn))
348 {
349 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdtemp", fn);
350 GNUNET_free (fn);
351 umask (omask);
352 return NULL;
353 }
354 umask (omask);
355 return fn;
356}
357
358
359void
360GNUNET_DISK_file_backup (const char *fil)
361{
362 size_t slen;
363 char *target;
364 unsigned int num;
365
366 slen = strlen (fil) + 20;
367 target = GNUNET_malloc (slen);
368 num = 0;
369 do
370 {
371 GNUNET_snprintf (target, slen, "%s.%u~", fil, num++);
372 }
373 while (0 == access (target, F_OK));
374 if (0 != rename (fil, target))
375 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "rename", fil);
376 GNUNET_free (target);
377}
378
379
380char *
381GNUNET_DISK_mktemp (const char *t)
382{
383 int fd;
384 char *fn;
385 mode_t omask;
386
387 omask = umask (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH);
388 fn = mktemp_name (t);
389 if (-1 == (fd = mkstemp (fn)))
390 {
391 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
392 GNUNET_free (fn);
393 umask (omask);
394 return NULL;
395 }
396 umask (omask);
397 if (0 != close (fd))
398 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
399 return fn;
400}
401
402
403enum GNUNET_GenericReturnValue
404GNUNET_DISK_directory_test (const char *fil, int is_readable)
405{
406 struct stat filestat;
407 int ret;
408
409 ret = stat (fil, &filestat);
410 if (ret != 0)
411 {
412 if (errno != ENOENT)
413 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
414 return GNUNET_SYSERR;
415 }
416 if (! S_ISDIR (filestat.st_mode))
417 {
418 LOG (GNUNET_ERROR_TYPE_INFO,
419 "A file already exits with the same name %s\n",
420 fil);
421 return GNUNET_NO;
422 }
423 if (GNUNET_YES == is_readable)
424 ret = access (fil, R_OK | X_OK);
425 else
426 ret = access (fil, X_OK);
427 if (ret < 0)
428 {
429 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
430 return GNUNET_NO;
431 }
432 return GNUNET_YES;
433}
434
435/**
436 * Check if fil can be accessed using amode.
437 *
438 * @param fil file to check for
439 * @param amode access mode
440 * @returns GNUnet error code
441 */
442static enum GNUNET_GenericReturnValue
443file_test_internal (const char *fil, int amode)
444{
445 struct stat filestat;
446 int ret;
447 char *rdir;
448
449 rdir = GNUNET_STRINGS_filename_expand (fil);
450 if (rdir == NULL)
451 return GNUNET_SYSERR;
452
453 ret = stat (rdir, &filestat);
454 if (0 != ret)
455 {
456 if (errno != ENOENT)
457 {
458 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", rdir);
459 GNUNET_free (rdir);
460 return GNUNET_SYSERR;
461 }
462 GNUNET_free (rdir);
463 return GNUNET_NO;
464 }
465 if (! S_ISREG (filestat.st_mode))
466 {
467 GNUNET_free (rdir);
468 return GNUNET_NO;
469 }
470 if (access (rdir, amode) < 0)
471 {
472 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "access", rdir);
473 GNUNET_free (rdir);
474 return GNUNET_SYSERR;
475 }
476 GNUNET_free (rdir);
477 return GNUNET_YES;
478}
479
480
481enum GNUNET_GenericReturnValue
482GNUNET_DISK_file_test (const char *fil)
483{
484 return file_test_internal (fil, F_OK);
485}
486
487
488enum GNUNET_GenericReturnValue
489GNUNET_DISK_file_test_read (const char *fil)
490{
491 return file_test_internal (fil, R_OK);
492}
493
494
495enum GNUNET_GenericReturnValue
496GNUNET_DISK_directory_create (const char *dir)
497{
498 char *rdir;
499 unsigned int len;
500 unsigned int pos;
501 unsigned int pos2;
502 int ret = GNUNET_OK;
503
504 rdir = GNUNET_STRINGS_filename_expand (dir);
505 if (rdir == NULL)
506 {
507 GNUNET_break (0);
508 return GNUNET_SYSERR;
509 }
510
511 len = strlen (rdir);
512
513 pos = 1; /* skip heading '/' */
514
515 /* Check which low level directories already exist */
516 pos2 = len;
517 rdir[len] = DIR_SEPARATOR;
518 while (pos <= pos2)
519 {
520 if (DIR_SEPARATOR == rdir[pos2])
521 {
522 rdir[pos2] = '\0';
523 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
524 if (GNUNET_NO == ret)
525 {
526 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
527 "Creating directory `%s' failed",
528 rdir);
529 GNUNET_free (rdir);
530 return GNUNET_SYSERR;
531 }
532 rdir[pos2] = DIR_SEPARATOR;
533 if (GNUNET_YES == ret)
534 {
535 pos2++;
536 break;
537 }
538 }
539 pos2--;
540 }
541 rdir[len] = '\0';
542 if (pos < pos2)
543 pos = pos2;
544 /* Start creating directories */
545 while (pos <= len)
546 {
547 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
548 {
549 rdir[pos] = '\0';
550 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
551 if (GNUNET_NO == ret)
552 {
553 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
554 "Creating directory `%s' failed",
555 rdir);
556 GNUNET_free (rdir);
557 return GNUNET_SYSERR;
558 }
559 if (GNUNET_SYSERR == ret)
560 {
561 ret = mkdir (rdir,
562 S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH
563 | S_IXOTH); /* 755 */
564
565 if ((ret != 0) && (errno != EEXIST))
566 {
567 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
568 GNUNET_free (rdir);
569 return GNUNET_SYSERR;
570 }
571 }
572 rdir[pos] = DIR_SEPARATOR;
573 }
574 pos++;
575 }
576 GNUNET_free (rdir);
577 return GNUNET_OK;
578}
579
580
581enum GNUNET_GenericReturnValue
582GNUNET_DISK_directory_create_for_file (const char *filename)
583{
584 char *rdir;
585 size_t len;
586 int eno;
587 enum GNUNET_GenericReturnValue res;
588
589 rdir = GNUNET_STRINGS_filename_expand (filename);
590 if (NULL == rdir)
591 {
592 errno = EINVAL;
593 return GNUNET_SYSERR;
594 }
595 if (0 == access (rdir, W_OK))
596 {
597 GNUNET_free (rdir);
598 return GNUNET_OK;
599 }
600 len = strlen (rdir);
601 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
602 len--;
603 rdir[len] = '\0';
604 /* The empty path is invalid and in this case refers to / */
605 if (0 == len)
606 {
607 GNUNET_free (rdir);
608 rdir = GNUNET_strdup ("/");
609 }
610 res = GNUNET_DISK_directory_create (rdir);
611 if ( (GNUNET_OK == res) &&
612 (0 != access (rdir, W_OK)) )
613 res = GNUNET_NO;
614 eno = errno;
615 GNUNET_free (rdir);
616 errno = eno;
617 return res;
618}
619
620
621ssize_t
622GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h,
623 void *result,
624 size_t len)
625{
626 if (NULL == h)
627 {
628 errno = EINVAL;
629 return GNUNET_SYSERR;
630 }
631 return read (h->fd, result, len);
632}
633
634
635ssize_t
636GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle *h,
637 void *result,
638 size_t len)
639{
640 int flags;
641 ssize_t ret;
642
643 if (NULL == h)
644 {
645 errno = EINVAL;
646 return GNUNET_SYSERR;
647 }
648 /* set to non-blocking, read, then set back */
649 flags = fcntl (h->fd, F_GETFL);
650 if (0 == (flags & O_NONBLOCK))
651 (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
652 ret = read (h->fd, result, len);
653 if (0 == (flags & O_NONBLOCK))
654 {
655 int eno = errno;
656 (void) fcntl (h->fd, F_SETFL, flags);
657 errno = eno;
658 }
659 return ret;
660}
661
662
663ssize_t
664GNUNET_DISK_fn_read (const char *fn,
665 void *result,
666 size_t len)
667{
668 struct GNUNET_DISK_FileHandle *fh;
669 ssize_t ret;
670 int eno;
671
672 fh = GNUNET_DISK_file_open (fn,
673 GNUNET_DISK_OPEN_READ,
674 GNUNET_DISK_PERM_NONE);
675 if (NULL == fh)
676 return GNUNET_SYSERR;
677 ret = GNUNET_DISK_file_read (fh, result, len);
678 eno = errno;
679 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
680 errno = eno;
681 return ret;
682}
683
684
685ssize_t
686GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h,
687 const void *buffer,
688 size_t n)
689{
690 if (NULL == h)
691 {
692 errno = EINVAL;
693 return GNUNET_SYSERR;
694 }
695
696 return write (h->fd, buffer, n);
697}
698
699
700ssize_t
701GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle *h,
702 const void *buffer,
703 size_t n)
704{
705 int flags;
706 ssize_t ret;
707
708 if (NULL == h)
709 {
710 errno = EINVAL;
711 return GNUNET_SYSERR;
712 }
713 /* set to blocking, write, then set back */
714 flags = fcntl (h->fd, F_GETFL);
715 if (0 != (flags & O_NONBLOCK))
716 (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
717 ret = write (h->fd, buffer, n);
718 if (0 == (flags & O_NONBLOCK))
719 (void) fcntl (h->fd, F_SETFL, flags);
720 return ret;
721}
722
723
724enum GNUNET_GenericReturnValue
725GNUNET_DISK_fn_write (const char *fn,
726 const void *buf,
727 size_t buf_size,
728 enum GNUNET_DISK_AccessPermissions mode)
729{
730 char *tmpl;
731 int fd;
732
733 if (GNUNET_OK !=
734 GNUNET_DISK_directory_create_for_file (fn))
735 {
736 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
737 "mkstemp",
738 fn);
739 return GNUNET_SYSERR;
740 }
741 {
742 char *dname;
743
744 dname = GNUNET_strdup (fn);
745 GNUNET_asprintf (&tmpl,
746 "%s/XXXXXX",
747 dirname (dname));
748 GNUNET_free (dname);
749 }
750 fd = mkstemp (tmpl);
751 if (-1 == fd)
752 {
753 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
754 "mkstemp",
755 tmpl);
756 GNUNET_free (tmpl);
757 return GNUNET_SYSERR;
758 }
759
760 if (0 != fchmod (fd,
761 translate_unix_perms (mode)))
762 {
763 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
764 "chmod",
765 tmpl);
766 GNUNET_assert (0 == close (fd));
767 if (0 != unlink (tmpl))
768 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
769 "unlink",
770 tmpl);
771 GNUNET_free (tmpl);
772 return GNUNET_SYSERR;
773 }
774 if (buf_size !=
775 write (fd,
776 buf,
777 buf_size))
778 {
779 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
780 "write",
781 tmpl);
782 GNUNET_assert (0 == close (fd));
783 if (0 != unlink (tmpl))
784 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
785 "unlink",
786 tmpl);
787 GNUNET_free (tmpl);
788 return GNUNET_SYSERR;
789 }
790 GNUNET_assert (0 == close (fd));
791
792 if (0 != link (tmpl,
793 fn))
794 {
795 if (0 != unlink (tmpl))
796 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
797 "unlink",
798 tmpl);
799 GNUNET_free (tmpl);
800 return GNUNET_NO;
801 }
802 if (0 != unlink (tmpl))
803 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
804 "unlink",
805 tmpl);
806 GNUNET_free (tmpl);
807 return GNUNET_OK;
808
809
810}
811
812
813int
814GNUNET_DISK_directory_scan (const char *dir_name,
815 GNUNET_FileNameCallback callback,
816 void *callback_cls)
817{
818 DIR *dinfo;
819 struct dirent *finfo;
820 struct stat istat;
821 int count = 0;
822 enum GNUNET_GenericReturnValue ret;
823 char *name;
824 char *dname;
825 unsigned int name_len;
826 unsigned int n_size;
827
828 GNUNET_assert (NULL != dir_name);
829 dname = GNUNET_STRINGS_filename_expand (dir_name);
830 if (NULL == dname)
831 return GNUNET_SYSERR;
832 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
833 dname[strlen (dname) - 1] = '\0';
834 if (0 != stat (dname, &istat))
835 {
836 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
837 GNUNET_free (dname);
838 return GNUNET_SYSERR;
839 }
840 if (! S_ISDIR (istat.st_mode))
841 {
842 LOG (GNUNET_ERROR_TYPE_WARNING,
843 _ ("Expected `%s' to be a directory!\n"),
844 dir_name);
845 GNUNET_free (dname);
846 return GNUNET_SYSERR;
847 }
848 errno = 0;
849 dinfo = opendir (dname);
850 if ((EACCES == errno) || (NULL == dinfo))
851 {
852 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
853 if (NULL != dinfo)
854 closedir (dinfo);
855 GNUNET_free (dname);
856 return GNUNET_SYSERR;
857 }
858 name_len = 256;
859 n_size = strlen (dname) + name_len + strlen (DIR_SEPARATOR_STR) + 1;
860 name = GNUNET_malloc (n_size);
861 while (NULL != (finfo = readdir (dinfo)))
862 {
863 if ((0 == strcmp (finfo->d_name, ".")) ||
864 (0 == strcmp (finfo->d_name, "..")))
865 continue;
866 if (NULL != callback)
867 {
868 if (name_len < strlen (finfo->d_name))
869 {
870 GNUNET_free (name);
871 name_len = strlen (finfo->d_name);
872 n_size = strlen (dname) + name_len + strlen (DIR_SEPARATOR_STR) + 1;
873 name = GNUNET_malloc (n_size);
874 }
875 /* dname can end in "/" only if dname == "/";
876 * if dname does not end in "/", we need to add
877 * a "/" (otherwise, we must not!) */
878 GNUNET_snprintf (name,
879 n_size,
880 "%s%s%s",
881 dname,
882 (0 == strcmp (dname, DIR_SEPARATOR_STR))
883 ? ""
884 : DIR_SEPARATOR_STR,
885 finfo->d_name);
886 ret = callback (callback_cls, name);
887 if (GNUNET_OK != ret)
888 {
889 closedir (dinfo);
890 GNUNET_free (name);
891 GNUNET_free (dname);
892 if (GNUNET_NO == ret)
893 return count;
894 return GNUNET_SYSERR;
895 }
896 }
897 count++;
898 }
899 closedir (dinfo);
900 GNUNET_free (name);
901 GNUNET_free (dname);
902 return count;
903}
904
905/**
906 * Check for a simple wildcard match.
907 * Only asterisks are allowed.
908 * Asterisks match everything, including slashes.
909 *
910 * @param pattern pattern with wildcards
911 * @param str string to match against
912 * @returns true on match, false otherwise
913 */
914static bool
915glob_match (const char *pattern, const char *str)
916{
917 /* Position in the input string */
918 const char *str_pos = str;
919 /* Position in the pattern */
920 const char *pat_pos = pattern;
921 /* Backtrack position in string */
922 const char *str_bt = NULL;
923 /* Backtrack position in pattern */
924 const char *pat_bt = NULL;
925
926 for (;;)
927 {
928 if (*pat_pos == '*')
929 {
930 str_bt = str_pos;
931 pat_bt = pat_pos++;
932 }
933 else if (*pat_pos == *str_pos)
934 {
935 if ('\0' == *pat_pos)
936 return true;
937 str_pos++;
938 pat_pos++;
939 }
940 else
941 {
942 if (NULL == str_bt)
943 return false;
944 /* Backtrack to match one more
945 character as part of the asterisk. */
946 str_pos = str_bt + 1;
947 if ('\0' == *str_pos)
948 return false;
949 pat_pos = pat_bt;
950 }
951 }
952}
953
954struct GlobClosure
955{
956 const char *glob;
957 GNUNET_FileNameCallback cb;
958 void *cls;
959
960 /**
961 * Number of files that actually matched the glob pattern.
962 */
963 int nres;
964};
965
966/**
967 * Function called with a filename.
968 *
969 * @param cls closure
970 * @param filename complete filename (absolute path)
971 * @return #GNUNET_OK to continue to iterate,
972 * #GNUNET_NO to stop iteration with no error,
973 * #GNUNET_SYSERR to abort iteration with error!
974 */
975static enum GNUNET_GenericReturnValue
976glob_cb (void *cls,
977 const char *filename)
978{
979 struct GlobClosure *gc = cls;
980 const char *fn;
981
982 fn = strrchr (filename, DIR_SEPARATOR);
983 fn = (NULL == fn) ? filename : (fn + 1);
984
985 LOG (GNUNET_ERROR_TYPE_DEBUG,
986 "checking glob '%s' against '%s'\n",
987 gc->glob,
988 fn);
989
990 if (glob_match (gc->glob, fn))
991 {
992 enum GNUNET_GenericReturnValue cbret;
993
994 LOG (GNUNET_ERROR_TYPE_DEBUG,
995 "found glob match '%s'\n",
996 filename);
997 gc->nres++;
998 cbret = gc->cb (gc->cls, filename);
999 if (GNUNET_OK != cbret)
1000 return cbret;
1001 }
1002 return GNUNET_OK;
1003}
1004
1005
1006int
1007GNUNET_DISK_glob (const char *glob_pattern,
1008 GNUNET_FileNameCallback callback,
1009 void *callback_cls)
1010{
1011 char *mypat = GNUNET_strdup (glob_pattern);
1012 char *sep;
1013 int ret;
1014
1015 if ( (NULL != strrchr (glob_pattern, '+')) ||
1016 (NULL != strrchr (glob_pattern, '[')) ||
1017 (NULL != strrchr (glob_pattern, '+')) ||
1018 (NULL != strrchr (glob_pattern, '~')) )
1019 {
1020 LOG (GNUNET_ERROR_TYPE_ERROR,
1021 "unsupported glob pattern: '%s'\n",
1022 glob_pattern);
1023 GNUNET_free (mypat);
1024 return -1;
1025 }
1026
1027 sep = strrchr (mypat, DIR_SEPARATOR);
1028 if (NULL == sep)
1029 {
1030 GNUNET_free (mypat);
1031 return -1;
1032 }
1033
1034 *sep = '\0';
1035
1036 if (NULL != strchr (mypat, '*'))
1037 {
1038 GNUNET_free (mypat);
1039 GNUNET_break (0);
1040 LOG (GNUNET_ERROR_TYPE_ERROR,
1041 "glob pattern may only contain '*' in the final path component\n");
1042 return -1;
1043 }
1044
1045 {
1046 struct GlobClosure gc = {
1047 .glob = sep + 1,
1048 .cb = callback,
1049 .cls = callback_cls,
1050 .nres = 0,
1051 };
1052 LOG (GNUNET_ERROR_TYPE_DEBUG,
1053 "scanning directory '%s' for glob matches on '%s'\n",
1054 mypat,
1055 gc.glob);
1056 ret = GNUNET_DISK_directory_scan (mypat,
1057 glob_cb,
1058 &gc
1059 );
1060 GNUNET_free (mypat);
1061 return (ret < 0) ? ret : gc.nres;
1062 }
1063}
1064
1065
1066/**
1067 * Function that removes the given directory by calling
1068 * #GNUNET_DISK_directory_remove().
1069 *
1070 * @param unused not used
1071 * @param fn directory to remove
1072 * @return #GNUNET_OK
1073 */
1074static enum GNUNET_GenericReturnValue
1075remove_helper (void *unused,
1076 const char *fn)
1077{
1078 (void) unused;
1079 (void) GNUNET_DISK_directory_remove (fn);
1080 return GNUNET_OK;
1081}
1082
1083
1084enum GNUNET_GenericReturnValue
1085GNUNET_DISK_directory_remove (const char *filename)
1086{
1087 struct stat istat;
1088
1089 if (NULL == filename)
1090 {
1091 GNUNET_break (0);
1092 return GNUNET_SYSERR;
1093 }
1094 if (0 != lstat (filename, &istat))
1095 return GNUNET_NO; /* file may not exist... */
1096 (void) chmod (filename,
1097 S_IWUSR | S_IRUSR | S_IXUSR);
1098 if (0 == unlink (filename))
1099 return GNUNET_OK;
1100 if ( (errno != EISDIR) &&
1101 /* EISDIR is not sufficient in all cases, e.g.
1102 * sticky /tmp directory may result in EPERM on BSD.
1103 * So we also explicitly check "isDirectory" */
1104 (GNUNET_YES !=
1105 GNUNET_DISK_directory_test (filename,
1106 GNUNET_YES)) )
1107 {
1108 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1109 return GNUNET_SYSERR;
1110 }
1111 if (GNUNET_SYSERR ==
1112 GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1113 return GNUNET_SYSERR;
1114 if (0 != rmdir (filename))
1115 {
1116 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1117 return GNUNET_SYSERR;
1118 }
1119 return GNUNET_OK;
1120}
1121
1122
1123enum GNUNET_GenericReturnValue
1124GNUNET_DISK_file_copy (const char *src,
1125 const char *dst)
1126{
1127 char *buf;
1128 uint64_t pos;
1129 uint64_t size;
1130 size_t len;
1131 ssize_t sret;
1132 struct GNUNET_DISK_FileHandle *in;
1133 struct GNUNET_DISK_FileHandle *out;
1134
1135 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1136 {
1137 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "stat", src);
1138 return GNUNET_SYSERR;
1139 }
1140 pos = 0;
1141 in =
1142 GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
1143 if (! in)
1144 {
1145 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", src);
1146 return GNUNET_SYSERR;
1147 }
1148 out =
1149 GNUNET_DISK_file_open (dst,
1150 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
1151 | GNUNET_DISK_OPEN_FAILIFEXISTS,
1152 GNUNET_DISK_PERM_USER_READ
1153 | GNUNET_DISK_PERM_USER_WRITE
1154 | GNUNET_DISK_PERM_GROUP_READ
1155 | GNUNET_DISK_PERM_GROUP_WRITE);
1156 if (! out)
1157 {
1158 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", dst);
1159 GNUNET_DISK_file_close (in);
1160 return GNUNET_SYSERR;
1161 }
1162 buf = GNUNET_malloc (COPY_BLK_SIZE);
1163 while (pos < size)
1164 {
1165 len = COPY_BLK_SIZE;
1166 if (len > size - pos)
1167 len = size - pos;
1168 sret = GNUNET_DISK_file_read (in, buf, len);
1169 if ((sret < 0) || (len != (size_t) sret))
1170 goto FAIL;
1171 sret = GNUNET_DISK_file_write (out, buf, len);
1172 if ((sret < 0) || (len != (size_t) sret))
1173 goto FAIL;
1174 pos += len;
1175 }
1176 GNUNET_free (buf);
1177 GNUNET_DISK_file_close (in);
1178 GNUNET_DISK_file_close (out);
1179 return GNUNET_OK;
1180 FAIL:
1181 GNUNET_free (buf);
1182 GNUNET_DISK_file_close (in);
1183 GNUNET_DISK_file_close (out);
1184 return GNUNET_SYSERR;
1185}
1186
1187
1188void
1189GNUNET_DISK_filename_canonicalize (char *fn)
1190{
1191 char *idx;
1192 char c;
1193
1194 for (idx = fn; *idx; idx++)
1195 {
1196 c = *idx;
1197
1198 if ((c == '/') || (c == '\\') || (c == ':') || (c == '*') || (c == '?') ||
1199 (c ==
1200 '"')
1201 ||
1202 (c == '<') || (c == '>') || (c == '|') )
1203 {
1204 *idx = '_';
1205 }
1206 }
1207}
1208
1209
1210enum GNUNET_GenericReturnValue
1211GNUNET_DISK_file_change_owner (const char *filename,
1212 const char *user)
1213{
1214 struct passwd *pws;
1215
1216 pws = getpwnam (user);
1217 if (NULL == pws)
1218 {
1219 LOG (GNUNET_ERROR_TYPE_ERROR,
1220 _ ("Cannot obtain information about user `%s': %s\n"),
1221 user,
1222 strerror (errno));
1223 return GNUNET_SYSERR;
1224 }
1225 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1226 {
1227 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1228 return GNUNET_SYSERR;
1229 }
1230 return GNUNET_OK;
1231}
1232
1233
1234struct GNUNET_DISK_FileHandle *
1235GNUNET_DISK_file_open (const char *fn,
1236 enum GNUNET_DISK_OpenFlags flags,
1237 enum GNUNET_DISK_AccessPermissions perm)
1238{
1239 char *expfn;
1240 struct GNUNET_DISK_FileHandle *ret;
1241
1242 int oflags;
1243 int mode;
1244 int fd;
1245
1246 expfn = GNUNET_STRINGS_filename_expand (fn);
1247 if (NULL == expfn)
1248 return NULL;
1249
1250 mode = 0;
1251 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1252 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1253 else if (flags & GNUNET_DISK_OPEN_READ)
1254 oflags = O_RDONLY;
1255 else if (flags & GNUNET_DISK_OPEN_WRITE)
1256 oflags = O_WRONLY;
1257 else
1258 {
1259 GNUNET_break (0);
1260 GNUNET_free (expfn);
1261 return NULL;
1262 }
1263 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1264 oflags |= (O_CREAT | O_EXCL);
1265 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1266 oflags |= O_TRUNC;
1267 if (flags & GNUNET_DISK_OPEN_APPEND)
1268 oflags |= O_APPEND;
1269 if (GNUNET_NO == GNUNET_DISK_file_test (fn))
1270 {
1271 if (flags & GNUNET_DISK_OPEN_CREATE)
1272 {
1273 (void) GNUNET_DISK_directory_create_for_file (expfn);
1274 oflags |= O_CREAT;
1275 mode = translate_unix_perms (perm);
1276 }
1277 }
1278
1279 fd = open (expfn,
1280 oflags
1281#if O_CLOEXEC
1282 | O_CLOEXEC
1283#endif
1284 | O_LARGEFILE,
1285 mode);
1286 if (fd == -1)
1287 {
1288 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1289 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1290 else
1291 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1292 GNUNET_free (expfn);
1293 return NULL;
1294 }
1295
1296 ret = GNUNET_new (struct GNUNET_DISK_FileHandle);
1297
1298 ret->fd = fd;
1299
1300 GNUNET_free (expfn);
1301 return ret;
1302}
1303
1304
1305enum GNUNET_GenericReturnValue
1306GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1307{
1308 enum GNUNET_GenericReturnValue ret;
1309
1310 if (NULL == h)
1311 {
1312 errno = EINVAL;
1313 return GNUNET_SYSERR;
1314 }
1315
1316 ret = GNUNET_OK;
1317 if (0 != close (h->fd))
1318 {
1319 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1320 ret = GNUNET_SYSERR;
1321 }
1322 GNUNET_free (h);
1323 return ret;
1324}
1325
1326
1327struct GNUNET_DISK_FileHandle *
1328GNUNET_DISK_get_handle_from_int_fd (int fno)
1329{
1330 struct GNUNET_DISK_FileHandle *fh;
1331
1332 if ((((off_t) -1) == lseek (fno, 0, SEEK_CUR)) && (EBADF == errno))
1333 return NULL; /* invalid FD */
1334
1335 fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1336
1337 fh->fd = fno;
1338
1339 return fh;
1340}
1341
1342
1343struct GNUNET_DISK_FileHandle *
1344GNUNET_DISK_get_handle_from_native (FILE *fd)
1345{
1346 int fno;
1347
1348 fno = fileno (fd);
1349 if (-1 == fno)
1350 return NULL;
1351 return GNUNET_DISK_get_handle_from_int_fd (fno);
1352}
1353
1354
1355/**
1356 * Handle for a memory-mapping operation.
1357 */
1358struct GNUNET_DISK_MapHandle
1359{
1360 /**
1361 * Address where the map is in memory.
1362 */
1363 void *addr;
1364
1365 /**
1366 * Number of bytes mapped.
1367 */
1368 size_t len;
1369};
1370
1371
1372#ifndef MAP_FAILED
1373#define MAP_FAILED ((void *) -1)
1374#endif
1375
1376
1377void *
1378GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1379 struct GNUNET_DISK_MapHandle **m,
1380 enum GNUNET_DISK_MapType access,
1381 size_t len)
1382{
1383 int prot;
1384
1385 if (NULL == h)
1386 {
1387 errno = EINVAL;
1388 return NULL;
1389 }
1390 prot = 0;
1391 if (access & GNUNET_DISK_MAP_TYPE_READ)
1392 prot = PROT_READ;
1393 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1394 prot |= PROT_WRITE;
1395 *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
1396 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1397 GNUNET_assert (NULL != (*m)->addr);
1398 if (MAP_FAILED == (*m)->addr)
1399 {
1400 GNUNET_free (*m);
1401 return NULL;
1402 }
1403 (*m)->len = len;
1404 return (*m)->addr;
1405}
1406
1407
1408enum GNUNET_GenericReturnValue
1409GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1410{
1411 enum GNUNET_GenericReturnValue ret;
1412
1413 if (NULL == h)
1414 {
1415 errno = EINVAL;
1416 return GNUNET_SYSERR;
1417 }
1418 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
1419 GNUNET_free (h);
1420 return ret;
1421}
1422
1423
1424enum GNUNET_GenericReturnValue
1425GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1426{
1427 if (h == NULL)
1428 {
1429 errno = EINVAL;
1430 return GNUNET_SYSERR;
1431 }
1432
1433#if ! defined(__linux__) || ! defined(GNU)
1434 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1435#else
1436 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1437#endif
1438}
1439
1440
1441struct GNUNET_DISK_PipeHandle *
1442GNUNET_DISK_pipe (enum GNUNET_DISK_PipeFlags pf)
1443{
1444 int fd[2];
1445
1446 if (-1 == pipe (fd))
1447 {
1448 int eno = errno;
1449
1450 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1451 errno = eno;
1452 return NULL;
1453 }
1454 return GNUNET_DISK_pipe_from_fd (pf, fd);
1455}
1456
1457
1458struct GNUNET_DISK_PipeHandle *
1459GNUNET_DISK_pipe_from_fd (enum GNUNET_DISK_PipeFlags pf,
1460 int fd[2])
1461{
1462 struct GNUNET_DISK_PipeHandle *p;
1463 int ret = 0;
1464 int flags;
1465 int eno = 0; /* make gcc happy */
1466
1467 p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
1468 if (fd[0] >= 0)
1469 {
1470 p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
1471 p->fd[0]->fd = fd[0];
1472 if (0 == (GNUNET_DISK_PF_BLOCKING_READ & pf))
1473 {
1474 flags = fcntl (fd[0], F_GETFL);
1475 flags |= O_NONBLOCK;
1476 if (0 > fcntl (fd[0], F_SETFL, flags))
1477 {
1478 ret = -1;
1479 eno = errno;
1480 }
1481 }
1482 flags = fcntl (fd[0], F_GETFD);
1483 flags |= FD_CLOEXEC;
1484 if (0 > fcntl (fd[0], F_SETFD, flags))
1485 {
1486 ret = -1;
1487 eno = errno;
1488 }
1489 }
1490
1491 if (fd[1] >= 0)
1492 {
1493 p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
1494 p->fd[1]->fd = fd[1];
1495 if (0 == (GNUNET_DISK_PF_BLOCKING_WRITE & pf))
1496 {
1497 flags = fcntl (fd[1], F_GETFL);
1498 flags |= O_NONBLOCK;
1499 if (0 > fcntl (fd[1], F_SETFL, flags))
1500 {
1501 ret = -1;
1502 eno = errno;
1503 }
1504 }
1505 flags = fcntl (fd[1], F_GETFD);
1506 flags |= FD_CLOEXEC;
1507 if (0 > fcntl (fd[1], F_SETFD, flags))
1508 {
1509 ret = -1;
1510 eno = errno;
1511 }
1512 }
1513 if (ret == -1)
1514 {
1515 errno = eno;
1516 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
1517 if (p->fd[0]->fd >= 0)
1518 GNUNET_break (0 == close (p->fd[0]->fd));
1519 if (p->fd[1]->fd >= 0)
1520 GNUNET_break (0 == close (p->fd[1]->fd));
1521 GNUNET_free (p->fd[0]);
1522 GNUNET_free (p->fd[1]);
1523 GNUNET_free (p);
1524 errno = eno;
1525 return NULL;
1526 }
1527 return p;
1528}
1529
1530
1531enum GNUNET_GenericReturnValue
1532GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
1533 enum GNUNET_DISK_PipeEnd end)
1534{
1535 enum GNUNET_GenericReturnValue ret = GNUNET_OK;
1536
1537 if (end == GNUNET_DISK_PIPE_END_READ)
1538 {
1539 if (p->fd[0])
1540 {
1541 ret = GNUNET_DISK_file_close (p->fd[0]);
1542 p->fd[0] = NULL;
1543 }
1544 }
1545 else if (end == GNUNET_DISK_PIPE_END_WRITE)
1546 {
1547 if (p->fd[1])
1548 {
1549 ret = GNUNET_DISK_file_close (p->fd[1]);
1550 p->fd[1] = NULL;
1551 }
1552 }
1553 return ret;
1554}
1555
1556
1557struct GNUNET_DISK_FileHandle *
1558GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
1559 enum GNUNET_DISK_PipeEnd end)
1560{
1561 struct GNUNET_DISK_FileHandle *ret = NULL;
1562
1563 if (end == GNUNET_DISK_PIPE_END_READ)
1564 {
1565 if (p->fd[0])
1566 {
1567 ret = p->fd[0];
1568 p->fd[0] = NULL;
1569 }
1570 }
1571 else if (end == GNUNET_DISK_PIPE_END_WRITE)
1572 {
1573 if (p->fd[1])
1574 {
1575 ret = p->fd[1];
1576 p->fd[1] = NULL;
1577 }
1578 }
1579
1580 return ret;
1581}
1582
1583
1584enum GNUNET_GenericReturnValue
1585GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
1586{
1587 int ret = GNUNET_OK;
1588
1589 int read_end_close;
1590 int write_end_close;
1591 int read_end_close_errno;
1592 int write_end_close_errno;
1593
1594 read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ);
1595 read_end_close_errno = errno;
1596 write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE);
1597 write_end_close_errno = errno;
1598 GNUNET_free (p);
1599
1600 if (GNUNET_OK != read_end_close)
1601 {
1602 errno = read_end_close_errno;
1603 ret = read_end_close;
1604 }
1605 else if (GNUNET_OK != write_end_close)
1606 {
1607 errno = write_end_close_errno;
1608 ret = write_end_close;
1609 }
1610
1611 return ret;
1612}
1613
1614
1615const struct GNUNET_DISK_FileHandle *
1616GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
1617 enum GNUNET_DISK_PipeEnd n)
1618{
1619 switch (n)
1620 {
1621 case GNUNET_DISK_PIPE_END_READ:
1622 case GNUNET_DISK_PIPE_END_WRITE:
1623 return p->fd[n];
1624
1625 default:
1626 GNUNET_break (0);
1627 return NULL;
1628 }
1629}
1630
1631
1632enum GNUNET_GenericReturnValue
1633GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
1634 void *dst,
1635 size_t dst_len)
1636{
1637 if (NULL == fh)
1638 return GNUNET_SYSERR;
1639 if (dst_len < sizeof(int))
1640 return GNUNET_SYSERR;
1641 *((int *) dst) = fh->fd;
1642 return GNUNET_OK;
1643}
1644
1645
1646/**
1647 * Helper function for #GNUNET_DISK_purge_cfg_dir.
1648 *
1649 * @param cls a `const char *` with the option to purge
1650 * @param cfg our configuration
1651 * @return #GNUNET_OK on success
1652 */
1653static enum GNUNET_GenericReturnValue
1654purge_cfg_dir (void *cls,
1655 const struct GNUNET_CONFIGURATION_Handle *cfg)
1656{
1657 const char *option = cls;
1658 char *tmpname;
1659
1660 if (GNUNET_OK !=
1661 GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", option, &tmpname))
1662 {
1663 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "PATHS", option);
1664 return GNUNET_NO;
1665 }
1666 if (GNUNET_SYSERR == GNUNET_DISK_directory_remove (tmpname))
1667 {
1668 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "remove", tmpname);
1669 GNUNET_free (tmpname);
1670 return GNUNET_OK;
1671 }
1672 GNUNET_free (tmpname);
1673 return GNUNET_OK;
1674}
1675
1676
1677void
1678GNUNET_DISK_purge_cfg_dir (const char *cfg_filename,
1679 const char *option)
1680{
1681 GNUNET_break (GNUNET_OK ==
1682 GNUNET_CONFIGURATION_parse_and_run (cfg_filename,
1683 &purge_cfg_dir,
1684 (void *) option));
1685}
1686
1687
1688/* end of disk.c */
diff --git a/src/util/disk.h b/src/util/disk.h
deleted file mode 100644
index 89ff76687..000000000
--- a/src/util/disk.h
+++ /dev/null
@@ -1,45 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 util/disk.h
23 * @brief Internal DISK related helper functions
24 * @author Nils Durner
25 */
26#ifndef GNUNET_DISK_H_
27#define GNUNET_DISK_H_
28
29#include "gnunet_crypto_lib.h"
30#include "gnunet_disk_lib.h"
31
32/**
33 * Retrieve OS file handle
34 *
35 * @internal
36 * @param fh GNUnet file descriptor
37 * @param dst destination buffer
38 * @param dst_len length of @a dst
39 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
40 */
41int
42GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
43 void *dst, size_t dst_len);
44
45#endif /* GNUNET_DISK_H_ */
diff --git a/src/util/dnsparser.c b/src/util/dnsparser.c
deleted file mode 100644
index 401723106..000000000
--- a/src/util/dnsparser.c
+++ /dev/null
@@ -1,1400 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 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 util/dnsparser.c
23 * @brief helper library to parse DNS packets.
24 * @author Philipp Toelke
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#if HAVE_LIBIDN2
29#if HAVE_IDN2_H
30#include <idn2.h>
31#elif HAVE_IDN2_IDN2_H
32#include <idn2/idn2.h>
33#endif
34#elif HAVE_LIBIDN
35#if HAVE_IDNA_H
36#include <idna.h>
37#elif HAVE_IDN_IDNA_H
38#include <idn/idna.h>
39#endif
40#endif
41#include "gnunet_util_lib.h"
42
43
44/**
45 * Check if a label in UTF-8 format can be coded into valid IDNA.
46 * This can fail if the ASCII-conversion becomes longer than 63 characters.
47 *
48 * @param label label to check (UTF-8 string)
49 * @return #GNUNET_OK if the label can be converted to IDNA,
50 * #GNUNET_SYSERR if the label is not valid for DNS names
51 */
52int
53GNUNET_DNSPARSER_check_label (const char *label)
54{
55 char *output;
56 size_t slen;
57
58 if (NULL != strchr (label, '.'))
59 return GNUNET_SYSERR; /* not a label! Did you mean GNUNET_DNSPARSER_check_name? */
60 if (0 == strcmp (label, "@")) /* '@' is reserved for the empty label, see #GNUNET_GNS_EMPTY_LABEL_AT */
61 return GNUNET_SYSERR;
62 if (IDNA_SUCCESS != idna_to_ascii_8z (label, &output, IDNA_ALLOW_UNASSIGNED))
63 return GNUNET_SYSERR;
64 slen = strlen (output);
65 free (output);
66 return (slen > 63) ? GNUNET_SYSERR : GNUNET_OK;
67}
68
69
70/**
71 * Check if a label in UTF-8 format can be coded into valid IDNA.
72 * This can fail if the ASCII-conversion becomes longer than 253 characters.
73 *
74 * @param name name to check (UTF-8 string)
75 * @return #GNUNET_OK if the label can be converted to IDNA,
76 * #GNUNET_SYSERR if the label is not valid for DNS names
77 */
78int
79GNUNET_DNSPARSER_check_name (const char *name)
80{
81 char *ldup;
82 char *output;
83 size_t slen;
84 char *tok;
85
86 ldup = GNUNET_strdup (name);
87 for (tok = strtok (ldup, "."); NULL != tok; tok = strtok (NULL, "."))
88 if (GNUNET_OK != GNUNET_DNSPARSER_check_label (tok))
89 {
90 GNUNET_free (ldup);
91 return GNUNET_SYSERR;
92 }
93 GNUNET_free (ldup);
94 if (IDNA_SUCCESS != idna_to_ascii_8z (name, &output, IDNA_ALLOW_UNASSIGNED))
95 return GNUNET_SYSERR;
96 slen = strlen (output);
97 free (output);
98 return (slen > 253) ? GNUNET_SYSERR : GNUNET_OK;
99}
100
101
102/**
103 * Free SOA information record.
104 *
105 * @param soa record to free
106 */
107void
108GNUNET_DNSPARSER_free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa)
109{
110 if (NULL == soa)
111 return;
112 GNUNET_free (soa->mname);
113 GNUNET_free (soa->rname);
114 GNUNET_free (soa);
115}
116
117
118/**
119 * Free CERT information record.
120 *
121 * @param cert record to free
122 */
123void
124GNUNET_DNSPARSER_free_cert (struct GNUNET_DNSPARSER_CertRecord *cert)
125{
126 if (NULL == cert)
127 return;
128 GNUNET_free (cert->certificate_data);
129 GNUNET_free (cert);
130}
131
132
133/**
134 * Free SRV information record.
135 *
136 * @param srv record to free
137 */
138void
139GNUNET_DNSPARSER_free_srv (struct GNUNET_DNSPARSER_SrvRecord *srv)
140{
141 if (NULL == srv)
142 return;
143 GNUNET_free (srv->target);
144 GNUNET_free (srv);
145}
146
147
148/**
149 * Free MX information record.
150 *
151 * @param mx record to free
152 */
153void
154GNUNET_DNSPARSER_free_mx (struct GNUNET_DNSPARSER_MxRecord *mx)
155{
156 if (NULL == mx)
157 return;
158 GNUNET_free (mx->mxhost);
159 GNUNET_free (mx);
160}
161
162
163/**
164 * Free the given DNS record.
165 *
166 * @param r record to free
167 */
168void
169GNUNET_DNSPARSER_free_record (struct GNUNET_DNSPARSER_Record *r)
170{
171 GNUNET_free (r->name);
172 switch (r->type)
173 {
174 case GNUNET_DNSPARSER_TYPE_MX:
175 GNUNET_DNSPARSER_free_mx (r->data.mx);
176 break;
177
178 case GNUNET_DNSPARSER_TYPE_SOA:
179 GNUNET_DNSPARSER_free_soa (r->data.soa);
180 break;
181
182 case GNUNET_DNSPARSER_TYPE_SRV:
183 GNUNET_DNSPARSER_free_srv (r->data.srv);
184 break;
185
186 case GNUNET_DNSPARSER_TYPE_CERT:
187 GNUNET_DNSPARSER_free_cert (r->data.cert);
188 break;
189
190 case GNUNET_DNSPARSER_TYPE_NS:
191 case GNUNET_DNSPARSER_TYPE_CNAME:
192 case GNUNET_DNSPARSER_TYPE_PTR:
193 GNUNET_free (r->data.hostname);
194 break;
195
196 default:
197 GNUNET_free (r->data.raw.data);
198 break;
199 }
200}
201
202
203/**
204 * Parse name inside of a DNS query or record.
205 *
206 * @param udp_payload entire UDP payload
207 * @param udp_payload_length length of @a udp_payload
208 * @param off pointer to the offset of the name to parse in the udp_payload (to be
209 * incremented by the size of the name)
210 * @param depth current depth of our recursion (to prevent stack overflow)
211 * @return name as 0-terminated C string on success, NULL if the payload is malformed
212 */
213static char *
214parse_name (const char *udp_payload,
215 size_t udp_payload_length,
216 size_t *off,
217 unsigned int depth)
218{
219 const uint8_t *input = (const uint8_t *) udp_payload;
220 char *ret;
221 char *tmp;
222 char *xstr;
223 uint8_t len;
224 size_t xoff;
225 char *utf8;
226 Idna_rc rc;
227
228 ret = GNUNET_strdup ("");
229 while (1)
230 {
231 if (*off >= udp_payload_length)
232 {
233 GNUNET_break_op (0);
234 goto error;
235 }
236 len = input[*off];
237 if (0 == len)
238 {
239 (*off)++;
240 break;
241 }
242 if (len < 64)
243 {
244 if (*off + 1 + len > udp_payload_length)
245 {
246 GNUNET_break_op (0);
247 goto error;
248 }
249 GNUNET_asprintf (&tmp, "%.*s", (int) len, &udp_payload[*off + 1]);
250 if (IDNA_SUCCESS !=
251 (rc = idna_to_unicode_8z8z (tmp, &utf8, IDNA_ALLOW_UNASSIGNED)))
252 {
253 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
254 _ ("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"),
255 tmp,
256 idna_strerror (rc));
257 GNUNET_free (tmp);
258 GNUNET_asprintf (&tmp,
259 "%s%.*s.",
260 ret,
261 (int) len,
262 &udp_payload[*off + 1]);
263 }
264 else
265 {
266 GNUNET_free (tmp);
267 GNUNET_asprintf (&tmp, "%s%s.", ret, utf8);
268 free (utf8);
269 }
270 GNUNET_free (ret);
271 ret = tmp;
272 *off += 1 + len;
273 }
274 else if ((64 | 128) == (len & (64 | 128)))
275 {
276 if (depth > 32)
277 {
278 GNUNET_break_op (0);
279 goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */
280 }
281 /* pointer to string */
282 if (*off + 1 > udp_payload_length)
283 {
284 GNUNET_break_op (0);
285 goto error;
286 }
287 xoff = ((len - (64 | 128)) << 8) + input[*off + 1];
288 xstr = parse_name (udp_payload, udp_payload_length, &xoff, depth + 1);
289 if (NULL == xstr)
290 {
291 GNUNET_break_op (0);
292 goto error;
293 }
294 GNUNET_asprintf (&tmp, "%s%s.", ret, xstr);
295 GNUNET_free (ret);
296 GNUNET_free (xstr);
297 ret = tmp;
298 if (strlen (ret) > udp_payload_length)
299 {
300 GNUNET_break_op (0);
301 goto error; /* we are looping (building an infinite string) */
302 }
303 *off += 2;
304 /* pointers always terminate names */
305 break;
306 }
307 else
308 {
309 /* neither pointer nor inline string, not supported... */
310 GNUNET_break_op (0);
311 goto error;
312 }
313 }
314 if (0 < strlen (ret))
315 ret[strlen (ret) - 1] = '\0'; /* eat tailing '.' */
316 return ret;
317error:
318 GNUNET_break_op (0);
319 GNUNET_free (ret);
320 return NULL;
321}
322
323
324/**
325 * Parse name inside of a DNS query or record.
326 *
327 * @param udp_payload entire UDP payload
328 * @param udp_payload_length length of @a udp_payload
329 * @param off pointer to the offset of the name to parse in the udp_payload (to be
330 * incremented by the size of the name)
331 * @return name as 0-terminated C string on success, NULL if the payload is malformed
332 */
333char *
334GNUNET_DNSPARSER_parse_name (const char *udp_payload,
335 size_t udp_payload_length,
336 size_t *off)
337{
338 return parse_name (udp_payload, udp_payload_length, off, 0);
339}
340
341
342/**
343 * Parse a DNS query entry.
344 *
345 * @param udp_payload entire UDP payload
346 * @param udp_payload_length length of @a udp_payload
347 * @param off pointer to the offset of the query to parse in the udp_payload (to be
348 * incremented by the size of the query)
349 * @param q where to write the query information
350 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the query is malformed
351 */
352int
353GNUNET_DNSPARSER_parse_query (const char *udp_payload,
354 size_t udp_payload_length,
355 size_t *off,
356 struct GNUNET_DNSPARSER_Query *q)
357{
358 char *name;
359 struct GNUNET_TUN_DnsQueryLine ql;
360
361 name = GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
362 if (NULL == name)
363 {
364 GNUNET_break_op (0);
365 return GNUNET_SYSERR;
366 }
367 q->name = name;
368 if (*off + sizeof(struct GNUNET_TUN_DnsQueryLine) > udp_payload_length)
369 {
370 GNUNET_break_op (0);
371 return GNUNET_SYSERR;
372 }
373 GNUNET_memcpy (&ql, &udp_payload[*off], sizeof(ql));
374 *off += sizeof(ql);
375 q->type = ntohs (ql.type);
376 q->dns_traffic_class = ntohs (ql.dns_traffic_class);
377 return GNUNET_OK;
378}
379
380
381/**
382 * Parse a DNS SOA record.
383 *
384 * @param udp_payload reference to UDP packet
385 * @param udp_payload_length length of @a udp_payload
386 * @param off pointer to the offset of the query to parse in the SOA record (to be
387 * incremented by the size of the record), unchanged on error
388 * @return the parsed SOA record, NULL on error
389 */
390struct GNUNET_DNSPARSER_SoaRecord *
391GNUNET_DNSPARSER_parse_soa (const char *udp_payload,
392 size_t udp_payload_length,
393 size_t *off)
394{
395 struct GNUNET_DNSPARSER_SoaRecord *soa;
396 struct GNUNET_TUN_DnsSoaRecord soa_bin;
397 size_t old_off;
398
399 old_off = *off;
400 soa = GNUNET_new (struct GNUNET_DNSPARSER_SoaRecord);
401 soa->mname =
402 GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
403 soa->rname =
404 GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
405 if ((NULL == soa->mname) || (NULL == soa->rname) ||
406 (*off + sizeof(struct GNUNET_TUN_DnsSoaRecord) > udp_payload_length))
407 {
408 GNUNET_break_op (0);
409 GNUNET_DNSPARSER_free_soa (soa);
410 *off = old_off;
411 return NULL;
412 }
413 GNUNET_memcpy (&soa_bin,
414 &udp_payload[*off],
415 sizeof(struct GNUNET_TUN_DnsSoaRecord));
416 soa->serial = ntohl (soa_bin.serial);
417 soa->refresh = ntohl (soa_bin.refresh);
418 soa->retry = ntohl (soa_bin.retry);
419 soa->expire = ntohl (soa_bin.expire);
420 soa->minimum_ttl = ntohl (soa_bin.minimum);
421 (*off) += sizeof(struct GNUNET_TUN_DnsSoaRecord);
422 return soa;
423}
424
425
426/**
427 * Parse a DNS MX record.
428 *
429 * @param udp_payload reference to UDP packet
430 * @param udp_payload_length length of @a udp_payload
431 * @param off pointer to the offset of the query to parse in the MX record (to be
432 * incremented by the size of the record), unchanged on error
433 * @return the parsed MX record, NULL on error
434 */
435struct GNUNET_DNSPARSER_MxRecord *
436GNUNET_DNSPARSER_parse_mx (const char *udp_payload,
437 size_t udp_payload_length,
438 size_t *off)
439{
440 struct GNUNET_DNSPARSER_MxRecord *mx;
441 uint16_t mxpref;
442 size_t old_off;
443
444 old_off = *off;
445 if (*off + sizeof(uint16_t) > udp_payload_length)
446 {
447 GNUNET_break_op (0);
448 return NULL;
449 }
450 GNUNET_memcpy (&mxpref, &udp_payload[*off], sizeof(uint16_t));
451 (*off) += sizeof(uint16_t);
452 mx = GNUNET_new (struct GNUNET_DNSPARSER_MxRecord);
453 mx->preference = ntohs (mxpref);
454 mx->mxhost =
455 GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
456 if (NULL == mx->mxhost)
457 {
458 GNUNET_break_op (0);
459 GNUNET_DNSPARSER_free_mx (mx);
460 *off = old_off;
461 return NULL;
462 }
463 return mx;
464}
465
466
467/**
468 * Parse a DNS SRV record.
469 *
470 * @param udp_payload reference to UDP packet
471 * @param udp_payload_length length of @a udp_payload
472 * @param off pointer to the offset of the query to parse in the SRV record (to be
473 * incremented by the size of the record), unchanged on error
474 * @return the parsed SRV record, NULL on error
475 */
476struct GNUNET_DNSPARSER_SrvRecord *
477GNUNET_DNSPARSER_parse_srv (const char *udp_payload,
478 size_t udp_payload_length,
479 size_t *off)
480{
481 struct GNUNET_DNSPARSER_SrvRecord *srv;
482 struct GNUNET_TUN_DnsSrvRecord srv_bin;
483 size_t old_off;
484
485 old_off = *off;
486 if (*off + sizeof(struct GNUNET_TUN_DnsSrvRecord) > udp_payload_length)
487 return NULL;
488 GNUNET_memcpy (&srv_bin,
489 &udp_payload[*off],
490 sizeof(struct GNUNET_TUN_DnsSrvRecord));
491 (*off) += sizeof(struct GNUNET_TUN_DnsSrvRecord);
492 srv = GNUNET_new (struct GNUNET_DNSPARSER_SrvRecord);
493 srv->priority = ntohs (srv_bin.prio);
494 srv->weight = ntohs (srv_bin.weight);
495 srv->port = ntohs (srv_bin.port);
496 srv->target =
497 GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
498 if (NULL == srv->target)
499 {
500 GNUNET_DNSPARSER_free_srv (srv);
501 *off = old_off;
502 return NULL;
503 }
504 return srv;
505}
506
507
508/**
509 * Parse a DNS CERT record.
510 *
511 * @param udp_payload reference to UDP packet
512 * @param udp_payload_length length of @a udp_payload
513 * @param off pointer to the offset of the query to parse in the CERT record (to be
514 * incremented by the size of the record), unchanged on error
515 * @return the parsed CERT record, NULL on error
516 */
517struct GNUNET_DNSPARSER_CertRecord *
518GNUNET_DNSPARSER_parse_cert (const char *udp_payload,
519 size_t udp_payload_length,
520 size_t *off)
521{
522 struct GNUNET_DNSPARSER_CertRecord *cert;
523 struct GNUNET_TUN_DnsCertRecord dcert;
524
525 if (*off + sizeof(struct GNUNET_TUN_DnsCertRecord) >= udp_payload_length)
526 {
527 GNUNET_break_op (0);
528 return NULL;
529 }
530 GNUNET_memcpy (&dcert,
531 &udp_payload[*off],
532 sizeof(struct GNUNET_TUN_DnsCertRecord));
533 (*off) += sizeof(struct GNUNET_TUN_DnsCertRecord);
534 cert = GNUNET_new (struct GNUNET_DNSPARSER_CertRecord);
535 cert->cert_type = ntohs (dcert.cert_type);
536 cert->cert_tag = ntohs (dcert.cert_tag);
537 cert->algorithm = dcert.algorithm;
538 cert->certificate_size = udp_payload_length - (*off);
539 cert->certificate_data = GNUNET_malloc (cert->certificate_size);
540 GNUNET_memcpy (cert->certificate_data,
541 &udp_payload[*off],
542 cert->certificate_size);
543 (*off) += cert->certificate_size;
544 return cert;
545}
546
547
548/**
549 * Parse a DNS record entry.
550 *
551 * @param udp_payload entire UDP payload
552 * @param udp_payload_length length of @a udp_payload
553 * @param off pointer to the offset of the record to parse in the udp_payload (to be
554 * incremented by the size of the record)
555 * @param r where to write the record information
556 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the record is malformed
557 */
558int
559GNUNET_DNSPARSER_parse_record (const char *udp_payload,
560 size_t udp_payload_length,
561 size_t *off,
562 struct GNUNET_DNSPARSER_Record *r)
563{
564 char *name;
565 struct GNUNET_TUN_DnsRecordLine rl;
566 size_t old_off;
567 uint16_t data_len;
568
569 name = GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
570 if (NULL == name)
571 {
572 GNUNET_break_op (0);
573 return GNUNET_SYSERR;
574 }
575 r->name = name;
576 if (*off + sizeof(struct GNUNET_TUN_DnsRecordLine) > udp_payload_length)
577 {
578 GNUNET_break_op (0);
579 return GNUNET_SYSERR;
580 }
581 GNUNET_memcpy (&rl, &udp_payload[*off], sizeof(rl));
582 (*off) += sizeof(rl);
583 r->type = ntohs (rl.type);
584 r->dns_traffic_class = ntohs (rl.dns_traffic_class);
585 r->expiration_time = GNUNET_TIME_relative_to_absolute (
586 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, ntohl (rl.ttl)));
587 data_len = ntohs (rl.data_len);
588 if (*off + data_len > udp_payload_length)
589 {
590 GNUNET_break_op (0);
591 return GNUNET_SYSERR;
592 }
593 old_off = *off;
594 switch (r->type)
595 {
596 case GNUNET_DNSPARSER_TYPE_NS:
597 case GNUNET_DNSPARSER_TYPE_CNAME:
598 case GNUNET_DNSPARSER_TYPE_DNAME:
599 case GNUNET_DNSPARSER_TYPE_PTR:
600 r->data.hostname =
601 GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
602 if ((NULL == r->data.hostname) || (old_off + data_len != *off))
603 return GNUNET_SYSERR;
604 return GNUNET_OK;
605
606 case GNUNET_DNSPARSER_TYPE_SOA:
607 r->data.soa =
608 GNUNET_DNSPARSER_parse_soa (udp_payload, udp_payload_length, off);
609 if ((NULL == r->data.soa) || (old_off + data_len != *off))
610 {
611 GNUNET_break_op (0);
612 return GNUNET_SYSERR;
613 }
614 return GNUNET_OK;
615
616 case GNUNET_DNSPARSER_TYPE_MX:
617 r->data.mx =
618 GNUNET_DNSPARSER_parse_mx (udp_payload, udp_payload_length, off);
619 if ((NULL == r->data.mx) || (old_off + data_len != *off))
620 {
621 GNUNET_break_op (0);
622 return GNUNET_SYSERR;
623 }
624 return GNUNET_OK;
625
626 case GNUNET_DNSPARSER_TYPE_SRV:
627 r->data.srv =
628 GNUNET_DNSPARSER_parse_srv (udp_payload, udp_payload_length, off);
629 if ((NULL == r->data.srv) || (old_off + data_len != *off))
630 {
631 GNUNET_break_op (0);
632 return GNUNET_SYSERR;
633 }
634 return GNUNET_OK;
635
636 default:
637 r->data.raw.data = GNUNET_malloc (data_len);
638 r->data.raw.data_len = data_len;
639 GNUNET_memcpy (r->data.raw.data, &udp_payload[*off], data_len);
640 break;
641 }
642 (*off) += data_len;
643 return GNUNET_OK;
644}
645
646
647/**
648 * Parse a UDP payload of a DNS packet in to a nice struct for further
649 * processing and manipulation.
650 *
651 * @param udp_payload wire-format of the DNS packet
652 * @param udp_payload_length number of bytes in @a udp_payload
653 * @return NULL on error, otherwise the parsed packet
654 */
655struct GNUNET_DNSPARSER_Packet *
656GNUNET_DNSPARSER_parse (const char *udp_payload, size_t udp_payload_length)
657{
658 struct GNUNET_DNSPARSER_Packet *p;
659 const struct GNUNET_TUN_DnsHeader *dns;
660 size_t off;
661 unsigned int n;
662
663 if (udp_payload_length < sizeof(struct GNUNET_TUN_DnsHeader))
664 return NULL;
665 dns = (const struct GNUNET_TUN_DnsHeader *) udp_payload;
666 off = sizeof(struct GNUNET_TUN_DnsHeader);
667 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
668 p->flags = dns->flags;
669 p->id = dns->id;
670 n = ntohs (dns->query_count);
671 if (n > 0)
672 {
673 p->queries = GNUNET_new_array (n, struct GNUNET_DNSPARSER_Query);
674 p->num_queries = n;
675 for (unsigned int i = 0; i < n; i++)
676 if (GNUNET_OK != GNUNET_DNSPARSER_parse_query (udp_payload,
677 udp_payload_length,
678 &off,
679 &p->queries[i]))
680 goto error;
681 }
682 n = ntohs (dns->answer_rcount);
683 if (n > 0)
684 {
685 p->answers = GNUNET_new_array (n, struct GNUNET_DNSPARSER_Record);
686 p->num_answers = n;
687 for (unsigned int i = 0; i < n; i++)
688 if (GNUNET_OK != GNUNET_DNSPARSER_parse_record (udp_payload,
689 udp_payload_length,
690 &off,
691 &p->answers[i]))
692 goto error;
693 }
694 n = ntohs (dns->authority_rcount);
695 if (n > 0)
696 {
697 p->authority_records = GNUNET_new_array (n, struct GNUNET_DNSPARSER_Record);
698 p->num_authority_records = n;
699 for (unsigned int i = 0; i < n; i++)
700 if (GNUNET_OK != GNUNET_DNSPARSER_parse_record (udp_payload,
701 udp_payload_length,
702 &off,
703 &p->authority_records[i]))
704 goto error;
705 }
706 n = ntohs (dns->additional_rcount);
707 if (n > 0)
708 {
709 p->additional_records =
710 GNUNET_new_array (n, struct GNUNET_DNSPARSER_Record);
711 p->num_additional_records = n;
712 for (unsigned int i = 0; i < n; i++)
713 {
714 if (GNUNET_OK !=
715 GNUNET_DNSPARSER_parse_record (udp_payload,
716 udp_payload_length,
717 &off,
718 &p->additional_records[i]))
719 goto error;
720 }
721 }
722 return p;
723error:
724 GNUNET_break_op (0);
725 GNUNET_DNSPARSER_free_packet (p);
726 return NULL;
727}
728
729
730/**
731 * Duplicate (deep-copy) the given DNS record
732 *
733 * @param r the record
734 * @return the newly allocated record
735 */
736struct GNUNET_DNSPARSER_Record *
737GNUNET_DNSPARSER_duplicate_record (const struct GNUNET_DNSPARSER_Record *r)
738{
739 struct GNUNET_DNSPARSER_Record *dup = GNUNET_memdup (r, sizeof(*r));
740
741 dup->name = GNUNET_strdup (r->name);
742 switch (r->type)
743 {
744 case GNUNET_DNSPARSER_TYPE_NS:
745 case GNUNET_DNSPARSER_TYPE_CNAME:
746 case GNUNET_DNSPARSER_TYPE_PTR: {
747 dup->data.hostname = GNUNET_strdup (r->data.hostname);
748 break;
749 }
750
751 case GNUNET_DNSPARSER_TYPE_SOA: {
752 dup->data.soa = GNUNET_DNSPARSER_duplicate_soa_record (r->data.soa);
753 break;
754 }
755
756 case GNUNET_DNSPARSER_TYPE_CERT: {
757 dup->data.cert = GNUNET_DNSPARSER_duplicate_cert_record (r->data.cert);
758 break;
759 }
760
761 case GNUNET_DNSPARSER_TYPE_MX: {
762 dup->data.mx = GNUNET_DNSPARSER_duplicate_mx_record (r->data.mx);
763 break;
764 }
765
766 case GNUNET_DNSPARSER_TYPE_SRV: {
767 dup->data.srv = GNUNET_DNSPARSER_duplicate_srv_record (r->data.srv);
768 break;
769 }
770
771 default: {
772 dup->data.raw.data = GNUNET_memdup (r->data.raw.data,
773 r->data.raw.data_len);
774 }
775 }
776 return dup;
777}
778
779
780/**
781 * Duplicate (deep-copy) the given DNS record
782 *
783 * @param r the record
784 * @return the newly allocated record
785 */
786struct GNUNET_DNSPARSER_SoaRecord *
787GNUNET_DNSPARSER_duplicate_soa_record (
788 const struct GNUNET_DNSPARSER_SoaRecord *r)
789{
790 struct GNUNET_DNSPARSER_SoaRecord *dup = GNUNET_memdup (r, sizeof(*r));
791
792 dup->mname = GNUNET_strdup (r->mname);
793 dup->rname = GNUNET_strdup (r->rname);
794 return dup;
795}
796
797
798/**
799 * Duplicate (deep-copy) the given DNS record
800 *
801 * @param r the record
802 * @return the newly allocated record
803 */
804struct GNUNET_DNSPARSER_CertRecord *
805GNUNET_DNSPARSER_duplicate_cert_record (
806 const struct GNUNET_DNSPARSER_CertRecord *r)
807{
808 struct GNUNET_DNSPARSER_CertRecord *dup = GNUNET_memdup (r, sizeof(*r));
809
810 dup->certificate_data = GNUNET_strdup (r->certificate_data);
811 return dup;
812}
813
814
815/**
816 * Duplicate (deep-copy) the given DNS record
817 *
818 * @param r the record
819 * @return the newly allocated record
820 */
821struct GNUNET_DNSPARSER_MxRecord *
822GNUNET_DNSPARSER_duplicate_mx_record (const struct GNUNET_DNSPARSER_MxRecord *r)
823{
824 struct GNUNET_DNSPARSER_MxRecord *dup = GNUNET_memdup (r, sizeof(*r));
825
826 dup->mxhost = GNUNET_strdup (r->mxhost);
827 return dup;
828}
829
830
831/**
832 * Duplicate (deep-copy) the given DNS record
833 *
834 * @param r the record
835 * @return the newly allocated record
836 */
837struct GNUNET_DNSPARSER_SrvRecord *
838GNUNET_DNSPARSER_duplicate_srv_record (
839 const struct GNUNET_DNSPARSER_SrvRecord *r)
840{
841 struct GNUNET_DNSPARSER_SrvRecord *dup = GNUNET_memdup (r, sizeof(*r));
842
843 dup->target = GNUNET_strdup (r->target);
844 return dup;
845}
846
847
848/**
849 * Free memory taken by a packet.
850 *
851 * @param p packet to free
852 */
853void
854GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
855{
856 for (unsigned int i = 0; i < p->num_queries; i++)
857 GNUNET_free (p->queries[i].name);
858 GNUNET_free (p->queries);
859 for (unsigned int i = 0; i < p->num_answers; i++)
860 GNUNET_DNSPARSER_free_record (&p->answers[i]);
861 GNUNET_free (p->answers);
862 for (unsigned int i = 0; i < p->num_authority_records; i++)
863 GNUNET_DNSPARSER_free_record (&p->authority_records[i]);
864 GNUNET_free (p->authority_records);
865 for (unsigned int i = 0; i < p->num_additional_records; i++)
866 GNUNET_DNSPARSER_free_record (&p->additional_records[i]);
867 GNUNET_free (p->additional_records);
868 GNUNET_free (p);
869}
870
871
872/* ********************** DNS packet assembly code **************** */
873
874
875/**
876 * Add a DNS name to the UDP packet at the given location, converting
877 * the name to IDNA notation as necessary.
878 *
879 * @param dst where to write the name (UDP packet)
880 * @param dst_len number of bytes in @a dst
881 * @param off pointer to offset where to write the name (increment by bytes used)
882 * must not be changed if there is an error
883 * @param name name to write
884 * @return #GNUNET_SYSERR if @a name is invalid
885 * #GNUNET_NO if @a name did not fit
886 * #GNUNET_OK if @a name was added to @a dst
887 */
888int
889GNUNET_DNSPARSER_builder_add_name (char *dst,
890 size_t dst_len,
891 size_t *off,
892 const char *name)
893{
894 const char *dot;
895 const char *idna_name;
896 char *idna_start;
897 size_t start;
898 size_t pos;
899 size_t len;
900 Idna_rc rc;
901
902 if (NULL == name)
903 return GNUNET_SYSERR;
904
905 if (IDNA_SUCCESS !=
906 (rc = idna_to_ascii_8z (name, &idna_start, IDNA_ALLOW_UNASSIGNED)))
907 {
908 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
909 _ (
910 "Failed to convert UTF-8 name `%s' to DNS IDNA format: %s\n"),
911 name,
912 idna_strerror (rc));
913 return GNUNET_NO;
914 }
915 idna_name = idna_start;
916 start = *off;
917 if (start + strlen (idna_name) + 2 > dst_len)
918 goto fail;
919 pos = start;
920 do
921 {
922 dot = strchr (idna_name, '.');
923 if (NULL == dot)
924 len = strlen (idna_name);
925 else
926 len = dot - idna_name;
927 if ((len >= 64) || (0 == len))
928 {
929 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
930 "Invalid DNS name `%s': label with %u characters encountered\n",
931 name,
932 (unsigned int) len);
933 goto fail; /* label too long or empty */
934 }
935 dst[pos++] = (char) (uint8_t) len;
936 GNUNET_memcpy (&dst[pos], idna_name, len);
937 pos += len;
938 idna_name += len + 1; /* also skip dot */
939 }
940 while (NULL != dot);
941 dst[pos++] = '\0'; /* terminator */
942 *off = pos;
943 free (idna_start);
944 return GNUNET_OK;
945fail:
946 free (idna_start);
947 return GNUNET_NO;
948}
949
950
951/**
952 * Add a DNS query to the UDP packet at the given location.
953 *
954 * @param dst where to write the query
955 * @param dst_len number of bytes in @a dst
956 * @param off pointer to offset where to write the query (increment by bytes used)
957 * must not be changed if there is an error
958 * @param query query to write
959 * @return #GNUNET_SYSERR if @a query is invalid
960 * #GNUNET_NO if @a query did not fit
961 * #GNUNET_OK if @a query was added to @a dst
962 */
963int
964GNUNET_DNSPARSER_builder_add_query (char *dst,
965 size_t dst_len,
966 size_t *off,
967 const struct GNUNET_DNSPARSER_Query *query)
968{
969 int ret;
970 struct GNUNET_TUN_DnsQueryLine ql;
971
972 ret = GNUNET_DNSPARSER_builder_add_name (dst,
973 dst_len
974 - sizeof(
975 struct GNUNET_TUN_DnsQueryLine),
976 off,
977 query->name);
978 if (ret != GNUNET_OK)
979 return ret;
980 ql.type = htons (query->type);
981 ql.dns_traffic_class = htons (query->dns_traffic_class);
982 GNUNET_memcpy (&dst[*off], &ql, sizeof(ql));
983 (*off) += sizeof(ql);
984 return GNUNET_OK;
985}
986
987
988/**
989 * Add an MX record to the UDP packet at the given location.
990 *
991 * @param dst where to write the mx record
992 * @param dst_len number of bytes in @a dst
993 * @param off pointer to offset where to write the mx information (increment by bytes used);
994 * can also change if there was an error
995 * @param mx mx information to write
996 * @return #GNUNET_SYSERR if @a mx is invalid
997 * #GNUNET_NO if @a mx did not fit
998 * #GNUNET_OK if @a mx was added to @a dst
999 */
1000int
1001GNUNET_DNSPARSER_builder_add_mx (char *dst,
1002 size_t dst_len,
1003 size_t *off,
1004 const struct GNUNET_DNSPARSER_MxRecord *mx)
1005{
1006 uint16_t mxpref;
1007
1008 if (*off + sizeof(uint16_t) > dst_len)
1009 return GNUNET_NO;
1010 mxpref = htons (mx->preference);
1011 GNUNET_memcpy (&dst[*off], &mxpref, sizeof(mxpref));
1012 (*off) += sizeof(mxpref);
1013 return GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, mx->mxhost);
1014}
1015
1016
1017/**
1018 * Add a CERT record to the UDP packet at the given location.
1019 *
1020 * @param dst where to write the CERT record
1021 * @param dst_len number of bytes in @a dst
1022 * @param off pointer to offset where to write the CERT information (increment by bytes used);
1023 * can also change if there was an error
1024 * @param cert CERT information to write
1025 * @return #GNUNET_SYSERR if @a cert is invalid
1026 * #GNUNET_NO if @a cert did not fit
1027 * #GNUNET_OK if @a cert was added to @a dst
1028 */
1029int
1030GNUNET_DNSPARSER_builder_add_cert (
1031 char *dst,
1032 size_t dst_len,
1033 size_t *off,
1034 const struct GNUNET_DNSPARSER_CertRecord *cert)
1035{
1036 struct GNUNET_TUN_DnsCertRecord dcert;
1037
1038#ifdef __clang__
1039#pragma clang diagnostic push
1040#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
1041#endif
1042 if ((cert->cert_type > UINT16_MAX) || (cert->algorithm > UINT8_MAX))
1043 {
1044 GNUNET_break (0);
1045 return GNUNET_SYSERR;
1046 }
1047#ifdef __clang__
1048#pragma clang diagnostic pop
1049#endif
1050 if (*off + sizeof(struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size >
1051 dst_len)
1052 return GNUNET_NO;
1053 dcert.cert_type = htons ((uint16_t) cert->cert_type);
1054 dcert.cert_tag = htons ((uint16_t) cert->cert_tag);
1055 dcert.algorithm = (uint8_t) cert->algorithm;
1056 GNUNET_memcpy (&dst[*off], &dcert, sizeof(dcert));
1057 (*off) += sizeof(dcert);
1058 GNUNET_memcpy (&dst[*off], cert->certificate_data, cert->certificate_size);
1059 (*off) += cert->certificate_size;
1060 return GNUNET_OK;
1061}
1062
1063
1064/**
1065 * Add an SOA record to the UDP packet at the given location.
1066 *
1067 * @param dst where to write the SOA record
1068 * @param dst_len number of bytes in @a dst
1069 * @param off pointer to offset where to write the SOA information (increment by bytes used)
1070 * can also change if there was an error
1071 * @param soa SOA information to write
1072 * @return #GNUNET_SYSERR if @a soa is invalid
1073 * #GNUNET_NO if @a soa did not fit
1074 * #GNUNET_OK if @a soa was added to @a dst
1075 */
1076int
1077GNUNET_DNSPARSER_builder_add_soa (char *dst,
1078 size_t dst_len,
1079 size_t *off,
1080 const struct GNUNET_DNSPARSER_SoaRecord *soa)
1081{
1082 struct GNUNET_TUN_DnsSoaRecord sd;
1083 int ret;
1084
1085 if ((GNUNET_OK !=
1086 (ret =
1087 GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, soa->mname))) ||
1088 (GNUNET_OK !=
1089 (ret =
1090 GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, soa->rname))))
1091 return ret;
1092 if (*off + sizeof(struct GNUNET_TUN_DnsSoaRecord) > dst_len)
1093 return GNUNET_NO;
1094 sd.serial = htonl (soa->serial);
1095 sd.refresh = htonl (soa->refresh);
1096 sd.retry = htonl (soa->retry);
1097 sd.expire = htonl (soa->expire);
1098 sd.minimum = htonl (soa->minimum_ttl);
1099 GNUNET_memcpy (&dst[*off], &sd, sizeof(sd));
1100 (*off) += sizeof(sd);
1101 return GNUNET_OK;
1102}
1103
1104
1105/**
1106 * Add an SRV record to the UDP packet at the given location.
1107 *
1108 * @param dst where to write the SRV record
1109 * @param dst_len number of bytes in @a dst
1110 * @param off pointer to offset where to write the SRV information (increment by bytes used)
1111 * can also change if there was an error
1112 * @param srv SRV information to write
1113 * @return #GNUNET_SYSERR if @a srv is invalid
1114 * #GNUNET_NO if @a srv did not fit
1115 * #GNUNET_OK if @a srv was added to @a dst
1116 */
1117int
1118GNUNET_DNSPARSER_builder_add_srv (char *dst,
1119 size_t dst_len,
1120 size_t *off,
1121 const struct GNUNET_DNSPARSER_SrvRecord *srv)
1122{
1123 struct GNUNET_TUN_DnsSrvRecord sd;
1124 int ret;
1125
1126 if (*off + sizeof(struct GNUNET_TUN_DnsSrvRecord) > dst_len)
1127 return GNUNET_NO;
1128 sd.prio = htons (srv->priority);
1129 sd.weight = htons (srv->weight);
1130 sd.port = htons (srv->port);
1131 GNUNET_memcpy (&dst[*off], &sd, sizeof(sd));
1132 (*off) += sizeof(sd);
1133 if (GNUNET_OK !=
1134 (ret =
1135 GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, srv->target)))
1136 return ret;
1137 return GNUNET_OK;
1138}
1139
1140
1141/**
1142 * Add a DNS record to the UDP packet at the given location.
1143 *
1144 * @param dst where to write the query
1145 * @param dst_len number of bytes in @a dst
1146 * @param off pointer to offset where to write the query (increment by bytes used)
1147 * must not be changed if there is an error
1148 * @param record record to write
1149 * @return #GNUNET_SYSERR if @a record is invalid
1150 * #GNUNET_NO if @a record did not fit
1151 * #GNUNET_OK if @a record was added to @a dst
1152 */
1153static int
1154add_record (char *dst,
1155 size_t dst_len,
1156 size_t *off,
1157 const struct GNUNET_DNSPARSER_Record *record)
1158{
1159 int ret;
1160 size_t start;
1161 size_t pos;
1162 struct GNUNET_TUN_DnsRecordLine rl;
1163
1164 start = *off;
1165 ret = GNUNET_DNSPARSER_builder_add_name (dst,
1166 dst_len
1167 - sizeof(
1168 struct GNUNET_TUN_DnsRecordLine),
1169 off,
1170 record->name);
1171 if (GNUNET_OK != ret)
1172 return ret;
1173 /* '*off' is now the position where we will need to write the record line */
1174
1175 pos = *off + sizeof(struct GNUNET_TUN_DnsRecordLine);
1176 switch (record->type)
1177 {
1178 case GNUNET_DNSPARSER_TYPE_MX:
1179 ret = GNUNET_DNSPARSER_builder_add_mx (dst, dst_len, &pos, record->data.mx);
1180 break;
1181
1182 case GNUNET_DNSPARSER_TYPE_CERT:
1183 ret =
1184 GNUNET_DNSPARSER_builder_add_cert (dst, dst_len, &pos, record->data.cert);
1185 break;
1186
1187 case GNUNET_DNSPARSER_TYPE_SOA:
1188 ret =
1189 GNUNET_DNSPARSER_builder_add_soa (dst, dst_len, &pos, record->data.soa);
1190 break;
1191
1192 case GNUNET_DNSPARSER_TYPE_NS:
1193 case GNUNET_DNSPARSER_TYPE_CNAME:
1194 case GNUNET_DNSPARSER_TYPE_PTR:
1195 ret = GNUNET_DNSPARSER_builder_add_name (dst,
1196 dst_len,
1197 &pos,
1198 record->data.hostname);
1199 break;
1200
1201 case GNUNET_DNSPARSER_TYPE_SRV:
1202 ret =
1203 GNUNET_DNSPARSER_builder_add_srv (dst, dst_len, &pos, record->data.srv);
1204 break;
1205
1206 default:
1207 if (pos + record->data.raw.data_len > dst_len)
1208 {
1209 ret = GNUNET_NO;
1210 break;
1211 }
1212 GNUNET_memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
1213 pos += record->data.raw.data_len;
1214 ret = GNUNET_OK;
1215 break;
1216 }
1217 if (GNUNET_OK != ret)
1218 {
1219 *off = start;
1220 return GNUNET_NO;
1221 }
1222
1223 if (pos - (*off + sizeof(struct GNUNET_TUN_DnsRecordLine)) > UINT16_MAX)
1224 {
1225 /* record data too long */
1226 *off = start;
1227 return GNUNET_NO;
1228 }
1229 rl.type = htons (record->type);
1230 rl.dns_traffic_class = htons (record->dns_traffic_class);
1231 rl.ttl = htonl (
1232 GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value_us
1233 / 1000LL / 1000LL); /* in seconds */
1234 rl.data_len = htons (
1235 (uint16_t) (pos - (*off + sizeof(struct GNUNET_TUN_DnsRecordLine))));
1236 GNUNET_memcpy (&dst[*off], &rl, sizeof(struct GNUNET_TUN_DnsRecordLine));
1237 *off = pos;
1238 return GNUNET_OK;
1239}
1240
1241
1242/**
1243 * Given a DNS packet @a p, generate the corresponding UDP payload.
1244 * Note that we do not attempt to pack the strings with pointers
1245 * as this would complicate the code and this is about being
1246 * simple and secure, not fast, fancy and broken like bind.
1247 *
1248 * @param p packet to pack
1249 * @param max maximum allowed size for the resulting UDP payload
1250 * @param buf set to a buffer with the packed message
1251 * @param buf_length set to the length of @a buf
1252 * @return #GNUNET_SYSERR if @a p is invalid
1253 * #GNUNET_NO if @a p was truncated (but there is still a result in @a buf)
1254 * #GNUNET_OK if @a p was packed completely into @a buf
1255 */
1256int
1257GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p,
1258 uint16_t max,
1259 char **buf,
1260 size_t *buf_length)
1261{
1262 struct GNUNET_TUN_DnsHeader dns;
1263 size_t off;
1264 char tmp[max];
1265 int ret;
1266 int trc;
1267
1268 if ((p->num_queries > UINT16_MAX) || (p->num_answers > UINT16_MAX) ||
1269 (p->num_authority_records > UINT16_MAX) ||
1270 (p->num_additional_records > UINT16_MAX))
1271 return GNUNET_SYSERR;
1272 dns.id = p->id;
1273 dns.flags = p->flags;
1274 dns.query_count = htons (p->num_queries);
1275 dns.answer_rcount = htons (p->num_answers);
1276 dns.authority_rcount = htons (p->num_authority_records);
1277 dns.additional_rcount = htons (p->num_additional_records);
1278
1279 off = sizeof(struct GNUNET_TUN_DnsHeader);
1280 trc = GNUNET_NO;
1281 for (unsigned int i = 0; i < p->num_queries; i++)
1282 {
1283 ret = GNUNET_DNSPARSER_builder_add_query (tmp,
1284 sizeof(tmp),
1285 &off,
1286 &p->queries[i]);
1287 if (GNUNET_SYSERR == ret)
1288 return GNUNET_SYSERR;
1289 if (GNUNET_NO == ret)
1290 {
1291 dns.query_count = htons ((uint16_t) (i - 1));
1292 trc = GNUNET_YES;
1293 break;
1294 }
1295 }
1296 for (unsigned int i = 0; i < p->num_answers; i++)
1297 {
1298 ret = add_record (tmp, sizeof(tmp), &off, &p->answers[i]);
1299 if (GNUNET_SYSERR == ret)
1300 return GNUNET_SYSERR;
1301 if (GNUNET_NO == ret)
1302 {
1303 dns.answer_rcount = htons ((uint16_t) (i - 1));
1304 trc = GNUNET_YES;
1305 break;
1306 }
1307 }
1308 for (unsigned int i = 0; i < p->num_authority_records; i++)
1309 {
1310 ret = add_record (tmp, sizeof(tmp), &off, &p->authority_records[i]);
1311 if (GNUNET_SYSERR == ret)
1312 return GNUNET_SYSERR;
1313 if (GNUNET_NO == ret)
1314 {
1315 dns.authority_rcount = htons ((uint16_t) (i - 1));
1316 trc = GNUNET_YES;
1317 break;
1318 }
1319 }
1320 for (unsigned int i = 0; i < p->num_additional_records; i++)
1321 {
1322 ret = add_record (tmp, sizeof(tmp), &off, &p->additional_records[i]);
1323 if (GNUNET_SYSERR == ret)
1324 return GNUNET_SYSERR;
1325 if (GNUNET_NO == ret)
1326 {
1327 dns.additional_rcount = htons (i - 1);
1328 trc = GNUNET_YES;
1329 break;
1330 }
1331 }
1332
1333 if (GNUNET_YES == trc)
1334 dns.flags.message_truncated = 1;
1335 GNUNET_memcpy (tmp, &dns, sizeof(struct GNUNET_TUN_DnsHeader));
1336
1337 *buf = GNUNET_malloc (off);
1338 *buf_length = off;
1339 GNUNET_memcpy (*buf, tmp, off);
1340 if (GNUNET_YES == trc)
1341 return GNUNET_NO;
1342 return GNUNET_OK;
1343}
1344
1345
1346/**
1347 * Convert a block of binary data to HEX.
1348 *
1349 * @param data binary data to convert
1350 * @param data_size number of bytes in @a data
1351 * @return HEX string (lower case)
1352 */
1353char *
1354GNUNET_DNSPARSER_bin_to_hex (const void *data, size_t data_size)
1355{
1356 char *ret;
1357 size_t off;
1358 const uint8_t *idata;
1359
1360 idata = data;
1361 ret = GNUNET_malloc (data_size * 2 + 1);
1362 for (off = 0; off < data_size; off++)
1363 sprintf (&ret[off * 2], "%02x", idata[off]);
1364 return ret;
1365}
1366
1367
1368/**
1369 * Convert a HEX string to block of binary data.
1370 *
1371 * @param hex HEX string to convert (may contain mixed case)
1372 * @param data where to write result, must be
1373 * at least `strlen(hex)/2` bytes long
1374 * @return number of bytes written to data
1375 */
1376size_t
1377GNUNET_DNSPARSER_hex_to_bin (const char *hex, void *data)
1378{
1379 size_t data_size;
1380 size_t off;
1381 uint8_t *idata;
1382 unsigned int h;
1383 char in[3];
1384
1385 data_size = strlen (hex) / 2;
1386 idata = data;
1387 in[2] = '\0';
1388 for (off = 0; off < data_size; off++)
1389 {
1390 in[0] = tolower ((unsigned char) hex[off * 2]);
1391 in[1] = tolower ((unsigned char) hex[off * 2 + 1]);
1392 if (1 != sscanf (in, "%x", &h))
1393 return off;
1394 idata[off] = (uint8_t) h;
1395 }
1396 return off;
1397}
1398
1399
1400/* end of dnsparser.c */
diff --git a/src/util/dnsstub.c b/src/util/dnsstub.c
deleted file mode 100644
index 1ac274c92..000000000
--- a/src/util/dnsstub.c
+++ /dev/null
@@ -1,706 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 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 * @file dns/dnsstub.c
22 * @brief DNS stub resolver which sends DNS requests to an actual resolver
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28/**
29 * Timeout for retrying DNS queries.
30 */
31#define DNS_RETRANSMIT_DELAY \
32 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
33
34
35/**
36 * DNS Server used for resolution.
37 */
38struct DnsServer;
39
40
41/**
42 * UDP socket we are using for sending DNS requests to the Internet.
43 */
44struct GNUNET_DNSSTUB_RequestSocket
45{
46 /**
47 * UDP socket we use for this request for IPv4
48 */
49 struct GNUNET_NETWORK_Handle *dnsout4;
50
51 /**
52 * UDP socket we use for this request for IPv6
53 */
54 struct GNUNET_NETWORK_Handle *dnsout6;
55
56 /**
57 * Function to call with result.
58 */
59 GNUNET_DNSSTUB_ResultCallback rc;
60
61 /**
62 * Closure for @e rc.
63 */
64 void *rc_cls;
65
66 /**
67 * Task for reading from dnsout4 and dnsout6.
68 */
69 struct GNUNET_SCHEDULER_Task *read_task;
70
71 /**
72 * Task for retrying transmission of the query.
73 */
74 struct GNUNET_SCHEDULER_Task *retry_task;
75
76 /**
77 * Next address we sent the DNS request to.
78 */
79 struct DnsServer *ds_pos;
80
81 /**
82 * Context this request executes in.
83 */
84 struct GNUNET_DNSSTUB_Context *ctx;
85
86 /**
87 * Query we sent to @e addr.
88 */
89 void *request;
90
91 /**
92 * Number of bytes in @a request.
93 */
94 size_t request_len;
95};
96
97
98/**
99 * DNS Server used for resolution.
100 */
101struct DnsServer
102{
103 /**
104 * Kept in a DLL.
105 */
106 struct DnsServer *next;
107
108 /**
109 * Kept in a DLL.
110 */
111 struct DnsServer *prev;
112
113 /**
114 * IP address of the DNS resolver.
115 */
116 struct sockaddr_storage ss;
117};
118
119
120/**
121 * Handle to the stub resolver.
122 */
123struct GNUNET_DNSSTUB_Context
124{
125 /**
126 * Array of all open sockets for DNS requests.
127 */
128 struct GNUNET_DNSSTUB_RequestSocket *sockets;
129
130 /**
131 * DLL of DNS resolvers we use.
132 */
133 struct DnsServer *dns_head;
134
135 /**
136 * DLL of DNS resolvers we use.
137 */
138 struct DnsServer *dns_tail;
139
140 /**
141 * How frequently do we retry requests?
142 */
143 struct GNUNET_TIME_Relative retry_freq;
144
145 /**
146 * Length of @e sockets array.
147 */
148 unsigned int num_sockets;
149};
150
151
152/**
153 * We're done with a `struct GNUNET_DNSSTUB_RequestSocket`, close it for now.
154 *
155 * @param rs request socket to clean up
156 */
157static void
158cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs)
159{
160 if (NULL != rs->dnsout4)
161 {
162 GNUNET_NETWORK_socket_close (rs->dnsout4);
163 rs->dnsout4 = NULL;
164 }
165 if (NULL != rs->dnsout6)
166 {
167 GNUNET_NETWORK_socket_close (rs->dnsout6);
168 rs->dnsout6 = NULL;
169 }
170 if (NULL != rs->read_task)
171 {
172 GNUNET_SCHEDULER_cancel (rs->read_task);
173 rs->read_task = NULL;
174 }
175 if (NULL != rs->retry_task)
176 {
177 GNUNET_SCHEDULER_cancel (rs->retry_task);
178 rs->retry_task = NULL;
179 }
180 if (NULL != rs->request)
181 {
182 GNUNET_free (rs->request);
183 rs->request = NULL;
184 }
185}
186
187
188/**
189 * Open source port for sending DNS requests
190 *
191 * @param af AF_INET or AF_INET6
192 * @return #GNUNET_OK on success
193 */
194static struct GNUNET_NETWORK_Handle *
195open_socket (int af)
196{
197 struct sockaddr_in a4;
198 struct sockaddr_in6 a6;
199 struct sockaddr *sa;
200 socklen_t alen;
201 struct GNUNET_NETWORK_Handle *ret;
202
203 ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
204 if (NULL == ret)
205 return NULL;
206 switch (af)
207 {
208 case AF_INET:
209 memset (&a4, 0, alen = sizeof(struct sockaddr_in));
210 sa = (struct sockaddr *) &a4;
211 break;
212
213 case AF_INET6:
214 memset (&a6, 0, alen = sizeof(struct sockaddr_in6));
215 sa = (struct sockaddr *) &a6;
216 break;
217
218 default:
219 GNUNET_break (0);
220 GNUNET_NETWORK_socket_close (ret);
221 return NULL;
222 }
223 sa->sa_family = af;
224 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret, sa, alen))
225 {
226 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
227 _ ("Could not bind to any port: %s\n"),
228 strerror (errno));
229 GNUNET_NETWORK_socket_close (ret);
230 return NULL;
231 }
232 return ret;
233}
234
235
236/**
237 * Get a socket of the specified address family to send out a
238 * UDP DNS request to the Internet.
239 *
240 * @param ctx the DNSSTUB context
241 * @return NULL on error
242 */
243static struct GNUNET_DNSSTUB_RequestSocket *
244get_request_socket (struct GNUNET_DNSSTUB_Context *ctx)
245{
246 struct GNUNET_DNSSTUB_RequestSocket *rs;
247
248 for (unsigned int i = 0; i < 256; i++)
249 {
250 rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
251 ctx->num_sockets)];
252 if (NULL == rs->rc)
253 break;
254 }
255 if (NULL != rs->rc)
256 {
257 /* signal "failure" */
258 rs->rc (rs->rc_cls, NULL, 0);
259 rs->rc = NULL;
260 }
261 if (NULL != rs->read_task)
262 {
263 GNUNET_SCHEDULER_cancel (rs->read_task);
264 rs->read_task = NULL;
265 }
266 if (NULL != rs->retry_task)
267 {
268 GNUNET_SCHEDULER_cancel (rs->retry_task);
269 rs->retry_task = NULL;
270 }
271 if (NULL != rs->request)
272 {
273 GNUNET_free (rs->request);
274 rs->request = NULL;
275 }
276 rs->ctx = ctx;
277 return rs;
278}
279
280
281/**
282 * Actually do the reading of a DNS packet from our UDP socket and see
283 * if we have a valid, matching, pending request.
284 *
285 * @param rs request socket with callback details
286 * @param dnsout socket to read from
287 * @return #GNUNET_OK on success, #GNUNET_NO on drop, #GNUNET_SYSERR on IO-errors (closed socket)
288 */
289static int
290do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
291 struct GNUNET_NETWORK_Handle *dnsout)
292{
293 struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
294 ssize_t r;
295 int len;
296
297 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
298 {
299 /* conservative choice: */
300 len = UINT16_MAX;
301 }
302
303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving %d byte DNS reply\n", len);
304 {
305 unsigned char buf[len] GNUNET_ALIGN;
306 int found;
307 struct sockaddr_storage addr;
308 socklen_t addrlen;
309 struct GNUNET_TUN_DnsHeader *dns;
310
311 addrlen = sizeof(addr);
312 memset (&addr, 0, sizeof(addr));
313 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
314 buf,
315 sizeof(buf),
316 (struct sockaddr *) &addr,
317 &addrlen);
318 if (-1 == r)
319 {
320 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
321 GNUNET_NETWORK_socket_close (dnsout);
322 return GNUNET_SYSERR;
323 }
324 found = GNUNET_NO;
325 for (struct DnsServer *ds = ctx->dns_head; NULL != ds; ds = ds->next)
326 {
327 if (0 == memcmp (&addr,
328 &ds->ss,
329 GNUNET_MIN (sizeof(struct sockaddr_storage), addrlen)))
330 {
331 found = GNUNET_YES;
332 break;
333 }
334 }
335 if (GNUNET_NO == found)
336 {
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 "Received DNS response from server we never asked (ignored)");
339 return GNUNET_NO;
340 }
341 if (sizeof(struct GNUNET_TUN_DnsHeader) > (size_t) r)
342 {
343 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
344 _ ("Received DNS response that is too small (%u bytes)"),
345 (unsigned int) r);
346 return GNUNET_NO;
347 }
348 dns = (struct GNUNET_TUN_DnsHeader *) buf;
349 if (NULL == rs->rc)
350 {
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352 "Request timeout or cancelled; ignoring reply\n");
353 return GNUNET_NO;
354 }
355 rs->rc (rs->rc_cls, dns, r);
356 }
357 return GNUNET_OK;
358}
359
360
361/**
362 * Read a DNS response from the (unhindered) UDP-Socket
363 *
364 * @param cls socket to read from
365 */
366static void
367read_response (void *cls);
368
369
370/**
371 * Schedule #read_response() task for @a rs.
372 *
373 * @param rs request to schedule read operation for
374 */
375static void
376schedule_read (struct GNUNET_DNSSTUB_RequestSocket *rs)
377{
378 struct GNUNET_NETWORK_FDSet *rset;
379
380 if (NULL != rs->read_task)
381 GNUNET_SCHEDULER_cancel (rs->read_task);
382 rset = GNUNET_NETWORK_fdset_create ();
383 if (NULL != rs->dnsout4)
384 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
385 if (NULL != rs->dnsout6)
386 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
387 rs->read_task =
388 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
389 GNUNET_TIME_UNIT_FOREVER_REL,
390 rset,
391 NULL,
392 &read_response,
393 rs);
394 GNUNET_NETWORK_fdset_destroy (rset);
395}
396
397
398/**
399 * Read a DNS response from the (unhindered) UDP-Socket
400 *
401 * @param cls `struct GNUNET_DNSSTUB_RequestSocket` to read from
402 */
403static void
404read_response (void *cls)
405{
406 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
407 const struct GNUNET_SCHEDULER_TaskContext *tc;
408
409 rs->read_task = NULL;
410 tc = GNUNET_SCHEDULER_get_task_context ();
411 /* read and process ready sockets */
412 if ((NULL != rs->dnsout4) &&
413 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
414 (GNUNET_SYSERR == do_dns_read (rs, rs->dnsout4)))
415 rs->dnsout4 = NULL;
416 if ((NULL != rs->dnsout6) &&
417 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
418 (GNUNET_SYSERR == do_dns_read (rs, rs->dnsout6)))
419 rs->dnsout6 = NULL;
420 /* re-schedule read task */
421 schedule_read (rs);
422}
423
424
425/**
426 * Task to (re)transmit the DNS query, possibly repeatedly until
427 * we succeed.
428 *
429 * @param cls our `struct GNUNET_DNSSTUB_RequestSocket *`
430 */
431static void
432transmit_query (void *cls)
433{
434 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
435 struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
436 const struct sockaddr *sa;
437 socklen_t salen;
438 struct DnsServer *ds;
439 struct GNUNET_NETWORK_Handle *dnsout;
440
441 rs->retry_task =
442 GNUNET_SCHEDULER_add_delayed (ctx->retry_freq, &transmit_query, rs);
443 ds = rs->ds_pos;
444 rs->ds_pos = ds->next;
445 if (NULL == rs->ds_pos)
446 rs->ds_pos = ctx->dns_head;
447 GNUNET_assert (NULL != ds);
448 dnsout = NULL;
449 switch (ds->ss.ss_family)
450 {
451 case AF_INET:
452 if (NULL == rs->dnsout4)
453 rs->dnsout4 = open_socket (AF_INET);
454 dnsout = rs->dnsout4;
455 sa = (const struct sockaddr *) &ds->ss;
456 salen = sizeof(struct sockaddr_in);
457 break;
458
459 case AF_INET6:
460 if (NULL == rs->dnsout6)
461 rs->dnsout6 = open_socket (AF_INET6);
462 dnsout = rs->dnsout6;
463 sa = (const struct sockaddr *) &ds->ss;
464 salen = sizeof(struct sockaddr_in6);
465 break;
466
467 default:
468 return;
469 }
470 if (NULL == dnsout)
471 {
472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
473 "Unable to use configure DNS server, skipping\n");
474 return;
475 }
476 if (GNUNET_SYSERR == GNUNET_NETWORK_socket_sendto (dnsout,
477 rs->request,
478 rs->request_len,
479 sa,
480 salen))
481 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
482 _ ("Failed to send DNS request to %s: %s\n"),
483 GNUNET_a2s (sa, salen),
484 strerror (errno));
485 else
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487 _ ("Sent DNS request to %s\n"),
488 GNUNET_a2s (sa, salen));
489 schedule_read (rs);
490}
491
492
493/**
494 * Perform DNS resolution using our default IP from init.
495 *
496 * @param ctx stub resolver to use
497 * @param request DNS request to transmit
498 * @param request_len number of bytes in msg
499 * @param rc function to call with result
500 * @param rc_cls closure for 'rc'
501 * @return socket used for the request, NULL on error
502 */
503struct GNUNET_DNSSTUB_RequestSocket *
504GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
505 const void *request,
506 size_t request_len,
507 GNUNET_DNSSTUB_ResultCallback rc,
508 void *rc_cls)
509{
510 struct GNUNET_DNSSTUB_RequestSocket *rs;
511
512 if (NULL == ctx->dns_head)
513 {
514 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
515 "No DNS server configured for resolution\n");
516 return NULL;
517 }
518 if (NULL == (rs = get_request_socket (ctx)))
519 {
520 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
521 "No request socket available for DNS resolution\n");
522 return NULL;
523 }
524 rs->ds_pos = ctx->dns_head;
525 rs->rc = rc;
526 rs->rc_cls = rc_cls;
527 rs->request = GNUNET_memdup (request, request_len);
528 rs->request_len = request_len;
529 rs->retry_task = GNUNET_SCHEDULER_add_now (&transmit_query, rs);
530 return rs;
531}
532
533
534/**
535 * Cancel DNS resolution.
536 *
537 * @param rs resolution to cancel
538 */
539void
540GNUNET_DNSSTUB_resolve_cancel (struct GNUNET_DNSSTUB_RequestSocket *rs)
541{
542 rs->rc = NULL;
543 if (NULL != rs->retry_task)
544 {
545 GNUNET_SCHEDULER_cancel (rs->retry_task);
546 rs->retry_task = NULL;
547 }
548 if (NULL != rs->read_task)
549 {
550 GNUNET_SCHEDULER_cancel (rs->read_task);
551 rs->read_task = NULL;
552 }
553}
554
555
556/**
557 * Start a DNS stub resolver.
558 *
559 * @param num_sockets how many sockets should we open
560 * in parallel for DNS queries for this stub?
561 * @return NULL on error
562 */
563struct GNUNET_DNSSTUB_Context *
564GNUNET_DNSSTUB_start (unsigned int num_sockets)
565{
566 struct GNUNET_DNSSTUB_Context *ctx;
567
568 if (0 == num_sockets)
569 {
570 GNUNET_break (0);
571 return NULL;
572 }
573 ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context);
574 ctx->num_sockets = num_sockets;
575 ctx->sockets =
576 GNUNET_new_array (num_sockets, struct GNUNET_DNSSTUB_RequestSocket);
577 ctx->retry_freq = DNS_RETRANSMIT_DELAY;
578 return ctx;
579}
580
581
582/**
583 * Add nameserver for use by the DNSSTUB. We will use
584 * all provided nameservers for resolution (round-robin).
585 *
586 * @param ctx resolver context to modify
587 * @param dns_ip target IP address to use (as string)
588 * @return #GNUNET_OK on success
589 */
590int
591GNUNET_DNSSTUB_add_dns_ip (struct GNUNET_DNSSTUB_Context *ctx,
592 const char *dns_ip)
593{
594 struct DnsServer *ds;
595 struct in_addr i4;
596 struct in6_addr i6;
597
598 ds = GNUNET_new (struct DnsServer);
599 if (1 == inet_pton (AF_INET, dns_ip, &i4))
600 {
601 struct sockaddr_in *s4 = (struct sockaddr_in *) &ds->ss;
602
603 s4->sin_family = AF_INET;
604 s4->sin_port = htons (53);
605 s4->sin_addr = i4;
606#if HAVE_SOCKADDR_IN_SIN_LEN
607 s4->sin_len = (u_char) sizeof(struct sockaddr_in);
608#endif
609 }
610 else if (1 == inet_pton (AF_INET6, dns_ip, &i6))
611 {
612 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ds->ss;
613
614 s6->sin6_family = AF_INET6;
615 s6->sin6_port = htons (53);
616 s6->sin6_addr = i6;
617#if HAVE_SOCKADDR_IN_SIN_LEN
618 s6->sin6_len = (u_char) sizeof(struct sockaddr_in6);
619#endif
620 }
621 else
622 {
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 "Malformed IP address `%s' for DNS server\n",
625 dns_ip);
626 GNUNET_free (ds);
627 return GNUNET_SYSERR;
628 }
629 GNUNET_CONTAINER_DLL_insert (ctx->dns_head, ctx->dns_tail, ds);
630 return GNUNET_OK;
631}
632
633
634/**
635 * Add nameserver for use by the DNSSTUB. We will use
636 * all provided nameservers for resolution (round-robin).
637 *
638 * @param ctx resolver context to modify
639 * @param sa socket address of DNS resolver to use
640 * @return #GNUNET_OK on success
641 */
642int
643GNUNET_DNSSTUB_add_dns_sa (struct GNUNET_DNSSTUB_Context *ctx,
644 const struct sockaddr *sa)
645{
646 struct DnsServer *ds;
647
648 ds = GNUNET_new (struct DnsServer);
649 switch (sa->sa_family)
650 {
651 case AF_INET:
652 GNUNET_memcpy (&ds->ss, sa, sizeof(struct sockaddr_in));
653 break;
654
655 case AF_INET6:
656 GNUNET_memcpy (&ds->ss, sa, sizeof(struct sockaddr_in6));
657 break;
658
659 default:
660 GNUNET_break (0);
661 GNUNET_free (ds);
662 return GNUNET_SYSERR;
663 }
664 GNUNET_CONTAINER_DLL_insert (ctx->dns_head, ctx->dns_tail, ds);
665 return GNUNET_OK;
666}
667
668
669/**
670 * How long should we try requests before timing out?
671 * Only effective for requests issued after this call.
672 *
673 * @param ctx resolver context to modify
674 * @param retry_freq how long to wait between retries
675 */
676void
677GNUNET_DNSSTUB_set_retry (struct GNUNET_DNSSTUB_Context *ctx,
678 struct GNUNET_TIME_Relative retry_freq)
679{
680 ctx->retry_freq = retry_freq;
681}
682
683
684/**
685 * Cleanup DNSSTUB resolver.
686 *
687 * @param ctx stub resolver to clean up
688 */
689void
690GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx)
691{
692 struct DnsServer *ds;
693
694 while (NULL != (ds = ctx->dns_head))
695 {
696 GNUNET_CONTAINER_DLL_remove (ctx->dns_head, ctx->dns_tail, ds);
697 GNUNET_free (ds);
698 }
699 for (unsigned int i = 0; i < ctx->num_sockets; i++)
700 cleanup_rs (&ctx->sockets[i]);
701 GNUNET_free (ctx->sockets);
702 GNUNET_free (ctx);
703}
704
705
706/* end of dnsstub.c */
diff --git a/src/util/getopt.c b/src/util/getopt.c
deleted file mode 100644
index 6dfad96da..000000000
--- a/src/util/getopt.c
+++ /dev/null
@@ -1,1014 +0,0 @@
1/* Getopt for GNU.
2 NOTE: getopt is now part of the C library, so if you don't know what
3 "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
4 before changing it!
5
6 Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
7 Free Software Foundation, Inc.
8
9 NOTE: The canonical source of this file is maintained with the GNU C Library.
10 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
11
12 This program is free software; you can redistribute it and/or modify it
13 under the terms of the GNU General Public License as published by the
14 Free Software Foundation; either version 3, or (at your option) any
15 later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25 USA.
26
27
28 This code was heavily modified for GNUnet.
29 Copyright (C) 2006, 2017 Christian Grothoff
30 */
31
32/**
33 * @file util/getopt.c
34 * @brief GNU style option parsing
35 *
36 * TODO: get rid of statics (make reentrant) and
37 * replace main GNU getopt parser with one that
38 * actually fits our API.
39 */
40#include "platform.h"
41#include "gnunet_util_lib.h"
42
43#ifdef VMS
44#include <unixlib.h>
45#if HAVE_STRING_H - 0
46#include <string.h>
47#endif
48#endif
49
50#define LOG(kind, ...) GNUNET_log_from (kind, "util-getopt", __VA_ARGS__)
51
52#define LOG_STRERROR(kind, syscall) \
53 GNUNET_log_from_strerror (kind, "util-getopt", syscall)
54
55#ifndef _
56/* This is for other GNU distributions with internationalized messages.
57 When compiling libc, the _ macro is predefined. */
58#ifdef HAVE_LIBINTL_H
59#include <libintl.h>
60#define _(msgid) gettext (msgid)
61#else
62#define _(msgid) (msgid)
63#endif
64#endif
65
66/* Describe the long-named options requested by the application.
67 The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
68 of `struct GNoption' terminated by an element containing a name which is
69 zero.
70
71 The field `has_arg' is:
72 no_argument (or 0) if the option does not take an argument,
73 required_argument (or 1) if the option requires an argument,
74 optional_argument (or 2) if the option takes an optional argument.
75
76 If the field `flag' is not NULL, it points to a variable that is set
77 to the value given in the field `val' when the option is found, but
78 left unchanged if the option is not found.
79
80 To have a long-named option do something other than set an `int' to
81 a compiled-in constant, such as set a value from `GNoptarg', set the
82 option's `flag' field to zero and its `val' field to a nonzero
83 value (the equivalent single-letter option character, if there is
84 one). For long options that have a zero `flag' field, `getopt'
85 returns the contents of the `val' field. */
86
87struct GNoption
88{
89 const char *name;
90 /* has_arg can't be an enum because some compilers complain about
91 * type mismatches in all the code that assumes it is an int. */
92 int has_arg;
93 int *flag;
94 int val;
95};
96
97
98/* This version of `getopt' appears to the caller like standard Unix `getopt'
99 but it behaves differently for the user, since it allows the user
100 to intersperse the options with the other arguments.
101
102 As `getopt' works, it permutes the elements of ARGV so that,
103 when it is done, all the options precede everything else. Thus
104 all application programs are extended to handle flexible argument order.
105
106 Setting the environment variable POSIXLY_CORRECT disables permutation.
107 Then the behavior is completely standard.
108
109 GNU application programs can use a third alternative mode in which
110 they can distinguish the relative order of options and other arguments. */
111
112/* For communication from `getopt' to the caller.
113 When `getopt' finds an option that takes an argument,
114 the argument value is returned here.
115 Also, when `ordering' is RETURN_IN_ORDER,
116 each non-option ARGV-element is returned here. */
117
118static char *GNoptarg = NULL;
119
120/* Index in ARGV of the next element to be scanned.
121 This is used for communication to and from the caller
122 and for communication between successive calls to `getopt'.
123
124 On entry to `getopt', zero means this is the first call; initialize.
125
126 When `getopt' returns -1, this is the index of the first of the
127 non-option elements that the caller should itself scan.
128
129 Otherwise, `GNoptind' communicates from one call to the next
130 how much of ARGV has been scanned so far. */
131
132/* 1003.2 says this must be 1 before any call. */
133static int GNoptind = 1;
134
135/* The next char to be scanned in the option-element
136 in which the last option character we returned was found.
137 This allows us to pick up the scan where we left off.
138
139 If this is zero, or a null string, it means resume the scan
140 by advancing to the next ARGV-element. */
141
142static char *nextchar;
143
144
145/* Describe how to deal with options that follow non-option ARGV-elements.
146
147 If the caller did not specify anything,
148 the default is REQUIRE_ORDER if the environment variable
149 POSIXLY_CORRECT is defined, PERMUTE otherwise.
150
151 REQUIRE_ORDER means don't recognize them as options;
152 stop option processing when the first non-option is seen.
153 This is what Unix does.
154 This mode of operation is selected by either setting the environment
155 variable POSIXLY_CORRECT, or using `+' as the first character
156 of the list of option characters.
157
158 PERMUTE is the default. We GNUNET_CRYPTO_random_permute the contents of ARGV as we scan,
159 so that eventually all the non-options are at the end. This allows options
160 to be given in any order, even with programs that were not written to
161 expect this.
162
163 RETURN_IN_ORDER is an option available to programs that were written
164 to expect GNoptions and other ARGV-elements in any order and that care about
165 the ordering of the two. We describe each non-option ARGV-element
166 as if it were the argument of an option with character code 1.
167 Using `-' as the first character of the list of option characters
168 selects this mode of operation.
169
170 The special argument `--' forces an end of option-scanning regardless
171 of the value of `ordering'. In the case of RETURN_IN_ORDER, only
172 `--' can cause `getopt' to return -1 with `GNoptind' != ARGC. */
173
174static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering;
175
176/* Value of POSIXLY_CORRECT environment variable. */
177static char *posixly_correct;
178
179#ifdef __GNU_LIBRARY__
180/* We want to avoid inclusion of string.h with non-GNU libraries
181 because there are many ways it can cause trouble.
182 On some systems, it contains special magic macros that don't work
183 in GCC. */
184#include <string.h>
185#define my_index strchr
186#else
187
188/* Avoid depending on library functions or files
189 whose names are inconsistent. */
190
191char *
192getenv ();
193
194static char *
195my_index (const char *str, int chr)
196{
197 while (*str)
198 {
199 if (*str == chr)
200 return (char *) str;
201 str++;
202 }
203 return 0;
204}
205
206
207/* If using GCC, we can safely declare strlen this way.
208 If not using GCC, it is ok not to declare it. */
209#ifdef __GNUC__
210/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
211 That was relevant to code that was here before. */
212#if ! defined(__STDC__) || ! __STDC__
213/* gcc with -traditional declares the built-in strlen to return int,
214 and has done so at least since version 2.4.5. -- rms. */
215extern int
216strlen (const char *);
217
218#endif /* not __STDC__ */
219#endif /* __GNUC__ */
220
221#endif /* not __GNU_LIBRARY__ */
222
223/* Handle permutation of arguments. */
224
225/* Describe the part of ARGV that contains non-options that have
226 been skipped. `first_nonopt' is the index in ARGV of the first of them;
227 `last_nonopt' is the index after the last of them. */
228
229static int first_nonopt;
230static int last_nonopt;
231
232#define SWAP_FLAGS(ch1, ch2)
233
234/* Exchange two adjacent subsequences of ARGV.
235 One subsequence is elements [first_nonopt,last_nonopt)
236 which contains all the non-options that have been skipped so far.
237 The other is elements [last_nonopt,GNoptind), which contains all
238 the options processed since those non-options were skipped.
239
240 `first_nonopt' and `last_nonopt' are relocated so that they describe
241 the new indices of the non-options in ARGV after they are moved. */
242
243#if defined(__STDC__) && __STDC__
244static void
245exchange (char **);
246
247#endif
248
249static void
250exchange (char **argv)
251{
252 int bottom = first_nonopt;
253 int middle = last_nonopt;
254 int top = GNoptind;
255 char *tem;
256
257 /* Exchange the shorter segment with the far end of the longer segment.
258 * That puts the shorter segment into the right place.
259 * It leaves the longer segment in the right place overall,
260 * but it consists of two parts that need to be swapped next. */
261
262 while (top > middle && middle > bottom)
263 {
264 if (top - middle > middle - bottom)
265 {
266 /* Bottom segment is the short one. */
267 int len = middle - bottom;
268 register int i;
269
270 /* Swap it with the top part of the top segment. */
271 for (i = 0; i < len; i++)
272 {
273 tem = argv[bottom + i];
274 argv[bottom + i] = argv[top - (middle - bottom) + i];
275 argv[top - (middle - bottom) + i] = tem;
276 SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
277 }
278 /* Exclude the moved bottom segment from further swapping. */
279 top -= len;
280 }
281 else
282 {
283 /* Top segment is the short one. */
284 int len = top - middle;
285 register int i;
286
287 /* Swap it with the bottom part of the bottom segment. */
288 for (i = 0; i < len; i++)
289 {
290 tem = argv[bottom + i];
291 argv[bottom + i] = argv[middle + i];
292 argv[middle + i] = tem;
293 SWAP_FLAGS (bottom + i, middle + i);
294 }
295 /* Exclude the moved top segment from further swapping. */
296 bottom += len;
297 }
298 }
299
300 /* Update records for the slots the non-options now occupy. */
301
302 first_nonopt += (GNoptind - last_nonopt);
303 last_nonopt = GNoptind;
304}
305
306
307/* Initialize the internal data when the first call is made. */
308
309#if defined(__STDC__) && __STDC__
310static const char *
311_getopt_initialize (int, char *const *, const char *);
312
313#endif
314static const char *
315_getopt_initialize (int argc, char *const *argv, const char *optstring)
316{
317 /* Start processing options with ARGV-element 1 (since ARGV-element 0
318 * is the program name); the sequence of previously skipped
319 * non-option ARGV-elements is empty. */
320
321 first_nonopt = last_nonopt = GNoptind;
322
323 nextchar = NULL;
324
325 posixly_correct = getenv ("POSIXLY_CORRECT");
326
327 /* Determine how to handle the ordering of options and nonoptions. */
328
329 if (optstring[0] == '-')
330 {
331 ordering = RETURN_IN_ORDER;
332 ++optstring;
333 }
334 else if (optstring[0] == '+')
335 {
336 ordering = REQUIRE_ORDER;
337 ++optstring;
338 }
339 else if (posixly_correct != NULL)
340 ordering = REQUIRE_ORDER;
341 else
342 ordering = PERMUTE;
343
344 return optstring;
345}
346
347
348/* Scan elements of ARGV (whose length is ARGC) for option characters
349 given in OPTSTRING.
350
351 If an element of ARGV starts with '-', and is not exactly "-" or "--",
352 then it is an option element. The characters of this element
353 (aside from the initial '-') are option characters. If `getopt'
354 is called repeatedly, it returns successively each of the option characters
355 from each of the option elements.
356
357 If `getopt' finds another option character, it returns that character,
358 updating `GNoptind' and `nextchar' so that the next call to `getopt' can
359 resume the scan with the following option character or ARGV-element.
360
361 If there are no more option characters, `getopt' returns -1.
362 Then `GNoptind' is the index in ARGV of the first ARGV-element
363 that is not an option. (The ARGV-elements have been permuted
364 so that those that are not options now come last.)
365
366 OPTSTRING is a string containing the legitimate option characters.
367 If an option character is seen that is not listed in OPTSTRING,
368 return '?' after printing an error message. If you set `GNopterr' to
369 zero, the error message is suppressed but we still return '?'.
370
371 If a char in OPTSTRING is followed by a colon, that means it wants an arg,
372 so the following text in the same ARGV-element, or the text of the following
373 ARGV-element, is returned in `GNoptarg'. Two colons mean an option that
374 wants an optional arg; if there is text in the current ARGV-element,
375 it is returned in `GNoptarg', otherwise `GNoptarg' is set to zero.
376
377 If OPTSTRING starts with `-' or `+', it requests different methods of
378 handling the non-option ARGV-elements.
379 See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
380
381 Long-named options begin with `--' instead of `-'.
382 Their names may be abbreviated as long as the abbreviation is unique
383 or is an exact match for some defined option. If they have an
384 argument, it follows the option name in the same ARGV-element, separated
385 from the option name by a `=', or else the in next ARGV-element.
386 When `getopt' finds a long-named option, it returns 0 if that option's
387 `flag' field is nonzero, the value of the option's `val' field
388 if the `flag' field is zero.
389
390 The elements of ARGV aren't really const, because we GNUNET_CRYPTO_random_permute them.
391 But we pretend they're const in the prototype to be compatible
392 with other systems.
393
394 LONGOPTS is a vector of `struct GNoption' terminated by an
395 element containing a name which is zero.
396
397 LONGIND returns the index in LONGOPT of the long-named option found.
398 It is only valid when a long-named option has been found by the most
399 recent call.
400
401 If LONG_ONLY is nonzero, '-' as well as '--' can introduce
402 long-named options. */
403
404static int
405GN_getopt_internal (int argc,
406 char *const *argv,
407 const char *optstring,
408 const struct GNoption *longopts,
409 int *longind,
410 int long_only)
411{
412 static int __getopt_initialized = 0;
413 static int GNopterr = 1;
414
415 GNoptarg = NULL;
416
417 if ((GNoptind == 0) || ! __getopt_initialized)
418 {
419 if (GNoptind == 0)
420 GNoptind = 1; /* Don't scan ARGV[0], the program name. */
421 optstring = _getopt_initialize (argc, argv, optstring);
422 __getopt_initialized = 1;
423 }
424
425 /* Test whether ARGV[GNoptind] points to a non-option argument.
426 * Either it does not have option syntax, or there is an environment flag
427 * from the shell indicating it is not an option. The later information
428 * is only used when the used in the GNU libc. */
429#define NONOPTION_P (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0')
430
431 if ((nextchar == NULL) || (*nextchar == '\0'))
432 {
433 /* Advance to the next ARGV-element. */
434
435 /* Give FIRST_NONOPT & LAST_NONOPT rational values if GNoptind has been
436 * moved back by the user (who may also have changed the arguments). */
437 if (last_nonopt > GNoptind)
438 last_nonopt = GNoptind;
439 if (first_nonopt > GNoptind)
440 first_nonopt = GNoptind;
441
442 if (ordering == PERMUTE)
443 {
444 /* If we have just processed some options following some non-options,
445 * exchange them so that the options come first. */
446
447 if ((first_nonopt != last_nonopt) && (last_nonopt != GNoptind) )
448 exchange ((char **) argv);
449 else if (last_nonopt != GNoptind)
450 first_nonopt = GNoptind;
451
452 /* Skip any additional non-options
453 * and extend the range of non-options previously skipped. */
454
455 while (GNoptind < argc && NONOPTION_P)
456 GNoptind++;
457 last_nonopt = GNoptind;
458 }
459
460 /* The special ARGV-element `--' means premature end of options.
461 * Skip it like a null option,
462 * then exchange with previous non-options as if it were an option,
463 * then skip everything else like a non-option. */
464 if ((GNoptind != argc) && ! strcmp (argv[GNoptind], "--"))
465 {
466 GNoptind++;
467
468 if ((first_nonopt != last_nonopt) && (last_nonopt != GNoptind) )
469 exchange ((char **) argv);
470 else if (first_nonopt == last_nonopt)
471 first_nonopt = GNoptind;
472 last_nonopt = argc;
473
474 GNoptind = argc;
475 }
476
477 /* If we have done all the ARGV-elements, stop the scan
478 * and back over any non-options that we skipped and permuted. */
479
480 if (GNoptind == argc)
481 {
482 /* Set the next-arg-index to point at the non-options
483 * that we previously skipped, so the caller will digest them. */
484 if (first_nonopt != last_nonopt)
485 GNoptind = first_nonopt;
486 return -1;
487 }
488
489 /* If we have come to a non-option and did not permute it,
490 * either stop the scan or describe it to the caller and pass it by. */
491
492 if (NONOPTION_P)
493 {
494 if (ordering == REQUIRE_ORDER)
495 return -1;
496 GNoptarg = argv[GNoptind++];
497 return 1;
498 }
499
500 /* We have found another option-ARGV-element.
501 * Skip the initial punctuation. */
502
503 nextchar =
504 (argv[GNoptind] + 1 + (longopts != NULL && argv[GNoptind][1] == '-'));
505 }
506
507 /* Decode the current option-ARGV-element. */
508
509 /* Check whether the ARGV-element is a long option.
510 *
511 * If long_only and the ARGV-element has the form "-f", where f is
512 * a valid short option, don't consider it an abbreviated form of
513 * a long option that starts with f. Otherwise there would be no
514 * way to give the -f short option.
515 *
516 * On the other hand, if there's a long option "fubar" and
517 * the ARGV-element is "-fu", do consider that an abbreviation of
518 * the long option, just like "--fu", and not "-f" with arg "u".
519 *
520 * This distinction seems to be the most useful approach. */if ((longopts != NULL) &&
521 ((argv[GNoptind][1] == '-') ||
522 (long_only &&
523 (argv[GNoptind][2] || ! my_index (optstring, argv[GNoptind][1])))))
524 {
525 char *nameend;
526 const struct GNoption *p;
527 const struct GNoption *pfound = NULL;
528 int exact = 0;
529 int ambig = 0;
530 int indfound = -1;
531 int option_index;
532
533 for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
534 /* Do nothing. */;
535
536 /* Test all long options for either exact match
537 * or abbreviated matches. */
538 for (p = longopts, option_index = 0; p->name; p++, option_index++)
539 if (! strncmp (p->name, nextchar, nameend - nextchar))
540 {
541 if ((unsigned int) (nameend - nextchar) ==
542 (unsigned int) strlen (p->name))
543 {
544 /* Exact match found. */
545 pfound = p;
546 indfound = option_index;
547 exact = 1;
548 break;
549 }
550 else if (pfound == NULL)
551 {
552 /* First nonexact match found. */
553 pfound = p;
554 indfound = option_index;
555 }
556 else
557 /* Second or later nonexact match found. */
558 ambig = 1;
559 }
560
561 if (ambig && ! exact)
562 {
563 if (GNopterr)
564 fprintf (stderr,
565 _ ("%s: option `%s' is ambiguous\n"),
566 argv[0],
567 argv[GNoptind]);
568 nextchar += strlen (nextchar);
569 GNoptind++;
570 return '?';
571 }
572
573 if (pfound != NULL)
574 {
575 option_index = indfound;
576 GNoptind++;
577 if (*nameend)
578 {
579 /* Don't test has_arg with >, because some C compilers don't
580 * allow it to be used on enums. */
581 if (pfound->has_arg)
582 GNoptarg = nameend + 1;
583 else
584 {
585 if (GNopterr)
586 {
587 if (argv[GNoptind - 1][1] == '-')
588 /* --option */
589 fprintf (stderr,
590 _ ("%s: option `--%s' does not allow an argument\n"),
591 argv[0],
592 pfound->name);
593 else
594 /* +option or -option */
595 fprintf (stderr,
596 _ ("%s: option `%c%s' does not allow an argument\n"),
597 argv[0],
598 argv[GNoptind - 1][0],
599 pfound->name);
600 }
601 nextchar += strlen (nextchar);
602 return '?';
603 }
604 }
605 else if (pfound->has_arg == 1)
606 {
607 if (GNoptind < argc)
608 {
609 GNoptarg = argv[GNoptind++];
610 }
611 else
612 {
613 if (GNopterr)
614 {
615 fprintf (stderr,
616 _ ("%s: option `%s' requires an argument\n"),
617 argv[0],
618 argv[GNoptind - 1]);
619 }
620 nextchar += strlen (nextchar);
621 return (optstring[0] == ':') ? ':' : '?';
622 }
623 }
624 nextchar += strlen (nextchar);
625 if (longind != NULL)
626 *longind = option_index;
627 if (pfound->flag)
628 {
629 *(pfound->flag) = pfound->val;
630 return 0;
631 }
632 return pfound->val;
633 }
634
635 /* Can't find it as a long option. If this is not getopt_long_only,
636 * or the option starts with '--' or is not a valid short
637 * option, then it's an error.
638 * Otherwise interpret it as a short option. */
639 if (! long_only || (argv[GNoptind][1] == '-') ||
640 (my_index (optstring, *nextchar) == NULL) )
641 {
642 if (GNopterr)
643 {
644 if (argv[GNoptind][1] == '-')
645 /* --option */
646 fprintf (stderr,
647 _ ("%s: unrecognized option `--%s'\n"),
648 argv[0],
649 nextchar);
650 else
651 /* +option or -option */
652 fprintf (stderr,
653 _ ("%s: unrecognized option `%c%s'\n"),
654 argv[0],
655 argv[GNoptind][0],
656 nextchar);
657 }
658 nextchar = (char *) "";
659 GNoptind++;
660 return '?';
661 }
662 }
663
664 /* Look at and handle the next short option-character. */
665
666 {
667 char c = *nextchar++;
668 char *temp = my_index (optstring, c);
669
670 /* Increment `GNoptind' when we start to process its last character. */
671 if (*nextchar == '\0')
672 ++GNoptind;
673
674 if ((temp == NULL) || (c == ':'))
675 {
676 if (GNopterr)
677 {
678 if (posixly_correct)
679 /* 1003.2 specifies the format of this message. */
680 fprintf (stderr, _ ("%s: illegal option -- %c\n"), argv[0], c);
681 else
682 fprintf (stderr, _ ("%s: invalid option -- %c\n"), argv[0], c);
683 }
684 return '?';
685 }
686 /* Convenience. Treat POSIX -W foo same as long option --foo */
687 if ((temp[0] == 'W') && (temp[1] == ';'))
688 {
689 char *nameend;
690 const struct GNoption *p;
691 const struct GNoption *pfound = NULL;
692 int exact = 0;
693 int ambig = 0;
694 int indfound = 0;
695 int option_index;
696
697 /* This is an option that requires an argument. */
698 if (*nextchar != '\0')
699 {
700 GNoptarg = nextchar;
701 /* If we end this ARGV-element by taking the rest as an arg,
702 * we must advance to the next element now. */
703 GNoptind++;
704 }
705 else if (GNoptind == argc)
706 {
707 if (GNopterr)
708 {
709 /* 1003.2 specifies the format of this message. */
710 fprintf (stderr,
711 _ ("%s: option requires an argument -- %c\n"),
712 argv[0],
713 c);
714 }
715 if (optstring[0] == ':')
716 c = ':';
717 else
718 c = '?';
719 return c;
720 }
721 else
722 /* We already incremented `GNoptind' once;
723 * increment it again when taking next ARGV-elt as argument. */
724 GNoptarg = argv[GNoptind++];
725
726 /* GNoptarg is now the argument, see if it's in the
727 * table of longopts. */
728
729 for (nextchar = nameend = GNoptarg; *nameend && *nameend != '=';
730 nameend++)
731 /* Do nothing. */;
732
733 /* Test all long options for either exact match
734 * or abbreviated matches. */
735 if (longopts != NULL)
736 for (p = longopts, option_index = 0; p->name; p++, option_index++)
737 if (! strncmp (p->name, nextchar, nameend - nextchar))
738 {
739 if ((unsigned int) (nameend - nextchar) == strlen (p->name))
740 {
741 /* Exact match found. */
742 pfound = p;
743 indfound = option_index;
744 exact = 1;
745 break;
746 }
747 else if (pfound == NULL)
748 {
749 /* First nonexact match found. */
750 pfound = p;
751 indfound = option_index;
752 }
753 else
754 /* Second or later nonexact match found. */
755 ambig = 1;
756 }
757 if (ambig && ! exact)
758 {
759 if (GNopterr)
760 fprintf (stderr,
761 _ ("%s: option `-W %s' is ambiguous\n"),
762 argv[0],
763 argv[GNoptind]);
764 nextchar += strlen (nextchar);
765 GNoptind++;
766 return '?';
767 }
768 if (pfound != NULL)
769 {
770 option_index = indfound;
771 if (*nameend)
772 {
773 /* Don't test has_arg with >, because some C compilers don't
774 * allow it to be used on enums. */
775 if (pfound->has_arg)
776 GNoptarg = nameend + 1;
777 else
778 {
779 if (GNopterr)
780 fprintf (stderr,
781 _ ("%s: option `-W %s' does not allow an argument\n"),
782 argv[0],
783 pfound->name);
784
785 nextchar += strlen (nextchar);
786 return '?';
787 }
788 }
789 else if (pfound->has_arg == 1)
790 {
791 if (GNoptind < argc)
792 GNoptarg = argv[GNoptind++];
793 else
794 {
795 if (GNopterr)
796 fprintf (stderr,
797 _ ("%s: option `%s' requires an argument\n"),
798 argv[0],
799 argv[GNoptind - 1]);
800 nextchar += strlen (nextchar);
801 return optstring[0] == ':' ? ':' : '?';
802 }
803 }
804 nextchar += strlen (nextchar);
805 if (longind != NULL)
806 *longind = option_index;
807 if (pfound->flag)
808 {
809 *(pfound->flag) = pfound->val;
810 return 0;
811 }
812 return pfound->val;
813 }
814 nextchar = NULL;
815 return 'W'; /* Let the application handle it. */
816 }
817 if (temp[1] == ':')
818 {
819 if (temp[2] == ':')
820 {
821 /* This is an option that accepts an argument optionally. */
822 if (*nextchar != '\0')
823 {
824 GNoptarg = nextchar;
825 GNoptind++;
826 }
827 else
828 GNoptarg = NULL;
829 nextchar = NULL;
830 }
831 else
832 {
833 /* This is an option that requires an argument. */
834 if (*nextchar != '\0')
835 {
836 GNoptarg = nextchar;
837 /* If we end this ARGV-element by taking the rest as an arg,
838 * we must advance to the next element now. */
839 GNoptind++;
840 }
841 else if (GNoptind == argc)
842 {
843 if (GNopterr)
844 {
845 /* 1003.2 specifies the format of this message. */
846 fprintf (stderr,
847 _ ("%s: option requires an argument -- %c\n"),
848 argv[0],
849 c);
850 }
851 if (optstring[0] == ':')
852 c = ':';
853 else
854 c = '?';
855 }
856 else
857 /* We already incremented `GNoptind' once;
858 * increment it again when taking next ARGV-elt as argument. */
859 GNoptarg = argv[GNoptind++];
860 nextchar = NULL;
861 }
862 }
863 return c;
864 }
865}
866
867
868static int
869GNgetopt_long (int argc,
870 char *const *argv,
871 const char *options,
872 const struct GNoption *long_options,
873 int *opt_index)
874{
875 return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0);
876}
877
878
879/* ******************** now the GNUnet specific modifications... ********************* */
880
881
882int
883GNUNET_GETOPT_run (const char *binaryOptions,
884 const struct GNUNET_GETOPT_CommandLineOption *allOptions,
885 unsigned int argc,
886 char *const *argv)
887{
888 struct GNoption *long_options;
889 struct GNUNET_GETOPT_CommandLineProcessorContext clpc;
890 int count;
891 char *shorts;
892 int spos;
893 enum GNUNET_GenericReturnValue cont;
894 uint8_t *seen;
895 unsigned int optmatch = 0;
896 const char *have_exclusive = NULL;
897
898 GNUNET_assert (argc > 0);
899 GNoptind = 0;
900 clpc.binaryName = argv[0];
901 clpc.binaryOptions = binaryOptions;
902 clpc.allOptions = allOptions;
903 clpc.argv = argv;
904 clpc.argc = argc;
905 for (count = 0; NULL != allOptions[count].name; count++)
906 ;
907
908 /* transform our option representation into the format
909 used by the GNU getopt copylib */
910 long_options = GNUNET_new_array (count + 1, struct GNoption);
911 seen = GNUNET_new_array (count, uint8_t);
912 shorts = GNUNET_malloc (count * 2 + 1);
913 spos = 0;
914 for (unsigned i = 0; i < count; i++)
915 {
916 long_options[i].name = allOptions[i].name;
917 long_options[i].has_arg = allOptions[i].require_argument;
918 long_options[i].flag = NULL;
919 long_options[i].val = allOptions[i].shortName;
920 shorts[spos++] = allOptions[i].shortName;
921 if (allOptions[i].require_argument != 0)
922 shorts[spos++] = ':';
923 }
924 long_options[count].name = NULL;
925 long_options[count].has_arg = 0;
926 long_options[count].flag = NULL;
927 long_options[count].val = '\0';
928 shorts[spos] = '\0';
929 cont = GNUNET_OK;
930
931 /* main getopt loop */
932 while (1)
933 {
934 int option_index = 0;
935 unsigned int i;
936 int c;
937
938 c = GNgetopt_long (argc,
939 argv,
940 shorts,
941 long_options,
942 &option_index);
943 if (c == GNUNET_SYSERR)
944 break; /* No more flags to process */
945
946 /* Check which of our program's options was given by the user */
947 for (i = 0; i < count; i++)
948 {
949 clpc.currentArgument = GNoptind - 1;
950 if ((char) c == allOptions[i].shortName)
951 {
952 optmatch++;
953 if (allOptions[i].option_exclusive)
954 have_exclusive = allOptions[i].name;
955 if (GNUNET_OK == cont)
956 {
957 /* parse the option using the option-specific processor */
958 cont = allOptions[i].processor (&clpc,
959 allOptions[i].scls,
960 allOptions[i].name,
961 GNoptarg);
962 }
963 seen[i] = 1;
964 break;
965 }
966 }
967 if (i == count)
968 {
969 fprintf (stderr,
970 _ ("Use %s to get a list of options.\n"),
971 "--help");
972 cont = GNUNET_SYSERR;
973 }
974 }
975 GNUNET_free (shorts);
976 GNUNET_free (long_options);
977
978 /* check that if any option that was marked as exclusive
979 is the only option that was provided */
980 if ((NULL != have_exclusive) && (optmatch > 1))
981 {
982 fprintf (stderr,
983 _ ("Option `%s' can't be used with other options.\n"),
984 have_exclusive);
985 cont = GNUNET_SYSERR;
986 }
987 if (GNUNET_YES == cont)
988 {
989 /* check that all mandatory options are present */
990 for (count = 0; NULL != allOptions[count].name; count++)
991 {
992 if ((0 == seen[count]) && (allOptions[count].option_mandatory))
993 {
994 fprintf (stderr,
995 _ ("Missing mandatory option `%s'.\n"),
996 allOptions[count].name);
997 cont = GNUNET_SYSERR;
998 }
999 }
1000 }
1001 GNUNET_free (seen);
1002
1003 /* call cleaners, if available */
1004 for (unsigned int i = 0; NULL != allOptions[i].name; i++)
1005 if (NULL != allOptions[i].cleaner)
1006 allOptions[i].cleaner (allOptions[i].scls);
1007
1008 if (GNUNET_OK != cont)
1009 return cont;
1010 return GNoptind;
1011}
1012
1013
1014/* end of getopt.c */
diff --git a/src/util/getopt_helpers.c b/src/util/getopt_helpers.c
deleted file mode 100644
index 592875531..000000000
--- a/src/util/getopt_helpers.c
+++ /dev/null
@@ -1,1104 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2006, 2011, 2020 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 src/util/getopt_helpers.c
23 * @brief implements command line that sets option
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "util-getopt", __VA_ARGS__)
30
31
32/**
33 * Print out program version (implements --version).
34 *
35 * @param ctx command line processing context
36 * @param scls additional closure (points to version string)
37 * @param option name of the option
38 * @param value not used (NULL)
39 * @return #GNUNET_NO (do not continue, not an error)
40 */
41static int
42print_version (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
43 void *scls,
44 const char *option,
45 const char *value)
46{
47 const char *version = scls;
48
49 (void) option;
50 (void) value;
51 printf ("%s v%s\n", ctx->binaryName, version);
52 return GNUNET_NO;
53}
54
55
56/**
57 * Define the option to print the version of
58 * the application (-v option)
59 *
60 * @param version string with the version number
61 */
62struct GNUNET_GETOPT_CommandLineOption
63GNUNET_GETOPT_option_version (const char *version)
64{
65 struct GNUNET_GETOPT_CommandLineOption clo = {
66 .shortName = 'v',
67 .name = "version",
68 .description = gettext_noop (
69 "print the version number"),
70 .option_exclusive = 1,
71 .processor = &print_version,
72 .scls = (void *) version
73 };
74
75 return clo;
76}
77
78
79/**
80 * At what offset does the help text start?
81 */
82#define BORDER 29
83
84/**
85 * Print out details on command line options (implements --help).
86 *
87 * @param ctx command line processing context
88 * @param scls additional closure (points to about text)
89 * @param option name of the option
90 * @param value not used (NULL)
91 * @return #GNUNET_NO (do not continue, not an error)
92 */
93static int
94format_help (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
95 void *scls,
96 const char *option,
97 const char *value)
98{
99 const char *about = scls;
100 size_t slen;
101 unsigned int i;
102 int j;
103 size_t ml;
104 size_t p;
105 char *scp;
106 const char *trans;
107 const struct GNUNET_GETOPT_CommandLineOption *opt;
108 const struct GNUNET_OS_ProjectData *pd;
109
110 (void) option;
111 (void) value;
112 if (NULL != about)
113 {
114 printf ("%s\n%s\n", ctx->binaryOptions, gettext (about));
115 printf (_ (
116 "Arguments mandatory for long options are also mandatory for short options.\n"));
117 }
118 i = 0;
119 opt = ctx->allOptions;
120 while (NULL != opt[i].description)
121 {
122 if (opt[i].shortName == '\0')
123 printf (" ");
124 else
125 printf (" -%c, ", opt[i].shortName);
126 printf ("--%s", opt[i].name);
127 slen = 8 + strlen (opt[i].name);
128 if (NULL != opt[i].argumentHelp)
129 {
130 printf ("=%s", opt[i].argumentHelp);
131 slen += 1 + strlen (opt[i].argumentHelp);
132 }
133 if (slen > BORDER)
134 {
135 printf ("\n%*s", BORDER, "");
136 slen = BORDER;
137 }
138 if (slen < BORDER)
139 {
140 printf ("%*s", (int) (BORDER - slen), "");
141 slen = BORDER;
142 }
143 if (0 < strlen (opt[i].description))
144 trans = gettext (opt[i].description);
145 else
146 trans = "";
147 ml = strlen (trans);
148 p = 0;
149OUTER:
150 while (ml - p > 78 - slen)
151 {
152 for (j = p + 78 - slen; j > (int) p; j--)
153 {
154 if (isspace ((unsigned char) trans[j]))
155 {
156 scp = GNUNET_malloc (j - p + 1);
157 GNUNET_memcpy (scp, &trans[p], j - p);
158 scp[j - p] = '\0';
159 printf ("%s\n%*s", scp, BORDER + 2, "");
160 GNUNET_free (scp);
161 p = j + 1;
162 slen = BORDER + 2;
163 goto OUTER;
164 }
165 }
166 /* could not find space to break line */
167 scp = GNUNET_malloc (78 - slen + 1);
168 GNUNET_memcpy (scp, &trans[p], 78 - slen);
169 scp[78 - slen] = '\0';
170 printf ("%s\n%*s", scp, BORDER + 2, "");
171 GNUNET_free (scp);
172 slen = BORDER + 2;
173 p = p + 78 - slen;
174 }
175 /* print rest */
176 if (p < ml)
177 printf ("%s\n", &trans[p]);
178 if (strlen (trans) == 0)
179 printf ("\n");
180 i++;
181 }
182 pd = GNUNET_OS_project_data_get ();
183 printf ("Report bugs to %s.\n"
184 "Home page: %s\n",
185 pd->bug_email,
186 pd->homepage);
187
188 if (0 != pd->is_gnu)
189 printf ("General help using GNU software: http://www.gnu.org/gethelp/\n");
190
191 return GNUNET_NO;
192}
193
194
195/**
196 * Defining the option to print the command line
197 * help text (-h option).
198 *
199 * @param about string with brief description of the application
200 */
201struct GNUNET_GETOPT_CommandLineOption
202GNUNET_GETOPT_option_help (const char *about)
203{
204 struct GNUNET_GETOPT_CommandLineOption clo = {
205 .shortName = 'h',
206 .name = "help",
207 .description = gettext_noop (
208 "print this help"),
209 .option_exclusive = 1,
210 .processor = format_help,
211 .scls = (void *) about
212 };
213
214 return clo;
215}
216
217
218/**
219 * Set an option of type 'unsigned int' from the command line. Each
220 * time the option flag is given, the value is incremented by one.
221 * A pointer to this function should be passed as part of the
222 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
223 * of this type. It should be followed by a pointer to a value of
224 * type 'int'.
225 *
226 * @param ctx command line processing context
227 * @param scls additional closure (will point to the 'unsigned int')
228 * @param option name of the option
229 * @param value not used (NULL)
230 * @return #GNUNET_OK
231 */
232static int
233increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
234 void *scls,
235 const char *option,
236 const char *value)
237{
238 unsigned int *val = scls;
239
240 (void) ctx;
241 (void) option;
242 (void) value;
243 (*val)++;
244 return GNUNET_OK;
245}
246
247
248/**
249 * Increment @a val each time the option flag is given by one.
250 *
251 * @param shortName short name of the option
252 * @param name long name of the option
253 * @param argumentHelp help text for the option argument
254 * @param description long help text for the option
255 * @param[out] val increment by 1 each time the option is present
256 */
257struct GNUNET_GETOPT_CommandLineOption
258GNUNET_GETOPT_option_increment_uint (char shortName,
259 const char *name,
260 const char *description,
261 unsigned int *val)
262{
263 struct GNUNET_GETOPT_CommandLineOption clo = {
264 .shortName = shortName,
265 .name = name,
266 .description = description,
267 .processor = &increment_value,
268 .scls = (void *) val
269 };
270
271 return clo;
272}
273
274
275/**
276 * Define the '-V' verbosity option. Using the option more
277 * than once increments @a level each time.
278 *
279 * @param[out] level set to the verbosity level
280 */
281struct GNUNET_GETOPT_CommandLineOption
282GNUNET_GETOPT_option_verbose (unsigned int *level)
283{
284 struct GNUNET_GETOPT_CommandLineOption clo = {
285 .shortName = 'V',
286 .name = "verbose",
287 .description =
288 gettext_noop ("be verbose"),
289 .processor = &increment_value,
290 .scls = (void *) level
291 };
292
293 return clo;
294}
295
296
297/**
298 * Set an option of type 'int' from the command line to 1 if the
299 * given option is present.
300 * A pointer to this function should be passed as part of the
301 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
302 * of this type. It should be followed by a pointer to a value of
303 * type 'int'.
304 *
305 * @param ctx command line processing context
306 * @param scls additional closure (will point to the 'int')
307 * @param option name of the option
308 * @param value not used (NULL)
309 * @return #GNUNET_OK
310 */
311static int
312set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
313 void *scls,
314 const char *option,
315 const char *value)
316{
317 int *val = scls;
318
319 (void) ctx;
320 (void) option;
321 (void) value;
322 *val = 1;
323 return GNUNET_OK;
324}
325
326
327/**
328 * Allow user to specify a flag (which internally means setting
329 * an integer to 1/#GNUNET_YES/#GNUNET_OK.
330 *
331 * @param shortName short name of the option
332 * @param name long name of the option
333 * @param argumentHelp help text for the option argument
334 * @param description long help text for the option
335 * @param[out] val set to 1 if the option is present
336 */
337struct GNUNET_GETOPT_CommandLineOption
338GNUNET_GETOPT_option_flag (char shortName,
339 const char *name,
340 const char *description,
341 int *val)
342{
343 struct GNUNET_GETOPT_CommandLineOption clo = {
344 .shortName = shortName,
345 .name = name,
346 .description = description,
347 .processor = &set_one,
348 .scls = (void *) val
349 };
350
351 return clo;
352}
353
354
355/**
356 * Set an option of type 'char *' from the command line.
357 * A pointer to this function should be passed as part of the
358 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
359 * of this type. It should be followed by a pointer to a value of
360 * type 'char *', which will be allocated with the requested string.
361 *
362 * @param ctx command line processing context
363 * @param scls additional closure (will point to the 'char *',
364 * which will be allocated)
365 * @param option name of the option
366 * @param value actual value of the option (a string)
367 * @return #GNUNET_OK
368 */
369static int
370set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
371 void *scls,
372 const char *option,
373 const char *value)
374{
375 char **val = scls;
376
377 (void) ctx;
378 (void) option;
379 GNUNET_assert (NULL != value);
380 GNUNET_free (*val);
381 *val = GNUNET_strdup (value);
382 return GNUNET_OK;
383}
384
385
386/**
387 * Allow user to specify a string.
388 *
389 * @param shortName short name of the option
390 * @param name long name of the option
391 * @param argumentHelp help text for the option argument
392 * @param description long help text for the option
393 * @param[out] str set to the string
394 */
395struct GNUNET_GETOPT_CommandLineOption
396GNUNET_GETOPT_option_string (char shortName,
397 const char *name,
398 const char *argumentHelp,
399 const char *description,
400 char **str)
401{
402 struct GNUNET_GETOPT_CommandLineOption clo = {
403 .shortName = shortName,
404 .name = name,
405 .argumentHelp = argumentHelp,
406 .description = description,
407 .require_argument = 1,
408 .processor = &set_string,
409 .scls = (void *) str
410 };
411
412 return clo;
413}
414
415
416/**
417 * Define the '-L' log level option. Note that we do not check
418 * that the log level is valid here.
419 *
420 * @param[out] level set to the log level
421 */
422struct GNUNET_GETOPT_CommandLineOption
423GNUNET_GETOPT_option_loglevel (char **level)
424{
425 struct GNUNET_GETOPT_CommandLineOption clo = {
426 .shortName = 'L',
427 .name = "log",
428 .argumentHelp = "LOGLEVEL",
429 .description = gettext_noop ("configure logging to use LOGLEVEL"),
430 .require_argument = 1,
431 .processor = &set_string,
432 .scls = (void *) level
433 };
434
435 return clo;
436}
437
438
439/**
440 * Set an option of type 'char *' from the command line with
441 * filename expansion a la #GNUNET_STRINGS_filename_expand().
442 *
443 * @param ctx command line processing context
444 * @param scls additional closure (will point to the `char *`,
445 * which will be allocated)
446 * @param option name of the option
447 * @param value actual value of the option (a string)
448 * @return #GNUNET_OK
449 */
450static int
451set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
452 void *scls,
453 const char *option,
454 const char *value)
455{
456 char **val = scls;
457
458 (void) ctx;
459 (void) option;
460 GNUNET_assert (NULL != value);
461 GNUNET_free (*val);
462 *val = GNUNET_STRINGS_filename_expand (value);
463 return GNUNET_OK;
464}
465
466
467/**
468 * Allow user to specify a filename (automatically path expanded).
469 *
470 * @param shortName short name of the option
471 * @param name long name of the option
472 * @param argumentHelp help text for the option argument
473 * @param description long help text for the option
474 * @param[out] str set to the string
475 */
476struct GNUNET_GETOPT_CommandLineOption
477GNUNET_GETOPT_option_filename (char shortName,
478 const char *name,
479 const char *argumentHelp,
480 const char *description,
481 char **str)
482{
483 struct GNUNET_GETOPT_CommandLineOption clo = {
484 .shortName = shortName,
485 .name = name,
486 .argumentHelp = argumentHelp,
487 .description = description,
488 .require_argument = 1,
489 .processor = &set_filename,
490 .scls = (void *) str
491 };
492
493 return clo;
494}
495
496
497/**
498 * Allow user to specify log file name (-l option)
499 *
500 * @param[out] logfn set to the name of the logfile
501 */
502struct GNUNET_GETOPT_CommandLineOption
503GNUNET_GETOPT_option_logfile (char **logfn)
504{
505 struct GNUNET_GETOPT_CommandLineOption clo = {
506 .shortName = 'l',
507 .name = "logfile",
508 .argumentHelp = "FILENAME",
509 .description =
510 gettext_noop ("configure logging to write logs to FILENAME"),
511 .require_argument = 1,
512 .processor = &set_filename,
513 .scls = (void *) logfn
514 };
515
516 return clo;
517}
518
519
520/**
521 * Allow user to specify configuration file name (-c option)
522 *
523 * @param[out] fn set to the name of the configuration file
524 */
525struct GNUNET_GETOPT_CommandLineOption
526GNUNET_GETOPT_option_cfgfile (char **fn)
527{
528 struct GNUNET_GETOPT_CommandLineOption clo = {
529 .shortName = 'c',
530 .name = "config",
531 .argumentHelp = "FILENAME",
532 .description = gettext_noop ("use configuration file FILENAME"),
533 .require_argument = 1,
534 .processor = &set_filename,
535 .scls = (void *) fn
536 };
537
538 return clo;
539}
540
541
542/**
543 * Set an option of type 'unsigned long long' from the command line.
544 * A pointer to this function should be passed as part of the
545 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
546 * of this type. It should be followed by a pointer to a value of
547 * type 'unsigned long long'.
548 *
549 * @param ctx command line processing context
550 * @param scls additional closure (will point to the 'unsigned long long')
551 * @param option name of the option
552 * @param value actual value of the option as a string.
553 * @return #GNUNET_OK if parsing the value worked
554 */
555static int
556set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
557 void *scls,
558 const char *option,
559 const char *value)
560{
561 unsigned long long *val = scls;
562 char dummy[2];
563
564 (void) ctx;
565 if (1 != sscanf (value, "%llu%1s", val, dummy))
566 {
567 fprintf (stderr,
568 _ ("You must pass a number to the `%s' option.\n"),
569 option);
570 return GNUNET_SYSERR;
571 }
572 return GNUNET_OK;
573}
574
575
576/**
577 * Allow user to specify an `unsigned long long`
578 *
579 * @param shortName short name of the option
580 * @param name long name of the option
581 * @param argumentHelp help text for the option argument
582 * @param description long help text for the option
583 * @param[out] val set to the value specified at the command line
584 */
585struct GNUNET_GETOPT_CommandLineOption
586GNUNET_GETOPT_option_ulong (char shortName,
587 const char *name,
588 const char *argumentHelp,
589 const char *description,
590 unsigned long long *val)
591{
592 struct GNUNET_GETOPT_CommandLineOption clo = {
593 .shortName = shortName,
594 .name = name,
595 .argumentHelp = argumentHelp,
596 .description = description,
597 .require_argument = 1,
598 .processor = &set_ulong,
599 .scls = (void *) val
600 };
601
602 return clo;
603}
604
605
606/**
607 * Set an option of type 'struct GNUNET_TIME_Relative' from the command line.
608 * A pointer to this function should be passed as part of the
609 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
610 * of this type. It should be followed by a pointer to a value of
611 * type 'struct GNUNET_TIME_Relative'.
612 *
613 * @param ctx command line processing context
614 * @param scls additional closure (will point to the 'struct GNUNET_TIME_Relative')
615 * @param option name of the option
616 * @param value actual value of the option as a string.
617 * @return #GNUNET_OK if parsing the value worked
618 */
619static int
620set_timetravel_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
621 void *scls,
622 const char *option,
623 const char *value)
624{
625 long long delta;
626 long long minus;
627 struct GNUNET_TIME_Relative rt;
628
629 (void) scls;
630 (void) ctx;
631 while (isspace (value[0]))
632 value++;
633 minus = 1;
634 if (value[0] == '-')
635 {
636 minus = -1;
637 value++;
638 }
639 else if (value[0] == '+')
640 {
641 value++;
642 }
643 if (GNUNET_OK !=
644 GNUNET_STRINGS_fancy_time_to_relative (value,
645 &rt))
646 {
647 fprintf (stderr,
648 _ (
649 "You must pass a relative time (optionally with sign) to the `%s' option.\n"),
650 option);
651 return GNUNET_SYSERR;
652 }
653 if (rt.rel_value_us > LLONG_MAX)
654 {
655 fprintf (stderr,
656 _ ("Value given for time travel `%s' option is too big.\n"),
657 option);
658 return GNUNET_SYSERR;
659 }
660 delta = (long long) rt.rel_value_us;
661 delta *= minus;
662 GNUNET_TIME_set_offset (delta);
663 return GNUNET_OK;
664}
665
666
667/**
668 * Allow user to specify a `long long` with an offset to add to the current
669 * system time to construct the time seen by the application. Used for
670 * debugging / testing.
671 *
672 * @param shortName short name of the option
673 * @param name long name of the option
674 * @param[out] val set to the time specified at the command line
675 */
676struct GNUNET_GETOPT_CommandLineOption
677GNUNET_GETOPT_option_timetravel (char shortName,
678 const char *name)
679{
680 struct GNUNET_GETOPT_CommandLineOption clo = {
681 .shortName = shortName,
682 .name = name,
683 .argumentHelp = _ ("[+/-]MICROSECONDS"),
684 .description = _ (
685 "modify system time by given offset (for debugging/testing only)"),
686 .require_argument = 1,
687 .processor =
688 &set_timetravel_time
689 };
690
691 return clo;
692}
693
694
695/**
696 * Set an option of type 'struct GNUNET_TIME_Relative' from the command line.
697 * A pointer to this function should be passed as part of the
698 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
699 * of this type. It should be followed by a pointer to a value of
700 * type 'struct GNUNET_TIME_Relative'.
701 *
702 * @param ctx command line processing context
703 * @param scls additional closure (will point to the 'struct GNUNET_TIME_Relative')
704 * @param option name of the option
705 * @param value actual value of the option as a string.
706 * @return #GNUNET_OK if parsing the value worked
707 */
708static int
709set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
710 void *scls,
711 const char *option,
712 const char *value)
713{
714 struct GNUNET_TIME_Relative *val = scls;
715
716 (void) ctx;
717 if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (value, val))
718 {
719 fprintf (stderr,
720 _ ("You must pass relative time to the `%s' option.\n"),
721 option);
722 return GNUNET_SYSERR;
723 }
724 return GNUNET_OK;
725}
726
727
728/**
729 * Allow user to specify a `struct GNUNET_TIME_Relative`
730 * (using human-readable "fancy" time).
731 *
732 * @param shortName short name of the option
733 * @param name long name of the option
734 * @param argumentHelp help text for the option argument
735 * @param description long help text for the option
736 * @param[out] val set to the time specified at the command line
737 */
738struct GNUNET_GETOPT_CommandLineOption
739GNUNET_GETOPT_option_relative_time (char shortName,
740 const char *name,
741 const char *argumentHelp,
742 const char *description,
743 struct GNUNET_TIME_Relative *val)
744{
745 struct GNUNET_GETOPT_CommandLineOption clo = {
746 .shortName = shortName,
747 .name = name,
748 .argumentHelp = argumentHelp,
749 .description = description,
750 .require_argument = 1,
751 .processor =
752 &set_relative_time,
753 .scls = (void *) val
754 };
755
756 return clo;
757}
758
759
760/**
761 * Set an option of type 'struct GNUNET_TIME_Absolute' from the command line.
762 * A pointer to this function should be passed as part of the
763 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
764 * of this type. It should be followed by a pointer to a value of
765 * type 'struct GNUNET_TIME_Absolute'.
766 *
767 * @param ctx command line processing context
768 * @param scls additional closure (will point to the `struct GNUNET_TIME_Absolute`)
769 * @param option name of the option
770 * @param value actual value of the option as a string.
771 * @return #GNUNET_OK if parsing the value worked
772 */
773static int
774set_absolute_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
775 void *scls,
776 const char *option,
777 const char *value)
778{
779 struct GNUNET_TIME_Absolute *val = scls;
780
781 (void) ctx;
782 if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (value, val))
783 {
784 fprintf (stderr,
785 _ ("You must pass absolute time to the `%s' option.\n"),
786 option);
787 return GNUNET_SYSERR;
788 }
789 return GNUNET_OK;
790}
791
792
793/**
794 * Allow user to specify a `struct GNUNET_TIME_Absolute`
795 * (using human-readable "fancy" time).
796 *
797 * @param shortName short name of the option
798 * @param name long name of the option
799 * @param argumentHelp help text for the option argument
800 * @param description long help text for the option
801 * @param[out] val set to the time specified at the command line
802 */
803struct GNUNET_GETOPT_CommandLineOption
804GNUNET_GETOPT_option_absolute_time (char shortName,
805 const char *name,
806 const char *argumentHelp,
807 const char *description,
808 struct GNUNET_TIME_Absolute *val)
809{
810 struct GNUNET_GETOPT_CommandLineOption clo = {
811 .shortName = shortName,
812 .name = name,
813 .argumentHelp = argumentHelp,
814 .description = description,
815 .require_argument = 1,
816 .processor =
817 &set_absolute_time,
818 .scls = (void *) val
819 };
820
821 return clo;
822}
823
824
825/**
826 * Set an option of type 'unsigned int' from the command line.
827 * A pointer to this function should be passed as part of the
828 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
829 * of this type. It should be followed by a pointer to a value of
830 * type 'unsigned int'.
831 *
832 * @param ctx command line processing context
833 * @param scls additional closure (will point to the 'unsigned int')
834 * @param option name of the option
835 * @param value actual value of the option as a string.
836 * @return #GNUNET_OK if parsing the value worked
837 */
838static int
839set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
840 void *scls,
841 const char *option,
842 const char *value)
843{
844 unsigned int *val = scls;
845 char dummy[2];
846
847 (void) ctx;
848 if ('-' == *value)
849 {
850 fprintf (stderr,
851 _ (
852 "Your input for the '%s' option has to be a non negative number\n"),
853 option);
854 return GNUNET_SYSERR;
855 }
856 if (1 != sscanf (value, "%u%1s", val, dummy))
857 {
858 fprintf (stderr,
859 _ ("You must pass a number to the `%s' option.\n"),
860 option);
861 return GNUNET_SYSERR;
862 }
863 return GNUNET_OK;
864}
865
866
867/**
868 * Allow user to specify an unsigned integer.
869 *
870 * @param shortName short name of the option
871 * @param name long name of the option
872 * @param argumentHelp help text for the option argument
873 * @param description long help text for the option
874 * @param[out] val set to the value specified at the command line
875 */
876struct GNUNET_GETOPT_CommandLineOption
877GNUNET_GETOPT_option_uint (char shortName,
878 const char *name,
879 const char *argumentHelp,
880 const char *description,
881 unsigned int *val)
882{
883 struct GNUNET_GETOPT_CommandLineOption clo = {
884 .shortName = shortName,
885 .name = name,
886 .argumentHelp = argumentHelp,
887 .description = description,
888 .require_argument = 1,
889 .processor = &set_uint,
890 .scls = (void *) val
891 };
892
893 return clo;
894}
895
896
897/**
898 * Set an option of type 'uint16_t' from the command line.
899 * A pointer to this function should be passed as part of the
900 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
901 * of this type. It should be followed by a pointer to a value of
902 * type 'uint16_t'.
903 *
904 * @param ctx command line processing context
905 * @param scls additional closure (will point to the 'unsigned int')
906 * @param option name of the option
907 * @param value actual value of the option as a string.
908 * @return #GNUNET_OK if parsing the value worked
909 */
910static int
911set_uint16 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
912 void *scls,
913 const char *option,
914 const char *value)
915{
916 uint16_t *val = scls;
917 unsigned int v;
918 char dummy[2];
919
920 (void) ctx;
921 if (1 != sscanf (value, "%u%1s", &v, dummy))
922 {
923 fprintf (stderr,
924 _ ("You must pass a number to the `%s' option.\n"),
925 option);
926 return GNUNET_SYSERR;
927 }
928 if (v > UINT16_MAX)
929 {
930 fprintf (stderr,
931 _ ("You must pass a number below %u to the `%s' option.\n"),
932 (unsigned int) UINT16_MAX,
933 option);
934 return GNUNET_SYSERR;
935 }
936 *val = (uint16_t) v;
937 return GNUNET_OK;
938}
939
940
941/**
942 * Allow user to specify an uint16_t.
943 *
944 * @param shortName short name of the option
945 * @param name long name of the option
946 * @param argumentHelp help text for the option argument
947 * @param description long help text for the option
948 * @param[out] val set to the value specified at the command line
949 */
950struct GNUNET_GETOPT_CommandLineOption
951GNUNET_GETOPT_option_uint16 (char shortName,
952 const char *name,
953 const char *argumentHelp,
954 const char *description,
955 uint16_t *val)
956{
957 struct GNUNET_GETOPT_CommandLineOption clo = {
958 .shortName = shortName,
959 .name = name,
960 .argumentHelp = argumentHelp,
961 .description = description,
962 .require_argument = 1,
963 .processor = &set_uint16,
964 .scls = (void *) val
965 };
966
967 return clo;
968}
969
970
971/**
972 * Closure for #set_base32().
973 */
974struct Base32Context
975{
976 /**
977 * Value to initialize (already allocated)
978 */
979 void *val;
980
981 /**
982 * Number of bytes expected for @e val.
983 */
984 size_t val_size;
985};
986
987
988/**
989 * Set an option of type 'unsigned int' from the command line.
990 * A pointer to this function should be passed as part of the
991 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
992 * of this type. It should be followed by a pointer to a value of
993 * type 'unsigned int'.
994 *
995 * @param ctx command line processing context
996 * @param scls additional closure (will point to the 'unsigned int')
997 * @param option name of the option
998 * @param value actual value of the option as a string.
999 * @return #GNUNET_OK if parsing the value worked
1000 */
1001static int
1002set_base32 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
1003 void *scls,
1004 const char *option,
1005 const char *value)
1006{
1007 struct Base32Context *bc = scls;
1008
1009 (void) ctx;
1010 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (value,
1011 strlen (value),
1012 bc->val,
1013 bc->val_size))
1014 {
1015 fprintf (
1016 stderr,
1017 _ (
1018 "Argument `%s' malformed. Expected base32 (Crockford) encoded value.\n"),
1019 option);
1020 return GNUNET_SYSERR;
1021 }
1022 return GNUNET_OK;
1023}
1024
1025
1026/**
1027 * Helper function to clean up after
1028 * #GNUNET_GETOPT_option_base32_fixed_size.
1029 *
1030 * @param cls value to GNUNET_free()
1031 */
1032static void
1033free_bc (void *cls)
1034{
1035 GNUNET_free (cls);
1036}
1037
1038
1039/**
1040 * Allow user to specify a binary value using Crockford
1041 * Base32 encoding.
1042 *
1043 * @param shortName short name of the option
1044 * @param name long name of the option
1045 * @param argumentHelp help text for the option argument
1046 * @param description long help text for the option
1047 * @param[out] val binary value decoded from Crockford Base32-encoded argument
1048 * @param val_size size of @a val in bytes
1049 */
1050struct GNUNET_GETOPT_CommandLineOption
1051GNUNET_GETOPT_option_base32_fixed_size (char shortName,
1052 const char *name,
1053 const char *argumentHelp,
1054 const char *description,
1055 void *val,
1056 size_t val_size)
1057{
1058 struct Base32Context *bc = GNUNET_new (struct Base32Context);
1059 struct GNUNET_GETOPT_CommandLineOption clo = {
1060 .shortName = shortName,
1061 .name = name,
1062 .argumentHelp = argumentHelp,
1063 .description = description,
1064 .require_argument = 1,
1065 .processor = &set_base32,
1066 .cleaner = &free_bc,
1067 .scls = (void *) bc
1068 };
1069
1070 bc->val = val;
1071 bc->val_size = val_size;
1072 return clo;
1073}
1074
1075
1076/**
1077 * Make the given option mandatory.
1078 *
1079 * @param opt option to modify
1080 * @return @a opt with the mandatory flag set.
1081 */
1082struct GNUNET_GETOPT_CommandLineOption
1083GNUNET_GETOPT_option_mandatory (struct GNUNET_GETOPT_CommandLineOption opt)
1084{
1085 opt.option_mandatory = 1;
1086 return opt;
1087}
1088
1089
1090/**
1091 * Make the given option mutually exclusive with other options.
1092 *
1093 * @param opt option to modify
1094 * @return @a opt with the exclusive flag set.
1095 */
1096struct GNUNET_GETOPT_CommandLineOption
1097GNUNET_GETOPT_option_exclusive (struct GNUNET_GETOPT_CommandLineOption opt)
1098{
1099 opt.option_exclusive = 1;
1100 return opt;
1101}
1102
1103
1104/* end of getopt_helpers.c */
diff --git a/src/util/gnunet-base32.c b/src/util/gnunet-base32.c
deleted file mode 100644
index 217185ed0..000000000
--- a/src/util/gnunet-base32.c
+++ /dev/null
@@ -1,154 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021 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 util/gnunet-base32.c
23 * @brief tool to encode/decode from/to the Crockford Base32 encoding GNUnet uses
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29
30/**
31 * The main function of gnunet-base32
32 *
33 * @param argc number of arguments from the command line
34 * @param argv command line arguments
35 * @return 0 ok, 1 on error
36 */
37int
38main (int argc,
39 char *const *argv)
40{
41 int decode = 0;
42 const struct GNUNET_GETOPT_CommandLineOption options[] = {
43 GNUNET_GETOPT_option_flag ('d',
44 "decode",
45 gettext_noop (
46 "run decoder modus, otherwise runs as encoder"),
47 &decode),
48 GNUNET_GETOPT_option_help ("Crockford base32 encoder/decoder"),
49 GNUNET_GETOPT_option_version (PACKAGE_VERSION),
50 GNUNET_GETOPT_OPTION_END
51 };
52 int ret;
53 char *in;
54 unsigned int in_size;
55 ssize_t iret;
56 char *out;
57 size_t out_size;
58
59 if (GNUNET_OK !=
60 GNUNET_STRINGS_get_utf8_args (argc, argv,
61 &argc, &argv))
62 return 2;
63 ret = GNUNET_GETOPT_run ("gnunet-base32",
64 options,
65 argc,
66 argv);
67 if (ret < 0)
68 return 1;
69 if (0 == ret)
70 return 0;
71 in_size = 0;
72 in = NULL;
73 iret = 1;
74 while (iret > 0)
75 {
76 /* read in blocks of 4k */
77 char buf[4092];
78
79 iret = read (0,
80 buf,
81 sizeof (buf));
82 if (iret < 0)
83 {
84 GNUNET_free (in);
85 return 2;
86 }
87 if (iret > 0)
88 {
89 if (iret + in_size < in_size)
90 {
91 GNUNET_break (0);
92 GNUNET_free (in);
93 return 1;
94 }
95 GNUNET_array_grow (in,
96 in_size,
97 in_size + iret);
98 memcpy (&in[in_size - iret],
99 buf,
100 iret);
101 }
102 }
103 if (decode)
104 {
105 /* This formula can overestimate by 1 byte, so we try both
106 out_size and out_size-1 below */
107 out_size = in_size * 5 / 8;
108 out = GNUNET_malloc (out_size);
109 if ( (GNUNET_OK !=
110 GNUNET_STRINGS_string_to_data (in,
111 in_size,
112 out,
113 out_size)) &&
114 (out_size > 0) )
115 {
116 out_size--;
117 if (GNUNET_OK !=
118 GNUNET_STRINGS_string_to_data (in,
119 in_size,
120 out,
121 out_size))
122 {
123 GNUNET_free (out);
124 GNUNET_free (in);
125 return 3;
126 }
127 }
128 }
129 else
130 {
131 out = GNUNET_STRINGS_data_to_string_alloc (in,
132 in_size);
133 out_size = strlen (out);
134 }
135 {
136 size_t pos = 0;
137
138 while (pos < out_size)
139 {
140 iret = write (1,
141 &out[pos],
142 out_size - pos);
143 if (iret <= 0)
144 return 4;
145 pos += iret;
146 }
147 }
148 GNUNET_free (out);
149 GNUNET_free_nz ((void *) argv);
150 return 0;
151}
152
153
154/* end of gnunet-uri.c */
diff --git a/src/util/gnunet-config-diff.c b/src/util/gnunet-config-diff.c
deleted file mode 100644
index 207b9518a..000000000
--- a/src/util/gnunet-config-diff.c
+++ /dev/null
@@ -1,23 +0,0 @@
1#include "platform.h"
2#include <gnunet_util_lib.h>
3
4int
5main (int argc, char **argv)
6{
7 struct GNUNET_CONFIGURATION_Handle *i1;
8 struct GNUNET_CONFIGURATION_Handle *i2;
9
10 if (argc != 3)
11 {
12 fprintf (stderr, "Invoke using `%s DEFAULTS-IN DIFFS'\n", argv[0]);
13 return 1;
14 }
15 i1 = GNUNET_CONFIGURATION_create ();
16 i2 = GNUNET_CONFIGURATION_create ();
17 if ((GNUNET_OK != GNUNET_CONFIGURATION_load (i1, argv[1])) ||
18 (GNUNET_OK != GNUNET_CONFIGURATION_load (i2, argv[2])))
19 return 1;
20 if (GNUNET_OK != GNUNET_CONFIGURATION_write_diffs (i1, i2, argv[2]))
21 return 2;
22 return 0;
23}
diff --git a/src/util/gnunet-config.c b/src/util/gnunet-config.c
deleted file mode 100644
index 2ca78577e..000000000
--- a/src/util/gnunet-config.c
+++ /dev/null
@@ -1,186 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2021 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 util/gnunet-config.c
23 * @brief tool to access and manipulate GNUnet configuration files
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29
30/**
31 * Backend to check if the respective plugin is
32 * loadable. NULL if no check is to be performed.
33 * The value is the "basename" of the plugin to load.
34 */
35static char *backend_check;
36
37
38/**
39 * If printing the value of CFLAGS has been requested.
40 */
41static int cflags;
42
43
44/**
45 * If printing the value of LIBS has been requested.
46 */
47static int libs;
48
49
50/**
51 * If printing the value of PREFIX has been requested.
52 */
53static int prefix;
54
55
56/**
57 * Print each option in a given section.
58 * Main task to run to perform operations typical for
59 * gnunet-config as per the configuration settings
60 * given in @a cls.
61 *
62 * @param cls closure with the `struct GNUNET_CONFIGURATION_ConfigSettings`
63 * @param args remaining command-line arguments
64 * @param cfgfile name of the configuration file used (for saving,
65 * can be NULL!)
66 * @param cfg configuration
67 */
68static void
69run (void *cls,
70 char *const *args,
71 const char *cfgfile,
72 const struct GNUNET_CONFIGURATION_Handle *cfg)
73{
74 struct GNUNET_CONFIGURATION_ConfigSettings *cs = cls;
75
76 if (1 == cflags || 1 == libs || 1 == prefix)
77 {
78 char *prefixdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_PREFIX);
79 char *libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
80
81 if (1 == cflags)
82 {
83 fprintf (stdout, "-I%sinclude\n", prefixdir);
84 }
85 if (1 == libs)
86 {
87 fprintf (stdout, "-L%s -lgnunetutil\n", libdir);
88 }
89 if (1 == prefix)
90 {
91 fprintf (stdout, "%s\n", prefixdir);
92 }
93 cs->global_ret = 0;
94 GNUNET_free (prefixdir);
95 GNUNET_free (libdir);
96 return;
97 }
98 if (NULL != backend_check)
99 {
100 char *name;
101
102 GNUNET_asprintf (&name,
103 "libgnunet_plugin_%s",
104 backend_check);
105 cs->global_ret = (GNUNET_OK ==
106 GNUNET_PLUGIN_test (name)) ? 0 : 77;
107 GNUNET_free (name);
108 return;
109 }
110 GNUNET_CONFIGURATION_config_tool_run (cs,
111 args,
112 cfgfile,
113 cfg);
114}
115
116
117/**
118 * Program to manipulate configuration files.
119 *
120 * @param argc number of arguments from the command line
121 * @param argv command line arguments
122 * @return 0 ok, 1 on error
123 */
124int
125main (int argc,
126 char *const *argv)
127{
128 struct GNUNET_CONFIGURATION_ConfigSettings cs = {
129 .api_version = GNUNET_UTIL_VERSION,
130 .global_ret = EXIT_SUCCESS
131 };
132 struct GNUNET_GETOPT_CommandLineOption options[] = {
133 GNUNET_GETOPT_option_exclusive (
134 GNUNET_GETOPT_option_string (
135 'b',
136 "supported-backend",
137 "BACKEND",
138 gettext_noop (
139 "test if the current installation supports the specified BACKEND"),
140 &backend_check)),
141 GNUNET_GETOPT_option_flag (
142 'C',
143 "cflags",
144 gettext_noop (
145 "Provide an appropriate value for CFLAGS to applications building on top of GNUnet"),
146 &cflags),
147 GNUNET_GETOPT_option_flag (
148 'j',
149 "libs",
150 gettext_noop (
151 "Provide an appropriate value for LIBS to applications building on top of GNUnet"),
152 &libs),
153 GNUNET_GETOPT_option_flag (
154 'p',
155 "prefix",
156 gettext_noop (
157 "Provide the path under which GNUnet was installed"),
158 &prefix),
159 GNUNET_CONFIGURATION_CONFIG_OPTIONS (&cs),
160 GNUNET_GETOPT_OPTION_END
161 };
162 enum GNUNET_GenericReturnValue ret;
163
164 if (GNUNET_OK !=
165 GNUNET_STRINGS_get_utf8_args (argc, argv,
166 &argc, &argv))
167 return EXIT_FAILURE;
168 ret =
169 GNUNET_PROGRAM_run (argc,
170 argv,
171 "gnunet-config [OPTIONS]",
172 gettext_noop ("Manipulate GNUnet configuration files"),
173 options,
174 &run,
175 &cs);
176 GNUNET_free_nz ((void *) argv);
177 GNUNET_CONFIGURATION_config_settings_free (&cs);
178 if (GNUNET_NO == ret)
179 return 0;
180 if (GNUNET_SYSERR == ret)
181 return EXIT_INVALIDARGUMENT;
182 return cs.global_ret;
183}
184
185
186/* end of gnunet-config.c */
diff --git a/src/util/gnunet-crypto-tvg.c b/src/util/gnunet-crypto-tvg.c
deleted file mode 100644
index 28e44e28b..000000000
--- a/src/util/gnunet-crypto-tvg.c
+++ /dev/null
@@ -1,1092 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 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 util/gnunet-crypto-tgv.c
23 * @brief Generate test vectors for cryptographic operations.
24 * @author Florian Dold
25 *
26 * Note that this program shouldn't depend on code in src/json/,
27 * so we're using raw jansson and no GNUnet JSON helpers.
28 *
29 * Test vectors have the following format (TypeScript pseudo code):
30 *
31 * interface TestVectorFile {
32 * encoding: "base32crockford";
33 * producer?: string;
34 * vectors: TestVector[];
35 * }
36 *
37 * enum Operation {
38 * Hash("hash"),
39 * ...
40 * }
41 *
42 * interface TestVector {
43 * operation: Operation;
44 * // Inputs for the operation
45 * [ k: string]: string | number;
46 * };
47 *
48 *
49 */
50#include "platform.h"
51#include "gnunet_util_lib.h"
52#include "gnunet_signatures.h"
53#include "gnunet_testing_lib.h"
54#include <jansson.h>
55#include <gcrypt.h>
56
57GNUNET_NETWORK_STRUCT_BEGIN
58
59/**
60 * Sample signature struct.
61 *
62 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TEST
63 */
64struct TestSignatureDataPS
65{
66 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
67 uint32_t testval;
68};
69
70GNUNET_NETWORK_STRUCT_END
71
72
73/**
74 * Should we verify or output test vectors?
75 */
76static int verify_flag = GNUNET_NO;
77
78
79/**
80 * Global exit code.
81 */
82static int global_ret = 0;
83
84
85/**
86 * Create a fresh test vector for a given operation label.
87 *
88 * @param vecs array of vectors to append the new vector to
89 * @param vecname label for the operation of the vector
90 * @returns the fresh test vector
91 */
92static json_t *
93vec_for (json_t *vecs, const char *vecname)
94{
95 json_t *t = json_object ();
96
97 json_object_set_new (t,
98 "operation",
99 json_string (vecname));
100 json_array_append_new (vecs, t);
101 return t;
102}
103
104
105/**
106 * Add a base32crockford encoded value
107 * to a test vector.
108 *
109 * @param vec test vector to add to
110 * @param label label for the value
111 * @param data data to add
112 * @param size size of data
113 */
114static void
115d2j (json_t *vec,
116 const char *label,
117 const void *data,
118 size_t size)
119{
120 char *buf;
121 json_t *json;
122
123 buf = GNUNET_STRINGS_data_to_string_alloc (data, size);
124 json = json_string (buf);
125 GNUNET_free (buf);
126 GNUNET_break (NULL != json);
127
128 json_object_set_new (vec, label, json);
129}
130
131
132/**
133 * Add a number to a test vector.
134 *
135 * @param vec test vector to add to
136 * @param label label for the value
137 * @param data data to add
138 * @param size size of data
139 */
140static void
141uint2j (json_t *vec,
142 const char *label,
143 unsigned int num)
144{
145 json_t *json = json_integer (num);
146
147 json_object_set_new (vec, label, json);
148}
149
150
151static int
152expect_data_fixed (json_t *vec,
153 const char *name,
154 void *data,
155 size_t expect_len)
156{
157 const char *s = json_string_value (json_object_get (vec, name));
158
159 if (NULL == s)
160 return GNUNET_NO;
161
162 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s,
163 strlen (s),
164 data,
165 expect_len))
166 return GNUNET_NO;
167 return GNUNET_OK;
168}
169
170
171static int
172expect_data_dynamic (json_t *vec,
173 const char *name,
174 void **data,
175 size_t *ret_len)
176{
177 const char *s = json_string_value (json_object_get (vec, name));
178 char *tmp;
179 size_t len;
180
181 if (NULL == s)
182 return GNUNET_NO;
183
184 len = (strlen (s) * 5) / 8;
185 if (NULL != ret_len)
186 *ret_len = len;
187 tmp = GNUNET_malloc (len);
188
189 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, strlen (s), tmp, len))
190 {
191 GNUNET_free (tmp);
192 return GNUNET_NO;
193 }
194 *data = tmp;
195 return GNUNET_OK;
196}
197
198
199/**
200 * Check a single vector.
201 *
202 * @param operation operator of the vector
203 * @param vec the vector, a JSON object.
204 *
205 * @returns GNUNET_OK if the vector is okay
206 */
207static int
208checkvec (const char *operation,
209 json_t *vec)
210{
211 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
212 "checking %s\n", operation);
213
214 if (0 == strcmp (operation, "hash"))
215 {
216 void *data;
217 size_t data_len;
218 struct GNUNET_HashCode hash_out;
219 struct GNUNET_HashCode hc;
220
221 if (GNUNET_OK != expect_data_dynamic (vec,
222 "input",
223 &data,
224 &data_len))
225 {
226 GNUNET_break (0);
227 return GNUNET_SYSERR;
228 }
229 if (GNUNET_OK != expect_data_fixed (vec,
230 "output",
231 &hash_out,
232 sizeof (hash_out)))
233 {
234 GNUNET_free (data);
235 GNUNET_break (0);
236 return GNUNET_NO;
237 }
238
239 GNUNET_CRYPTO_hash (data, data_len, &hc);
240
241 if (0 != GNUNET_memcmp (&hc, &hash_out))
242 {
243 GNUNET_free (data);
244 GNUNET_break (0);
245 return GNUNET_NO;
246 }
247 GNUNET_free (data);
248 }
249 else if (0 == strcmp (operation, "ecc_ecdh"))
250 {
251 struct GNUNET_CRYPTO_EcdhePrivateKey priv1;
252 struct GNUNET_CRYPTO_EcdhePublicKey pub1;
253 struct GNUNET_CRYPTO_EcdhePrivateKey priv2;
254 struct GNUNET_HashCode skm;
255 struct GNUNET_HashCode skm_comp;
256
257 if (GNUNET_OK != expect_data_fixed (vec,
258 "priv1",
259 &priv1,
260 sizeof (priv1)))
261 {
262 GNUNET_break (0);
263 return GNUNET_NO;
264 }
265 if (GNUNET_OK != expect_data_fixed (vec,
266 "priv2",
267 &priv2,
268 sizeof (priv2)))
269 {
270 GNUNET_break (0);
271 return GNUNET_NO;
272 }
273 if (GNUNET_OK != expect_data_fixed (vec,
274 "pub1",
275 &pub1,
276 sizeof (pub1)))
277 {
278 GNUNET_break (0);
279 return GNUNET_NO;
280 }
281 if (GNUNET_OK != expect_data_fixed (vec,
282 "skm",
283 &skm,
284 sizeof (skm)))
285 {
286 GNUNET_break (0);
287 return GNUNET_NO;
288 }
289 GNUNET_assert (GNUNET_OK ==
290 GNUNET_CRYPTO_ecc_ecdh (&priv2,
291 &pub1,
292 &skm_comp));
293 if (0 != GNUNET_memcmp (&skm, &skm_comp))
294 {
295 GNUNET_break (0);
296 return GNUNET_NO;
297 }
298 }
299 else if (0 == strcmp (operation, "eddsa_key_derivation"))
300 {
301 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
302 struct GNUNET_CRYPTO_EddsaPublicKey pub;
303 struct GNUNET_CRYPTO_EddsaPublicKey pub_comp;
304
305 if (GNUNET_OK != expect_data_fixed (vec,
306 "priv",
307 &priv,
308 sizeof (priv)))
309 {
310 GNUNET_break (0);
311 return GNUNET_NO;
312 }
313
314 if (GNUNET_OK != expect_data_fixed (vec,
315 "pub",
316 &pub,
317 sizeof (pub)))
318 {
319 GNUNET_break (0);
320 return GNUNET_NO;
321 }
322
323 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
324 &pub_comp);
325 if (0 != GNUNET_memcmp (&pub, &pub_comp))
326 {
327 GNUNET_break (0);
328 return GNUNET_NO;
329 }
330
331 }
332 else if (0 == strcmp (operation, "eddsa_signing"))
333 {
334 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
335 struct GNUNET_CRYPTO_EddsaPublicKey pub;
336 struct TestSignatureDataPS data = { 0 };
337 struct GNUNET_CRYPTO_EddsaSignature sig;
338 struct GNUNET_CRYPTO_EddsaSignature sig_comp;
339
340 if (GNUNET_OK != expect_data_fixed (vec,
341 "priv",
342 &priv,
343 sizeof (priv)))
344 {
345 GNUNET_break (0);
346 return GNUNET_NO;
347 }
348
349 if (GNUNET_OK != expect_data_fixed (vec,
350 "pub",
351 &pub,
352 sizeof (pub)))
353 {
354 GNUNET_break (0);
355 return GNUNET_NO;
356 }
357
358 if (GNUNET_OK != expect_data_fixed (vec,
359 "data",
360 &data,
361 sizeof (data)))
362 {
363 GNUNET_break (0);
364 return GNUNET_NO;
365 }
366
367 if (GNUNET_OK != expect_data_fixed (vec,
368 "sig",
369 &sig,
370 sizeof (sig)))
371 {
372 GNUNET_break (0);
373 return GNUNET_NO;
374 }
375
376 GNUNET_CRYPTO_eddsa_sign (&priv,
377 &data,
378 &sig_comp);
379 GNUNET_assert (GNUNET_OK ==
380 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST,
381 &data,
382 &sig,
383 &pub));
384 if (0 != GNUNET_memcmp (&sig, &sig_comp))
385 {
386 GNUNET_break (0);
387 return GNUNET_NO;
388 }
389 }
390 else if (0 == strcmp (operation, "kdf"))
391 {
392 size_t out_len;
393 void *out;
394 size_t out_len_comp;
395 void *out_comp;
396 void *ikm;
397 size_t ikm_len;
398 void *salt;
399 size_t salt_len;
400 void *ctx;
401 size_t ctx_len;
402
403 if (GNUNET_OK != expect_data_dynamic (vec,
404 "out",
405 &out,
406 &out_len))
407 {
408 GNUNET_break (0);
409 return GNUNET_SYSERR;
410 }
411
412 out_len_comp = out_len;
413 out_comp = GNUNET_malloc (out_len_comp);
414
415 if (GNUNET_OK != expect_data_dynamic (vec,
416 "ikm",
417 &ikm,
418 &ikm_len))
419 {
420 GNUNET_free (out);
421 GNUNET_free (out_comp);
422 GNUNET_break (0);
423 return GNUNET_SYSERR;
424 }
425
426 if (GNUNET_OK != expect_data_dynamic (vec,
427 "salt",
428 &salt,
429 &salt_len))
430 {
431 GNUNET_free (out);
432 GNUNET_free (out_comp);
433 GNUNET_free (ikm);
434 GNUNET_break (0);
435 return GNUNET_SYSERR;
436 }
437
438 if (GNUNET_OK != expect_data_dynamic (vec,
439 "ctx",
440 &ctx,
441 &ctx_len))
442 {
443 GNUNET_free (out);
444 GNUNET_free (out_comp);
445 GNUNET_free (ikm);
446 GNUNET_free (salt);
447 GNUNET_break (0);
448 return GNUNET_SYSERR;
449 }
450
451 GNUNET_assert (GNUNET_OK ==
452 GNUNET_CRYPTO_kdf (out_comp,
453 out_len_comp,
454 salt,
455 salt_len,
456 ikm,
457 ikm_len,
458 ctx,
459 ctx_len,
460 NULL));
461
462 if (0 != memcmp (out, out_comp, out_len))
463 {
464 GNUNET_free (out);
465 GNUNET_free (out_comp);
466 GNUNET_free (ikm);
467 GNUNET_free (salt);
468 GNUNET_free (ctx);
469 GNUNET_break (0);
470 return GNUNET_NO;
471 }
472 GNUNET_free (out);
473 GNUNET_free (out_comp);
474 GNUNET_free (ikm);
475 GNUNET_free (salt);
476 GNUNET_free (ctx);
477 }
478 else if (0 == strcmp (operation, "eddsa_ecdh"))
479 {
480 struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdhe;
481 struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe;
482 struct GNUNET_CRYPTO_EddsaPrivateKey priv_eddsa;
483 struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa;
484 struct GNUNET_HashCode key_material;
485 struct GNUNET_HashCode key_material_comp;
486
487 if (GNUNET_OK != expect_data_fixed (vec,
488 "priv_ecdhe",
489 &priv_ecdhe,
490 sizeof (priv_ecdhe)))
491 {
492 GNUNET_break (0);
493 return GNUNET_NO;
494 }
495
496 if (GNUNET_OK != expect_data_fixed (vec,
497 "pub_ecdhe",
498 &pub_ecdhe,
499 sizeof (pub_ecdhe)))
500 {
501 GNUNET_break (0);
502 return GNUNET_NO;
503 }
504
505 if (GNUNET_OK != expect_data_fixed (vec,
506 "priv_eddsa",
507 &priv_eddsa,
508 sizeof (priv_eddsa)))
509 {
510 GNUNET_break (0);
511 return GNUNET_NO;
512 }
513
514 if (GNUNET_OK != expect_data_fixed (vec,
515 "pub_eddsa",
516 &pub_eddsa,
517 sizeof (pub_eddsa)))
518 {
519 GNUNET_break (0);
520 return GNUNET_NO;
521 }
522
523 if (GNUNET_OK != expect_data_fixed (vec,
524 "key_material",
525 &key_material,
526 sizeof (key_material)))
527 {
528 GNUNET_break (0);
529 return GNUNET_NO;
530 }
531
532 GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdhe, &pub_eddsa, &key_material_comp);
533
534 if (0 != GNUNET_memcmp (&key_material, &key_material_comp))
535 {
536 GNUNET_break (0);
537 return GNUNET_NO;
538 }
539 }
540 else if (0 == strcmp (operation, "rsa_blind_signing"))
541 {
542 struct GNUNET_CRYPTO_RsaPrivateKey *skey;
543 struct GNUNET_CRYPTO_RsaPublicKey *pkey;
544 struct GNUNET_HashCode message_hash;
545 struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
546 struct GNUNET_CRYPTO_RsaSignature *blinded_sig;
547 struct GNUNET_CRYPTO_RsaSignature *sig;
548 void *blinded_data;
549 size_t blinded_len;
550 void *blinded_data_comp;
551 size_t blinded_len_comp;
552 void *public_enc_data;
553 size_t public_enc_len;
554 void *secret_enc_data;
555 size_t secret_enc_len;
556 void *sig_enc_data;
557 size_t sig_enc_length;
558 void *sig_enc_data_comp;
559 size_t sig_enc_length_comp;
560
561 if (GNUNET_OK != expect_data_fixed (vec,
562 "message_hash",
563 &message_hash,
564 sizeof (message_hash)))
565 {
566 GNUNET_break (0);
567 return GNUNET_SYSERR;
568 }
569
570 if (GNUNET_OK != expect_data_fixed (vec,
571 "blinding_key_secret",
572 &bks,
573 sizeof (bks)))
574 {
575 GNUNET_break (0);
576 return GNUNET_SYSERR;
577 }
578
579 if (GNUNET_OK != expect_data_dynamic (vec,
580 "blinded_message",
581 &blinded_data,
582 &blinded_len))
583 {
584 GNUNET_break (0);
585 return GNUNET_SYSERR;
586 }
587
588 if (GNUNET_OK != expect_data_dynamic (vec,
589 "rsa_public_key",
590 &public_enc_data,
591 &public_enc_len))
592 {
593 GNUNET_free (blinded_data);
594 GNUNET_break (0);
595 return GNUNET_SYSERR;
596 }
597
598 if (GNUNET_OK != expect_data_dynamic (vec,
599 "rsa_private_key",
600 &secret_enc_data,
601 &secret_enc_len))
602 {
603 GNUNET_free (blinded_data);
604 GNUNET_free (public_enc_data);
605 GNUNET_break (0);
606 return GNUNET_SYSERR;
607 }
608
609 if (GNUNET_OK != expect_data_dynamic (vec,
610 "sig",
611 &sig_enc_data,
612 &sig_enc_length))
613 {
614 GNUNET_free (blinded_data);
615 GNUNET_free (public_enc_data);
616 GNUNET_free (secret_enc_data);
617 GNUNET_break (0);
618 return GNUNET_SYSERR;
619 }
620
621 pkey = GNUNET_CRYPTO_rsa_public_key_decode (public_enc_data,
622 public_enc_len);
623 GNUNET_assert (NULL != pkey);
624 skey = GNUNET_CRYPTO_rsa_private_key_decode (secret_enc_data,
625 secret_enc_len);
626 GNUNET_assert (NULL != skey);
627
628 GNUNET_assert (GNUNET_YES ==
629 GNUNET_CRYPTO_rsa_blind (&message_hash,
630 &bks,
631 pkey,
632 &blinded_data_comp,
633 &blinded_len_comp));
634 if ( (blinded_len != blinded_len_comp) || (0 != memcmp (blinded_data,
635 blinded_data_comp,
636 blinded_len)) )
637 {
638 GNUNET_free (blinded_data);
639 GNUNET_free (public_enc_data);
640 GNUNET_free (secret_enc_data);
641 GNUNET_free (sig_enc_data);
642 GNUNET_free (skey);
643 GNUNET_break (0);
644 return GNUNET_NO;
645 }
646 blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey, blinded_data,
647 blinded_len);
648 sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig, &bks, pkey);
649 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_verify (&message_hash, sig,
650 pkey));
651 public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
652 &public_enc_data);
653 sig_enc_length_comp = GNUNET_CRYPTO_rsa_signature_encode (sig,
654 &sig_enc_data_comp);
655
656 if ( (sig_enc_length != sig_enc_length_comp) ||
657 (0 != memcmp (sig_enc_data, sig_enc_data_comp, sig_enc_length) ))
658 {
659 GNUNET_free (blinded_sig);
660 GNUNET_free (blinded_data);
661 GNUNET_free (public_enc_data);
662 GNUNET_free (secret_enc_data);
663 GNUNET_free (sig_enc_data);
664 GNUNET_free (skey);
665 GNUNET_break (0);
666 return GNUNET_NO;
667 }
668 GNUNET_free (blinded_sig);
669 GNUNET_free (blinded_data);
670 GNUNET_free (public_enc_data);
671 GNUNET_free (secret_enc_data);
672 GNUNET_free (sig_enc_data);
673 GNUNET_free (skey);
674 }
675 else
676 {
677 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
678 "unsupported operation '%s'\n", operation);
679 }
680
681 return GNUNET_OK;
682}
683
684
685/**
686 * Check test vectors from stdin.
687 *
688 * @returns global exit code
689 */
690static int
691check_vectors ()
692{
693 json_error_t err;
694 json_t *vecfile = json_loadf (stdin, 0, &err);
695 const char *encoding;
696 json_t *vectors;
697
698 if (NULL == vecfile)
699 {
700 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unable to parse JSON\n");
701 return 1;
702 }
703 encoding = json_string_value (json_object_get (vecfile,
704 "encoding"));
705 if ( (NULL == encoding) || (0 != strcmp (encoding, "base32crockford")) )
706 {
707 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unsupported or missing encoding\n");
708 json_decref (vecfile);
709 return 1;
710 }
711 vectors = json_object_get (vecfile, "vectors");
712 if (! json_is_array (vectors))
713 {
714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bad vectors\n");
715 json_decref (vecfile);
716 return 1;
717 }
718 {
719 /* array is a JSON array */
720 size_t index;
721 json_t *value;
722 int ret;
723
724 json_array_foreach (vectors, index, value) {
725 const char *op = json_string_value (json_object_get (value,
726 "operation"));
727
728 if (NULL == op)
729 {
730 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
731 "missing operation\n");
732 ret = GNUNET_SYSERR;
733 break;
734 }
735 ret = checkvec (op, value);
736 if (GNUNET_OK != ret)
737 {
738 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
739 "bad vector %u\n",
740 (unsigned int) index);
741 break;
742 }
743 }
744 return (ret == GNUNET_OK) ? 0 : 1;
745 }
746}
747
748
749/**
750 * Output test vectors.
751 *
752 * @returns global exit code
753 */
754static int
755output_vectors ()
756{
757 json_t *vecfile = json_object ();
758 json_t *vecs = json_array ();
759
760 json_object_set_new (vecfile,
761 "encoding",
762 json_string ("base32crockford"));
763 json_object_set_new (vecfile,
764 "producer",
765 json_string ("GNUnet " PACKAGE_VERSION " " VCS_VERSION));
766 json_object_set_new (vecfile,
767 "vectors",
768 vecs);
769
770 {
771 json_t *vec = vec_for (vecs, "hash");
772 struct GNUNET_HashCode hc;
773 char *str = "Hello, GNUnet";
774
775 GNUNET_CRYPTO_hash (str, strlen (str), &hc);
776
777 d2j (vec, "input", str, strlen (str));
778 d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode));
779 }
780 {
781 json_t *vec = vec_for (vecs, "ecc_ecdh");
782 struct GNUNET_CRYPTO_EcdhePrivateKey priv1;
783 struct GNUNET_CRYPTO_EcdhePublicKey pub1;
784 struct GNUNET_CRYPTO_EcdhePrivateKey priv2;
785 struct GNUNET_HashCode skm;
786
787 GNUNET_CRYPTO_ecdhe_key_create (&priv1);
788 GNUNET_CRYPTO_ecdhe_key_create (&priv2);
789 GNUNET_CRYPTO_ecdhe_key_get_public (&priv1,
790 &pub1);
791 GNUNET_assert (GNUNET_OK ==
792 GNUNET_CRYPTO_ecc_ecdh (&priv2,
793 &pub1,
794 &skm));
795
796 d2j (vec,
797 "priv1",
798 &priv1,
799 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
800 d2j (vec,
801 "pub1",
802 &pub1,
803 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
804 d2j (vec,
805 "priv2",
806 &priv2,
807 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
808 d2j (vec,
809 "skm",
810 &skm,
811 sizeof (struct GNUNET_HashCode));
812 }
813
814 {
815 json_t *vec = vec_for (vecs, "eddsa_key_derivation");
816 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
817 struct GNUNET_CRYPTO_EddsaPublicKey pub;
818
819 GNUNET_CRYPTO_eddsa_key_create (&priv);
820 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
821 &pub);
822
823 d2j (vec,
824 "priv",
825 &priv,
826 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
827 d2j (vec,
828 "pub",
829 &pub,
830 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
831 }
832 {
833 json_t *vec = vec_for (vecs, "eddsa_signing");
834 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
835 struct GNUNET_CRYPTO_EddsaPublicKey pub;
836 struct GNUNET_CRYPTO_EddsaSignature sig;
837 struct TestSignatureDataPS data = { 0 };
838
839 GNUNET_CRYPTO_eddsa_key_create (&priv);
840 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
841 &pub);
842 data.purpose.size = htonl (sizeof (data));
843 data.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
844 GNUNET_CRYPTO_eddsa_sign (&priv,
845 &data,
846 &sig);
847 GNUNET_assert (GNUNET_OK ==
848 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST,
849 &data,
850 &sig,
851 &pub));
852
853 d2j (vec,
854 "priv",
855 &priv,
856 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
857 d2j (vec,
858 "pub",
859 &pub,
860 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
861 d2j (vec,
862 "data",
863 &data,
864 sizeof (struct TestSignatureDataPS));
865 d2j (vec,
866 "sig",
867 &sig,
868 sizeof (struct GNUNET_CRYPTO_EddsaSignature));
869 }
870
871 {
872 json_t *vec = vec_for (vecs, "kdf");
873 size_t out_len = 64;
874 char out[out_len];
875 char *ikm = "I'm the secret input key material";
876 char *salt = "I'm very salty";
877 char *ctx = "I'm a context chunk, also known as 'info' in the RFC";
878
879 GNUNET_assert (GNUNET_OK ==
880 GNUNET_CRYPTO_kdf (&out,
881 out_len,
882 salt,
883 strlen (salt),
884 ikm,
885 strlen (ikm),
886 ctx,
887 strlen (ctx),
888 NULL));
889
890 d2j (vec,
891 "salt",
892 salt,
893 strlen (salt));
894 d2j (vec,
895 "ikm",
896 ikm,
897 strlen (ikm));
898 d2j (vec,
899 "ctx",
900 ctx,
901 strlen (ctx));
902 uint2j (vec,
903 "out_len",
904 (unsigned int) out_len);
905 d2j (vec,
906 "out",
907 out,
908 out_len);
909 }
910 {
911 json_t *vec = vec_for (vecs, "eddsa_ecdh");
912 struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdhe;
913 struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe;
914 struct GNUNET_CRYPTO_EddsaPrivateKey priv_eddsa;
915 struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa;
916 struct GNUNET_HashCode key_material;
917
918 GNUNET_CRYPTO_ecdhe_key_create (&priv_ecdhe);
919 GNUNET_CRYPTO_ecdhe_key_get_public (&priv_ecdhe, &pub_ecdhe);
920 GNUNET_CRYPTO_eddsa_key_create (&priv_eddsa);
921 GNUNET_CRYPTO_eddsa_key_get_public (&priv_eddsa, &pub_eddsa);
922 GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdhe, &pub_eddsa, &key_material);
923
924 d2j (vec, "priv_ecdhe",
925 &priv_ecdhe,
926 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
927 d2j (vec, "pub_ecdhe",
928 &pub_ecdhe,
929 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
930 d2j (vec, "priv_eddsa",
931 &priv_eddsa,
932 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
933 d2j (vec, "pub_eddsa",
934 &pub_eddsa,
935 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
936 d2j (vec, "key_material",
937 &key_material,
938 sizeof (struct GNUNET_HashCode));
939 }
940
941 {
942 json_t *vec = vec_for (vecs, "rsa_blind_signing");
943
944 struct GNUNET_CRYPTO_RsaPrivateKey *skey;
945 struct GNUNET_CRYPTO_RsaPublicKey *pkey;
946 struct GNUNET_HashCode message_hash;
947 struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
948 struct GNUNET_CRYPTO_RsaSignature *blinded_sig;
949 struct GNUNET_CRYPTO_RsaSignature *sig;
950 void *blinded_data;
951 size_t blinded_len;
952 void *public_enc_data;
953 size_t public_enc_len;
954 void *secret_enc_data;
955 size_t secret_enc_len;
956 void *blinded_sig_enc_data;
957 size_t blinded_sig_enc_length;
958 void *sig_enc_data;
959 size_t sig_enc_length;
960
961 skey = GNUNET_CRYPTO_rsa_private_key_create (2048);
962 pkey = GNUNET_CRYPTO_rsa_private_key_get_public (skey);
963 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
964 &message_hash,
965 sizeof (struct GNUNET_HashCode));
966 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
967 &bks,
968 sizeof (struct
969 GNUNET_CRYPTO_RsaBlindingKeySecret));
970 GNUNET_assert (GNUNET_YES ==
971 GNUNET_CRYPTO_rsa_blind (&message_hash,
972 &bks,
973 pkey,
974 &blinded_data,
975 &blinded_len));
976 blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey, blinded_data,
977 blinded_len);
978 sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig, &bks, pkey);
979 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_verify (&message_hash, sig,
980 pkey));
981 public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
982 &public_enc_data);
983 secret_enc_len = GNUNET_CRYPTO_rsa_private_key_encode (skey,
984 &secret_enc_data);
985 blinded_sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (blinded_sig,
986 &
987 blinded_sig_enc_data);
988 sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (sig, &sig_enc_data);
989 d2j (vec,
990 "message_hash",
991 &message_hash,
992 sizeof (struct GNUNET_HashCode));
993 d2j (vec,
994 "rsa_public_key",
995 public_enc_data,
996 public_enc_len);
997 d2j (vec,
998 "rsa_private_key",
999 secret_enc_data,
1000 secret_enc_len);
1001 d2j (vec,
1002 "blinding_key_secret",
1003 &bks,
1004 sizeof (struct GNUNET_CRYPTO_RsaBlindingKeySecret));
1005 d2j (vec,
1006 "blinded_message",
1007 blinded_data,
1008 blinded_len);
1009 d2j (vec,
1010 "blinded_sig",
1011 blinded_sig_enc_data,
1012 blinded_sig_enc_length);
1013 d2j (vec,
1014 "sig",
1015 sig_enc_data,
1016 sig_enc_length);
1017 GNUNET_CRYPTO_rsa_private_key_free (skey);
1018 GNUNET_CRYPTO_rsa_public_key_free (pkey);
1019 GNUNET_CRYPTO_rsa_signature_free (sig);
1020 GNUNET_CRYPTO_rsa_signature_free (blinded_sig);
1021 GNUNET_free (public_enc_data);
1022 GNUNET_free (blinded_data);
1023 GNUNET_free (sig_enc_data);
1024 GNUNET_free (blinded_sig_enc_data);
1025 GNUNET_free (secret_enc_data);
1026 }
1027
1028 json_dumpf (vecfile, stdout, JSON_INDENT (2));
1029 json_decref (vecfile);
1030 printf ("\n");
1031
1032 return 0;
1033}
1034
1035
1036/**
1037 * Main function that will be run.
1038 *
1039 * @param cls closure
1040 * @param args remaining command-line arguments
1041 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1042 * @param cfg configuration
1043 */
1044static void
1045run (void *cls,
1046 char *const *args,
1047 const char *cfgfile,
1048 const struct GNUNET_CONFIGURATION_Handle *cfg)
1049{
1050 if (GNUNET_YES == verify_flag)
1051 global_ret = check_vectors ();
1052 else
1053 global_ret = output_vectors ();
1054}
1055
1056
1057/**
1058 * The main function of the test vector generation tool.
1059 *
1060 * @param argc number of arguments from the command line
1061 * @param argv command line arguments
1062 * @return 0 ok, 1 on error
1063 */
1064int
1065main (int argc,
1066 char *const *argv)
1067{
1068 const struct GNUNET_GETOPT_CommandLineOption options[] = {
1069 GNUNET_GETOPT_option_flag ('V',
1070 "verify",
1071 gettext_noop (
1072 "verify a test vector from stdin"),
1073 &verify_flag),
1074 GNUNET_GETOPT_OPTION_END
1075 };
1076
1077 GNUNET_assert (GNUNET_OK ==
1078 GNUNET_log_setup ("gnunet-crypto-tvg",
1079 "INFO",
1080 NULL));
1081 if (GNUNET_OK !=
1082 GNUNET_PROGRAM_run (argc, argv,
1083 "gnunet-crypto-tvg",
1084 "Generate test vectors for cryptographic operations",
1085 options,
1086 &run, NULL))
1087 return 1;
1088 return global_ret;
1089}
1090
1091
1092/* end of gnunet-crypto-tvg.c */
diff --git a/src/util/gnunet-ecc.c b/src/util/gnunet-ecc.c
deleted file mode 100644
index 8e30ac416..000000000
--- a/src/util/gnunet-ecc.c
+++ /dev/null
@@ -1,509 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 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 util/gnunet-ecc.c
23 * @brief tool to manipulate EDDSA key files
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_lib.h"
29#include <gcrypt.h>
30
31/**
32 * Number of characters a Base32-encoded public key requires.
33 */
34#define KEY_STR_LEN sizeof(struct GNUNET_CRYPTO_EddsaPublicKey) * 8 / 5 + 1
35
36/**
37 * Flag for listing public key.
38 */
39static int list_keys;
40
41/**
42 * Flag for listing public key.
43 */
44static unsigned int list_keys_count;
45
46/**
47 * Flag for printing public key.
48 */
49static int print_public_key;
50
51/**
52 * Flag for printing private key.
53 */
54static int print_private_key;
55
56/**
57 * Flag for printing public key in hex.
58 */
59static int print_public_key_hex;
60
61/**
62 * Flag for printing the output of random example operations.
63 */
64static int print_examples_flag;
65
66/**
67 * Option set to create a bunch of keys at once.
68 */
69static unsigned int make_keys;
70
71
72/**
73 * Create a flat file with a large number of key pairs for testing.
74 *
75 * @param fn File name to store the keys.
76 * @param prefix Desired prefix for the public keys, NULL if any key is OK.
77 */
78static void
79create_keys (const char *fn, const char *prefix)
80{
81 FILE *f;
82 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
83 struct GNUNET_CRYPTO_EddsaPublicKey target_pub;
84 static char vanity[KEY_STR_LEN + 1];
85 size_t len;
86 size_t n;
87 size_t rest;
88 unsigned char mask;
89 unsigned target_byte;
90 char *s;
91
92 if (NULL == (f = fopen (fn, "w+")))
93 {
94 fprintf (stderr, _ ("Failed to open `%s': %s\n"), fn, strerror (errno));
95 return;
96 }
97 if (NULL != prefix)
98 {
99 len = GNUNET_strlcpy (vanity, prefix, sizeof(vanity));
100 n = len * 5 / 8;
101 rest = len * 5 % 8;
102
103 memset (&vanity[len], '0', KEY_STR_LEN - len);
104 vanity[KEY_STR_LEN] = '\0';
105 GNUNET_assert (GNUNET_OK ==
106 GNUNET_CRYPTO_eddsa_public_key_from_string (vanity,
107 KEY_STR_LEN,
108 &target_pub));
109 if (0 != rest)
110 {
111 /**
112 * Documentation by example:
113 * vanity = "A"
114 * len = 1
115 * n = 5/8 = 0 (bytes)
116 * rest = 5%8 = 5 (bits)
117 * mask = ~(2**(8 - 5) - 1) = ~(2**3 - 1) = ~(8 - 1) = ~b111 = b11111000
118 */mask = ~((int) pow (2, 8 - rest) - 1);
119 target_byte = ((unsigned char *) &target_pub)[n] & mask;
120 }
121 else
122 {
123 /* Just so old (debian) versions of GCC calm down with the warnings. */
124 mask = target_byte = 0;
125 }
126 s = GNUNET_CRYPTO_eddsa_public_key_to_string (&target_pub);
127 fprintf (stderr,
128 _ ("Generating %u keys like %s, please wait"),
129 make_keys,
130 s);
131 GNUNET_free (s);
132 fprintf (stderr, "\nattempt %s [%u, %X]\n", vanity, (unsigned int) n, mask);
133 }
134 else
135 {
136 fprintf (stderr, _ ("Generating %u keys, please wait"), make_keys);
137 /* Just so old (debian) versions of GCC calm down with the warnings. */
138 n = rest = target_byte = mask = 0;
139 }
140
141 while (0 < make_keys--)
142 {
143 fprintf (stderr, ".");
144 GNUNET_CRYPTO_eddsa_key_create (&pk);
145 if (NULL != prefix)
146 {
147 struct GNUNET_CRYPTO_EddsaPublicKey newkey;
148
149 GNUNET_CRYPTO_eddsa_key_get_public (&pk,
150 &newkey);
151 if (0 != memcmp (&target_pub,
152 &newkey,
153 n))
154 {
155 make_keys++;
156 continue;
157 }
158 if (0 != rest)
159 {
160 unsigned char new_byte;
161
162 new_byte = ((unsigned char *) &newkey)[n] & mask;
163 if (target_byte != new_byte)
164 {
165 make_keys++;
166 continue;
167 }
168 }
169 }
170 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
171 fwrite (&pk,
172 1,
173 GNUNET_TESTING_HOSTKEYFILESIZE,
174 f))
175 {
176 fprintf (stderr,
177 _ ("\nFailed to write to `%s': %s\n"),
178 fn,
179 strerror (errno));
180 break;
181 }
182 }
183 if (UINT_MAX == make_keys)
184 fprintf (stderr, _ ("\nFinished!\n"));
185 else
186 fprintf (stderr, _ ("\nError, %u keys not generated\n"), make_keys);
187 fclose (f);
188}
189
190
191static void
192print_hex (const char *msg, const void *buf, size_t size)
193{
194 printf ("%s: ", msg);
195 for (size_t i = 0; i < size; i++)
196 {
197 printf ("%02hhx", ((const uint8_t *) buf)[i]);
198 }
199 printf ("\n");
200}
201
202
203static void
204print_examples_ecdh (void)
205{
206 struct GNUNET_CRYPTO_EcdhePrivateKey dh_priv1;
207 struct GNUNET_CRYPTO_EcdhePublicKey dh_pub1;
208 struct GNUNET_CRYPTO_EcdhePrivateKey dh_priv2;
209 struct GNUNET_CRYPTO_EcdhePublicKey dh_pub2;
210 struct GNUNET_HashCode hash;
211 char buf[128];
212
213 GNUNET_CRYPTO_ecdhe_key_create (&dh_priv1);
214 GNUNET_CRYPTO_ecdhe_key_create (&dh_priv2);
215 GNUNET_CRYPTO_ecdhe_key_get_public (&dh_priv1,
216 &dh_pub1);
217 GNUNET_CRYPTO_ecdhe_key_get_public (&dh_priv2,
218 &dh_pub2);
219
220 GNUNET_assert (NULL !=
221 GNUNET_STRINGS_data_to_string (&dh_priv1,
222 sizeof (dh_priv1),
223 buf,
224 sizeof (buf)));
225 printf ("ECDHE key 1:\n");
226 printf ("private: %s\n",
227 buf);
228 print_hex ("private(hex)",
229 &dh_priv1, sizeof (dh_priv1));
230 GNUNET_assert (NULL !=
231 GNUNET_STRINGS_data_to_string (&dh_pub1,
232 sizeof (dh_pub1),
233 buf,
234 sizeof (buf)));
235 printf ("public: %s\n",
236 buf);
237 print_hex ("public(hex)",
238 &dh_pub1,
239 sizeof (dh_pub1));
240
241 GNUNET_assert (NULL !=
242 GNUNET_STRINGS_data_to_string (&dh_priv2,
243 sizeof (dh_priv2),
244 buf,
245 sizeof (buf)));
246 printf ("ECDHE key 2:\n");
247 printf ("private: %s\n", buf);
248 print_hex ("private(hex)",
249 &dh_priv2,
250 sizeof (dh_priv2));
251 GNUNET_assert (NULL !=
252 GNUNET_STRINGS_data_to_string (&dh_pub2,
253 sizeof (dh_pub2),
254 buf,
255 sizeof (buf)));
256 printf ("public: %s\n", buf);
257 print_hex ("public(hex)",
258 &dh_pub2,
259 sizeof (dh_pub2));
260
261 GNUNET_assert (GNUNET_OK ==
262 GNUNET_CRYPTO_ecc_ecdh (&dh_priv1,
263 &dh_pub2,
264 &hash));
265 GNUNET_assert (NULL !=
266 GNUNET_STRINGS_data_to_string (&hash,
267 sizeof (hash),
268 buf,
269 sizeof (buf)));
270 printf ("ECDH shared secret: %s\n",
271 buf);
272
273}
274
275
276/**
277 * Print some random example operations to stdout.
278 */
279static void
280print_examples (void)
281{
282 print_examples_ecdh ();
283 // print_examples_ecdsa ();
284 // print_examples_eddsa ();
285}
286
287
288static void
289print_key (const char *filename)
290{
291 struct GNUNET_DISK_FileHandle *fd;
292 struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
293 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
294 char *hostkeys_data;
295 char *hostkey_str;
296 uint64_t fs;
297 unsigned int total_hostkeys;
298 unsigned int c;
299 ssize_t sret;
300
301 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
302 {
303 fprintf (stderr, _ ("Hostkeys file `%s' not found\n"), filename);
304 return;
305 }
306
307 /* Check hostkey file size, read entire thing into memory */
308 if (GNUNET_OK !=
309 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
310 fs = 0;
311 if (0 == fs)
312 {
313 fprintf (stderr, _ ("Hostkeys file `%s' is empty\n"), filename);
314 return; /* File is empty */
315 }
316 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
317 {
318 fprintf (stderr, _ ("Incorrect hostkey file format: %s\n"), filename);
319 return;
320 }
321 fd = GNUNET_DISK_file_open (filename,
322 GNUNET_DISK_OPEN_READ,
323 GNUNET_DISK_PERM_NONE);
324 if (NULL == fd)
325 {
326 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
327 return;
328 }
329 hostkeys_data = GNUNET_malloc (fs);
330 sret = GNUNET_DISK_file_read (fd, hostkeys_data, fs);
331 if ((sret < 0) || (fs != (size_t) sret))
332 {
333 fprintf (stderr, _ ("Could not read hostkey file: %s\n"), filename);
334 GNUNET_free (hostkeys_data);
335 GNUNET_DISK_file_close (fd);
336 return;
337 }
338 GNUNET_DISK_file_close (fd);
339
340 if (NULL == hostkeys_data)
341 return;
342 total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
343 for (c = 0; (c < total_hostkeys) && (c < list_keys_count); c++)
344 {
345 GNUNET_memcpy (&private_key,
346 hostkeys_data + (c * GNUNET_TESTING_HOSTKEYFILESIZE),
347 GNUNET_TESTING_HOSTKEYFILESIZE);
348 GNUNET_CRYPTO_eddsa_key_get_public (&private_key, &public_key);
349 hostkey_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&public_key);
350 if (NULL != hostkey_str)
351 {
352 fprintf (stderr, "%4u: %s\n", c, hostkey_str);
353 GNUNET_free (hostkey_str);
354 }
355 else
356 fprintf (stderr, "%4u: %s\n", c, "invalid");
357 }
358 GNUNET_free (hostkeys_data);
359}
360
361
362/**
363 * Main function that will be run by the scheduler.
364 *
365 * @param cls closure, NULL
366 * @param args remaining command-line arguments
367 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
368 * @param cfg configuration
369 */
370static void
371run (void *cls,
372 char *const *args,
373 const char *cfgfile,
374 const struct GNUNET_CONFIGURATION_Handle *cfg)
375{
376 (void) cls;
377 (void) cfgfile;
378 (void) cfg;
379
380 if (print_examples_flag)
381 {
382 print_examples ();
383 return;
384 }
385 if (NULL == args[0])
386 {
387 fprintf (stderr, "%s", _ ("No hostkey file specified on command line\n"));
388 return;
389 }
390 if (list_keys)
391 {
392 print_key (args[0]);
393 return;
394 }
395 if (make_keys > 0)
396 {
397 create_keys (args[0], args[1]);
398 return;
399 }
400 if (print_public_key || print_public_key_hex || print_private_key)
401 {
402 char *str;
403 struct GNUNET_DISK_FileHandle *keyfile;
404 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
405 struct GNUNET_CRYPTO_EddsaPublicKey pub;
406
407 keyfile = GNUNET_DISK_file_open (args[0],
408 GNUNET_DISK_OPEN_READ,
409 GNUNET_DISK_PERM_NONE);
410 if (NULL == keyfile)
411 return;
412 while (sizeof(pk) == GNUNET_DISK_file_read (keyfile, &pk, sizeof(pk)))
413 {
414 GNUNET_CRYPTO_eddsa_key_get_public (&pk, &pub);
415 if (print_public_key_hex)
416 {
417 print_hex ("HEX:", &pub, sizeof(pub));
418 }
419 else if (print_public_key)
420 {
421 str = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
422 fprintf (stdout, "%s\n", str);
423 GNUNET_free (str);
424 }
425 else if (print_private_key)
426 {
427 str = GNUNET_CRYPTO_eddsa_private_key_to_string (&pk);
428 fprintf (stdout, "%s\n", str);
429 GNUNET_free (str);
430 }
431 }
432 GNUNET_DISK_file_close (keyfile);
433 }
434}
435
436
437/**
438 * Program to manipulate ECC key files.
439 *
440 * @param argc number of arguments from the command line
441 * @param argv command line arguments
442 * @return 0 ok, 1 on error
443 */
444int
445main (int argc, char *const *argv)
446{
447 struct GNUNET_GETOPT_CommandLineOption options[] =
448 { GNUNET_GETOPT_option_flag ('i',
449 "iterate",
450 gettext_noop (
451 "list keys included in a file (for testing)"),
452 &list_keys),
453 GNUNET_GETOPT_option_uint (
454 'e',
455 "end=",
456 "COUNT",
457 gettext_noop ("number of keys to list included in a file (for testing)"),
458 &list_keys_count),
459 GNUNET_GETOPT_option_uint (
460 'g',
461 "generate-keys",
462 "COUNT",
463 gettext_noop ("create COUNT public-private key pairs (for testing)"),
464 &make_keys),
465 GNUNET_GETOPT_option_flag ('p',
466 "print-public-key",
467 gettext_noop (
468 "print the public key in ASCII format"),
469 &print_public_key),
470 GNUNET_GETOPT_option_flag ('P',
471 "print-private-key",
472 gettext_noop (
473 "print the private key in ASCII format"),
474 &print_private_key),
475 GNUNET_GETOPT_option_flag ('x',
476 "print-hex",
477 gettext_noop (
478 "print the public key in HEX format"),
479 &print_public_key_hex),
480 GNUNET_GETOPT_option_flag (
481 'E',
482 "examples",
483 gettext_noop (
484 "print examples of ECC operations (used for compatibility testing)"),
485 &print_examples_flag),
486 GNUNET_GETOPT_OPTION_END };
487 int ret;
488
489 list_keys_count = UINT32_MAX;
490 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
491 return 2;
492
493 ret = (GNUNET_OK ==
494 GNUNET_PROGRAM_run (argc,
495 argv,
496 "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]",
497 gettext_noop (
498 "Manipulate GNUnet private ECC key files"),
499 options,
500 &run,
501 NULL))
502 ? 0
503 : 1;
504 GNUNET_free_nz ((void *) argv);
505 return ret;
506}
507
508
509/* end of gnunet-ecc.c */
diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c
deleted file mode 100644
index 5bccd3916..000000000
--- a/src/util/gnunet-qr.c
+++ /dev/null
@@ -1,596 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013-2019 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 * @file util/gnunet-qr.c
22 * @author Hartmut Goebel (original implementation)
23 * @author Martin Schanzenbach (integrate gnunet-uri)
24 * @author Christian Grothoff (error handling)
25 */
26#include <stdio.h>
27#include <stdbool.h>
28#include <signal.h>
29#include <zbar.h>
30
31#include "platform.h"
32#include "gnunet_util_lib.h"
33
34#if HAVE_PNG
35#include <png.h>
36#endif
37
38/**
39 * Global exit code.
40 * Set to non-zero if an error occurs after the scheduler has started.
41 */
42static int exit_code = 0;
43
44/**
45 * Video device to capture from.
46 * Used by default if PNG support is disabled or no PNG file is specified.
47 * Defaults to /dev/video0.
48 */
49static char *device = NULL;
50
51#if HAVE_PNG
52/**
53 * Name of the file to read from.
54 * If the file is not a PNG-encoded image of a QR code, an error will be
55 * thrown.
56 */
57static char *pngfilename = NULL;
58#endif
59
60/**
61 * Requested verbosity.
62 */
63static unsigned int verbosity = 0;
64
65/**
66 * Child process handle.
67 */
68struct GNUNET_OS_Process *childproc = NULL;
69
70/**
71 * Child process handle for waiting.
72 */
73static struct GNUNET_ChildWaitHandle *waitchildproc = NULL;
74
75/**
76 * Macro to handle verbosity when printing messages.
77 */
78#define LOG(fmt, ...) \
79 do \
80 { \
81 if (0 < verbosity) \
82 { \
83 GNUNET_log (GNUNET_ERROR_TYPE_INFO, fmt, ##__VA_ARGS__); \
84 if (verbosity > 1) \
85 { \
86 fprintf (stdout, fmt, ##__VA_ARGS__); \
87 } \
88 } \
89 } \
90 while (0)
91
92/**
93 * Executed when program is terminating.
94 */
95static void
96shutdown_program (void *cls)
97{
98 if (NULL != waitchildproc)
99 {
100 GNUNET_wait_child_cancel (waitchildproc);
101 }
102 if (NULL != childproc)
103 {
104 /* A bit brutal, but this process is terminating so we're out of time */
105 GNUNET_OS_process_kill (childproc, SIGKILL);
106 }
107}
108
109/**
110 * Callback executed when the child process terminates.
111 *
112 * @param cls closure
113 * @param type status of the child process
114 * @param code the exit code of the child process
115 */
116static void
117wait_child (void *cls,
118 enum GNUNET_OS_ProcessStatusType type,
119 long unsigned int code)
120{
121 GNUNET_OS_process_destroy (childproc);
122 childproc = NULL;
123 waitchildproc = NULL;
124
125 char *uri = cls;
126
127 if (0 != exit_code)
128 {
129 fprintf (stdout, _("Failed to add URI %s\n"), uri);
130 }
131 else
132 {
133 fprintf (stdout, _("Added URI %s\n"), uri);
134 }
135
136 GNUNET_free (uri);
137
138 GNUNET_SCHEDULER_shutdown ();
139}
140
141/**
142 * Dispatch URIs to the appropriate GNUnet helper process.
143 *
144 * @param cls closure
145 * @param uri URI to dispatch
146 * @param cfgfile name of the configuration file in use
147 * @param cfg the configuration in use
148 */
149static void
150handle_uri (void *cls,
151 const char *uri,
152 const char *cfgfile,
153 const struct GNUNET_CONFIGURATION_Handle *cfg)
154{
155 const char *cursor = uri;
156
157 if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://")))
158 {
159 fprintf (stderr,
160 _("Invalid URI: does not start with `gnunet://'\n"));
161 exit_code = 1;
162 return;
163 }
164
165 cursor += strlen ("gnunet://");
166
167 const char *slash = strchr (cursor, '/');
168 if (NULL == slash)
169 {
170 fprintf (stderr, _("Invalid URI: fails to specify a subsystem\n"));
171 exit_code = 1;
172 return;
173 }
174
175 char *subsystem = GNUNET_strndup (cursor, slash - cursor);
176 char *program = NULL;
177
178 if (GNUNET_OK !=
179 GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program))
180 {
181 fprintf (stderr, _("No known handler for subsystem `%s'\n"), subsystem);
182 GNUNET_free (subsystem);
183 exit_code = 1;
184 return;
185 }
186
187 GNUNET_free (subsystem);
188
189 char **childargv = NULL;
190 unsigned int childargc = 0;
191
192 for (const char *token=strtok (program, " ");
193 NULL!=token;
194 token=strtok(NULL, " "))
195 {
196 GNUNET_array_append (childargv, childargc, GNUNET_strdup (token));
197 }
198 GNUNET_array_append (childargv, childargc, GNUNET_strdup (uri));
199 GNUNET_array_append (childargv, childargc, NULL);
200
201 childproc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ALL,
202 NULL,
203 NULL,
204 NULL,
205 childargv[0],
206 childargv);
207 for (size_t i=0; i<childargc-1; ++i)
208 {
209 GNUNET_free (childargv[i]);
210 }
211
212 GNUNET_array_grow (childargv, childargc, 0);
213
214 if (NULL == childproc)
215 {
216 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
217 _("Unable to start child process `%s'\n"),
218 program);
219 GNUNET_free (program);
220 exit_code = 1;
221 return;
222 }
223
224 waitchildproc = GNUNET_wait_child (childproc, &wait_child, (void *)uri);
225}
226
227/**
228 * Obtain a QR code symbol from @a proc.
229 *
230 * @param proc the zbar processor to use
231 * @return NULL on error
232 */
233static const zbar_symbol_t *
234get_symbol (zbar_processor_t *proc)
235{
236 if (0 != zbar_processor_parse_config (proc, "enable"))
237 {
238 GNUNET_break (0);
239 return NULL;
240 }
241
242 int r = zbar_processor_init (proc, device, 1);
243 if (0 != r)
244 {
245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
246 _("Failed to open device: `%s': %d\n"),
247 device,
248 r);
249 return NULL;
250 }
251
252 r = zbar_processor_set_visible (proc, 1);
253 r += zbar_processor_set_active (proc, 1);
254 if (0 != r)
255 {
256 GNUNET_break (0);
257 return NULL;
258 }
259
260 LOG (_("Capturing...\n"));
261
262 int n = zbar_process_one (proc, -1);
263
264 zbar_processor_set_active (proc, 0);
265 zbar_processor_set_visible (proc, 0);
266
267 if (-1 == n)
268 {
269 LOG (_("No captured images\n"));
270 return NULL;
271 }
272
273 LOG(_("Got %d images\n"), n);
274
275 const zbar_symbol_set_t *symbols = zbar_processor_get_results (proc);
276 if (NULL == symbols)
277 {
278 GNUNET_break (0);
279 return NULL;
280 }
281
282 return zbar_symbol_set_first_symbol (symbols);
283}
284
285/**
286 * Run the zbar QR code parser.
287 *
288 * @return NULL on error
289 */
290static char *
291run_zbar (void)
292{
293 zbar_processor_t *proc = zbar_processor_create (1);
294 if (NULL == proc)
295 {
296 GNUNET_break (0);
297 return NULL;
298 }
299
300 if (NULL == device)
301 {
302 device = GNUNET_strdup ("/dev/video0");
303 }
304
305 const zbar_symbol_t *symbol = get_symbol (proc);
306 if (NULL == symbol)
307 {
308 zbar_processor_destroy (proc);
309 return NULL;
310 }
311
312 const char *data = zbar_symbol_get_data (symbol);
313 if (NULL == data)
314 {
315 GNUNET_break (0);
316 zbar_processor_destroy (proc);
317 return NULL;
318 }
319
320 LOG (_("Found %s: \"%s\"\n"),
321 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
322 data);
323
324 char *copy = GNUNET_strdup (data);
325
326 zbar_processor_destroy (proc);
327 GNUNET_free (device);
328
329 return copy;
330}
331
332#if HAVE_PNG
333/**
334 * Decode the PNG-encoded file to a raw byte buffer.
335 *
336 * @param width[out] where to store the image width
337 * @param height[out] where to store the image height
338 */
339static char *
340png_parse (uint32_t *width, uint32_t *height)
341{
342 if (NULL == width || NULL == height)
343 {
344 return NULL;
345 }
346
347 FILE *pngfile = fopen (pngfilename, "rb");
348 if (NULL == pngfile)
349 {
350 return NULL;
351 }
352
353 unsigned char header[8];
354 if (8 != fread (header, 1, 8, pngfile))
355 {
356 fclose (pngfile);
357 return NULL;
358 }
359
360 if (png_sig_cmp (header, 0, 8))
361 {
362 fclose (pngfile);
363 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
364 _("%s is not a PNG file\n"),
365 pngfilename);
366 fprintf (stderr, _("%s is not a PNG file\n"), pngfilename);
367 return NULL;
368 }
369
370 /* libpng's default error handling might or might not conflict with GNUnet's
371 scheduler and event loop. Beware of strange interactions. */
372 png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
373 NULL,
374 NULL,
375 NULL);
376 if (NULL == png)
377 {
378 GNUNET_break (0);
379 fclose (pngfile);
380 return NULL;
381 }
382
383 png_infop pnginfo = png_create_info_struct (png);
384 if (NULL == pnginfo)
385 {
386 GNUNET_break (0);
387 png_destroy_read_struct (&png, NULL, NULL);
388 fclose (pngfile);
389 return NULL;
390 }
391
392 if (setjmp (png_jmpbuf (png)))
393 {
394 GNUNET_break (0);
395 png_destroy_read_struct (&png, &pnginfo, NULL);
396 fclose (pngfile);
397 return NULL;
398 }
399
400 png_init_io (png, pngfile);
401 png_set_sig_bytes (png, 8);
402
403 png_read_info (png, pnginfo);
404
405 png_byte pngcolor = png_get_color_type (png, pnginfo);
406 png_byte pngdepth = png_get_bit_depth (png, pnginfo);
407
408 /* Normalize picture --- based on a zbar example */
409 if (0 != (pngcolor & PNG_COLOR_TYPE_PALETTE))
410 {
411 png_set_palette_to_rgb (png);
412 }
413
414 if (pngcolor == PNG_COLOR_TYPE_GRAY && pngdepth < 8)
415 {
416 png_set_expand_gray_1_2_4_to_8 (png);
417 }
418
419 if (16 == pngdepth)
420 {
421 png_set_strip_16 (png);
422 }
423
424 if (0 != (pngcolor & PNG_COLOR_MASK_ALPHA))
425 {
426 png_set_strip_alpha (png);
427 }
428
429 if (0 != (pngcolor & PNG_COLOR_MASK_COLOR))
430 {
431 png_set_rgb_to_gray_fixed (png, 1, -1, -1);
432 }
433
434 png_uint_32 pngwidth = png_get_image_width (png, pnginfo);
435 png_uint_32 pngheight = png_get_image_height (png, pnginfo);
436
437 char *buffer = GNUNET_new_array (pngwidth * pngheight, char);
438 png_bytepp rows = GNUNET_new_array (pngheight, png_bytep);
439
440 for (png_uint_32 i=0; i<pngheight; ++i)
441 {
442 rows[i] = (unsigned char *)buffer + (pngwidth * i);
443 }
444
445 png_read_image (png, rows);
446
447 GNUNET_free (rows);
448 fclose (pngfile);
449
450 *width = pngwidth;
451 *height = pngheight;
452
453 return buffer;
454}
455
456/**
457 * Parse a PNG-encoded file for a QR code.
458 *
459 * @return NULL on error
460 */
461static char *
462run_png_reader (void)
463{
464 uint32_t width = 0;
465 uint32_t height = 0;
466 char *buffer = png_parse (&width, &height);
467 if (NULL == buffer)
468 {
469 return NULL;
470 }
471
472 zbar_image_scanner_t *scanner = zbar_image_scanner_create ();
473 zbar_image_scanner_set_config (scanner,0, ZBAR_CFG_ENABLE, 1);
474
475 zbar_image_t *zimage = zbar_image_create ();
476 zbar_image_set_format (zimage, zbar_fourcc ('Y', '8', '0', '0'));
477 zbar_image_set_size (zimage, width, height);
478 zbar_image_set_data (zimage, buffer, width * height, &zbar_image_free_data);
479
480 int n = zbar_scan_image (scanner, zimage);
481
482 if (-1 == n)
483 {
484 LOG (_("No captured images\n"));
485 return NULL;
486 }
487
488 LOG(_("Got %d images\n"), n);
489
490 const zbar_symbol_t *symbol = zbar_image_first_symbol (zimage);
491
492 const char *data = zbar_symbol_get_data (symbol);
493 if (NULL == data)
494 {
495 GNUNET_break (0);
496 zbar_image_destroy (zimage);
497 zbar_image_scanner_destroy (scanner);
498 return NULL;
499 }
500
501 LOG (_("Found %s: \"%s\"\n"),
502 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
503 data);
504
505 char *copy = GNUNET_strdup (data);
506
507 zbar_image_destroy (zimage);
508 zbar_image_scanner_destroy (scanner);
509
510 return copy;
511}
512#endif
513
514/**
515 * Main function executed by the scheduler.
516 *
517 * @param cls closure
518 * @param args remaining command line arguments
519 * @param cfgfile name of the configuration file being used
520 * @param cfg the used configuration
521 */
522static void
523run (void *cls,
524 char *const *args,
525 const char *cfgfile,
526 const struct GNUNET_CONFIGURATION_Handle *cfg)
527{
528 char *data = NULL;
529
530 GNUNET_SCHEDULER_add_shutdown (&shutdown_program, NULL);
531
532#if HAVE_PNG
533 if (NULL != pngfilename)
534 {
535 data = run_png_reader ();
536 }
537 else
538#endif
539 {
540 data = run_zbar ();
541 }
542
543 if (NULL == data)
544 {
545 LOG (_("No data found\n"));
546 exit_code = 1;
547 GNUNET_SCHEDULER_shutdown ();
548 return;
549 }
550
551 handle_uri (cls, data, cfgfile, cfg);
552
553 if (0 != exit_code)
554 {
555 fprintf (stdout, _("Failed to add URI %s\n"), data);
556 GNUNET_free (data);
557 GNUNET_SCHEDULER_shutdown ();
558 return;
559 }
560
561 LOG (_("Dispatching the URI\n"));
562}
563
564int
565main (int argc, char *const *argv)
566{
567 struct GNUNET_GETOPT_CommandLineOption options[] = {
568 GNUNET_GETOPT_option_string (
569 'd',
570 "device",
571 "DEVICE",
572 gettext_noop ("use the video device DEVICE (defaults to /dev/video0)"),
573 &device),
574#if HAVE_PNG
575 GNUNET_GETOPT_option_string (
576 'f',
577 "file",
578 "FILE",
579 gettext_noop ("read from the PNG-encoded file FILE"),
580 &pngfilename),
581#endif
582 GNUNET_GETOPT_option_verbose (&verbosity),
583 GNUNET_GETOPT_OPTION_END,
584 };
585
586 enum GNUNET_GenericReturnValue ret =
587 GNUNET_PROGRAM_run (argc,
588 argv,
589 "gnunet-qr",
590 gettext_noop ("Scan a QR code and import the URI read"),
591 options,
592 &run,
593 NULL);
594
595 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
596}
diff --git a/src/util/gnunet-resolver.c b/src/util/gnunet-resolver.c
deleted file mode 100644
index d8e6a1f0d..000000000
--- a/src/util/gnunet-resolver.c
+++ /dev/null
@@ -1,190 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010 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 util/gnunet-resolver.c
23 * @brief tool to test resolver
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_resolver_service.h"
29
30#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
31
32/**
33 * Flag for reverse lookup.
34 */
35static int reverse;
36
37
38/**
39 * Prints each hostname obtained from DNS.
40 *
41 * @param cls closure (unused)
42 * @param hostname one of the names for the host, NULL
43 * on the last call to the callback
44 */
45static void
46print_hostname (void *cls,
47 const char *hostname)
48{
49 (void) cls;
50 if (NULL == hostname)
51 return;
52 fprintf (stdout,
53 "%s\n",
54 hostname);
55}
56
57
58/**
59 * Callback function to display address.
60 *
61 * @param cls closure (unused)
62 * @param addr one of the addresses of the host, NULL for the last address
63 * @param addrlen length of the address
64 */
65static void
66print_sockaddr (void *cls,
67 const struct sockaddr *addr,
68 socklen_t addrlen)
69{
70 (void) cls;
71 if (NULL == addr)
72 return;
73 fprintf (stdout,
74 "%s\n",
75 GNUNET_a2s (addr,
76 addrlen));
77}
78
79
80/**
81 * Main function that will be run by the scheduler.
82 *
83 * @param cls closure
84 * @param args remaining command-line arguments
85 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
86 * @param cfg configuration
87 */
88static void
89run (void *cls,
90 char *const *args,
91 const char *cfgfile,
92 const struct GNUNET_CONFIGURATION_Handle *cfg)
93{
94 const struct sockaddr *sa;
95 socklen_t salen;
96 struct sockaddr_in v4;
97 struct sockaddr_in6 v6;
98
99 (void) cls;
100 (void) cfgfile;
101 (void) cfg;
102 if (NULL == args[0])
103 return;
104 if (! reverse)
105 {
106 GNUNET_RESOLVER_ip_get (args[0],
107 AF_UNSPEC,
108 GET_TIMEOUT,
109 &print_sockaddr,
110 NULL);
111 return;
112 }
113
114 sa = NULL;
115 memset (&v4, 0, sizeof(v4));
116 v4.sin_family = AF_INET;
117#if HAVE_SOCKADDR_IN_SIN_LEN
118 v4.sin_len = sizeof(v4);
119#endif
120 if (1 == inet_pton (AF_INET,
121 args[0],
122 &v4.sin_addr))
123 {
124 sa = (struct sockaddr *) &v4;
125 salen = sizeof(v4);
126 }
127 memset (&v6, 0, sizeof(v6));
128 v6.sin6_family = AF_INET6;
129#if HAVE_SOCKADDR_IN_SIN_LEN
130 v6.sin6_len = sizeof(v6);
131#endif
132 if (1 == inet_pton (AF_INET6,
133 args[0],
134 &v6.sin6_addr))
135 {
136 sa = (struct sockaddr *) &v6;
137 salen = sizeof(v6);
138 }
139 if (NULL == sa)
140 {
141 fprintf (stderr,
142 "`%s' is not a valid IP: %s\n",
143 args[0],
144 strerror (errno));
145 return;
146 }
147 GNUNET_RESOLVER_hostname_get (sa, salen,
148 GNUNET_YES,
149 GET_TIMEOUT,
150 &print_hostname,
151 NULL);
152}
153
154
155/**
156 * The main function to access GNUnet's DNS resolver.
157 *
158 * @param argc number of arguments from the command line
159 * @param argv command line arguments
160 * @return 0 ok, 1 on error
161 */
162int
163main (int argc, char *const *argv)
164{
165 struct GNUNET_GETOPT_CommandLineOption options[] = {
166 GNUNET_GETOPT_option_flag ('r',
167 "reverse",
168 gettext_noop ("perform a reverse lookup"),
169 &reverse),
170 GNUNET_GETOPT_OPTION_END
171 };
172 int ret;
173
174 if (GNUNET_OK !=
175 GNUNET_STRINGS_get_utf8_args (argc, argv,
176 &argc, &argv))
177 return 2;
178
179 ret = (GNUNET_OK ==
180 GNUNET_PROGRAM_run (argc, argv,
181 "gnunet-resolver [hostname]",
182 gettext_noop ("Use built-in GNUnet stub resolver"),
183 options,
184 &run, NULL)) ? 0 : 1;
185 GNUNET_free_nz ((void *) argv);
186 return ret;
187}
188
189
190/* end of gnunet-resolver.c */
diff --git a/src/util/gnunet-scrypt.c b/src/util/gnunet-scrypt.c
deleted file mode 100644
index fe8b6769f..000000000
--- a/src/util/gnunet-scrypt.c
+++ /dev/null
@@ -1,342 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014 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 * @file util/gnunet-scrypt.c
22 * @brief tool to manipulate SCRYPT proofs of work.
23 * @author Bart Polot
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include <gcrypt.h>
28
29
30/**
31 * Salt for PoW calcualations.
32 */
33static struct GNUNET_CRYPTO_PowSalt salt = { "gnunet-nse-proof" };
34
35
36/**
37 * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
38 */
39static unsigned long long nse_work_required;
40
41/**
42 * Interval between proof find runs.
43 */
44static struct GNUNET_TIME_Relative proof_find_delay;
45
46static struct GNUNET_CRYPTO_EddsaPublicKey pub;
47
48static uint64_t proof;
49
50static struct GNUNET_SCHEDULER_Task *proof_task;
51
52static const struct GNUNET_CONFIGURATION_Handle *cfg;
53
54static char *pkfn;
55
56static char *pwfn;
57
58
59/**
60 * Write our current proof to disk.
61 *
62 * @param cls closure
63 */
64static void
65shutdown_task (void *cls)
66{
67 (void) cls;
68 if (GNUNET_OK !=
69 GNUNET_DISK_fn_write (pwfn,
70 &proof,
71 sizeof(proof),
72 GNUNET_DISK_PERM_USER_READ
73 | GNUNET_DISK_PERM_USER_WRITE))
74 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
75 "write",
76 pwfn);
77}
78
79
80/**
81 * Count the leading zeroes in hash.
82 *
83 * @param hash to count leading zeros in
84 * @return the number of leading zero bits.
85 */
86static unsigned int
87count_leading_zeroes (const struct GNUNET_HashCode *hash)
88{
89 unsigned int hash_count;
90
91 hash_count = 0;
92 while (0 == GNUNET_CRYPTO_hash_get_bit_ltr (hash, hash_count))
93 hash_count++;
94 return hash_count;
95}
96
97
98/**
99 * Find our proof of work.
100 *
101 * @param cls closure (unused)
102 * @param tc task context
103 */
104static void
105find_proof (void *cls)
106{
107#define ROUND_SIZE 10
108 uint64_t counter;
109 char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
110 + sizeof(uint64_t)] GNUNET_ALIGN;
111 struct GNUNET_HashCode result;
112 unsigned int i;
113 struct GNUNET_TIME_Absolute timestamp;
114 struct GNUNET_TIME_Relative elapsed;
115
116 (void) cls;
117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
118 "Got Proof of Work %llu\n",
119 (unsigned long long) proof);
120 proof_task = NULL;
121 GNUNET_memcpy (&buf[sizeof(uint64_t)],
122 &pub,
123 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey));
124 i = 0;
125 counter = proof;
126 timestamp = GNUNET_TIME_absolute_get ();
127 while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
128 {
129 GNUNET_memcpy (buf, &counter, sizeof(uint64_t));
130 GNUNET_CRYPTO_pow_hash (&salt,
131 buf,
132 sizeof(buf),
133 &result);
134 if (nse_work_required <= count_leading_zeroes (&result))
135 {
136 proof = counter;
137 fprintf (stdout,
138 "Proof of work found: %llu!\n",
139 (unsigned long long) proof);
140 GNUNET_SCHEDULER_shutdown ();
141 return;
142 }
143 counter++;
144 i++;
145 }
146 elapsed = GNUNET_TIME_absolute_get_duration (timestamp);
147 elapsed = GNUNET_TIME_relative_divide (elapsed, ROUND_SIZE);
148 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
149 "Current: %llu [%s/proof]\n",
150 (unsigned long long) counter,
151 GNUNET_STRINGS_relative_time_to_string (elapsed, 0));
152 if (proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
153 {
154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155 "Testing proofs currently at %llu\n",
156 (unsigned long long) counter);
157 /* remember progress every 100 rounds */
158 proof = counter;
159 shutdown_task (NULL);
160 }
161 else
162 {
163 proof = counter;
164 }
165 proof_task =
166 GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
167 GNUNET_SCHEDULER_PRIORITY_IDLE,
168 &find_proof,
169 NULL);
170}
171
172
173/**
174 * Main function that will be run by the scheduler.
175 *
176 * @param cls closure
177 * @param args remaining command-line arguments
178 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
179 * @param cfg configuration
180 */
181static void
182run (void *cls,
183 char *const *args,
184 const char *cfgfile,
185 const struct GNUNET_CONFIGURATION_Handle *config)
186{
187 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
188 char *pids;
189
190 (void) cls;
191 (void) args;
192 (void) cfgfile;
193 cfg = config;
194 /* load proof of work */
195 if (NULL == pwfn)
196 {
197 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
198 "NSE",
199 "PROOFFILE",
200 &pwfn))
201 {
202 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE");
203 GNUNET_SCHEDULER_shutdown ();
204 return;
205 }
206 }
207 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Proof of Work file: %s\n", pwfn);
208 if ((GNUNET_YES != GNUNET_DISK_file_test (pwfn)) ||
209 (sizeof(proof) != GNUNET_DISK_fn_read (pwfn, &proof, sizeof(proof))))
210 proof = 0;
211
212 /* load private key */
213 if (NULL == pkfn)
214 {
215 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
216 "PEER",
217 "PRIVATE_KEY",
218 &pkfn))
219 {
220 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
221 "PEER",
222 "PRIVATE_KEY");
223 return;
224 }
225 }
226 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Private Key file: %s\n", pkfn);
227 if (GNUNET_SYSERR ==
228 GNUNET_CRYPTO_eddsa_key_from_file (pkfn,
229 GNUNET_YES,
230 &pk))
231 {
232 fprintf (stderr, _ ("Loading hostkey from `%s' failed.\n"), pkfn);
233 GNUNET_free (pkfn);
234 return;
235 }
236 GNUNET_free (pkfn);
237 GNUNET_CRYPTO_eddsa_key_get_public (&pk,
238 &pub);
239 pids = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
240 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer ID: %s\n", pids);
241 GNUNET_free (pids);
242
243 /* get target bit amount */
244 if (0 == nse_work_required)
245 {
246 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
247 "NSE",
248 "WORKBITS",
249 &nse_work_required))
250 {
251 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS");
252 GNUNET_SCHEDULER_shutdown ();
253 return;
254 }
255 if (nse_work_required >= sizeof(struct GNUNET_HashCode) * 8)
256 {
257 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
258 "NSE",
259 "WORKBITS",
260 _ ("Value is too large.\n"));
261 GNUNET_SCHEDULER_shutdown ();
262 return;
263 }
264 else if (0 == nse_work_required)
265 {
266 GNUNET_SCHEDULER_shutdown ();
267 return;
268 }
269 }
270 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Bits: %llu\n", nse_work_required);
271
272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
273 "Delay between tries: %s\n",
274 GNUNET_STRINGS_relative_time_to_string (proof_find_delay, 1));
275 proof_task =
276 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
277 &find_proof,
278 NULL);
279 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
280}
281
282
283/**
284 * Program to manipulate ECC key files.
285 *
286 * @param argc number of arguments from the command line
287 * @param argv command line arguments
288 * @return 0 ok, 1 on error
289 */
290int
291main (int argc, char *const *argv)
292{
293 struct GNUNET_GETOPT_CommandLineOption options[] = {
294 GNUNET_GETOPT_option_ulong (
295 'b',
296 "bits",
297 "BITS",
298 gettext_noop ("number of bits to require for the proof of work"),
299 &nse_work_required),
300 GNUNET_GETOPT_option_filename (
301 'k',
302 "keyfile",
303 "FILE",
304 gettext_noop ("file with private key, otherwise default is used"),
305 &pkfn),
306 GNUNET_GETOPT_option_filename (
307 'o',
308 "outfile",
309 "FILE",
310 gettext_noop ("file with proof of work, otherwise default is used"),
311 &pwfn),
312 GNUNET_GETOPT_option_relative_time ('t',
313 "timeout",
314 "TIME",
315 gettext_noop (
316 "time to wait between calculations"),
317 &proof_find_delay),
318 GNUNET_GETOPT_OPTION_END
319 };
320 int ret;
321
322 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
323 return 2;
324
325 ret =
326 (GNUNET_OK ==
327 GNUNET_PROGRAM_run (argc,
328 argv,
329 "gnunet-scrypt [OPTIONS] prooffile",
330 gettext_noop ("Manipulate GNUnet proof of work files"),
331 options,
332 &run,
333 NULL))
334 ? 0
335 : 1;
336 GNUNET_free_nz ((void *) argv);
337 GNUNET_free (pwfn);
338 return ret;
339}
340
341
342/* end of gnunet-scrypt.c */
diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c
deleted file mode 100644
index 9bde04117..000000000
--- a/src/util/gnunet-service-resolver.c
+++ /dev/null
@@ -1,1383 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2007-2016 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 util/gnunet-service-resolver.c
23 * @brief code to do DNS resolution
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_statistics_service.h"
30#include "resolver.h"
31
32
33/**
34 * How long do we wait for DNS answers?
35 */
36#define DNS_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
37
38/**
39 * Maximum number of hostnames we cache results for.
40 */
41#define MAX_CACHE 1024
42
43/**
44 * Entry in list of cached DNS records for a hostname.
45 */
46struct RecordListEntry
47{
48 /**
49 * This is a doubly linked list.
50 */
51 struct RecordListEntry *next;
52
53 /**
54 * This is a doubly linked list.
55 */
56 struct RecordListEntry *prev;
57
58 /**
59 * Cached data.
60 */
61 struct GNUNET_DNSPARSER_Record *record;
62};
63
64
65/**
66 * A cached DNS lookup result.
67 */
68struct ResolveCache
69{
70 /**
71 * This is a doubly linked list.
72 */
73 struct ResolveCache *next;
74
75 /**
76 * This is a doubly linked list.
77 */
78 struct ResolveCache *prev;
79
80 /**
81 * Which hostname is this cache for?
82 */
83 char *hostname;
84
85 /**
86 * head of a double linked list containing the lookup results
87 */
88 struct RecordListEntry *records_head;
89
90 /**
91 * tail of a double linked list containing the lookup results
92 */
93 struct RecordListEntry *records_tail;
94};
95
96
97/**
98 * Information about pending lookups.
99 */
100struct ActiveLookup
101{
102 /**
103 * Stored in a DLL.
104 */
105 struct ActiveLookup *next;
106
107 /**
108 * Stored in a DLL.
109 */
110 struct ActiveLookup *prev;
111
112 /**
113 * The client that queried the records contained in this cache entry.
114 */
115 struct GNUNET_SERVICE_Client *client;
116
117 /**
118 * handle for cancelling a request
119 */
120 struct GNUNET_DNSSTUB_RequestSocket *resolve_handle;
121
122 /**
123 * handle for the resolution timeout task
124 */
125 struct GNUNET_SCHEDULER_Task *timeout_task;
126
127 /**
128 * Which hostname are we resolving?
129 */
130 char *hostname;
131
132 /**
133 * If @a record_type is #GNUNET_DNSPARSER_TYPE_ALL, did we go again
134 * for the AAAA records yet?
135 */
136 int did_aaaa;
137
138 /**
139 * type of queried DNS record
140 */
141 uint16_t record_type;
142
143 /**
144 * Unique request ID of a client if a query for this hostname/record_type
145 * is currently pending, undefined otherwise.
146 */
147 uint32_t client_request_id;
148
149 /**
150 * Unique DNS request ID of a client if a query for this hostname/record_type
151 * is currently pending, undefined otherwise.
152 */
153 uint16_t dns_id;
154};
155
156
157/**
158 * Start of the linked list of cached DNS lookup results.
159 */
160static struct ResolveCache *cache_head;
161
162/**
163 * Tail of the linked list of cached DNS lookup results.
164 */
165static struct ResolveCache *cache_tail;
166
167/**
168 * Head of the linked list of DNS lookup results from /etc/hosts.
169 */
170static struct ResolveCache *hosts_head;
171
172/**
173 * Tail of the linked list of DNS lookup results from /etc/hosts.
174 */
175static struct ResolveCache *hosts_tail;
176
177/**
178 * Start of the linked list of active DNS lookups.
179 */
180static struct ActiveLookup *lookup_head;
181
182/**
183 * Tail of the linked list of active DNS lookups.
184 */
185static struct ActiveLookup *lookup_tail;
186
187/**
188 * context of dnsstub library
189 */
190static struct GNUNET_DNSSTUB_Context *dnsstub_ctx;
191
192/**
193 * My domain, to be appended to the hostname to get a FQDN.
194 */
195static char *my_domain;
196
197/**
198 * How many entries do we have in #cache_head DLL?
199 */
200static unsigned int cache_size;
201
202
203/**
204 * Remove @a entry from cache.
205 *
206 * @param rc entry to free
207 */
208static void
209free_cache_entry (struct ResolveCache *rc)
210{
211 struct RecordListEntry *pos;
212
213 while (NULL != (pos = rc->records_head))
214 {
215 GNUNET_CONTAINER_DLL_remove (rc->records_head, rc->records_tail, pos);
216 GNUNET_DNSPARSER_free_record (pos->record);
217 GNUNET_free (pos->record);
218 GNUNET_free (pos);
219 }
220 GNUNET_free (rc->hostname);
221 GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, rc);
222 cache_size--;
223 GNUNET_free (rc);
224}
225
226
227/**
228 * Remove @a entry from cache.
229 *
230 * @param rc entry to free
231 */
232static void
233free_hosts_entry (struct ResolveCache *rc)
234{
235 struct RecordListEntry *pos;
236
237 while (NULL != (pos = rc->records_head))
238 {
239 GNUNET_CONTAINER_DLL_remove (rc->records_head, rc->records_tail, pos);
240 GNUNET_DNSPARSER_free_record (pos->record);
241 GNUNET_free (pos->record);
242 GNUNET_free (pos);
243 }
244 GNUNET_free (rc->hostname);
245 GNUNET_CONTAINER_DLL_remove (hosts_head, hosts_tail, rc);
246 cache_size--;
247 GNUNET_free (rc);
248}
249
250
251/**
252 * Release resources associated with @a al
253 *
254 * @param al an active lookup
255 */
256static void
257free_active_lookup (struct ActiveLookup *al)
258{
259 GNUNET_CONTAINER_DLL_remove (lookup_head, lookup_tail, al);
260 if (NULL != al->resolve_handle)
261 {
262 GNUNET_DNSSTUB_resolve_cancel (al->resolve_handle);
263 al->resolve_handle = NULL;
264 }
265 if (NULL != al->timeout_task)
266 {
267 GNUNET_SCHEDULER_cancel (al->timeout_task);
268 al->timeout_task = NULL;
269 }
270 GNUNET_free (al->hostname);
271 GNUNET_free (al);
272}
273
274
275/**
276 * Find out if the configuration file line contains a string
277 * starting with "nameserver ", and if so, return a copy of
278 * the nameserver's IP.
279 *
280 * @param line line to parse
281 * @param line_len number of characters in @a line
282 * @return NULL if no nameserver is configured in this @a line
283 */
284static char *
285extract_dns_server (const char *line, size_t line_len)
286{
287 if (0 == strncmp (line, "nameserver ", strlen ("nameserver ")))
288 return GNUNET_strndup (line + strlen ("nameserver "),
289 line_len - strlen ("nameserver "));
290 return NULL;
291}
292
293
294/**
295 * Find out if the configuration file line contains a string
296 * starting with "search ", and if so, return a copy of
297 * the machine's search domain.
298 *
299 * @param line line to parse
300 * @param line_len number of characters in @a line
301 * @return NULL if no nameserver is configured in this @a line
302 */
303static char *
304extract_search_domain (const char *line, size_t line_len)
305{
306 if (0 == strncmp (line, "search ", strlen ("search ")))
307 return GNUNET_strndup (line + strlen ("search "),
308 line_len - strlen ("search "));
309 return NULL;
310}
311
312
313/**
314 * Reads the list of nameservers from /etc/resolve.conf
315 *
316 * @param server_addrs[out] a list of null-terminated server address strings
317 * @return the number of server addresses in @server_addrs, -1 on error
318 */
319static int
320lookup_dns_servers (char ***server_addrs)
321{
322 struct GNUNET_DISK_FileHandle *fh;
323 struct GNUNET_DISK_MapHandle *mh;
324 off_t bytes_read;
325 const char *buf;
326 size_t read_offset;
327 unsigned int num_dns_servers;
328
329 fh = GNUNET_DISK_file_open ("/etc/resolv.conf",
330 GNUNET_DISK_OPEN_READ,
331 GNUNET_DISK_PERM_NONE);
332 if (NULL == fh)
333 {
334 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
335 "Could not open /etc/resolv.conf. "
336 "DNS resolution will not be possible.\n");
337 return -1;
338 }
339 if (GNUNET_OK != GNUNET_DISK_file_handle_size (fh, &bytes_read))
340 {
341 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
342 "Could not determine size of /etc/resolv.conf. "
343 "DNS resolution will not be possible.\n");
344 GNUNET_DISK_file_close (fh);
345 return -1;
346 }
347 if (((unsigned long long) bytes_read) > (unsigned long long) SIZE_MAX)
348 {
349 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
350 "/etc/resolv.conf file too large to mmap. "
351 "DNS resolution will not be possible.\n");
352 GNUNET_DISK_file_close (fh);
353 return -1;
354 }
355 buf = GNUNET_DISK_file_map (fh,
356 &mh,
357 GNUNET_DISK_MAP_TYPE_READ,
358 (size_t) bytes_read);
359 *server_addrs = NULL;
360 read_offset = 0;
361 num_dns_servers = 0;
362 while (read_offset < (size_t) bytes_read)
363 {
364 const char *newline;
365 size_t line_len;
366 char *dns_server;
367
368 newline = strchr (buf + read_offset, '\n');
369 if (NULL == newline)
370 break;
371 line_len = newline - buf - read_offset;
372 dns_server = extract_dns_server (buf + read_offset, line_len);
373 if (NULL != dns_server)
374 {
375 GNUNET_array_append (*server_addrs, num_dns_servers, dns_server);
376 }
377 else if (NULL == my_domain)
378 {
379 my_domain = extract_search_domain (buf + read_offset, line_len);
380 }
381 read_offset += line_len + 1;
382 }
383 GNUNET_DISK_file_unmap (mh);
384 GNUNET_DISK_file_close (fh);
385 return (int) num_dns_servers;
386}
387
388
389/**
390 * Compute name to use for DNS reverse lookups from @a ip.
391 *
392 * @param ip IP address to resolve, in binary format, network byte order
393 * @param af address family of @a ip, AF_INET or AF_INET6
394 */
395static char *
396make_reverse_hostname (const void *ip, int af)
397{
398 char *buf = GNUNET_new_array (80, char);
399 int pos = 0;
400
401 if (AF_INET == af)
402 {
403 struct in_addr *addr = (struct in_addr *) ip;
404 uint32_t ip_int = addr->s_addr;
405
406 for (int i = 3; i >= 0; i--)
407 {
408 int n =
409 GNUNET_snprintf (buf + pos, 80 - pos, "%u.", ((uint8_t *) &ip_int)[i]);
410 if (n < 0)
411 {
412 GNUNET_free (buf);
413 return NULL;
414 }
415 pos += n;
416 }
417 pos += GNUNET_snprintf (buf + pos, 80 - pos, "in-addr.arpa");
418 }
419 else if (AF_INET6 == af)
420 {
421 struct in6_addr *addr = (struct in6_addr *) ip;
422 for (int i = 15; i >= 0; i--)
423 {
424 int n =
425 GNUNET_snprintf (buf + pos, 80 - pos, "%x.", addr->s6_addr[i] & 0xf);
426 if (n < 0)
427 {
428 GNUNET_free (buf);
429 return NULL;
430 }
431 pos += n;
432 n = GNUNET_snprintf (buf + pos, 80 - pos, "%x.", addr->s6_addr[i] >> 4);
433 if (n < 0)
434 {
435 GNUNET_free (buf);
436 return NULL;
437 }
438 pos += n;
439 }
440 pos += GNUNET_snprintf (buf + pos, 80 - pos, "ip6.arpa");
441 }
442 buf[pos] = '\0';
443 return buf;
444}
445
446
447/**
448 * Send DNS @a record back to our @a client.
449 *
450 * @param record information to transmit
451 * @param record_type requested record type from client
452 * @param client_request_id to which request are we responding
453 * @param client where to send @a record
454 * @return #GNUNET_YES if we sent a reply,
455 * #GNUNET_NO if the record type is not understood or
456 * does not match @a record_type
457 */
458static int
459send_reply (struct GNUNET_DNSPARSER_Record *record,
460 uint16_t record_type,
461 uint32_t client_request_id,
462 struct GNUNET_SERVICE_Client *client)
463{
464 struct GNUNET_RESOLVER_ResponseMessage *msg;
465 struct GNUNET_MQ_Envelope *env;
466 const void *payload;
467 size_t payload_len;
468
469 switch (record->type)
470 {
471 case GNUNET_DNSPARSER_TYPE_CNAME:
472 if (GNUNET_DNSPARSER_TYPE_CNAME != record_type)
473 return GNUNET_NO;
474 payload = record->data.hostname;
475 payload_len = strlen (record->data.hostname) + 1;
476 break;
477
478 case GNUNET_DNSPARSER_TYPE_PTR:
479 if (GNUNET_DNSPARSER_TYPE_PTR != record_type)
480 return GNUNET_NO;
481 payload = record->data.hostname;
482 payload_len = strlen (record->data.hostname) + 1;
483 break;
484
485 case GNUNET_DNSPARSER_TYPE_A:
486 if ((GNUNET_DNSPARSER_TYPE_A != record_type) &&
487 (GNUNET_DNSPARSER_TYPE_ALL != record_type))
488 return GNUNET_NO;
489 payload = record->data.raw.data;
490 payload_len = record->data.raw.data_len;
491 break;
492
493 case GNUNET_DNSPARSER_TYPE_AAAA:
494 if ((GNUNET_DNSPARSER_TYPE_AAAA != record_type) &&
495 (GNUNET_DNSPARSER_TYPE_ALL != record_type))
496 return GNUNET_NO;
497 payload = record->data.raw.data;
498 payload_len = record->data.raw.data_len;
499 break;
500
501 default:
502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
503 "Cannot handle DNS response type %u: not supported here\n",
504 record->type);
505 return GNUNET_NO;
506 }
507 env = GNUNET_MQ_msg_extra (msg,
508 payload_len,
509 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
510 msg->client_id = client_request_id;
511 GNUNET_memcpy (&msg[1], payload, payload_len);
512 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
513 return GNUNET_YES;
514}
515
516
517/**
518 * Send message to @a client that we transmitted all
519 * responses for @a client_request_id
520 *
521 * @param client_request_id to which request are we responding
522 * @param client where to send @a record
523 */
524static void
525send_end_msg (uint32_t client_request_id, struct GNUNET_SERVICE_Client *client)
526{
527 struct GNUNET_RESOLVER_ResponseMessage *msg;
528 struct GNUNET_MQ_Envelope *env;
529
530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending END message\n");
531 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
532 msg->client_id = client_request_id;
533 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
534}
535
536
537/**
538 * Remove expired entries from @a rc
539 *
540 * @param rc entry in resolver cache
541 * @return #GNUNET_YES if @a rc was completely expired
542 * #GNUNET_NO if some entries are left
543 */
544static int
545remove_expired (struct ResolveCache *rc)
546{
547 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
548 struct RecordListEntry *n;
549
550 for (struct RecordListEntry *pos = rc->records_head; NULL != pos; pos = n)
551 {
552 n = pos->next;
553 if (now.abs_value_us > pos->record->expiration_time.abs_value_us)
554 {
555 GNUNET_CONTAINER_DLL_remove (rc->records_head, rc->records_tail, pos);
556 GNUNET_DNSPARSER_free_record (pos->record);
557 GNUNET_free (pos->record);
558 GNUNET_free (pos);
559 }
560 }
561 if (NULL == rc->records_head)
562 {
563 free_cache_entry (rc);
564 return GNUNET_YES;
565 }
566 return GNUNET_NO;
567}
568
569
570/**
571 * Process DNS request for @a hostname with request ID @a request_id
572 * from @a client demanding records of type @a record_type.
573 *
574 * @param hostname DNS name to resolve
575 * @param record_type desired record type
576 * @param client_request_id client's request ID
577 * @param client who should get the result?
578 */
579static void
580process_get (const char *hostname,
581 uint16_t record_type,
582 uint32_t client_request_id,
583 struct GNUNET_SERVICE_Client *client);
584
585
586/**
587 * Get an IP address as a string (works for both IPv4 and IPv6). Note
588 * that the resolution happens asynchronously and that the first call
589 * may not immediately result in the FQN (but instead in a
590 * human-readable IP address).
591 *
592 * @param hostname what hostname was to be resolved
593 * @param record_type what type of record was requested
594 * @param client_request_id unique identification of the client's request
595 * @param client handle to the client making the request (for sending the reply)
596 */
597static int
598try_cache (const char *hostname,
599 uint16_t record_type,
600 uint32_t client_request_id,
601 struct GNUNET_SERVICE_Client *client)
602{
603 struct ResolveCache *pos;
604 struct ResolveCache *next;
605 int found;
606 int in_hosts;
607
608 in_hosts = GNUNET_NO;
609 for (pos = hosts_head; NULL != pos; pos = pos->next)
610 if (0 == strcmp (pos->hostname, hostname))
611 {
612 in_hosts = GNUNET_YES;
613 break;
614 }
615 if (NULL == pos)
616 {
617 next = cache_head;
618 for (pos = next; NULL != pos; pos = next)
619 {
620 next = pos->next;
621 if (GNUNET_YES == remove_expired (pos))
622 continue;
623 if (0 == strcmp (pos->hostname, hostname))
624 break;
625 }
626 }
627 if (NULL == pos)
628 {
629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cache entry for '%s'\n", hostname);
630 return GNUNET_NO;
631 }
632 if ((GNUNET_NO == in_hosts) && (cache_head != pos))
633 {
634 /* move result to head to achieve LRU for cache eviction */
635 GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, pos);
636 GNUNET_CONTAINER_DLL_insert (cache_head, cache_tail, pos);
637 }
638 found = GNUNET_NO;
639 for (struct RecordListEntry *rle = pos->records_head; NULL != rle;
640 rle = rle->next)
641 {
642 const struct GNUNET_DNSPARSER_Record *record = rle->record;
643
644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645 "Checking cache entry for '%s', record is for '%s'\n",
646 hostname,
647 record->name);
648 if ((GNUNET_DNSPARSER_TYPE_CNAME == record->type) &&
649 (GNUNET_DNSPARSER_TYPE_CNAME != record_type) && (GNUNET_NO == found))
650 {
651 const char *hostname = record->data.hostname;
652
653 process_get (hostname, record_type, client_request_id, client);
654 return GNUNET_YES; /* counts as a cache "hit" */
655 }
656 if (0 == strcmp (record->name, hostname))
657 found |= send_reply (rle->record, record_type, client_request_id, client);
658 }
659 if (GNUNET_NO == found)
660 return GNUNET_NO; /* had records, but none matched! */
661 send_end_msg (client_request_id, client);
662 return GNUNET_YES;
663}
664
665
666/**
667 * Create DNS query for @a hostname of type @a type
668 * with DNS request ID @a dns_id.
669 *
670 * @param hostname DNS name to query
671 * @param type requested DNS record type
672 * @param dns_id what should be the DNS request ID
673 * @param packet_buf[out] where to write the request packet
674 * @param packet_size[out] set to size of @a packet_buf on success
675 * @return #GNUNET_OK on success
676 */
677static int
678pack (const char *hostname,
679 uint16_t type,
680 uint16_t dns_id,
681 char **packet_buf,
682 size_t *packet_size)
683{
684 struct GNUNET_DNSPARSER_Query query;
685 struct GNUNET_DNSPARSER_Packet packet;
686
687 query.name = (char *) hostname;
688 query.type = type;
689 query.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
690 memset (&packet, 0, sizeof(packet));
691 packet.num_queries = 1;
692 packet.queries = &query;
693 packet.id = htons (dns_id);
694 packet.flags.recursion_desired = 1;
695 if (GNUNET_OK !=
696 GNUNET_DNSPARSER_pack (&packet, UINT16_MAX, packet_buf, packet_size))
697 {
698 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
699 "Failed to pack query for hostname `%s'\n",
700 hostname);
701 packet_buf = NULL;
702 return GNUNET_SYSERR;
703 }
704 return GNUNET_OK;
705}
706
707
708static void
709cache_answers (const char *name,
710 struct GNUNET_DNSPARSER_Record *records,
711 unsigned int num_records)
712{
713 struct ResolveCache *rc;
714 struct GNUNET_DNSPARSER_Record *record;
715 struct RecordListEntry *rle;
716
717 for (unsigned int i = 0; i != num_records; i++)
718 {
719 record = &records[i];
720
721 for (rc = cache_head; NULL != rc; rc = rc->next)
722 if (0 == strcasecmp (rc->hostname, name))
723 break;
724 if (NULL == rc)
725 {
726 rc = GNUNET_new (struct ResolveCache);
727 rc->hostname = GNUNET_strdup (name);
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 "Caching record for name %s under %s\n",
730 record->name, name);
731 GNUNET_CONTAINER_DLL_insert (cache_head, cache_tail, rc);
732 cache_size++;
733 }
734 /* TODO: ought to check first if we have this exact record
735 already in the cache! */
736 rle = GNUNET_new (struct RecordListEntry);
737 rle->record = GNUNET_DNSPARSER_duplicate_record (record);
738 GNUNET_CONTAINER_DLL_insert (rc->records_head, rc->records_tail, rle);
739 }
740}
741
742
743/**
744 * We got a result from DNS. Add it to the cache and
745 * see if we can make our client happy...
746 *
747 * @param cls the `struct ActiveLookup`
748 * @param dns the DNS response
749 * @param dns_len number of bytes in @a dns
750 */
751static void
752handle_resolve_result (void *cls,
753 const struct GNUNET_TUN_DnsHeader *dns,
754 size_t dns_len)
755{
756 struct ActiveLookup *al = cls;
757 struct GNUNET_DNSPARSER_Packet *parsed;
758
759 parsed = GNUNET_DNSPARSER_parse ((const char *) dns, dns_len);
760 if (NULL == parsed)
761 {
762 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
763 "Failed to parse DNS reply (hostname %s, request ID %u)\n",
764 al->hostname,
765 al->dns_id);
766 return;
767 }
768 if (al->dns_id != ntohs (parsed->id))
769 {
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771 "Request ID in DNS reply does not match\n");
772 GNUNET_DNSPARSER_free_packet (parsed);
773 return;
774 }
775 if (0 == parsed->num_answers + parsed->num_authority_records
776 + parsed->num_additional_records)
777 {
778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
779 "DNS reply (hostname %s, request ID %u) contains no answers\n",
780 al->hostname,
781 (unsigned int) al->client_request_id);
782 /* resume by trying again from cache */
783 if (GNUNET_NO == try_cache (al->hostname,
784 al->record_type,
785 al->client_request_id,
786 al->client))
787 /* cache failed, tell client we could not get an answer */
788 {
789 send_end_msg (al->client_request_id, al->client);
790 }
791 GNUNET_DNSPARSER_free_packet (parsed);
792 free_active_lookup (al);
793 return;
794 }
795 /* LRU-based cache eviction: we remove from tail */
796 while (cache_size > MAX_CACHE)
797 free_cache_entry (cache_tail);
798
799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
800 "Got reply for hostname %s and request ID %u\n",
801 al->hostname,
802 (unsigned int) al->client_request_id);
803 /* add to cache */
804 cache_answers (al->hostname, parsed->answers, parsed->num_answers);
805 cache_answers (al->hostname,
806 parsed->authority_records,
807 parsed->num_authority_records);
808 cache_answers (al->hostname,
809 parsed->additional_records,
810 parsed->num_additional_records);
811
812 /* see if we need to do the 2nd request for AAAA records */
813 if ((GNUNET_DNSPARSER_TYPE_ALL == al->record_type) &&
814 (GNUNET_NO == al->did_aaaa))
815 {
816 char *packet_buf;
817 size_t packet_size;
818 uint16_t dns_id;
819
820 dns_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
821 UINT16_MAX);
822 if (GNUNET_OK == pack (al->hostname,
823 GNUNET_DNSPARSER_TYPE_AAAA,
824 dns_id,
825 &packet_buf,
826 &packet_size))
827 {
828 al->did_aaaa = GNUNET_YES;
829 al->dns_id = dns_id;
830 GNUNET_DNSSTUB_resolve_cancel (al->resolve_handle);
831 al->resolve_handle = GNUNET_DNSSTUB_resolve (dnsstub_ctx,
832 packet_buf,
833 packet_size,
834 &handle_resolve_result,
835 al);
836 GNUNET_free (packet_buf);
837 GNUNET_DNSPARSER_free_packet (parsed);
838 return;
839 }
840 }
841
842 /* resume by trying again from cache */
843 if (GNUNET_NO == try_cache (al->hostname,
844 al->record_type,
845 al->client_request_id,
846 al->client))
847 /* cache failed, tell client we could not get an answer */
848 {
849 send_end_msg (al->client_request_id, al->client);
850 }
851 free_active_lookup (al);
852 GNUNET_DNSPARSER_free_packet (parsed);
853}
854
855
856/**
857 * We encountered a timeout trying to perform a
858 * DNS lookup.
859 *
860 * @param cls a `struct ActiveLookup`
861 */
862static void
863handle_resolve_timeout (void *cls)
864{
865 struct ActiveLookup *al = cls;
866
867 al->timeout_task = NULL;
868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DNS lookup timeout!\n");
869 send_end_msg (al->client_request_id, al->client);
870 free_active_lookup (al);
871}
872
873
874/**
875 * Initiate an active lookup, then cache the result and
876 * try to then complete the resolution.
877 *
878 * @param hostname DNS name to resolve
879 * @param record_type record type to locate
880 * @param client_request_id client request ID
881 * @param client handle to the client
882 * @return #GNUNET_OK if the DNS query is now pending
883 */
884static int
885resolve_and_cache (const char *hostname,
886 uint16_t record_type,
887 uint32_t client_request_id,
888 struct GNUNET_SERVICE_Client *client)
889{
890 char *packet_buf;
891 size_t packet_size;
892 struct ActiveLookup *al;
893 uint16_t dns_id;
894 uint16_t type;
895
896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "resolve_and_cache `%s'\n", hostname);
897 dns_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
898 UINT16_MAX);
899
900 if (GNUNET_DNSPARSER_TYPE_ALL == record_type)
901 type = GNUNET_DNSPARSER_TYPE_A;
902 else
903 type = record_type;
904 if (GNUNET_OK != pack (hostname, type, dns_id, &packet_buf, &packet_size))
905 {
906 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
907 "Failed to pack query for hostname `%s'\n",
908 hostname);
909 return GNUNET_SYSERR;
910 }
911
912 al = GNUNET_new (struct ActiveLookup);
913 al->hostname = GNUNET_strdup (hostname);
914 al->record_type = record_type;
915 al->client_request_id = client_request_id;
916 al->dns_id = dns_id;
917 al->client = client;
918 al->timeout_task =
919 GNUNET_SCHEDULER_add_delayed (DNS_TIMEOUT, &handle_resolve_timeout, al);
920 al->resolve_handle = GNUNET_DNSSTUB_resolve (dnsstub_ctx,
921 packet_buf,
922 packet_size,
923 &handle_resolve_result,
924 al);
925 GNUNET_free (packet_buf);
926 GNUNET_CONTAINER_DLL_insert (lookup_head, lookup_tail, al);
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
928 "Resolving %s, client_request_id = %u, dns_id = %u\n",
929 hostname,
930 (unsigned int) client_request_id,
931 (unsigned int) dns_id);
932 return GNUNET_OK;
933}
934
935
936/**
937 * Process DNS request for @a hostname with request ID @a client_request_id
938 * from @a client demanding records of type @a record_type.
939 *
940 * @param hostname DNS name to resolve
941 * @param record_type desired record type
942 * @param client_request_id client's request ID
943 * @param client who should get the result?
944 */
945static void
946process_get (const char *hostname,
947 uint16_t record_type,
948 uint32_t client_request_id,
949 struct GNUNET_SERVICE_Client *client)
950{
951 char fqdn[255];
952
953 if (GNUNET_NO != try_cache (hostname, record_type, client_request_id, client))
954 return;
955 if ((NULL != my_domain) && (NULL == strchr (hostname, (unsigned char) '.')) &&
956 (strlen (hostname) + strlen (my_domain) <= 253))
957 {
958 GNUNET_snprintf (fqdn, sizeof(fqdn), "%s.%s", hostname, my_domain);
959 }
960 else if (strlen (hostname) < 255)
961 {
962 GNUNET_snprintf (fqdn, sizeof(fqdn), "%s", hostname);
963 }
964 else
965 {
966 GNUNET_break (0);
967 GNUNET_SERVICE_client_drop (client);
968 return;
969 }
970 if (GNUNET_NO == try_cache (fqdn, record_type, client_request_id, client))
971 {
972 if (GNUNET_OK !=
973 resolve_and_cache (fqdn, record_type, client_request_id, client))
974 {
975 send_end_msg (client_request_id, client);
976 }
977 }
978}
979
980
981/**
982 * Verify well-formedness of GET-message.
983 *
984 * @param cls closure, unused
985 * @param get the actual message
986 * @return #GNUNET_OK if @a get is well-formed
987 */
988static int
989check_get (void *cls, const struct GNUNET_RESOLVER_GetMessage *get)
990{
991 uint16_t size;
992 int direction;
993 int af;
994
995 (void) cls;
996 size = ntohs (get->header.size) - sizeof(*get);
997 direction = ntohl (get->direction);
998 if (GNUNET_NO == direction)
999 {
1000 GNUNET_MQ_check_zero_termination (get);
1001 return GNUNET_OK;
1002 }
1003 af = ntohl (get->af);
1004 switch (af)
1005 {
1006 case AF_INET:
1007 if (size != sizeof(struct in_addr))
1008 {
1009 GNUNET_break (0);
1010 return GNUNET_SYSERR;
1011 }
1012 break;
1013
1014 case AF_INET6:
1015 if (size != sizeof(struct in6_addr))
1016 {
1017 GNUNET_break (0);
1018 return GNUNET_SYSERR;
1019 }
1020 break;
1021
1022 default:
1023 GNUNET_break (0);
1024 return GNUNET_SYSERR;
1025 }
1026 return GNUNET_OK;
1027}
1028
1029
1030/**
1031 * Handle GET-message.
1032 *
1033 * @param cls identification of the client
1034 * @param msg the actual message
1035 */
1036static void
1037handle_get (void *cls, const struct GNUNET_RESOLVER_GetMessage *msg)
1038{
1039 struct GNUNET_SERVICE_Client *client = cls;
1040 int direction;
1041 int af;
1042 uint32_t client_request_id;
1043 char *hostname;
1044
1045 direction = ntohl (msg->direction);
1046 af = ntohl (msg->af);
1047 client_request_id = msg->client_id;
1048 GNUNET_SERVICE_client_continue (client);
1049 if (GNUNET_NO == direction)
1050 {
1051 /* IP from hostname */
1052 hostname = GNUNET_strdup ((const char *) &msg[1]);
1053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1054 "Client asks to resolve `%s'\n",
1055 hostname);
1056 switch (af)
1057 {
1058 case AF_UNSPEC: {
1059 process_get (hostname,
1060 GNUNET_DNSPARSER_TYPE_ALL,
1061 client_request_id,
1062 client);
1063 break;
1064 }
1065
1066 case AF_INET: {
1067 process_get (hostname,
1068 GNUNET_DNSPARSER_TYPE_A,
1069 client_request_id,
1070 client);
1071 break;
1072 }
1073
1074 case AF_INET6: {
1075 process_get (hostname,
1076 GNUNET_DNSPARSER_TYPE_AAAA,
1077 client_request_id,
1078 client);
1079 break;
1080 }
1081
1082 default: {
1083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got invalid af: %d\n", af);
1084 GNUNET_assert (0);
1085 }
1086 }
1087 }
1088 else
1089 {
1090 /* hostname from IP */
1091 hostname = make_reverse_hostname (&msg[1], af);
1092 process_get (hostname,
1093 GNUNET_DNSPARSER_TYPE_PTR,
1094 client_request_id,
1095 client);
1096 }
1097 GNUNET_free (hostname);
1098}
1099
1100
1101/**
1102 * Service is shutting down, clean up.
1103 *
1104 * @param cls NULL, unused
1105 */
1106static void
1107shutdown_task (void *cls)
1108{
1109 (void) cls;
1110
1111 while (NULL != lookup_head)
1112 free_active_lookup (lookup_head);
1113 while (NULL != cache_head)
1114 free_cache_entry (cache_head);
1115 while (NULL != hosts_head)
1116 free_hosts_entry (hosts_head);
1117 GNUNET_DNSSTUB_stop (dnsstub_ctx);
1118 GNUNET_free (my_domain);
1119}
1120
1121
1122/**
1123 * Add information about a host from /etc/hosts
1124 * to our cache.
1125 *
1126 * @param hostname the name of the host
1127 * @param rec_type DNS record type to use
1128 * @param data payload
1129 * @param data_size number of bytes in @a data
1130 */
1131static void
1132add_host (const char *hostname,
1133 uint16_t rec_type,
1134 const void *data,
1135 size_t data_size)
1136{
1137 struct ResolveCache *rc;
1138 struct RecordListEntry *rle;
1139 struct GNUNET_DNSPARSER_Record *rec;
1140
1141 rec = GNUNET_malloc (sizeof(struct GNUNET_DNSPARSER_Record));
1142 rec->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS;
1143 rec->type = rec_type;
1144 rec->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1145 rec->name = GNUNET_strdup (hostname);
1146 rec->data.raw.data = GNUNET_memdup (data, data_size);
1147 rec->data.raw.data_len = data_size;
1148 rle = GNUNET_new (struct RecordListEntry);
1149 rle->record = rec;
1150 rc = GNUNET_new (struct ResolveCache);
1151 rc->hostname = GNUNET_strdup (hostname);
1152 GNUNET_CONTAINER_DLL_insert (rc->records_head, rc->records_tail, rle);
1153 GNUNET_CONTAINER_DLL_insert (hosts_head, hosts_tail, rc);
1154}
1155
1156
1157/**
1158 * Extract host information from a line in /etc/hosts
1159 *
1160 * @param line the line to parse
1161 * @param line_len number of bytes in @a line
1162 */
1163static void
1164extract_hosts (const char *line, size_t line_len)
1165{
1166 const char *c;
1167 struct in_addr v4;
1168 struct in6_addr v6;
1169 char *tbuf;
1170 char *tok;
1171
1172 /* ignore everything after '#' */
1173 c = memrchr (line, (unsigned char) '#', line_len);
1174 if (NULL != c)
1175 line_len = c - line;
1176 /* ignore leading whitespace */
1177 while ((0 < line_len) && isspace ((unsigned char) *line))
1178 {
1179 line++;
1180 line_len--;
1181 }
1182 tbuf = GNUNET_strndup (line, line_len);
1183 tok = strtok (tbuf, " \t");
1184 if (NULL == tok)
1185 {
1186 GNUNET_free (tbuf);
1187 return;
1188 }
1189 if (1 == inet_pton (AF_INET, tok, &v4))
1190 {
1191 while (NULL != (tok = strtok (NULL, " \t")))
1192 add_host (tok, GNUNET_DNSPARSER_TYPE_A, &v4, sizeof(struct in_addr));
1193 }
1194 else if (1 == inet_pton (AF_INET6, tok, &v6))
1195 {
1196 while (NULL != (tok = strtok (NULL, " \t")))
1197 add_host (tok, GNUNET_DNSPARSER_TYPE_AAAA, &v6, sizeof(struct in6_addr));
1198 }
1199 GNUNET_free (tbuf);
1200}
1201
1202
1203/**
1204 * Reads the list of hosts from /etc/hosts.
1205 */
1206static void
1207load_etc_hosts (void)
1208{
1209 struct GNUNET_DISK_FileHandle *fh;
1210 struct GNUNET_DISK_MapHandle *mh;
1211 off_t bytes_read;
1212 const char *buf;
1213 size_t read_offset;
1214
1215 fh = GNUNET_DISK_file_open ("/etc/hosts",
1216 GNUNET_DISK_OPEN_READ,
1217 GNUNET_DISK_PERM_NONE);
1218 if (NULL == fh)
1219 {
1220 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failed to open /etc/hosts");
1221 return;
1222 }
1223 if (GNUNET_OK != GNUNET_DISK_file_handle_size (fh, &bytes_read))
1224 {
1225 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1226 "Could not determine size of /etc/hosts. "
1227 "DNS resolution will not be possible.\n");
1228 GNUNET_DISK_file_close (fh);
1229 return;
1230 }
1231 if (((unsigned long long) bytes_read) > (unsigned long long) SIZE_MAX)
1232 {
1233 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1234 "/etc/hosts file too large to mmap. "
1235 "DNS resolution will not be possible.\n");
1236 GNUNET_DISK_file_close (fh);
1237 return;
1238 }
1239 buf = GNUNET_DISK_file_map (fh,
1240 &mh,
1241 GNUNET_DISK_MAP_TYPE_READ,
1242 (size_t) bytes_read);
1243 read_offset = 0;
1244 while (read_offset < (size_t) bytes_read)
1245 {
1246 const char *newline;
1247 size_t line_len;
1248
1249 newline = strchr (buf + read_offset, '\n');
1250 if (NULL == newline)
1251 break;
1252 line_len = newline - buf - read_offset;
1253 extract_hosts (buf + read_offset, line_len);
1254 read_offset += line_len + 1;
1255 }
1256 GNUNET_DISK_file_unmap (mh);
1257 GNUNET_DISK_file_close (fh);
1258}
1259
1260
1261/**
1262 * Service is starting, initialize everything.
1263 *
1264 * @param cls NULL, unused
1265 * @param cfg our configuration
1266 * @param sh service handle
1267 */
1268static void
1269init_cb (void *cls,
1270 const struct GNUNET_CONFIGURATION_Handle *cfg,
1271 struct GNUNET_SERVICE_Handle *sh)
1272{
1273 char **dns_servers;
1274 int num_dns_servers;
1275
1276 (void) cfg;
1277 (void) sh;
1278 load_etc_hosts ();
1279 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, cls);
1280 dnsstub_ctx = GNUNET_DNSSTUB_start (128);
1281 dns_servers = NULL;
1282 num_dns_servers = lookup_dns_servers (&dns_servers);
1283 if (0 >= num_dns_servers)
1284 {
1285 GNUNET_log (
1286 GNUNET_ERROR_TYPE_ERROR,
1287 _ ("No DNS server available. DNS resolution will not be possible.\n"));
1288 return;
1289 }
1290 for (int i = 0; i < num_dns_servers; i++)
1291 {
1292 int result = GNUNET_DNSSTUB_add_dns_ip (dnsstub_ctx, dns_servers[i]);
1293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1294 "Adding DNS server '%s': %s\n",
1295 dns_servers[i],
1296 GNUNET_OK == result ? "success" : "failure");
1297 GNUNET_free (dns_servers[i]);
1298 }
1299 GNUNET_free (dns_servers);
1300}
1301
1302
1303/**
1304 * Callback called when a client connects to the service.
1305 *
1306 * @param cls closure for the service, unused
1307 * @param c the new client that connected to the service
1308 * @param mq the message queue used to send messages to the client
1309 * @return @a c
1310 */
1311static void *
1312connect_cb (void *cls,
1313 struct GNUNET_SERVICE_Client *c,
1314 struct GNUNET_MQ_Handle *mq)
1315{
1316 (void) cls;
1317 (void) mq;
1318
1319 return c;
1320}
1321
1322
1323/**
1324 * Callback called when a client disconnected from the service
1325 *
1326 * @param cls closure for the service
1327 * @param c the client that disconnected
1328 * @param internal_cls should be equal to @a c
1329 */
1330static void
1331disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
1332{
1333 struct ActiveLookup *n;
1334
1335 (void) cls;
1336
1337 GNUNET_assert (c == internal_cls);
1338 n = lookup_head;
1339 for (struct ActiveLookup *al = n; NULL != al; al = n)
1340 {
1341 n = al->next;
1342 if (al->client == c)
1343 free_active_lookup (al);
1344 }
1345}
1346
1347
1348/**
1349 * Define "main" method using service macro.
1350 */
1351GNUNET_SERVICE_MAIN (
1352 "resolver",
1353 GNUNET_SERVICE_OPTION_NONE,
1354 &init_cb,
1355 &connect_cb,
1356 &disconnect_cb,
1357 NULL,
1358 GNUNET_MQ_hd_var_size (get,
1359 GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST,
1360 struct GNUNET_RESOLVER_GetMessage,
1361 NULL),
1362 GNUNET_MQ_handler_end ());
1363
1364
1365#if defined(__linux__) && defined(__GLIBC__)
1366#include <malloc.h>
1367
1368/**
1369 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1370 */
1371void __attribute__ ((constructor))
1372GNUNET_RESOLVER_memory_init ()
1373{
1374 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1375 mallopt (M_TOP_PAD, 1 * 1024);
1376 malloc_trim (0);
1377}
1378
1379
1380#endif
1381
1382
1383/* end of gnunet-service-resolver.c */
diff --git a/src/util/gnunet-timeout.c b/src/util/gnunet-timeout.c
deleted file mode 100644
index 4c3c9125d..000000000
--- a/src/util/gnunet-timeout.c
+++ /dev/null
@@ -1,118 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010 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, or
8 (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 src/util/gnunet-timeout.c
23 * @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period
24 * @author Matthias Wachs
25 */
26
27#include <sys/types.h>
28#include <sys/wait.h>
29#include <signal.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33
34static pid_t child;
35
36
37static void
38sigchld_handler (int val)
39{
40 int status = 0;
41 int ret = 0;
42
43 (void) val;
44 waitpid (child, &status, 0);
45 if (WIFEXITED (status) != 0)
46 {
47 ret = WEXITSTATUS (status);
48 _exit (ret); /* return same status code */
49 }
50 if (WIFSIGNALED (status) != 0)
51 {
52 ret = WTERMSIG (status);
53 kill (getpid (), ret); /* kill self with the same signal */
54 }
55 _exit (-1);
56}
57
58
59static void
60sigint_handler (int val)
61{
62 kill (0, val);
63 _exit (val);
64}
65
66
67int
68main (int argc, char *argv[])
69{
70 int timeout = 0;
71 pid_t gpid = 0;
72
73 if (argc < 3)
74 {
75 fprintf (stderr,
76 "arg 1: timeout in sec., arg 2: executable, arg<n> arguments\n");
77 exit (-1);
78 }
79
80 timeout = atoi (argv[1]);
81
82 if (timeout == 0)
83 timeout = 600;
84
85 /* with getpgid() it does not compile, but getpgrp is the BSD version and working */
86 gpid = getpgrp ();
87
88 signal (SIGCHLD, sigchld_handler);
89 signal (SIGABRT, sigint_handler);
90 signal (SIGFPE, sigint_handler);
91 signal (SIGILL, sigint_handler);
92 signal (SIGINT, sigint_handler);
93 signal (SIGSEGV, sigint_handler);
94 signal (SIGTERM, sigint_handler);
95
96 child = fork ();
97 if (child == 0)
98 {
99 /* int setpgrp(pid_t pid, pid_t pgid); is not working on this machine */
100 // setpgrp (0, pid_t gpid);
101 if (-1 != gpid)
102 setpgid (0, gpid);
103 execvp (argv[2], &argv[2]);
104 exit (-1);
105 }
106 if (child > 0)
107 {
108 sleep (timeout);
109 printf ("Child processes were killed after timeout of %u seconds\n",
110 timeout);
111 kill (0, SIGTERM);
112 exit (3);
113 }
114 exit (-1);
115}
116
117
118/* end of timeout_watchdog.c */
diff --git a/src/util/gnunet-uri.c b/src/util/gnunet-uri.c
deleted file mode 100644
index de0ff1f92..000000000
--- a/src/util/gnunet-uri.c
+++ /dev/null
@@ -1,191 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012 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 util/gnunet-uri.c
23 * @brief tool to dispatch URIs to the appropriate GNUnet helper process
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29/**
30 * Handler exit code
31 */
32static long unsigned int exit_code = 0;
33
34/**
35 * Helper process we started.
36 */
37static struct GNUNET_OS_Process *p;
38
39/**
40 * Pipe used to communicate shutdown via signal.
41 */
42static struct GNUNET_DISK_PipeHandle *sigpipe;
43
44
45/**
46 * Task triggered whenever we receive a SIGCHLD (child
47 * process died) or when user presses CTRL-C.
48 *
49 * @param cls closure, NULL
50 */
51static void
52maint_child_death (void *cls)
53{
54 enum GNUNET_OS_ProcessStatusType type;
55
56 (void) cls;
57 if ((GNUNET_OK != GNUNET_OS_process_status (p, &type, &exit_code)) ||
58 (type != GNUNET_OS_PROCESS_EXITED))
59 GNUNET_break (0 == GNUNET_OS_process_kill (p, GNUNET_TERM_SIG));
60 GNUNET_OS_process_destroy (p);
61}
62
63
64/**
65 * Main function that will be run by the scheduler.
66 *
67 * @param cls closure
68 * @param args remaining command-line arguments
69 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
70 * @param cfg configuration
71 */
72static void
73run (void *cls,
74 char *const *args,
75 const char *cfgfile,
76 const struct GNUNET_CONFIGURATION_Handle *cfg)
77{
78 const char *uri;
79 const char *slash;
80 char *subsystem;
81 char *program;
82 struct GNUNET_SCHEDULER_Task *rt;
83
84 (void) cls;
85 (void) cfgfile;
86 if (NULL == (uri = args[0]))
87 {
88 fprintf (stderr, _ ("No URI specified on command line\n"));
89 return;
90 }
91 if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://")))
92 {
93 fprintf (stderr,
94 _ ("Invalid URI: does not start with `%s'\n"),
95 "gnunet://");
96 return;
97 }
98 uri += strlen ("gnunet://");
99 if (NULL == (slash = strchr (uri, '/')))
100 {
101 fprintf (stderr, _ ("Invalid URI: fails to specify subsystem\n"));
102 return;
103 }
104 subsystem = GNUNET_strndup (uri, slash - uri);
105 if (GNUNET_OK !=
106 GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program))
107 {
108 fprintf (stderr, _ ("No handler known for subsystem `%s'\n"), subsystem);
109 GNUNET_free (subsystem);
110 return;
111 }
112 GNUNET_free (subsystem);
113 rt = GNUNET_SCHEDULER_add_read_file (
114 GNUNET_TIME_UNIT_FOREVER_REL,
115 GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
116 &maint_child_death,
117 NULL);
118 p = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_NONE,
119 NULL,
120 NULL,
121 NULL,
122 program,
123 program,
124 args[0],
125 NULL);
126 GNUNET_free (program);
127 if (NULL == p)
128 GNUNET_SCHEDULER_cancel (rt);
129}
130
131
132/**
133 * Signal handler called for SIGCHLD. Triggers the
134 * respective handler by writing to the trigger pipe.
135 */
136static void
137sighandler_child_death ()
138{
139 static char c;
140 int old_errno = errno; /* back-up errno */
141
142 GNUNET_break (
143 1 ==
144 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
145 GNUNET_DISK_PIPE_END_WRITE),
146 &c,
147 sizeof(c)));
148 errno = old_errno; /* restore errno */
149}
150
151
152/**
153 * The main function to handle gnunet://-URIs.
154 *
155 * @param argc number of arguments from the command line
156 * @param argv command line arguments
157 * @return 0 ok, 1 on error
158 */
159int
160main (int argc, char *const *argv)
161{
162 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
163 GNUNET_GETOPT_OPTION_END
164 };
165 struct GNUNET_SIGNAL_Context *shc_chld;
166 int ret;
167
168 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
169 return 2;
170 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
171 GNUNET_assert (sigpipe != NULL);
172 shc_chld =
173 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
174 ret = GNUNET_PROGRAM_run (argc,
175 argv,
176 "gnunet-uri URI",
177 gettext_noop (
178 "Perform default-actions for GNUnet URIs"),
179 options,
180 &run,
181 NULL);
182 GNUNET_SIGNAL_handler_uninstall (shc_chld);
183 shc_chld = NULL;
184 GNUNET_DISK_pipe_close (sigpipe);
185 sigpipe = NULL;
186 GNUNET_free_nz ((void *) argv);
187 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
188}
189
190
191/* end of gnunet-uri.c */
diff --git a/src/util/helper.c b/src/util/helper.c
deleted file mode 100644
index 0809c1f17..000000000
--- a/src/util/helper.c
+++ /dev/null
@@ -1,720 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2012 Christian Grothoff
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 util/helper.c
23 * @brief API for dealing with (SUID) helper processes that communicate via
24 * GNUNET_MessageHeaders on stdin/stdout
25 * @author Philipp Toelke
26 * @author Christian Grothoff
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_mst_lib.h"
31
32
33/**
34 * Entry in the queue of messages we need to transmit to the helper.
35 */
36struct GNUNET_HELPER_SendHandle
37{
38 /**
39 * This is an entry in a DLL.
40 */
41 struct GNUNET_HELPER_SendHandle *next;
42
43 /**
44 * This is an entry in a DLL.
45 */
46 struct GNUNET_HELPER_SendHandle *prev;
47
48 /**
49 * Message to transmit (allocated at the end of this struct)
50 */
51 const struct GNUNET_MessageHeader *msg;
52
53 /**
54 * The handle to a helper process.
55 */
56 struct GNUNET_HELPER_Handle *h;
57
58 /**
59 * Function to call upon completion.
60 */
61 GNUNET_HELPER_Continuation cont;
62
63 /**
64 * Closure to 'cont'.
65 */
66 void *cont_cls;
67
68 /**
69 * Current write position.
70 */
71 unsigned int wpos;
72};
73
74
75/**
76 * The handle to a helper process.
77 */
78struct GNUNET_HELPER_Handle
79{
80 /**
81 * PipeHandle to receive data from the helper
82 */
83 struct GNUNET_DISK_PipeHandle *helper_in;
84
85 /**
86 * PipeHandle to send data to the helper
87 */
88 struct GNUNET_DISK_PipeHandle *helper_out;
89
90 /**
91 * FileHandle to receive data from the helper
92 */
93 const struct GNUNET_DISK_FileHandle *fh_from_helper;
94
95 /**
96 * FileHandle to send data to the helper
97 */
98 const struct GNUNET_DISK_FileHandle *fh_to_helper;
99
100 /**
101 * The process id of the helper
102 */
103 struct GNUNET_OS_Process *helper_proc;
104
105 /**
106 * The Message-Tokenizer that tokenizes the messages coming from the helper
107 */
108 struct GNUNET_MessageStreamTokenizer *mst;
109
110 /**
111 * The exception callback
112 */
113 GNUNET_HELPER_ExceptionCallback exp_cb;
114
115 /**
116 * The closure for callbacks
117 */
118 void *cb_cls;
119
120 /**
121 * First message queued for transmission to helper.
122 */
123 struct GNUNET_HELPER_SendHandle *sh_head;
124
125 /**
126 * Last message queued for transmission to helper.
127 */
128 struct GNUNET_HELPER_SendHandle *sh_tail;
129
130 /**
131 * Binary to run.
132 */
133 char *binary_name;
134
135 /**
136 * NULL-terminated list of command-line arguments.
137 */
138 char **binary_argv;
139
140 /**
141 * Task to read from the helper.
142 */
143 struct GNUNET_SCHEDULER_Task *read_task;
144
145 /**
146 * Task to read from the helper.
147 */
148 struct GNUNET_SCHEDULER_Task *write_task;
149
150 /**
151 * Restart task.
152 */
153 struct GNUNET_SCHEDULER_Task *restart_task;
154
155 /**
156 * Does the helper support the use of a control pipe for signalling?
157 */
158 int with_control_pipe;
159
160 /**
161 * Count start attempts to increase linear back off
162 */
163 unsigned int retry_back_off;
164};
165
166
167/**
168 * Sends termination signal to the helper process. The helper process is not
169 * reaped; call GNUNET_HELPER_wait() for reaping the dead helper process.
170 *
171 * @param h the helper handle
172 * @param soft_kill if GNUNET_YES, signals termination by closing the helper's
173 * stdin; GNUNET_NO to signal termination by sending SIGTERM to helper
174 * @return #GNUNET_OK on success; #GNUNET_SYSERR on error
175 */
176int
177GNUNET_HELPER_kill (struct GNUNET_HELPER_Handle *h, int soft_kill)
178{
179 struct GNUNET_HELPER_SendHandle *sh;
180 int ret;
181
182 while (NULL != (sh = h->sh_head))
183 {
184 GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh);
185 if (NULL != sh->cont)
186 sh->cont (sh->cont_cls, GNUNET_NO);
187 GNUNET_free (sh);
188 }
189 if (NULL != h->restart_task)
190 {
191 GNUNET_SCHEDULER_cancel (h->restart_task);
192 h->restart_task = NULL;
193 }
194 if (NULL != h->read_task)
195 {
196 GNUNET_SCHEDULER_cancel (h->read_task);
197 h->read_task = NULL;
198 }
199 if (NULL == h->helper_proc)
200 return GNUNET_SYSERR;
201 if (GNUNET_YES == soft_kill)
202 {
203 /* soft-kill only possible with pipes */
204 GNUNET_assert (NULL != h->helper_in);
205 ret = GNUNET_DISK_pipe_close (h->helper_in);
206 h->helper_in = NULL;
207 h->fh_to_helper = NULL;
208 return ret;
209 }
210 if (0 != GNUNET_OS_process_kill (h->helper_proc, GNUNET_TERM_SIG))
211 return GNUNET_SYSERR;
212 return GNUNET_OK;
213}
214
215
216/**
217 * Reap the helper process. This call is blocking(!). The helper process
218 * should either be sent a termination signal before or should be dead before
219 * calling this function
220 *
221 * @param h the helper handle
222 * @return #GNUNET_OK on success; #GNUNET_SYSERR on error
223 */
224int
225GNUNET_HELPER_wait (struct GNUNET_HELPER_Handle *h)
226{
227 struct GNUNET_HELPER_SendHandle *sh;
228 int ret;
229
230 ret = GNUNET_SYSERR;
231 if (NULL != h->helper_proc)
232 {
233 ret = GNUNET_OS_process_wait (h->helper_proc);
234 GNUNET_OS_process_destroy (h->helper_proc);
235 h->helper_proc = NULL;
236 }
237 if (NULL != h->read_task)
238 {
239 GNUNET_SCHEDULER_cancel (h->read_task);
240 h->read_task = NULL;
241 }
242 if (NULL != h->write_task)
243 {
244 GNUNET_SCHEDULER_cancel (h->write_task);
245 h->write_task = NULL;
246 }
247 if (NULL != h->helper_in)
248 {
249 GNUNET_DISK_pipe_close (h->helper_in);
250 h->helper_in = NULL;
251 h->fh_to_helper = NULL;
252 }
253 if (NULL != h->helper_out)
254 {
255 GNUNET_DISK_pipe_close (h->helper_out);
256 h->helper_out = NULL;
257 h->fh_from_helper = NULL;
258 }
259 while (NULL != (sh = h->sh_head))
260 {
261 GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh);
262 if (NULL != sh->cont)
263 sh->cont (sh->cont_cls, GNUNET_NO);
264 GNUNET_free (sh);
265 }
266 /* purge MST buffer */
267 if (NULL != h->mst)
268 (void) GNUNET_MST_from_buffer (h->mst, NULL, 0, GNUNET_YES, GNUNET_NO);
269 return ret;
270}
271
272
273/**
274 * Stop the helper process, we're closing down or had an error.
275 *
276 * @param h handle to the helper process
277 * @param soft_kill if #GNUNET_YES, signals termination by closing the helper's
278 * stdin; #GNUNET_NO to signal termination by sending SIGTERM to helper
279 */
280static void
281stop_helper (struct GNUNET_HELPER_Handle *h, int soft_kill)
282{
283 if (NULL != h->restart_task)
284 {
285 GNUNET_SCHEDULER_cancel (h->restart_task);
286 h->restart_task = NULL;
287 }
288 else
289 {
290 GNUNET_break (GNUNET_OK == GNUNET_HELPER_kill (h, soft_kill));
291 GNUNET_break (GNUNET_OK == GNUNET_HELPER_wait (h));
292 }
293}
294
295
296/**
297 * Restart the helper process.
298 *
299 * @param cls handle to the helper process
300 */
301static void
302restart_task (void *cls);
303
304
305/**
306 * Read from the helper-process
307 *
308 * @param cls handle to the helper process
309 */
310static void
311helper_read (void *cls)
312{
313 struct GNUNET_HELPER_Handle *h = cls;
314 char buf[GNUNET_MAX_MESSAGE_SIZE] GNUNET_ALIGN;
315 ssize_t t;
316
317 h->read_task = NULL;
318 t = GNUNET_DISK_file_read (h->fh_from_helper, &buf, sizeof(buf));
319 if (t < 0)
320 {
321 /* On read-error, restart the helper */
322 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
323 _ ("Error reading from `%s': %s\n"),
324 h->binary_name,
325 strerror (errno));
326 if (NULL != h->exp_cb)
327 {
328 h->exp_cb (h->cb_cls);
329 GNUNET_HELPER_stop (h, GNUNET_NO);
330 return;
331 }
332 stop_helper (h, GNUNET_NO);
333 /* Restart the helper */
334 h->restart_task = GNUNET_SCHEDULER_add_delayed (
335 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
336 h->retry_back_off),
337 &restart_task,
338 h);
339 return;
340 }
341 if (0 == t)
342 {
343 /* this happens if the helper is shut down via a
344 signal, so it is not a "hard" error */
345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
346 "Got 0 bytes from helper `%s' (EOF)\n",
347 h->binary_name);
348 if (NULL != h->exp_cb)
349 {
350 h->exp_cb (h->cb_cls);
351 GNUNET_HELPER_stop (h, GNUNET_NO);
352 return;
353 }
354 stop_helper (h, GNUNET_NO);
355 /* Restart the helper */
356 h->restart_task = GNUNET_SCHEDULER_add_delayed (
357 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
358 h->retry_back_off),
359 &restart_task,
360 h);
361 return;
362 }
363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
364 "Got %u bytes from helper `%s'\n",
365 (unsigned int) t,
366 h->binary_name);
367 h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
368 h->fh_from_helper,
369 &helper_read,
370 h);
371 if (GNUNET_SYSERR ==
372 GNUNET_MST_from_buffer (h->mst, buf, t, GNUNET_NO, GNUNET_NO))
373 {
374 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
375 _ ("Failed to parse inbound message from helper `%s'\n"),
376 h->binary_name);
377 if (NULL != h->exp_cb)
378 {
379 h->exp_cb (h->cb_cls);
380 GNUNET_HELPER_stop (h, GNUNET_NO);
381 return;
382 }
383 stop_helper (h, GNUNET_NO);
384 /* Restart the helper */
385 h->restart_task = GNUNET_SCHEDULER_add_delayed (
386 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
387 h->retry_back_off),
388 &restart_task,
389 h);
390 return;
391 }
392}
393
394
395/**
396 * Start the helper process.
397 *
398 * @param h handle to the helper process
399 */
400static void
401start_helper (struct GNUNET_HELPER_Handle *h)
402{
403 h->helper_in =
404 GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
405 h->helper_out =
406 GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
407 if ((h->helper_in == NULL) || (h->helper_out == NULL))
408 {
409 /* out of file descriptors? try again later... */
410 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
411 "out of file descriptors? try again later\n");
412 stop_helper (h, GNUNET_NO);
413 h->restart_task = GNUNET_SCHEDULER_add_delayed (
414 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
415 h->retry_back_off),
416 &restart_task,
417 h);
418 return;
419 }
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "Starting HELPER process `%s'\n",
422 h->binary_name);
423 h->fh_from_helper =
424 GNUNET_DISK_pipe_handle (h->helper_out, GNUNET_DISK_PIPE_END_READ);
425 h->fh_to_helper =
426 GNUNET_DISK_pipe_handle (h->helper_in, GNUNET_DISK_PIPE_END_WRITE);
427 h->helper_proc = GNUNET_OS_start_process_vap (h->with_control_pipe
428 ? GNUNET_OS_INHERIT_STD_ERR
429 | GNUNET_OS_USE_PIPE_CONTROL
430 : GNUNET_OS_INHERIT_STD_ERR,
431 h->helper_in,
432 h->helper_out,
433 NULL,
434 h->binary_name,
435 h->binary_argv);
436 if (NULL == h->helper_proc)
437 {
438 /* failed to start process? try again later... */
439 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
440 "failed to start process? try again later\n");
441 stop_helper (h, GNUNET_NO);
442 h->restart_task = GNUNET_SCHEDULER_add_delayed (
443 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
444 h->retry_back_off),
445 &restart_task,
446 h);
447 return;
448 }
449 GNUNET_DISK_pipe_close_end (h->helper_out, GNUNET_DISK_PIPE_END_WRITE);
450 GNUNET_DISK_pipe_close_end (h->helper_in, GNUNET_DISK_PIPE_END_READ);
451 if (NULL != h->mst)
452 h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
453 h->fh_from_helper,
454 &helper_read,
455 h);
456}
457
458
459/**
460 * Restart the helper process.
461 *
462 * @param cls handle to the helper process
463 */
464static void
465restart_task (void *cls)
466{
467 struct GNUNET_HELPER_Handle *h = cls;
468
469 h->restart_task = NULL;
470 h->retry_back_off++;
471 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
472 "Restarting helper with back-off %u\n",
473 h->retry_back_off);
474 start_helper (h);
475}
476
477
478/**
479 * Starts a helper and begins reading from it. The helper process is
480 * restarted when it dies except when it is stopped using GNUNET_HELPER_stop()
481 * or when the exp_cb callback is not NULL.
482 *
483 * @param with_control_pipe does the helper support the use of a control pipe for signalling?
484 * @param binary_name name of the binary to run
485 * @param binary_argv NULL-terminated list of arguments to give when starting the binary (this
486 * argument must not be modified by the client for
487 * the lifetime of the helper handle)
488 * @param cb function to call if we get messages from the helper
489 * @param exp_cb the exception callback to call. Set this to NULL if the helper
490 * process has to be restarted automatically when it dies/crashes
491 * @param cb_cls closure for the above callback
492 * @return the new Handle, NULL on error
493 */
494struct GNUNET_HELPER_Handle *
495GNUNET_HELPER_start (int with_control_pipe,
496 const char *binary_name,
497 char *const binary_argv[],
498 GNUNET_MessageTokenizerCallback cb,
499 GNUNET_HELPER_ExceptionCallback exp_cb,
500 void *cb_cls)
501{
502 struct GNUNET_HELPER_Handle *h;
503 unsigned int c;
504
505 h = GNUNET_new (struct GNUNET_HELPER_Handle);
506 h->with_control_pipe = with_control_pipe;
507 /* Lookup in libexec path only if we are starting gnunet helpers */
508 if (NULL != strstr (binary_name, "gnunet"))
509 h->binary_name = GNUNET_OS_get_libexec_binary_path (binary_name);
510 else
511 h->binary_name = GNUNET_strdup (binary_name);
512 for (c = 0; NULL != binary_argv[c]; c++)
513 ;
514 h->binary_argv = GNUNET_malloc (sizeof(char *) * (c + 1));
515 for (c = 0; NULL != binary_argv[c]; c++)
516 h->binary_argv[c] = GNUNET_strdup (binary_argv[c]);
517 h->binary_argv[c] = NULL;
518 h->cb_cls = cb_cls;
519 if (NULL != cb)
520 h->mst = GNUNET_MST_create (cb, h->cb_cls);
521 h->exp_cb = exp_cb;
522 h->retry_back_off = 0;
523 start_helper (h);
524 return h;
525}
526
527
528/**
529 * Free's the resources occupied by the helper handle
530 *
531 * @param h the helper handle to free
532 */
533void
534GNUNET_HELPER_destroy (struct GNUNET_HELPER_Handle *h)
535{
536 unsigned int c;
537 struct GNUNET_HELPER_SendHandle *sh;
538
539 if (NULL != h->write_task)
540 {
541 GNUNET_SCHEDULER_cancel (h->write_task);
542 h->write_task = NULL;
543 }
544 GNUNET_assert (NULL == h->read_task);
545 GNUNET_assert (NULL == h->restart_task);
546 while (NULL != (sh = h->sh_head))
547 {
548 GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh);
549 if (NULL != sh->cont)
550 sh->cont (sh->cont_cls, GNUNET_SYSERR);
551 GNUNET_free (sh);
552 }
553 if (NULL != h->mst)
554 GNUNET_MST_destroy (h->mst);
555 GNUNET_free (h->binary_name);
556 for (c = 0; h->binary_argv[c] != NULL; c++)
557 GNUNET_free (h->binary_argv[c]);
558 GNUNET_free (h->binary_argv);
559 GNUNET_free (h);
560}
561
562
563/**
564 * Kills the helper, closes the pipe and frees the handle
565 *
566 * @param h handle to helper to stop
567 * @param soft_kill if #GNUNET_YES, signals termination by closing the helper's
568 * stdin; #GNUNET_NO to signal termination by sending SIGTERM to helper
569 */
570void
571GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h, int soft_kill)
572{
573 h->exp_cb = NULL;
574 stop_helper (h, soft_kill);
575 GNUNET_HELPER_destroy (h);
576}
577
578
579/**
580 * Write to the helper-process
581 *
582 * @param cls handle to the helper process
583 */
584static void
585helper_write (void *cls)
586{
587 struct GNUNET_HELPER_Handle *h = cls;
588 struct GNUNET_HELPER_SendHandle *sh;
589 const char *buf;
590 ssize_t t;
591
592 h->write_task = NULL;
593 if (NULL == (sh = h->sh_head))
594 {
595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Helper write had no work!\n");
596 return; /* how did this happen? */
597 }
598 buf = (const char *) sh->msg;
599 t = GNUNET_DISK_file_write (h->fh_to_helper,
600 &buf[sh->wpos],
601 ntohs (sh->msg->size) - sh->wpos);
602 if (-1 == t)
603 {
604 /* On write-error, restart the helper */
605 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
606 _ ("Error writing to `%s': %s\n"),
607 h->binary_name,
608 strerror (errno));
609 if (NULL != h->exp_cb)
610 {
611 h->exp_cb (h->cb_cls);
612 GNUNET_HELPER_stop (h, GNUNET_NO);
613 return;
614 }
615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
616 "Stopping and restarting helper task!\n");
617 stop_helper (h, GNUNET_NO);
618 /* Restart the helper */
619 h->restart_task = GNUNET_SCHEDULER_add_delayed (
620 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
621 h->retry_back_off),
622 &restart_task,
623 h);
624 return;
625 }
626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
627 "Transmitted %u bytes to %s\n",
628 (unsigned int) t,
629 h->binary_name);
630 sh->wpos += t;
631 if (sh->wpos == ntohs (sh->msg->size))
632 {
633 GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh);
634 if (NULL != sh->cont)
635 sh->cont (sh->cont_cls, GNUNET_YES);
636 GNUNET_free (sh);
637 }
638 if (NULL != h->sh_head)
639 h->write_task =
640 GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
641 h->fh_to_helper,
642 &helper_write,
643 h);
644}
645
646
647/**
648 * Send an message to the helper.
649 *
650 * @param h helper to send message to
651 * @param msg message to send
652 * @param can_drop can the message be dropped if there is already one in the queue?
653 * @param cont continuation to run once the message is out (#GNUNET_OK on success, #GNUNET_NO
654 * if the helper process died, #GNUNET_SYSERR during #GNUNET_HELPER_destroy).
655 * @param cont_cls closure for @a cont
656 * @return NULL if the message was dropped,
657 * otherwise handle to cancel *cont* (actual transmission may
658 * not be abortable)
659 */
660struct GNUNET_HELPER_SendHandle *
661GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h,
662 const struct GNUNET_MessageHeader *msg,
663 int can_drop,
664 GNUNET_HELPER_Continuation cont,
665 void *cont_cls)
666{
667 struct GNUNET_HELPER_SendHandle *sh;
668 uint16_t mlen;
669
670 if (NULL == h->fh_to_helper)
671 return NULL;
672 if ((GNUNET_YES == can_drop) && (NULL != h->sh_head))
673 return NULL;
674 mlen = ntohs (msg->size);
675 sh = GNUNET_malloc (sizeof(struct GNUNET_HELPER_SendHandle) + mlen);
676 sh->msg = (const struct GNUNET_MessageHeader *) &sh[1];
677 GNUNET_memcpy (&sh[1], msg, mlen);
678 sh->h = h;
679 sh->cont = cont;
680 sh->cont_cls = cont_cls;
681 GNUNET_CONTAINER_DLL_insert_tail (h->sh_head, h->sh_tail, sh);
682 if (NULL == h->write_task)
683 h->write_task =
684 GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
685 h->fh_to_helper,
686 &helper_write,
687 h);
688
689 return sh;
690}
691
692
693/**
694 * Cancel a #GNUNET_HELPER_send operation. If possible, transmitting the
695 * message is also aborted, but at least 'cont' won't be
696 * called.
697 *
698 * @param sh operation to cancel
699 */
700void
701GNUNET_HELPER_send_cancel (struct GNUNET_HELPER_SendHandle *sh)
702{
703 struct GNUNET_HELPER_Handle *h = sh->h;
704
705 sh->cont = NULL;
706 sh->cont_cls = NULL;
707 if (0 == sh->wpos)
708 {
709 GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh);
710 GNUNET_free (sh);
711 if (NULL == h->sh_head)
712 {
713 GNUNET_SCHEDULER_cancel (h->write_task);
714 h->write_task = NULL;
715 }
716 }
717}
718
719
720/* end of helper.c */
diff --git a/src/util/load.c b/src/util/load.c
deleted file mode 100644
index 64f0b19c1..000000000
--- a/src/util/load.c
+++ /dev/null
@@ -1,256 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2013 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 util/load.c
23 * @brief functions related to load calculations
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "util-load", __VA_ARGS__)
31
32/**
33 * Values we track for load calculations.
34 */
35struct GNUNET_LOAD_Value
36{
37 /**
38 * How fast should the load decline if no values are added?
39 */
40 struct GNUNET_TIME_Relative autodecline;
41
42 /**
43 * Last time this load value was updated by an event.
44 */
45 struct GNUNET_TIME_Absolute last_update;
46
47 /**
48 * Sum of all datastore delays ever observed (in ms). Note that
49 * delays above 64k ms are excluded (to avoid overflow within
50 * first 4 billion requests).
51 */
52 uint64_t cummulative_delay;
53
54 /**
55 * Sum of squares of all datastore delays ever observed (in ms). Note that
56 * delays above 64k ms are excluded (to avoid overflow within
57 * first 4 billion requests).
58 */
59 uint64_t cummulative_squared_delay;
60
61 /**
62 * Total number of requests included in the cumulative datastore delay values.
63 */
64 uint64_t cummulative_request_count;
65
66 /**
67 * Current running average datastore delay. Its relation to the
68 * average datastore delay and it std. dev. (as calculated from the
69 * cumulative values) tells us our current load.
70 */
71 double runavg_delay;
72
73 /**
74 * How high is the load? 0 for below average, otherwise
75 * the number of std. devs we are above average, or 100 if the
76 * load is so high that we currently cannot calculate it.
77 */
78 double load;
79};
80
81
82static void
83internal_update (struct GNUNET_LOAD_Value *load)
84{
85 struct GNUNET_TIME_Relative delta;
86 unsigned int n;
87
88 if (load->autodecline.rel_value_us ==
89 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
90 return;
91 delta = GNUNET_TIME_absolute_get_duration (load->last_update);
92 if (delta.rel_value_us < load->autodecline.rel_value_us)
93 return;
94 if (0 == load->autodecline.rel_value_us)
95 {
96 load->runavg_delay = 0.0;
97 load->load = 0;
98 return;
99 }
100 n = delta.rel_value_us / load->autodecline.rel_value_us;
101 if (n > 16)
102 {
103 load->runavg_delay = 0.0;
104 load->load = 0;
105 return;
106 }
107 while (n > 0)
108 {
109 n--;
110 load->runavg_delay = (load->runavg_delay * 7.0) / 8.0;
111 }
112}
113
114
115/**
116 * Create a new load value.
117 *
118 * @param autodecline speed at which this value should automatically
119 * decline in the absence of external events; at the given
120 * frequency, 0-load values will be added to the load
121 * @return the new load value
122 */
123struct GNUNET_LOAD_Value *
124GNUNET_LOAD_value_init (struct GNUNET_TIME_Relative autodecline)
125{
126 struct GNUNET_LOAD_Value *ret;
127
128 ret = GNUNET_new (struct GNUNET_LOAD_Value);
129 ret->autodecline = autodecline;
130 ret->last_update = GNUNET_TIME_absolute_get ();
131 return ret;
132}
133
134
135/**
136 * Change the value by which the load automatically declines.
137 *
138 * @param load load to update
139 * @param autodecline frequency of load decline
140 */
141void
142GNUNET_LOAD_value_set_decline (struct GNUNET_LOAD_Value *load,
143 struct GNUNET_TIME_Relative autodecline)
144{
145 internal_update (load);
146 load->autodecline = autodecline;
147}
148
149
150/**
151 * Recalculate our load value.
152 *
153 * @param load load to update
154 */
155static void
156calculate_load (struct GNUNET_LOAD_Value *load)
157{
158 double stddev;
159 double avgdel;
160 double sum_val_i;
161 double n;
162 double nm1;
163
164 if (load->cummulative_request_count <= 1)
165 return;
166 /* calculate std dev of latency; we have for n values of "i" that:
167 *
168 * avg = (sum val_i) / n
169 * stddev = (sum (val_i - avg)^2) / (n-1)
170 * = (sum (val_i^2 - 2 avg val_i + avg^2) / (n-1)
171 * = (sum (val_i^2) - 2 avg sum (val_i) + n * avg^2) / (n-1)
172 */sum_val_i = (double) load->cummulative_delay;
173 n = ((double) load->cummulative_request_count);
174 nm1 = n - 1.0;
175 avgdel = sum_val_i / n;
176 stddev =
177 (((double) load->cummulative_squared_delay) - 2.0 * avgdel * sum_val_i
178 + n * avgdel * avgdel) / nm1;
179 if (stddev <= 0)
180 stddev = 0.01; /* must have been rounding error or zero; prevent division by zero */
181 /* now calculate load based on how far out we are from
182 * std dev; or if we are below average, simply assume load zero */
183 if (load->runavg_delay < avgdel)
184 load->load = 0.0;
185 else
186 load->load = (load->runavg_delay - avgdel) / stddev;
187}
188
189
190/**
191 * Get the current load.
192 *
193 * @param load load handle
194 * @return zero for below-average load, otherwise
195 * number of std. devs we are above average;
196 * 100 if the latest updates were so large
197 * that we could not do proper calculations
198 */
199double
200GNUNET_LOAD_get_load (struct GNUNET_LOAD_Value *load)
201{
202 internal_update (load);
203 calculate_load (load);
204 return load->load;
205}
206
207
208/**
209 * Get the average value given to update so far.
210 *
211 * @param load load handle
212 * @return zero if update was never called
213 */
214double
215GNUNET_LOAD_get_average (struct GNUNET_LOAD_Value *load)
216{
217 double n;
218 double sum_val_i;
219
220 internal_update (load);
221 if (load->cummulative_request_count == 0)
222 return 0.0;
223 n = ((double) load->cummulative_request_count);
224 sum_val_i = (double) load->cummulative_delay;
225 return sum_val_i / n;
226}
227
228
229/**
230 * Update the current load.
231 *
232 * @param load to update
233 * @param data latest measurement value (for example, delay)
234 */
235void
236GNUNET_LOAD_update (struct GNUNET_LOAD_Value *load, uint64_t data)
237{
238 uint32_t dv;
239
240 internal_update (load);
241 load->last_update = GNUNET_TIME_absolute_get ();
242 if (data > 64 * 1024)
243 {
244 /* very large */
245 load->load = 100.0;
246 return;
247 }
248 dv = (uint32_t) data;
249 load->cummulative_delay += dv;
250 load->cummulative_squared_delay += dv * dv;
251 load->cummulative_request_count++;
252 load->runavg_delay = ((load->runavg_delay * 7.0) + dv) / 8.0;
253}
254
255
256/* end of load.c */
diff --git a/src/util/mq.c b/src/util/mq.c
deleted file mode 100644
index b09837459..000000000
--- a/src/util/mq.c
+++ /dev/null
@@ -1,1335 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2019 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 * @author Florian Dold
23 * @file util/mq.c
24 * @brief general purpose request queue
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "util-mq", __VA_ARGS__)
30
31
32struct GNUNET_MQ_Envelope
33{
34 /**
35 * Messages are stored in a linked list.
36 * Each queue has its own list of envelopes.
37 */
38 struct GNUNET_MQ_Envelope *next;
39
40 /**
41 * Messages are stored in a linked list
42 * Each queue has its own list of envelopes.
43 */
44 struct GNUNET_MQ_Envelope *prev;
45
46 /**
47 * Actual allocated message header.
48 * The GNUNET_MQ_Envelope header is allocated at
49 * the end of the message.
50 */
51 struct GNUNET_MessageHeader *mh;
52
53 /**
54 * Queue the message is queued in, NULL if message is not queued.
55 */
56 struct GNUNET_MQ_Handle *parent_queue;
57
58 /**
59 * Called after the message was sent irrevocably.
60 */
61 GNUNET_SCHEDULER_TaskCallback sent_cb;
62
63 /**
64 * Closure for @e send_cb
65 */
66 void *sent_cls;
67
68 /**
69 * Flags that were set for this envelope by
70 * #GNUNET_MQ_env_set_options(). Only valid if
71 * @e have_custom_options is set.
72 */
73 enum GNUNET_MQ_PriorityPreferences priority;
74
75 /**
76 * Did the application call #GNUNET_MQ_env_set_options()?
77 */
78 int have_custom_options;
79};
80
81
82/**
83 * Handle to a message queue.
84 */
85struct GNUNET_MQ_Handle
86{
87 /**
88 * Handlers array, or NULL if the queue should not receive messages
89 */
90 struct GNUNET_MQ_MessageHandler *handlers;
91
92 /**
93 * Actual implementation of message sending,
94 * called when a message is added
95 */
96 GNUNET_MQ_SendImpl send_impl;
97
98 /**
99 * Implementation-dependent queue destruction function
100 */
101 GNUNET_MQ_DestroyImpl destroy_impl;
102
103 /**
104 * Implementation-dependent send cancel function
105 */
106 GNUNET_MQ_CancelImpl cancel_impl;
107
108 /**
109 * Implementation-specific state
110 */
111 void *impl_state;
112
113 /**
114 * Callback will be called when an error occurs.
115 */
116 GNUNET_MQ_ErrorHandler error_handler;
117
118 /**
119 * Closure for the error handler.
120 */
121 void *error_handler_cls;
122
123 /**
124 * Task to asynchronously run #impl_send_continue().
125 */
126 struct GNUNET_SCHEDULER_Task *send_task;
127
128 /**
129 * Linked list of messages pending to be sent
130 */
131 struct GNUNET_MQ_Envelope *envelope_head;
132
133 /**
134 * Linked list of messages pending to be sent
135 */
136 struct GNUNET_MQ_Envelope *envelope_tail;
137
138 /**
139 * Message that is currently scheduled to be
140 * sent. Not the head of the message queue, as the implementation
141 * needs to know if sending has been already scheduled or not.
142 */
143 struct GNUNET_MQ_Envelope *current_envelope;
144
145 /**
146 * Map of associations, lazily allocated
147 */
148 struct GNUNET_CONTAINER_MultiHashMap32 *assoc_map;
149
150 /**
151 * Functions to call on queue destruction; kept in a DLL.
152 */
153 struct GNUNET_MQ_DestroyNotificationHandle *dnh_head;
154
155 /**
156 * Functions to call on queue destruction; kept in a DLL.
157 */
158 struct GNUNET_MQ_DestroyNotificationHandle *dnh_tail;
159
160 /**
161 * Flags that were set for this queue by
162 * #GNUNET_MQ_set_options(). Default is 0.
163 */
164 enum GNUNET_MQ_PriorityPreferences priority;
165
166 /**
167 * Next id that should be used for the @e assoc_map,
168 * initialized lazily to a random value together with
169 * @e assoc_map
170 */
171 uint32_t assoc_id;
172
173 /**
174 * Number of entries we have in the envelope-DLL.
175 */
176 unsigned int queue_length;
177
178 /**
179 * #GNUNET_YES if GNUNET_MQ_impl_evacuate was called.
180 * FIXME: is this dead?
181 */
182 int evacuate_called;
183
184 /**
185 * #GNUNET_YES if GNUNET_MQ_impl_send_in_flight() was called.
186 */
187 int in_flight;
188};
189
190
191/**
192 * Call the message message handler that was registered
193 * for the type of the given message in the given message queue.
194 *
195 * This function is intended to be used for the implementation
196 * of message queues.
197 *
198 * @param mq message queue with the handlers
199 * @param mh message to dispatch
200 */
201void
202GNUNET_MQ_inject_message (struct GNUNET_MQ_Handle *mq,
203 const struct GNUNET_MessageHeader *mh)
204{
205 int ret;
206
207 ret = GNUNET_MQ_handle_message (mq->handlers, mh);
208 if (GNUNET_SYSERR == ret)
209 {
210 GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_MALFORMED);
211 return;
212 }
213}
214
215
216/**
217 * Call the message message handler that was registered
218 * for the type of the given message in the given @a handlers list.
219 *
220 * This function is intended to be used for the implementation
221 * of message queues.
222 *
223 * @param handlers a set of handlers
224 * @param mh message to dispatch
225 * @return #GNUNET_OK on success, #GNUNET_NO if no handler matched,
226 * #GNUNET_SYSERR if message was rejected by check function
227 */
228int
229GNUNET_MQ_handle_message (const struct GNUNET_MQ_MessageHandler *handlers,
230 const struct GNUNET_MessageHeader *mh)
231{
232 const struct GNUNET_MQ_MessageHandler *handler;
233 int handled = GNUNET_NO;
234 uint16_t msize = ntohs (mh->size);
235 uint16_t mtype = ntohs (mh->type);
236
237 LOG (GNUNET_ERROR_TYPE_DEBUG,
238 "Received message of type %u and size %u\n",
239 mtype,
240 msize);
241
242 if (NULL == handlers)
243 goto done;
244 for (handler = handlers; NULL != handler->cb; handler++)
245 {
246 if (handler->type == mtype)
247 {
248 handled = GNUNET_YES;
249 if ((handler->expected_size > msize) ||
250 ((handler->expected_size != msize) && (NULL == handler->mv)))
251 {
252 /* Too small, or not an exact size and
253 no 'mv' handler to check rest */
254 LOG (GNUNET_ERROR_TYPE_ERROR,
255 "Received malformed message of type %u\n",
256 (unsigned int) handler->type);
257 return GNUNET_SYSERR;
258 }
259 if ((NULL == handler->mv) ||
260 (GNUNET_OK == handler->mv (handler->cls, mh)))
261 {
262 /* message well-formed, pass to handler */
263 handler->cb (handler->cls, mh);
264 }
265 else
266 {
267 /* Message rejected by check routine */
268 LOG (GNUNET_ERROR_TYPE_ERROR,
269 "Received malformed message of type %u\n",
270 (unsigned int) handler->type);
271 return GNUNET_SYSERR;
272 }
273 break;
274 }
275 }
276done:
277 if (GNUNET_NO == handled)
278 {
279 LOG (GNUNET_ERROR_TYPE_INFO,
280 "No handler for message of type %u and size %u\n",
281 mtype,
282 msize);
283 return GNUNET_NO;
284 }
285 return GNUNET_OK;
286}
287
288
289/**
290 * Call the error handler of a message queue with the given
291 * error code. If there is no error handler, log a warning.
292 *
293 * This function is intended to be used by the implementation
294 * of message queues.
295 *
296 * @param mq message queue
297 * @param error the error type
298 */
299void
300GNUNET_MQ_inject_error (struct GNUNET_MQ_Handle *mq,
301 enum GNUNET_MQ_Error error)
302{
303 if (NULL == mq->error_handler)
304 {
305 LOG (GNUNET_ERROR_TYPE_WARNING,
306 "Got error %d, but no handler installed\n",
307 (int) error);
308 return;
309 }
310 mq->error_handler (mq->error_handler_cls,
311 error);
312}
313
314
315/**
316 * Discard the message queue message, free all
317 * allocated resources. Must be called in the event
318 * that a message is created but should not actually be sent.
319 *
320 * @param mqm the message to discard
321 */
322void
323GNUNET_MQ_discard (struct GNUNET_MQ_Envelope *ev)
324{
325 GNUNET_assert (NULL == ev->parent_queue);
326 GNUNET_free (ev);
327}
328
329
330/**
331 * Obtain the current length of the message queue.
332 *
333 * @param mq queue to inspect
334 * @return number of queued, non-transmitted messages
335 */
336unsigned int
337GNUNET_MQ_get_length (struct GNUNET_MQ_Handle *mq)
338{
339 if (GNUNET_YES != mq->in_flight)
340 {
341 return mq->queue_length;
342 }
343 return mq->queue_length - 1;
344}
345
346
347/**
348 * Send a message with the given message queue.
349 * May only be called once per message.
350 *
351 * @param mq message queue
352 * @param ev the envelope with the message to send.
353 */
354void
355GNUNET_MQ_send (struct GNUNET_MQ_Handle *mq,
356 struct GNUNET_MQ_Envelope *ev)
357{
358 if (NULL == mq)
359 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
360 "mq is NUll when sending message of type %u\n",
361 (unsigned int) ntohs (ev->mh->type));
362 GNUNET_assert (NULL != mq);
363 GNUNET_assert (NULL == ev->parent_queue);
364
365 mq->queue_length++;
366 if (mq->queue_length >= 10000000)
367 {
368 /* This would seem like a bug... */
369 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
370 "MQ with %u entries extended by message of type %u (FC broken?)\n",
371 (unsigned int) mq->queue_length,
372 (unsigned int) ntohs (ev->mh->type));
373 }
374 ev->parent_queue = mq;
375 /* is the implementation busy? queue it! */
376 if ((NULL != mq->current_envelope) || (NULL != mq->send_task))
377 {
378 GNUNET_CONTAINER_DLL_insert_tail (mq->envelope_head,
379 mq->envelope_tail,
380 ev);
381 return;
382 }
383 GNUNET_assert (NULL == mq->envelope_head);
384 mq->current_envelope = ev;
385
386 LOG (GNUNET_ERROR_TYPE_DEBUG,
387 "sending message of type %u, queue empty (MQ: %p)\n",
388 ntohs (ev->mh->type),
389 mq);
390
391 mq->send_impl (mq,
392 ev->mh,
393 mq->impl_state);
394}
395
396
397/**
398 * Remove the first envelope that has not yet been sent from the message
399 * queue and return it.
400 *
401 * @param mq queue to remove envelope from
402 * @return NULL if queue is empty (or has no envelope that is not under transmission)
403 */
404struct GNUNET_MQ_Envelope *
405GNUNET_MQ_unsent_head (struct GNUNET_MQ_Handle *mq)
406{
407 struct GNUNET_MQ_Envelope *env;
408
409 env = mq->envelope_head;
410 GNUNET_CONTAINER_DLL_remove (mq->envelope_head, mq->envelope_tail, env);
411 mq->queue_length--;
412 env->parent_queue = NULL;
413 return env;
414}
415
416
417/**
418 * Function to copy an envelope. The envelope must not yet
419 * be in any queue or have any options or callbacks set.
420 *
421 * @param env envelope to copy
422 * @return copy of @a env
423 */
424struct GNUNET_MQ_Envelope *
425GNUNET_MQ_env_copy (struct GNUNET_MQ_Envelope *env)
426{
427 GNUNET_assert (NULL == env->next);
428 GNUNET_assert (NULL == env->parent_queue);
429 GNUNET_assert (NULL == env->sent_cb);
430 GNUNET_assert (GNUNET_NO == env->have_custom_options);
431 return GNUNET_MQ_msg_copy (env->mh);
432}
433
434
435/**
436 * Send a copy of a message with the given message queue.
437 * Can be called repeatedly on the same envelope.
438 *
439 * @param mq message queue
440 * @param ev the envelope with the message to send.
441 */
442void
443GNUNET_MQ_send_copy (struct GNUNET_MQ_Handle *mq,
444 const struct GNUNET_MQ_Envelope *ev)
445{
446 struct GNUNET_MQ_Envelope *env;
447 uint16_t msize;
448
449 msize = ntohs (ev->mh->size);
450 env = GNUNET_malloc (sizeof(struct GNUNET_MQ_Envelope) + msize);
451 env->mh = (struct GNUNET_MessageHeader *) &env[1];
452 env->sent_cb = ev->sent_cb;
453 env->sent_cls = ev->sent_cls;
454 GNUNET_memcpy (&env[1], ev->mh, msize);
455 GNUNET_MQ_send (mq, env);
456}
457
458
459/**
460 * Task run to call the send implementation for the next queued
461 * message, if any. Only useful for implementing message queues,
462 * results in undefined behavior if not used carefully.
463 *
464 * @param cls message queue to send the next message with
465 */
466static void
467impl_send_continue (void *cls)
468{
469 struct GNUNET_MQ_Handle *mq = cls;
470
471 mq->send_task = NULL;
472 /* call is only valid if we're actually currently sending
473 * a message */
474 if (NULL == mq->envelope_head)
475 return;
476 mq->current_envelope = mq->envelope_head;
477 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
478 mq->envelope_tail,
479 mq->current_envelope);
480
481 LOG (GNUNET_ERROR_TYPE_DEBUG,
482 "sending message of type %u from queue\n",
483 ntohs (mq->current_envelope->mh->type));
484
485 mq->send_impl (mq,
486 mq->current_envelope->mh,
487 mq->impl_state);
488}
489
490
491/**
492 * Call the send implementation for the next queued message, if any.
493 * Only useful for implementing message queues, results in undefined
494 * behavior if not used carefully.
495 *
496 * @param mq message queue to send the next message with
497 */
498void
499GNUNET_MQ_impl_send_continue (struct GNUNET_MQ_Handle *mq)
500{
501 struct GNUNET_MQ_Envelope *current_envelope;
502 GNUNET_SCHEDULER_TaskCallback cb;
503
504 GNUNET_assert (0 < mq->queue_length);
505 mq->queue_length--;
506 mq->in_flight = GNUNET_NO;
507 current_envelope = mq->current_envelope;
508 current_envelope->parent_queue = NULL;
509 mq->current_envelope = NULL;
510 GNUNET_assert (NULL == mq->send_task);
511 mq->send_task = GNUNET_SCHEDULER_add_now (&impl_send_continue, mq);
512 if (NULL != (cb = current_envelope->sent_cb))
513 {
514 current_envelope->sent_cb = NULL;
515 cb (current_envelope->sent_cls);
516 }
517 GNUNET_free (current_envelope);
518}
519
520
521/**
522 * Call the send notification for the current message, but do not
523 * try to send the next message until #GNUNET_MQ_impl_send_continue
524 * is called.
525 *
526 * Only useful for implementing message queues, results in undefined
527 * behavior if not used carefully.
528 *
529 * @param mq message queue to send the next message with
530 */
531void
532GNUNET_MQ_impl_send_in_flight (struct GNUNET_MQ_Handle *mq)
533{
534 struct GNUNET_MQ_Envelope *current_envelope;
535 GNUNET_SCHEDULER_TaskCallback cb;
536
537 mq->in_flight = GNUNET_YES;
538 /* call is only valid if we're actually currently sending
539 * a message */
540 current_envelope = mq->current_envelope;
541 GNUNET_assert (NULL != current_envelope);
542 /* can't call cancel from now on anymore */
543 current_envelope->parent_queue = NULL;
544 if (NULL != (cb = current_envelope->sent_cb))
545 {
546 current_envelope->sent_cb = NULL;
547 cb (current_envelope->sent_cls);
548 }
549}
550
551
552/**
553 * Create a message queue for the specified handlers.
554 *
555 * @param send function the implements sending messages
556 * @param destroy function that implements destroying the queue
557 * @param cancel function that implements canceling a message
558 * @param impl_state for the queue, passed to 'send' and 'destroy'
559 * @param handlers array of message handlers
560 * @param error_handler handler for read and write errors
561 * @param error_handler_cls closure for @a error_handler
562 * @return a new message queue
563 */
564struct GNUNET_MQ_Handle *
565GNUNET_MQ_queue_for_callbacks (GNUNET_MQ_SendImpl send,
566 GNUNET_MQ_DestroyImpl destroy,
567 GNUNET_MQ_CancelImpl cancel,
568 void *impl_state,
569 const struct GNUNET_MQ_MessageHandler *handlers,
570 GNUNET_MQ_ErrorHandler error_handler,
571 void *error_handler_cls)
572{
573 struct GNUNET_MQ_Handle *mq;
574
575 mq = GNUNET_new (struct GNUNET_MQ_Handle);
576 mq->send_impl = send;
577 mq->destroy_impl = destroy;
578 mq->cancel_impl = cancel;
579 mq->handlers = GNUNET_MQ_copy_handlers (handlers);
580 mq->error_handler = error_handler;
581 mq->error_handler_cls = error_handler_cls;
582 mq->impl_state = impl_state;
583
584 return mq;
585}
586
587
588/**
589 * Change the closure argument in all of the `handlers` of the
590 * @a mq.
591 *
592 * @param mq to modify
593 * @param handlers_cls new closure to use
594 */
595void
596GNUNET_MQ_set_handlers_closure (struct GNUNET_MQ_Handle *mq, void *handlers_cls)
597{
598 if (NULL == mq->handlers)
599 return;
600 for (unsigned int i = 0; NULL != mq->handlers[i].cb; i++)
601 mq->handlers[i].cls = handlers_cls;
602}
603
604
605/**
606 * Get the message that should currently be sent.
607 * Fails if there is no current message.
608 * Only useful for implementing message queues,
609 * results in undefined behavior if not used carefully.
610 *
611 * @param mq message queue with the current message
612 * @return message to send, never NULL
613 */
614const struct GNUNET_MessageHeader *
615GNUNET_MQ_impl_current (struct GNUNET_MQ_Handle *mq)
616{
617 GNUNET_assert (NULL != mq->current_envelope);
618 GNUNET_assert (NULL != mq->current_envelope->mh);
619 return mq->current_envelope->mh;
620}
621
622
623/**
624 * Get the implementation state associated with the
625 * message queue.
626 *
627 * While the GNUNET_MQ_Impl* callbacks receive the
628 * implementation state, continuations that are scheduled
629 * by the implementation function often only have one closure
630 * argument, with this function it is possible to get at the
631 * implementation state when only passing the GNUNET_MQ_Handle
632 * as closure.
633 *
634 * @param mq message queue with the current message
635 * @return message to send, never NULL
636 */
637void *
638GNUNET_MQ_impl_state (struct GNUNET_MQ_Handle *mq)
639{
640 return mq->impl_state;
641}
642
643
644struct GNUNET_MQ_Envelope *
645GNUNET_MQ_msg_ (struct GNUNET_MessageHeader **mhp, uint16_t size, uint16_t type)
646{
647 struct GNUNET_MQ_Envelope *ev;
648
649 ev = GNUNET_malloc (size + sizeof(struct GNUNET_MQ_Envelope));
650 ev->mh = (struct GNUNET_MessageHeader *) &ev[1];
651 ev->mh->size = htons (size);
652 ev->mh->type = htons (type);
653 if (NULL != mhp)
654 *mhp = ev->mh;
655 return ev;
656}
657
658
659/**
660 * Create a new envelope by copying an existing message.
661 *
662 * @param hdr header of the message to copy
663 * @return envelope containing @a hdr
664 */
665struct GNUNET_MQ_Envelope *
666GNUNET_MQ_msg_copy (const struct GNUNET_MessageHeader *hdr)
667{
668 struct GNUNET_MQ_Envelope *mqm;
669 uint16_t size = ntohs (hdr->size);
670
671 mqm = GNUNET_malloc (sizeof(*mqm) + size);
672 mqm->mh = (struct GNUNET_MessageHeader *) &mqm[1];
673 GNUNET_memcpy (mqm->mh,
674 hdr,
675 size);
676 return mqm;
677}
678
679
680/**
681 * Implementation of the #GNUNET_MQ_msg_nested_mh macro.
682 *
683 * @param mhp pointer to the message header pointer that will be changed to allocate at
684 * the newly allocated space for the message.
685 * @param base_size size of the data before the nested message
686 * @param type type of the message in the envelope
687 * @param nested_mh the message to append to the message after base_size
688 */
689struct GNUNET_MQ_Envelope *
690GNUNET_MQ_msg_nested_mh_ (struct GNUNET_MessageHeader **mhp,
691 uint16_t base_size,
692 uint16_t type,
693 const struct GNUNET_MessageHeader *nested_mh)
694{
695 struct GNUNET_MQ_Envelope *mqm;
696 uint16_t size;
697
698 if (NULL == nested_mh)
699 return GNUNET_MQ_msg_ (mhp, base_size, type);
700
701 size = base_size + ntohs (nested_mh->size);
702
703 /* check for uint16_t overflow */
704 if (size < base_size)
705 return NULL;
706
707 mqm = GNUNET_MQ_msg_ (mhp, size, type);
708 GNUNET_memcpy ((char *) mqm->mh + base_size,
709 nested_mh,
710 ntohs (nested_mh->size));
711
712 return mqm;
713}
714
715
716/**
717 * Associate the assoc_data in mq with a unique request id.
718 *
719 * @param mq message queue, id will be unique for the queue
720 * @param assoc_data to associate
721 */
722uint32_t
723GNUNET_MQ_assoc_add (struct GNUNET_MQ_Handle *mq, void *assoc_data)
724{
725 uint32_t id;
726
727 if (NULL == mq->assoc_map)
728 {
729 mq->assoc_map = GNUNET_CONTAINER_multihashmap32_create (8);
730 mq->assoc_id = 1;
731 }
732 id = mq->assoc_id++;
733 GNUNET_assert (GNUNET_OK ==
734 GNUNET_CONTAINER_multihashmap32_put (
735 mq->assoc_map,
736 id,
737 assoc_data,
738 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
739 return id;
740}
741
742
743/**
744 * Get the data associated with a @a request_id in a queue
745 *
746 * @param mq the message queue with the association
747 * @param request_id the request id we are interested in
748 * @return the associated data
749 */
750void *
751GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq, uint32_t request_id)
752{
753 if (NULL == mq->assoc_map)
754 return NULL;
755 return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, request_id);
756}
757
758
759/**
760 * Remove the association for a @a request_id
761 *
762 * @param mq the message queue with the association
763 * @param request_id the request id we want to remove
764 * @return the associated data
765 */
766void *
767GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq, uint32_t request_id)
768{
769 void *val;
770
771 if (NULL == mq->assoc_map)
772 return NULL;
773 val = GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, request_id);
774 GNUNET_CONTAINER_multihashmap32_remove_all (mq->assoc_map, request_id);
775 return val;
776}
777
778
779/**
780 * Call a callback once the envelope has been sent, that is,
781 * sending it can not be canceled anymore.
782 * There can be only one notify sent callback per envelope.
783 *
784 * @param ev message to call the notify callback for
785 * @param cb the notify callback
786 * @param cb_cls closure for the callback
787 */
788void
789GNUNET_MQ_notify_sent (struct GNUNET_MQ_Envelope *ev,
790 GNUNET_SCHEDULER_TaskCallback cb,
791 void *cb_cls)
792{
793 /* allow setting *OR* clearing callback */
794 GNUNET_assert ((NULL == ev->sent_cb) || (NULL == cb));
795 ev->sent_cb = cb;
796 ev->sent_cls = cb_cls;
797}
798
799
800/**
801 * Handle we return for callbacks registered to be
802 * notified when #GNUNET_MQ_destroy() is called on a queue.
803 */
804struct GNUNET_MQ_DestroyNotificationHandle
805{
806 /**
807 * Kept in a DLL.
808 */
809 struct GNUNET_MQ_DestroyNotificationHandle *prev;
810
811 /**
812 * Kept in a DLL.
813 */
814 struct GNUNET_MQ_DestroyNotificationHandle *next;
815
816 /**
817 * Queue to notify about.
818 */
819 struct GNUNET_MQ_Handle *mq;
820
821 /**
822 * Function to call.
823 */
824 GNUNET_SCHEDULER_TaskCallback cb;
825
826 /**
827 * Closure for @e cb.
828 */
829 void *cb_cls;
830};
831
832
833/**
834 * Destroy the message queue.
835 *
836 * @param mq message queue to destroy
837 */
838void
839GNUNET_MQ_destroy (struct GNUNET_MQ_Handle *mq)
840{
841 struct GNUNET_MQ_DestroyNotificationHandle *dnh;
842
843 if (NULL != mq->destroy_impl)
844 {
845 mq->destroy_impl (mq, mq->impl_state);
846 }
847 if (NULL != mq->send_task)
848 {
849 GNUNET_SCHEDULER_cancel (mq->send_task);
850 mq->send_task = NULL;
851 }
852 while (NULL != mq->envelope_head)
853 {
854 struct GNUNET_MQ_Envelope *ev;
855
856 ev = mq->envelope_head;
857 ev->parent_queue = NULL;
858 GNUNET_CONTAINER_DLL_remove (mq->envelope_head, mq->envelope_tail, ev);
859 GNUNET_assert (0 < mq->queue_length);
860 mq->queue_length--;
861 LOG (GNUNET_ERROR_TYPE_DEBUG,
862 "MQ destroy drops message of type %u\n",
863 ntohs (ev->mh->type));
864 GNUNET_MQ_discard (ev);
865 }
866 if (NULL != mq->current_envelope)
867 {
868 /* we can only discard envelopes that
869 * are not queued! */
870 mq->current_envelope->parent_queue = NULL;
871 LOG (GNUNET_ERROR_TYPE_DEBUG,
872 "MQ destroy drops current message of type %u\n",
873 ntohs (mq->current_envelope->mh->type));
874 GNUNET_MQ_discard (mq->current_envelope);
875 mq->current_envelope = NULL;
876 GNUNET_assert (0 < mq->queue_length);
877 mq->queue_length--;
878 }
879 GNUNET_assert (0 == mq->queue_length);
880 while (NULL != (dnh = mq->dnh_head))
881 {
882 dnh->cb (dnh->cb_cls);
883 GNUNET_MQ_destroy_notify_cancel (dnh);
884 }
885 if (NULL != mq->assoc_map)
886 {
887 GNUNET_CONTAINER_multihashmap32_destroy (mq->assoc_map);
888 mq->assoc_map = NULL;
889 }
890 GNUNET_free (mq->handlers);
891 GNUNET_free (mq);
892}
893
894
895const struct GNUNET_MessageHeader *
896GNUNET_MQ_extract_nested_mh_ (const struct GNUNET_MessageHeader *mh,
897 uint16_t base_size)
898{
899 uint16_t whole_size;
900 uint16_t nested_size;
901 const struct GNUNET_MessageHeader *nested_msg;
902
903 whole_size = ntohs (mh->size);
904 GNUNET_assert (whole_size >= base_size);
905 nested_size = whole_size - base_size;
906 if (0 == nested_size)
907 return NULL;
908 if (nested_size < sizeof(struct GNUNET_MessageHeader))
909 {
910 GNUNET_break_op (0);
911 return NULL;
912 }
913 nested_msg = (const struct GNUNET_MessageHeader *) ((char *) mh + base_size);
914 if (ntohs (nested_msg->size) != nested_size)
915 {
916 GNUNET_break_op (0);
917 return NULL;
918 }
919 return nested_msg;
920}
921
922
923/**
924 * Cancel sending the message. Message must have been sent with
925 * #GNUNET_MQ_send before. May not be called after the notify sent
926 * callback has been called
927 *
928 * @param ev queued envelope to cancel
929 */
930void
931GNUNET_MQ_send_cancel (struct GNUNET_MQ_Envelope *ev)
932{
933 struct GNUNET_MQ_Handle *mq = ev->parent_queue;
934
935 GNUNET_assert (NULL != mq);
936 GNUNET_assert (NULL != mq->cancel_impl);
937
938 mq->evacuate_called = GNUNET_NO;
939
940 if (mq->current_envelope == ev)
941 {
942 /* complex case, we already started with transmitting
943 the message using the callbacks. */
944 GNUNET_assert (GNUNET_NO == mq->in_flight);
945 GNUNET_assert (0 < mq->queue_length);
946 mq->queue_length--;
947 mq->cancel_impl (mq,
948 mq->impl_state);
949 /* continue sending the next message, if any */
950 mq->current_envelope = mq->envelope_head;
951 if (NULL != mq->current_envelope)
952 {
953 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
954 mq->envelope_tail,
955 mq->current_envelope);
956
957 LOG (GNUNET_ERROR_TYPE_DEBUG,
958 "sending canceled message of type %u queue\n",
959 ntohs (ev->mh->type));
960 mq->send_impl (mq,
961 mq->current_envelope->mh,
962 mq->impl_state);
963 }
964 }
965 else
966 {
967 /* simple case, message is still waiting in the queue */
968 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
969 mq->envelope_tail,
970 ev);
971 GNUNET_assert (0 < mq->queue_length);
972 mq->queue_length--;
973 }
974
975 if (GNUNET_YES != mq->evacuate_called)
976 {
977 ev->parent_queue = NULL;
978 ev->mh = NULL;
979 /* also frees ev */
980 GNUNET_free (ev);
981 }
982}
983
984
985/**
986 * Function to obtain the current envelope
987 * from within #GNUNET_MQ_SendImpl implementations.
988 *
989 * @param mq message queue to interrogate
990 * @return the current envelope
991 */
992struct GNUNET_MQ_Envelope *
993GNUNET_MQ_get_current_envelope (struct GNUNET_MQ_Handle *mq)
994{
995 return mq->current_envelope;
996}
997
998
999/**
1000 * Function to obtain the last envelope in the queue.
1001 *
1002 * @param mq message queue to interrogate
1003 * @return the last envelope in the queue
1004 */
1005struct GNUNET_MQ_Envelope *
1006GNUNET_MQ_get_last_envelope (struct GNUNET_MQ_Handle *mq)
1007{
1008 if (NULL != mq->envelope_tail)
1009 return mq->envelope_tail;
1010
1011 return mq->current_envelope;
1012}
1013
1014
1015/**
1016 * Set application-specific preferences for this envelope.
1017 * Overrides the options set for the queue with
1018 * #GNUNET_MQ_set_options() for this message only.
1019 *
1020 * @param env message to set options for
1021 * @param pp priorities and preferences to apply
1022 */
1023void
1024GNUNET_MQ_env_set_options (struct GNUNET_MQ_Envelope *env,
1025 enum GNUNET_MQ_PriorityPreferences pp)
1026{
1027 env->priority = pp;
1028 env->have_custom_options = GNUNET_YES;
1029}
1030
1031
1032/**
1033 * Get application-specific options for this envelope.
1034 *
1035 * @param env message to set options for
1036 * @return priorities and preferences to apply for @a env
1037 */
1038enum GNUNET_MQ_PriorityPreferences
1039GNUNET_MQ_env_get_options (struct GNUNET_MQ_Envelope *env)
1040{
1041 struct GNUNET_MQ_Handle *mq = env->parent_queue;
1042
1043 if (GNUNET_YES == env->have_custom_options)
1044 return env->priority;
1045 if (NULL == mq)
1046 return 0;
1047 return mq->priority;
1048}
1049
1050
1051/**
1052 * Combine performance preferences set for different
1053 * envelopes that are being combined into one larger envelope.
1054 *
1055 * @param p1 one set of preferences
1056 * @param p2 second set of preferences
1057 * @return combined priority and preferences to use
1058 */
1059enum GNUNET_MQ_PriorityPreferences
1060GNUNET_MQ_env_combine_options (enum GNUNET_MQ_PriorityPreferences p1,
1061 enum GNUNET_MQ_PriorityPreferences p2)
1062{
1063 enum GNUNET_MQ_PriorityPreferences ret;
1064
1065 ret = GNUNET_MAX (p1 & GNUNET_MQ_PRIORITY_MASK, p2 & GNUNET_MQ_PRIORITY_MASK);
1066 ret |= ((p1 & GNUNET_MQ_PREF_UNRELIABLE) & (p2 & GNUNET_MQ_PREF_UNRELIABLE));
1067 ret |=
1068 ((p1 & GNUNET_MQ_PREF_LOW_LATENCY) | (p2 & GNUNET_MQ_PREF_LOW_LATENCY));
1069 ret |=
1070 ((p1 & GNUNET_MQ_PREF_CORK_ALLOWED) & (p2 & GNUNET_MQ_PREF_CORK_ALLOWED));
1071 ret |= ((p1 & GNUNET_MQ_PREF_GOODPUT) & (p2 & GNUNET_MQ_PREF_GOODPUT));
1072 ret |=
1073 ((p1 & GNUNET_MQ_PREF_OUT_OF_ORDER) & (p2 & GNUNET_MQ_PREF_OUT_OF_ORDER));
1074 return ret;
1075}
1076
1077
1078/**
1079 * Set application-specific default options for this queue.
1080 *
1081 * @param mq message queue to set options for
1082 * @param pp priorities and preferences to apply
1083 */
1084void
1085GNUNET_MQ_set_options (struct GNUNET_MQ_Handle *mq,
1086 enum GNUNET_MQ_PriorityPreferences pp)
1087{
1088 mq->priority = pp;
1089}
1090
1091
1092/**
1093 * Obtain message contained in envelope.
1094 *
1095 * @param env the envelope
1096 * @return message contained in the envelope
1097 */
1098const struct GNUNET_MessageHeader *
1099GNUNET_MQ_env_get_msg (const struct GNUNET_MQ_Envelope *env)
1100{
1101 return env->mh;
1102}
1103
1104
1105/**
1106 * Return next envelope in queue.
1107 *
1108 * @param env a queued envelope
1109 * @return next one, or NULL
1110 */
1111const struct GNUNET_MQ_Envelope *
1112GNUNET_MQ_env_next (const struct GNUNET_MQ_Envelope *env)
1113{
1114 return env->next;
1115}
1116
1117
1118/**
1119 * Register function to be called whenever @a mq is being
1120 * destroyed.
1121 *
1122 * @param mq message queue to watch
1123 * @param cb function to call on @a mq destruction
1124 * @param cb_cls closure for @a cb
1125 * @return handle for #GNUNET_MQ_destroy_notify_cancel().
1126 */
1127struct GNUNET_MQ_DestroyNotificationHandle *
1128GNUNET_MQ_destroy_notify (struct GNUNET_MQ_Handle *mq,
1129 GNUNET_SCHEDULER_TaskCallback cb,
1130 void *cb_cls)
1131{
1132 struct GNUNET_MQ_DestroyNotificationHandle *dnh;
1133
1134 dnh = GNUNET_new (struct GNUNET_MQ_DestroyNotificationHandle);
1135 dnh->mq = mq;
1136 dnh->cb = cb;
1137 dnh->cb_cls = cb_cls;
1138 GNUNET_CONTAINER_DLL_insert (mq->dnh_head, mq->dnh_tail, dnh);
1139 return dnh;
1140}
1141
1142
1143/**
1144 * Cancel registration from #GNUNET_MQ_destroy_notify().
1145 *
1146 * @param dnh handle for registration to cancel
1147 */
1148void
1149GNUNET_MQ_destroy_notify_cancel (struct
1150 GNUNET_MQ_DestroyNotificationHandle *dnh)
1151{
1152 struct GNUNET_MQ_Handle *mq = dnh->mq;
1153
1154 GNUNET_CONTAINER_DLL_remove (mq->dnh_head, mq->dnh_tail, dnh);
1155 GNUNET_free (dnh);
1156}
1157
1158
1159/**
1160 * Insert @a env into the envelope DLL starting at @a env_head
1161 * Note that @a env must not be in any MQ while this function
1162 * is used with DLLs defined outside of the MQ module. This
1163 * is just in case some application needs to also manage a
1164 * FIFO of envelopes independent of MQ itself and wants to
1165 * re-use the pointers internal to @a env. Use with caution.
1166 *
1167 * @param[in|out] env_head of envelope DLL
1168 * @param[in|out] env_tail tail of envelope DLL
1169 * @param[in|out] env element to insert at the tail
1170 */
1171void
1172GNUNET_MQ_dll_insert_head (struct GNUNET_MQ_Envelope **env_head,
1173 struct GNUNET_MQ_Envelope **env_tail,
1174 struct GNUNET_MQ_Envelope *env)
1175{
1176 GNUNET_CONTAINER_DLL_insert (*env_head, *env_tail, env);
1177}
1178
1179
1180/**
1181 * Insert @a env into the envelope DLL starting at @a env_head
1182 * Note that @a env must not be in any MQ while this function
1183 * is used with DLLs defined outside of the MQ module. This
1184 * is just in case some application needs to also manage a
1185 * FIFO of envelopes independent of MQ itself and wants to
1186 * re-use the pointers internal to @a env. Use with caution.
1187 *
1188 * @param[in|out] env_head of envelope DLL
1189 * @param[in|out] env_tail tail of envelope DLL
1190 * @param[in|out] env element to insert at the tail
1191 */
1192void
1193GNUNET_MQ_dll_insert_tail (struct GNUNET_MQ_Envelope **env_head,
1194 struct GNUNET_MQ_Envelope **env_tail,
1195 struct GNUNET_MQ_Envelope *env)
1196{
1197 GNUNET_CONTAINER_DLL_insert_tail (*env_head, *env_tail, env);
1198}
1199
1200
1201/**
1202 * Remove @a env from the envelope DLL starting at @a env_head.
1203 * Note that @a env must not be in any MQ while this function
1204 * is used with DLLs defined outside of the MQ module. This
1205 * is just in case some application needs to also manage a
1206 * FIFO of envelopes independent of MQ itself and wants to
1207 * re-use the pointers internal to @a env. Use with caution.
1208 *
1209 * @param[in|out] env_head of envelope DLL
1210 * @param[in|out] env_tail tail of envelope DLL
1211 * @param[in|out] env element to remove from the DLL
1212 */
1213void
1214GNUNET_MQ_dll_remove (struct GNUNET_MQ_Envelope **env_head,
1215 struct GNUNET_MQ_Envelope **env_tail,
1216 struct GNUNET_MQ_Envelope *env)
1217{
1218 GNUNET_CONTAINER_DLL_remove (*env_head, *env_tail, env);
1219}
1220
1221
1222/**
1223 * Copy an array of handlers.
1224 *
1225 * Useful if the array has been declared in local memory and needs to be
1226 * persisted for future use.
1227 *
1228 * @param handlers Array of handlers to be copied. Can be NULL (nothing done).
1229 * @return A newly allocated array of handlers.
1230 * Needs to be freed with #GNUNET_free.
1231 */
1232struct GNUNET_MQ_MessageHandler *
1233GNUNET_MQ_copy_handlers (const struct GNUNET_MQ_MessageHandler *handlers)
1234{
1235 struct GNUNET_MQ_MessageHandler *copy;
1236 unsigned int count;
1237
1238 if (NULL == handlers)
1239 return NULL;
1240
1241 count = GNUNET_MQ_count_handlers (handlers);
1242 copy = GNUNET_new_array (count + 1, struct GNUNET_MQ_MessageHandler);
1243 GNUNET_memcpy (copy,
1244 handlers,
1245 count * sizeof(struct GNUNET_MQ_MessageHandler));
1246 return copy;
1247}
1248
1249
1250/**
1251 * Copy an array of handlers, appending AGPL handler.
1252 *
1253 * Useful if the array has been declared in local memory and needs to be
1254 * persisted for future use.
1255 *
1256 * @param handlers Array of handlers to be copied. Can be NULL (nothing done).
1257 * @param agpl_handler function to call for AGPL handling
1258 * @param agpl_cls closure for @a agpl_handler
1259 * @return A newly allocated array of handlers.
1260 * Needs to be freed with #GNUNET_free.
1261 */
1262struct GNUNET_MQ_MessageHandler *
1263GNUNET_MQ_copy_handlers2 (const struct GNUNET_MQ_MessageHandler *handlers,
1264 GNUNET_MQ_MessageCallback agpl_handler,
1265 void *agpl_cls)
1266{
1267 struct GNUNET_MQ_MessageHandler *copy;
1268 unsigned int count;
1269
1270 if (NULL == handlers)
1271 return NULL;
1272 count = GNUNET_MQ_count_handlers (handlers);
1273 copy = GNUNET_new_array (count + 2, struct GNUNET_MQ_MessageHandler);
1274 GNUNET_memcpy (copy,
1275 handlers,
1276 count * sizeof(struct GNUNET_MQ_MessageHandler));
1277 copy[count].mv = NULL;
1278 copy[count].cb = agpl_handler;
1279 copy[count].cls = agpl_cls;
1280 copy[count].type = GNUNET_MESSAGE_TYPE_REQUEST_AGPL;
1281 copy[count].expected_size = sizeof(struct GNUNET_MessageHeader);
1282 return copy;
1283}
1284
1285
1286/**
1287 * Count the handlers in a handler array.
1288 *
1289 * @param handlers Array of handlers to be counted.
1290 * @return The number of handlers in the array.
1291 */
1292unsigned int
1293GNUNET_MQ_count_handlers (const struct GNUNET_MQ_MessageHandler *handlers)
1294{
1295 unsigned int i;
1296
1297 if (NULL == handlers)
1298 return 0;
1299
1300 for (i = 0; NULL != handlers[i].cb; i++)
1301 ;
1302
1303 return i;
1304}
1305
1306
1307/**
1308 * Convert an `enum GNUNET_MQ_PreferenceType` to a string
1309 *
1310 * @param type the preference type
1311 * @return a string or NULL if invalid
1312 */
1313const char *
1314GNUNET_MQ_preference_to_string (enum GNUNET_MQ_PreferenceKind type)
1315{
1316 switch (type)
1317 {
1318 case GNUNET_MQ_PREFERENCE_NONE:
1319 return "NONE";
1320
1321 case GNUNET_MQ_PREFERENCE_BANDWIDTH:
1322 return "BANDWIDTH";
1323
1324 case GNUNET_MQ_PREFERENCE_LATENCY:
1325 return "LATENCY";
1326
1327 case GNUNET_MQ_PREFERENCE_RELIABILITY:
1328 return "RELIABILITY";
1329 }
1330 ;
1331 return NULL;
1332}
1333
1334
1335/* end of mq.c */
diff --git a/src/util/mst.c b/src/util/mst.c
deleted file mode 100644
index 13835ffd0..000000000
--- a/src/util/mst.c
+++ /dev/null
@@ -1,418 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2016, 2017 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 util/mst.c
23 * @brief convenience functions for handling inbound message buffers
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30
31#if HAVE_UNALIGNED_64_ACCESS
32#define ALIGN_FACTOR 4
33#else
34#define ALIGN_FACTOR 8
35#endif
36
37#define LOG(kind, ...) GNUNET_log_from (kind, "util-mst", __VA_ARGS__)
38
39
40/**
41 * Handle to a message stream tokenizer.
42 */
43struct GNUNET_MessageStreamTokenizer
44{
45 /**
46 * Function to call on completed messages.
47 */
48 GNUNET_MessageTokenizerCallback cb;
49
50 /**
51 * Closure for @e cb.
52 */
53 void *cb_cls;
54
55 /**
56 * Size of the buffer (starting at @e hdr).
57 */
58 size_t curr_buf;
59
60 /**
61 * How many bytes in buffer have we already processed?
62 */
63 size_t off;
64
65 /**
66 * How many bytes in buffer are valid right now?
67 */
68 size_t pos;
69
70 /**
71 * Beginning of the buffer. Typed like this to force alignment.
72 */
73 struct GNUNET_MessageHeader *hdr;
74};
75
76
77/**
78 * Create a message stream tokenizer.
79 *
80 * @param cb function to call on completed messages
81 * @param cb_cls closure for @a cb
82 * @return handle to tokenizer
83 */
84struct GNUNET_MessageStreamTokenizer *
85GNUNET_MST_create (GNUNET_MessageTokenizerCallback cb,
86 void *cb_cls)
87{
88 struct GNUNET_MessageStreamTokenizer *ret;
89
90 ret = GNUNET_new (struct GNUNET_MessageStreamTokenizer);
91 ret->hdr = GNUNET_malloc (GNUNET_MIN_MESSAGE_SIZE);
92 ret->curr_buf = GNUNET_MIN_MESSAGE_SIZE;
93 ret->cb = cb;
94 ret->cb_cls = cb_cls;
95 return ret;
96}
97
98
99/**
100 * Add incoming data to the receive buffer and call the
101 * callback for all complete messages.
102 *
103 * @param mst tokenizer to use
104 * @param buf input data to add
105 * @param size number of bytes in @a buf
106 * @param purge should any excess bytes in the buffer be discarded
107 * (i.e. for packet-based services like UDP)
108 * @param one_shot only call callback once, keep rest of message in buffer
109 * @return #GNUNET_OK if we are done processing (need more data)
110 * #GNUNET_NO if @a one_shot was set and we have another message ready
111 * #GNUNET_SYSERR if the data stream is corrupt
112 */
113int
114GNUNET_MST_from_buffer (struct GNUNET_MessageStreamTokenizer *mst,
115 const char *buf,
116 size_t size,
117 int purge,
118 int one_shot)
119{
120 const struct GNUNET_MessageHeader *hdr;
121 size_t delta;
122 uint16_t want;
123 char *ibuf;
124 int need_align;
125 unsigned long offset;
126 int ret;
127 int cbret;
128
129 GNUNET_assert (mst->off <= mst->pos);
130 GNUNET_assert (mst->pos <= mst->curr_buf);
131 LOG (GNUNET_ERROR_TYPE_DEBUG,
132 "MST receives %u bytes with %u bytes already in private buffer\n",
133 (unsigned int) size,
134 (unsigned int) (mst->pos - mst->off));
135 ret = GNUNET_OK;
136 ibuf = (char *) mst->hdr;
137 while (mst->pos > 0)
138 {
139do_align:
140 GNUNET_assert (mst->pos >= mst->off);
141 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
142 (0 != (mst->off % ALIGN_FACTOR)))
143 {
144 /* need to align or need more space */
145 mst->pos -= mst->off;
146 memmove (ibuf,
147 &ibuf[mst->off],
148 mst->pos);
149 mst->off = 0;
150 }
151 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
152 {
153 delta
154 = GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
155 - (mst->pos - mst->off),
156 size);
157 GNUNET_memcpy (&ibuf[mst->pos],
158 buf,
159 delta);
160 mst->pos += delta;
161 buf += delta;
162 size -= delta;
163 }
164 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
165 {
166 if (purge)
167 {
168 mst->off = 0;
169 mst->pos = 0;
170 }
171 return GNUNET_OK;
172 }
173 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
174 want = ntohs (hdr->size);
175 if (want < sizeof(struct GNUNET_MessageHeader))
176 {
177 GNUNET_break_op (0);
178 return GNUNET_SYSERR;
179 }
180 if ((mst->curr_buf - mst->off < want) &&
181 (mst->off > 0))
182 {
183 /* can get more space by moving */
184 mst->pos -= mst->off;
185 memmove (ibuf,
186 &ibuf[mst->off],
187 mst->pos);
188 mst->off = 0;
189 }
190 if (mst->curr_buf < want)
191 {
192 /* need to get more space by growing buffer */
193 GNUNET_assert (0 == mst->off);
194 mst->hdr = GNUNET_realloc (mst->hdr,
195 want);
196 ibuf = (char *) mst->hdr;
197 mst->curr_buf = want;
198 }
199 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
200 if (mst->pos - mst->off < want)
201 {
202 delta = GNUNET_MIN (want - (mst->pos - mst->off),
203 size);
204 GNUNET_assert (mst->pos + delta <= mst->curr_buf);
205 GNUNET_memcpy (&ibuf[mst->pos],
206 buf,
207 delta);
208 mst->pos += delta;
209 buf += delta;
210 size -= delta;
211 }
212 if (mst->pos - mst->off < want)
213 {
214 if (purge)
215 {
216 mst->off = 0;
217 mst->pos = 0;
218 }
219 return GNUNET_OK;
220 }
221 if (one_shot == GNUNET_SYSERR)
222 {
223 /* cannot call callback again, but return value saying that
224 * we have another full message in the buffer */
225 ret = GNUNET_NO;
226 goto copy;
227 }
228 if (one_shot == GNUNET_YES)
229 one_shot = GNUNET_SYSERR;
230 mst->off += want;
231 if (GNUNET_OK !=
232 (cbret = mst->cb (mst->cb_cls,
233 hdr)))
234 {
235 if (GNUNET_SYSERR == cbret)
236 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
237 "Failure processing message of type %u and size %u\n",
238 ntohs (hdr->type),
239 ntohs (hdr->size));
240 return GNUNET_SYSERR;
241 }
242 if (mst->off == mst->pos)
243 {
244 /* reset to beginning of buffer, it's free right now! */
245 mst->off = 0;
246 mst->pos = 0;
247 }
248 }
249 GNUNET_assert (0 == mst->pos);
250 while (size > 0)
251 {
252 LOG (GNUNET_ERROR_TYPE_DEBUG,
253 "Server-mst has %u bytes left in inbound buffer\n",
254 (unsigned int) size);
255 if (size < sizeof(struct GNUNET_MessageHeader))
256 break;
257 offset = (unsigned long) buf;
258 need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
259 if (GNUNET_NO == need_align)
260 {
261 /* can try to do zero-copy and process directly from original buffer */
262 hdr = (const struct GNUNET_MessageHeader *) buf;
263 want = ntohs (hdr->size);
264 if (want < sizeof(struct GNUNET_MessageHeader))
265 {
266 GNUNET_break_op (0);
267 mst->off = 0;
268 return GNUNET_SYSERR;
269 }
270 if (size < want)
271 break; /* or not: buffer incomplete, so copy to private buffer... */
272 if (one_shot == GNUNET_SYSERR)
273 {
274 /* cannot call callback again, but return value saying that
275 * we have another full message in the buffer */
276 ret = GNUNET_NO;
277 goto copy;
278 }
279 if (one_shot == GNUNET_YES)
280 one_shot = GNUNET_SYSERR;
281 if (GNUNET_OK !=
282 (cbret = mst->cb (mst->cb_cls,
283 hdr)))
284 {
285 if (GNUNET_SYSERR == cbret)
286 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
287 "Failure processing message of type %u and size %u\n",
288 ntohs (hdr->type),
289 ntohs (hdr->size));
290 return GNUNET_SYSERR;
291 }
292 buf += want;
293 size -= want;
294 }
295 else
296 {
297 /* need to copy to private buffer to align;
298 * yes, we go a bit more spaghetti than usual here */
299 goto do_align;
300 }
301 }
302copy:
303 if ((size > 0) && (! purge))
304 {
305 if (size + mst->pos > mst->curr_buf)
306 {
307 mst->hdr = GNUNET_realloc (mst->hdr,
308 size + mst->pos);
309 ibuf = (char *) mst->hdr;
310 mst->curr_buf = size + mst->pos;
311 }
312 GNUNET_assert (size + mst->pos <= mst->curr_buf);
313 GNUNET_memcpy (&ibuf[mst->pos],
314 buf,
315 size);
316 mst->pos += size;
317 }
318 if (purge)
319 {
320 mst->off = 0;
321 mst->pos = 0;
322 }
323 LOG (GNUNET_ERROR_TYPE_DEBUG,
324 "Server-mst leaves %u bytes in private buffer\n",
325 (unsigned int) (mst->pos - mst->off));
326 return ret;
327}
328
329
330/**
331 * Add incoming data to the receive buffer and call the
332 * callback for all complete messages.
333 *
334 * @param mst tokenizer to use
335 * @param buf input data to add
336 * @param size number of bytes in @a buf
337 * @param purge should any excess bytes in the buffer be discarded
338 * (i.e. for packet-based services like UDP)
339 * @param one_shot only call callback once, keep rest of message in buffer
340 * @return #GNUNET_OK if we are done processing (need more data)
341 * #GNUNET_NO if one_shot was set and we have another message ready
342 * #GNUNET_SYSERR if the data stream is corrupt
343 */
344int
345GNUNET_MST_read (struct GNUNET_MessageStreamTokenizer *mst,
346 struct GNUNET_NETWORK_Handle *sock,
347 int purge,
348 int one_shot)
349{
350 ssize_t ret;
351 size_t left;
352 char *buf;
353
354 left = mst->curr_buf - mst->pos;
355 buf = (char *) mst->hdr;
356 ret = GNUNET_NETWORK_socket_recv (sock,
357 &buf[mst->pos],
358 left);
359 if (-1 == ret)
360 {
361 if ((EAGAIN == errno) ||
362 (EINTR == errno))
363 return GNUNET_OK;
364 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
365 "recv");
366 return GNUNET_SYSERR;
367 }
368 if (0 == ret)
369 {
370 /* other side closed connection, treat as error */
371 return GNUNET_SYSERR;
372 }
373 mst->pos += ret;
374 return GNUNET_MST_from_buffer (mst,
375 NULL,
376 0,
377 purge,
378 one_shot);
379}
380
381
382/**
383 * Obtain the next message from the @a mst, assuming that
384 * there are more unprocessed messages in the internal buffer
385 * of the @a mst.
386 *
387 * @param mst tokenizer to use
388 * @param one_shot only call callback once, keep rest of message in buffer
389 * @return #GNUNET_OK if we are done processing (need more data)
390 * #GNUNET_NO if one_shot was set and we have another message ready
391 * #GNUNET_SYSERR if the data stream is corrupt
392 */
393int
394GNUNET_MST_next (struct GNUNET_MessageStreamTokenizer *mst,
395 int one_shot)
396{
397 return GNUNET_MST_from_buffer (mst,
398 NULL,
399 0,
400 GNUNET_NO,
401 one_shot);
402}
403
404
405/**
406 * Destroys a tokenizer.
407 *
408 * @param mst tokenizer to destroy
409 */
410void
411GNUNET_MST_destroy (struct GNUNET_MessageStreamTokenizer *mst)
412{
413 GNUNET_free (mst->hdr);
414 GNUNET_free (mst);
415}
416
417
418/* end of server_mst.c */
diff --git a/src/util/nc.c b/src/util/nc.c
deleted file mode 100644
index 49c95c14e..000000000
--- a/src/util/nc.c
+++ /dev/null
@@ -1,227 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2016 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 util/nc.c
23 * @brief convenience functions for transmission of
24 * messages to multiple clients
25 * @author Christian Grothoff
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-nc", __VA_ARGS__)
32
33
34/**
35 * Lists of subscribers we manage for notifications.
36 */
37struct SubscriberList
38{
39 /**
40 * This is a doubly linked list.
41 */
42 struct SubscriberList *next;
43
44 /**
45 * This is a doubly linked list.
46 */
47 struct SubscriberList *prev;
48
49 /**
50 * Overall context this subscriber belongs to.
51 */
52 struct GNUNET_NotificationContext *nc;
53
54 /**
55 * Handle where we registered with @e mq to be told about
56 * the MQ's destruction.
57 */
58 struct GNUNET_MQ_DestroyNotificationHandle *mq_nh;
59
60 /**
61 * Message queue for the subscriber.
62 */
63 struct GNUNET_MQ_Handle *mq;
64};
65
66
67/**
68 * The notification context is the key datastructure for a convenience
69 * API used for transmission of notifications to the subscriber until the
70 * subscriber disconnects (or the notification context is destroyed, in
71 * which case we disconnect these subscribers). Essentially, all
72 * (notification) messages are queued up until the subscriber is able to
73 * read them.
74 */
75struct GNUNET_NotificationContext
76{
77 /**
78 * Head of list of subscribers receiving notifications.
79 */
80 struct SubscriberList *subscribers_head;
81
82 /**
83 * Tail of list of subscribers receiving notifications.
84 */
85 struct SubscriberList *subscribers_tail;
86
87 /**
88 * Maximum number of optional messages to queue per subscriber.
89 */
90 unsigned int queue_length;
91};
92
93
94/**
95 * Subscriber has disconnected, clean up.
96 *
97 * @param cls our `struct SubscriberList *`
98 */
99static void
100handle_mq_destroy (void *cls)
101{
102 struct SubscriberList *pos = cls;
103 struct GNUNET_NotificationContext *nc = pos->nc;
104
105 GNUNET_CONTAINER_DLL_remove (nc->subscribers_head,
106 nc->subscribers_tail,
107 pos);
108 GNUNET_free (pos);
109}
110
111
112/**
113 * Create a new notification context.
114 *
115 * @param queue_length maximum number of messages to keep in
116 * the notification queue; optional messages are dropped
117 * if the queue gets longer than this number of messages
118 * @return handle to the notification context
119 */
120struct GNUNET_NotificationContext *
121GNUNET_notification_context_create (unsigned int queue_length)
122{
123 struct GNUNET_NotificationContext *nc;
124
125 nc = GNUNET_new (struct GNUNET_NotificationContext);
126 nc->queue_length = queue_length;
127 return nc;
128}
129
130
131/**
132 * Destroy the context, force disconnect for all subscribers.
133 *
134 * @param nc context to destroy.
135 */
136void
137GNUNET_notification_context_destroy (struct GNUNET_NotificationContext *nc)
138{
139 struct SubscriberList *pos;
140
141 while (NULL != (pos = nc->subscribers_head))
142 {
143 GNUNET_CONTAINER_DLL_remove (nc->subscribers_head,
144 nc->subscribers_tail,
145 pos);
146 GNUNET_MQ_destroy_notify_cancel (pos->mq_nh);
147 GNUNET_free (pos);
148 }
149 GNUNET_free (nc);
150}
151
152
153/**
154 * Add a subscriber to the notification context.
155 *
156 * @param nc context to modify
157 * @param mq message queue add
158 */
159void
160GNUNET_notification_context_add (struct GNUNET_NotificationContext *nc,
161 struct GNUNET_MQ_Handle *mq)
162{
163 struct SubscriberList *cl;
164
165 for (cl = nc->subscribers_head; NULL != cl; cl = cl->next)
166 if (cl->mq == mq)
167 return;
168 /* already present */
169 cl = GNUNET_new (struct SubscriberList);
170 GNUNET_CONTAINER_DLL_insert (nc->subscribers_head,
171 nc->subscribers_tail,
172 cl);
173 cl->nc = nc;
174 cl->mq = mq;
175 cl->mq_nh = GNUNET_MQ_destroy_notify (cl->mq,
176 &handle_mq_destroy,
177 cl);
178}
179
180
181/**
182 * Send a message to all subscribers of this context.
183 *
184 * @param nc context to modify
185 * @param msg message to send
186 * @param can_drop can this message be dropped due to queue length limitations
187 */
188void
189GNUNET_notification_context_broadcast (struct GNUNET_NotificationContext *nc,
190 const struct GNUNET_MessageHeader *msg,
191 int can_drop)
192{
193 struct SubscriberList *pos;
194 struct GNUNET_MQ_Envelope *env;
195
196 for (pos = nc->subscribers_head; NULL != pos; pos = pos->next)
197 {
198 if ((GNUNET_YES == can_drop) &&
199 (GNUNET_MQ_get_length (pos->mq) > nc->queue_length))
200 continue;
201 env = GNUNET_MQ_msg_copy (msg);
202 GNUNET_MQ_send (pos->mq,
203 env);
204 }
205}
206
207
208/**
209 * Return active number of subscribers in this context.
210 *
211 * @param nc context to query
212 * @return number of current subscribers
213 */
214unsigned int
215GNUNET_notification_context_get_size (struct GNUNET_NotificationContext *nc)
216{
217 unsigned int num;
218 struct SubscriberList *pos;
219
220 num = 0;
221 for (pos = nc->subscribers_head; NULL != pos; pos = pos->next)
222 num++;
223 return num;
224}
225
226
227/* end of nc.c */
diff --git a/src/util/network.c b/src/util/network.c
deleted file mode 100644
index 688c37665..000000000
--- a/src/util/network.c
+++ /dev/null
@@ -1,1333 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 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 util/network.c
23 * @brief basic, low-level networking interface
24 * @author Nils Durner
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "disk.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-network", __VA_ARGS__)
32#define LOG_STRERROR_FILE(kind, syscall, \
33 filename) GNUNET_log_from_strerror_file (kind, \
34 "util-network", \
35 syscall, \
36 filename)
37#define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \
38 "util-network", \
39 syscall)
40
41#define DEBUG_NETWORK GNUNET_EXTRA_LOGGING
42
43
44#ifndef INVALID_SOCKET
45#define INVALID_SOCKET -1
46#endif
47
48
49/**
50 * @brief handle to a socket
51 */
52struct GNUNET_NETWORK_Handle
53{
54 int fd;
55
56 /**
57 * Address family / domain.
58 */
59 int af;
60
61 /**
62 * Type of the socket
63 */
64 int type;
65
66 /**
67 * Number of bytes in addr.
68 */
69 socklen_t addrlen;
70
71 /**
72 * Address we were bound to, or NULL.
73 */
74 struct sockaddr *addr;
75};
76
77
78enum GNUNET_GenericReturnValue
79GNUNET_NETWORK_test_pf (int pf)
80{
81 static int cache_v4 = -1;
82 static int cache_v6 = -1;
83 static int cache_un = -1;
84 int s;
85 int ret;
86
87 switch (pf)
88 {
89 case PF_INET:
90 if (-1 != cache_v4)
91 return cache_v4;
92 break;
93
94 case PF_INET6:
95 if (-1 != cache_v6)
96 return cache_v6;
97 break;
98
99#ifdef PF_UNIX
100 case PF_UNIX:
101 if (-1 != cache_un)
102 return cache_un;
103 break;
104#endif
105 }
106 s = socket (pf, SOCK_STREAM, 0);
107 if (-1 == s)
108 {
109 if (EAFNOSUPPORT != errno)
110 {
111 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
112 "socket");
113 return GNUNET_SYSERR;
114 }
115 ret = GNUNET_NO;
116 }
117 else
118 {
119 GNUNET_break (0 == close (s));
120 ret = GNUNET_OK;
121 }
122 switch (pf)
123 {
124 case PF_INET:
125 cache_v4 = ret;
126 break;
127
128 case PF_INET6:
129 cache_v6 = ret;
130 break;
131
132#ifdef PF_UNIX
133 case PF_UNIX:
134 cache_un = ret;
135 break;
136#endif
137 }
138 return ret;
139}
140
141
142char *
143GNUNET_NETWORK_shorten_unixpath (char *unixpath)
144{
145 struct sockaddr_un dummy;
146 size_t slen;
147 char *end;
148 struct GNUNET_HashCode sh;
149 struct GNUNET_CRYPTO_HashAsciiEncoded ae;
150 size_t upm;
151
152 upm = sizeof(dummy.sun_path);
153 slen = strlen (unixpath);
154 if (slen < upm)
155 return unixpath; /* no shortening required */
156 GNUNET_CRYPTO_hash (unixpath, slen, &sh);
157 while (16 + strlen (unixpath) >= upm)
158 {
159 if (NULL == (end = strrchr (unixpath, '/')))
160 {
161 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
162 _ (
163 "Unable to shorten unix path `%s' while keeping name unique\n"),
164 unixpath);
165 GNUNET_free (unixpath);
166 return NULL;
167 }
168 *end = '\0';
169 }
170 GNUNET_CRYPTO_hash_to_enc (&sh, &ae);
171 ae.encoding[16] = '\0';
172 strcat (unixpath, (char *) ae.encoding);
173 return unixpath;
174}
175
176
177void
178GNUNET_NETWORK_unix_precheck (const struct sockaddr_un *un)
179{
180 int s;
181 int eno;
182 struct stat sbuf;
183 int ret;
184
185 s = socket (AF_UNIX, SOCK_STREAM, 0);
186 if (-1 == s)
187 {
188 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
189 "Failed to open AF_UNIX socket");
190 return;
191 }
192 ret = connect (s,
193 (struct sockaddr *) un,
194 sizeof(struct sockaddr_un));
195 eno = errno;
196 GNUNET_break (0 == close (s));
197 if (0 == ret)
198 return; /* another process is listening, do not remove! */
199 if (ECONNREFUSED != eno)
200 return; /* some other error, likely "no such file or directory" -- all well */
201 /* should unlink, but sanity checks first */
202 if (0 != stat (un->sun_path,
203 &sbuf))
204 return; /* failed to 'stat', likely does not exist after all */
205 if (S_IFSOCK != (S_IFMT & sbuf.st_mode))
206 return; /* refuse to unlink anything except sockets */
207 /* finally, really unlink */
208 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
209 "Removing left-over `%s' from previous exeuction\n",
210 un->sun_path);
211 if (0 != unlink (un->sun_path))
212 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
213 "unlink",
214 un->sun_path);
215}
216
217
218#ifndef FD_COPY
219#define FD_COPY(s, d) do { GNUNET_memcpy ((d), (s), sizeof(fd_set)); } while (0)
220#endif
221
222
223enum GNUNET_GenericReturnValue
224GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Handle *fd,
225 int doBlock)
226{
227 int flags = fcntl (fd->fd, F_GETFL);
228
229 if (flags == -1)
230 {
231 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
232 "fcntl");
233 return GNUNET_SYSERR;
234 }
235 if (doBlock)
236 flags &= ~O_NONBLOCK;
237
238 else
239 flags |= O_NONBLOCK;
240 if (0 != fcntl (fd->fd,
241 F_SETFL,
242 flags))
243
244 {
245 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
246 "fcntl");
247 return GNUNET_SYSERR;
248 }
249 return GNUNET_OK;
250}
251
252
253/**
254 * Make a socket non-inheritable to child processes
255 *
256 * @param h the socket to make non-inheritable
257 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
258 * @warning Not implemented on Windows
259 */
260static int
261socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h)
262{
263 int i;
264 i = fcntl (h->fd, F_GETFD);
265 if (i < 0)
266 return GNUNET_SYSERR;
267 if (i == (i | FD_CLOEXEC))
268 return GNUNET_OK;
269 i |= FD_CLOEXEC;
270 if (fcntl (h->fd, F_SETFD, i) < 0)
271 return GNUNET_SYSERR;
272
273 return GNUNET_OK;
274}
275
276
277#ifdef DARWIN
278/**
279 * The MSG_NOSIGNAL equivalent on Mac OS X
280 *
281 * @param h the socket to make non-delaying
282 */
283static int
284socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
285{
286 int abs_value = 1;
287
288 if (0 !=
289 setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE,
290 (const void *) &abs_value,
291 sizeof(abs_value)))
292 return GNUNET_SYSERR;
293 return GNUNET_OK;
294}
295
296
297#endif
298
299
300/**
301 * Disable delays when sending data via the socket.
302 * (GNUnet makes sure that messages are as big as
303 * possible already).
304 *
305 * @param h the socket to make non-delaying
306 */
307static void
308socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h)
309{
310 int value = 1;
311
312 if (0 !=
313 setsockopt (h->fd,
314 IPPROTO_TCP,
315 TCP_NODELAY,
316 &value, sizeof(value)))
317 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
318 "setsockopt");
319}
320
321
322/**
323 * Perform proper canonical initialization for a network handle.
324 * Set it to non-blocking, make it non-inheritable to child
325 * processes, disable SIGPIPE, enable "nodelay" (if non-UNIX
326 * stream socket) and check that it is smaller than FD_SETSIZE.
327 *
328 * @param h socket to initialize
329 * @param af address family of the socket
330 * @param type socket type
331 * @return #GNUNET_OK on success, #GNUNET_SYSERR if initialization
332 * failed and the handle was destroyed
333 */
334static int
335initialize_network_handle (struct GNUNET_NETWORK_Handle *h,
336 int af,
337 int type)
338{
339 int eno;
340
341 h->af = af;
342 h->type = type;
343 if (h->fd == INVALID_SOCKET)
344 {
345 eno = errno;
346 GNUNET_free (h);
347 errno = eno;
348 return GNUNET_SYSERR;
349 }
350
351 if (h->fd >= FD_SETSIZE)
352 {
353 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
354 errno = EMFILE;
355 return GNUNET_SYSERR;
356 }
357
358 if (GNUNET_OK != socket_set_inheritable (h))
359 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
360 "socket_set_inheritable");
361
362 if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (h, GNUNET_NO))
363 {
364 eno = errno;
365 GNUNET_break (0);
366 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
367 errno = eno;
368 return GNUNET_SYSERR;
369 }
370#ifdef DARWIN
371 if (GNUNET_SYSERR == socket_set_nosigpipe (h))
372 {
373 eno = errno;
374 GNUNET_break (0);
375 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
376 errno = eno;
377 return GNUNET_SYSERR;
378 }
379#endif
380 if ((type == SOCK_STREAM)
381#ifdef AF_UNIX
382 && (af != AF_UNIX)
383#endif
384 )
385 socket_set_nodelay (h);
386 return GNUNET_OK;
387}
388
389
390struct GNUNET_NETWORK_Handle *
391GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
392 struct sockaddr *address,
393 socklen_t *address_len)
394{
395 struct GNUNET_NETWORK_Handle *ret;
396 int eno;
397
398 ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
399#if DEBUG_NETWORK
400 {
401 struct sockaddr_storage name;
402 socklen_t namelen = sizeof(name);
403
404 int gsn = getsockname (desc->fd,
405 (struct sockaddr *) &name,
406 &namelen);
407
408 if (0 == gsn)
409 LOG (GNUNET_ERROR_TYPE_DEBUG,
410 "Accepting connection on `%s'\n",
411 GNUNET_a2s ((const struct sockaddr *) &name,
412 namelen));
413 }
414#endif
415 ret->fd = accept (desc->fd,
416 address,
417 address_len);
418 if (-1 == ret->fd)
419 {
420 eno = errno;
421 GNUNET_free (ret);
422 errno = eno;
423 return NULL;
424 }
425 if (GNUNET_OK !=
426 initialize_network_handle (ret,
427 (NULL != address) ? address->sa_family :
428 desc->af,
429 SOCK_STREAM))
430 {
431 return NULL;
432 }
433 return ret;
434}
435
436
437enum GNUNET_GenericReturnValue
438GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
439 const struct sockaddr *address,
440 socklen_t address_len)
441{
442 int ret;
443
444#ifdef IPV6_V6ONLY
445#ifdef IPPROTO_IPV6
446 {
447 const int on = 1;
448
449 if (AF_INET6 == desc->af)
450 if (setsockopt (desc->fd,
451 IPPROTO_IPV6,
452 IPV6_V6ONLY,
453 (const void *) &on,
454 sizeof(on)))
455 LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
456 "setsockopt");
457 }
458#endif
459#endif
460 if (AF_UNIX == address->sa_family)
461 GNUNET_NETWORK_unix_precheck ((const struct sockaddr_un *) address);
462
463 {
464 const int on = 1;
465
466 if ( (SOCK_STREAM == desc->type) &&
467 (0 != setsockopt (desc->fd,
468 SOL_SOCKET,
469 SO_REUSEADDR,
470 &on, sizeof(on))) )
471 LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
472 "setsockopt");
473 }
474 {
475 /* set permissions of newly created non-abstract UNIX domain socket to
476 "user-only"; applications can choose to relax this later */
477 mode_t old_mask = 0; /* assigned to make compiler happy */
478 const struct sockaddr_un *un = (const struct sockaddr_un *) address;
479 int not_abstract = 0;
480
481 if ((AF_UNIX == address->sa_family)
482 && ('\0' != un->sun_path[0])) /* Not an abstract socket */
483 not_abstract = 1;
484 if (not_abstract)
485 old_mask = umask (S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH
486 | S_IXOTH);
487
488 ret = bind (desc->fd,
489 address,
490 address_len);
491
492 if (not_abstract)
493 (void) umask (old_mask);
494 }
495 if (0 != ret)
496 return GNUNET_SYSERR;
497
498 desc->addr = GNUNET_malloc (address_len);
499 GNUNET_memcpy (desc->addr, address, address_len);
500 desc->addrlen = address_len;
501
502 return GNUNET_OK;
503}
504
505
506enum GNUNET_GenericReturnValue
507GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
508{
509 int ret;
510
511 ret = close (desc->fd);
512
513 const struct sockaddr_un *un = (const struct sockaddr_un *) desc->addr;
514
515 /* Cleanup the UNIX domain socket and its parent directories in case of non
516 abstract sockets */
517 if ((AF_UNIX == desc->af) &&
518 (NULL != desc->addr) &&
519 ('\0' != un->sun_path[0]))
520 {
521 char *dirname = GNUNET_strndup (un->sun_path,
522 sizeof(un->sun_path));
523
524 if (0 != unlink (dirname))
525 {
526 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
527 "unlink",
528 dirname);
529 }
530 else
531 {
532 size_t len;
533
534 len = strlen (dirname);
535 while ((len > 0) && (dirname[len] != DIR_SEPARATOR))
536 len--;
537 dirname[len] = '\0';
538 if ((0 != len) && (0 != rmdir (dirname)))
539 {
540 switch (errno)
541 {
542 case EACCES:
543 case ENOTEMPTY:
544 case EPERM:
545 /* these are normal and can just be ignored */
546 break;
547
548 default:
549 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
550 "rmdir",
551 dirname);
552 break;
553 }
554 }
555 }
556 GNUNET_free (dirname);
557 }
558 GNUNET_NETWORK_socket_free_memory_only_ (desc);
559 return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;
560}
561
562
563/**
564 * Only free memory of a socket, keep the file descriptor untouched.
565 *
566 * @param desc socket
567 */
568void
569GNUNET_NETWORK_socket_free_memory_only_ (struct GNUNET_NETWORK_Handle *desc)
570{
571 GNUNET_free (desc->addr);
572 GNUNET_free (desc);
573}
574
575
576/**
577 * Box a native socket (and check that it is a socket).
578 *
579 * @param fd socket to box
580 * @return NULL on error (including not supported on target platform)
581 */
582struct GNUNET_NETWORK_Handle *
583GNUNET_NETWORK_socket_box_native (int fd)
584{
585 struct GNUNET_NETWORK_Handle *ret;
586
587 if (fcntl (fd, F_GETFD) < 0)
588 return NULL; /* invalid FD */
589 ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
590 ret->fd = fd;
591 ret->af = AF_UNSPEC;
592 return ret;
593}
594
595
596/**
597 * Connect a socket to some remote address.
598 *
599 * @param desc socket
600 * @param address peer address
601 * @param address_len length of @a address
602 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
603 */
604int
605GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,
606 const struct sockaddr *address,
607 socklen_t address_len)
608{
609 int ret;
610
611 ret = connect (desc->fd,
612 address,
613 address_len);
614
615 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
616}
617
618
619/**
620 * Get socket options
621 *
622 * @param desc socket
623 * @param level protocol level of the option
624 * @param optname identifier of the option
625 * @param optval options
626 * @param optlen length of @a optval
627 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
628 */
629int
630GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,
631 int level,
632 int optname,
633 void *optval,
634 socklen_t *optlen)
635{
636 int ret;
637
638 ret = getsockopt (desc->fd,
639 level,
640 optname,
641 optval, optlen);
642
643 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
644}
645
646
647/**
648 * Listen on a socket
649 *
650 * @param desc socket
651 * @param backlog length of the listen queue
652 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
653 */
654int
655GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
656 int backlog)
657{
658 int ret;
659
660 ret = listen (desc->fd,
661 backlog);
662
663 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
664}
665
666
667/**
668 * How much data is available to be read on this descriptor?
669 *
670 * @param desc socket
671 * @returns #GNUNET_SYSERR if no data is available, or on error!
672 */
673ssize_t
674GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle *desc)
675{
676 int error;
677
678 /* How much is there to be read? */
679 int pending;
680
681 error = ioctl (desc->fd,
682 FIONREAD,
683 &pending);
684 if (0 == error)
685 return (ssize_t) pending;
686 return GNUNET_SYSERR;
687}
688
689
690/**
691 * Read data from a socket (always non-blocking).
692 *
693 * @param desc socket
694 * @param buffer buffer
695 * @param length length of @a buffer
696 * @param src_addr either the source to recv from, or all zeroes
697 * to be filled in by recvfrom
698 * @param addrlen length of the @a src_addr
699 */
700ssize_t
701GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle *desc,
702 void *buffer,
703 size_t length,
704 struct sockaddr *src_addr,
705 socklen_t *addrlen)
706{
707 int flags = 0;
708
709#ifdef MSG_DONTWAIT
710 flags |= MSG_DONTWAIT;
711#endif
712 return recvfrom (desc->fd,
713 buffer,
714 length,
715 flags,
716 src_addr,
717 addrlen);
718}
719
720
721/**
722 * Read data from a connected socket (always non-blocking).
723 *
724 * @param desc socket
725 * @param buffer buffer
726 * @param length length of @a buffer
727 * @return number of bytes received, -1 on error
728 */
729ssize_t
730GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle *desc,
731 void *buffer,
732 size_t length)
733{
734 int ret;
735 int flags;
736
737 flags = 0;
738
739#ifdef MSG_DONTWAIT
740 flags |= MSG_DONTWAIT;
741#endif
742 ret = recv (desc->fd,
743 buffer,
744 length,
745 flags);
746 return ret;
747}
748
749
750/**
751 * Send data (always non-blocking).
752 *
753 * @param desc socket
754 * @param buffer data to send
755 * @param length size of the @a buffer
756 * @return number of bytes sent, #GNUNET_SYSERR on error
757 */
758ssize_t
759GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle *desc,
760 const void *buffer,
761 size_t length)
762{
763 int ret;
764 int flags;
765
766 flags = 0;
767#ifdef MSG_DONTWAIT
768 flags |= MSG_DONTWAIT;
769#endif
770#ifdef MSG_NOSIGNAL
771 flags |= MSG_NOSIGNAL;
772#endif
773 ret = send (desc->fd,
774 buffer,
775 length,
776 flags);
777 return ret;
778}
779
780
781/**
782 * Send data to a particular destination (always non-blocking).
783 * This function only works for UDP sockets.
784 *
785 * @param desc socket
786 * @param message data to send
787 * @param length size of the @a message
788 * @param dest_addr destination address
789 * @param dest_len length of @a address
790 * @return number of bytes sent, #GNUNET_SYSERR on error
791 */
792ssize_t
793GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle *desc,
794 const void *message,
795 size_t length,
796 const struct sockaddr *dest_addr,
797 socklen_t dest_len)
798{
799 int flags = 0;
800
801#ifdef MSG_DONTWAIT
802 flags |= MSG_DONTWAIT;
803#endif
804#ifdef MSG_NOSIGNAL
805 flags |= MSG_NOSIGNAL;
806#endif
807 return sendto (desc->fd,
808 message,
809 length,
810 flags,
811 dest_addr,
812 dest_len);
813}
814
815
816/**
817 * Set socket option
818 *
819 * @param fd socket
820 * @param level protocol level of the option
821 * @param option_name option identifier
822 * @param option_value value to set
823 * @param option_len size of @a option_value
824 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
825 */
826int
827GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd,
828 int level,
829 int option_name,
830 const void *option_value,
831 socklen_t option_len)
832{
833 return (0 == setsockopt (fd->fd,
834 level,
835 option_name,
836 option_value,
837 option_len))
838 ? GNUNET_OK
839 : GNUNET_SYSERR;
840}
841
842
843/**
844 * Create a new socket. Configure it for non-blocking IO and
845 * mark it as non-inheritable to child processes (set the
846 * close-on-exec flag).
847 *
848 * @param domain domain of the socket
849 * @param type socket type
850 * @param protocol network protocol
851 * @return new socket, NULL on error
852 */
853struct GNUNET_NETWORK_Handle *
854GNUNET_NETWORK_socket_create (int domain,
855 int type,
856 int protocol)
857{
858 struct GNUNET_NETWORK_Handle *ret;
859 int fd;
860
861 fd = socket (domain, type, protocol);
862 if (-1 == fd)
863 return NULL;
864 ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
865 ret->fd = fd;
866 if (GNUNET_OK !=
867 initialize_network_handle (ret,
868 domain,
869 type))
870 return NULL;
871 return ret;
872}
873
874
875/**
876 * Shut down socket operations
877 * @param desc socket
878 * @param how type of shutdown
879 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
880 */
881int
882GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc,
883 int how)
884{
885 int ret;
886
887 ret = shutdown (desc->fd, how);
888
889 return (0 == ret) ? GNUNET_OK : GNUNET_SYSERR;
890}
891
892
893/**
894 * Disable the "CORK" feature for communication with the given socket,
895 * forcing the OS to immediately flush the buffer on transmission
896 * instead of potentially buffering multiple messages. Essentially
897 * reduces the OS send buffers to zero.
898 *
899 * @param desc socket
900 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
901 */
902int
903GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc)
904{
905 int ret = 0;
906
907#ifdef __linux__
908 int value = 0;
909
910 if (0 !=
911 (ret =
912 setsockopt (desc->fd,
913 SOL_SOCKET,
914 SO_SNDBUF,
915 &value,
916 sizeof(value))))
917 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
918 "setsockopt");
919 if (0 !=
920 (ret =
921 setsockopt (desc->fd,
922 SOL_SOCKET,
923 SO_RCVBUF,
924 &value,
925 sizeof(value))))
926 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
927 "setsockopt");
928#endif
929 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
930}
931
932
933/**
934 * Reset FD set
935 *
936 * @param fds fd set
937 */
938void
939GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
940{
941 FD_ZERO (&fds->sds);
942 fds->nsds = 0;
943}
944
945
946/**
947 * Add a socket to the FD set
948 *
949 * @param fds fd set
950 * @param desc socket to add
951 */
952void
953GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,
954 const struct GNUNET_NETWORK_Handle *desc)
955{
956 FD_SET (desc->fd,
957 &fds->sds);
958 fds->nsds = GNUNET_MAX (fds->nsds,
959 desc->fd + 1);
960}
961
962
963/**
964 * Check whether a socket is part of the fd set
965 *
966 * @param fds fd set
967 * @param desc socket
968 * @return 0 if the FD is not set
969 */
970int
971GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,
972 const struct GNUNET_NETWORK_Handle *desc)
973{
974 return FD_ISSET (desc->fd,
975 &fds->sds);
976}
977
978
979/**
980 * Add one fd set to another
981 *
982 * @param dst the fd set to add to
983 * @param src the fd set to add from
984 */
985void
986GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
987 const struct GNUNET_NETWORK_FDSet *src)
988{
989 int nfds;
990
991 for (nfds = src->nsds; nfds >= 0; nfds--)
992 if (FD_ISSET (nfds, &src->sds))
993 FD_SET (nfds, &dst->sds);
994 dst->nsds = GNUNET_MAX (dst->nsds,
995 src->nsds);
996}
997
998
999/**
1000 * Copy one fd set to another
1001 *
1002 * @param to destination
1003 * @param from source
1004 */
1005void
1006GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
1007 const struct GNUNET_NETWORK_FDSet *from)
1008{
1009 FD_COPY (&from->sds,
1010 &to->sds);
1011 to->nsds = from->nsds;
1012}
1013
1014
1015/**
1016 * Return file descriptor for this network handle
1017 *
1018 * @param desc wrapper to process
1019 * @return POSIX file descriptor
1020 */
1021int
1022GNUNET_NETWORK_get_fd (const struct GNUNET_NETWORK_Handle *desc)
1023{
1024 return desc->fd;
1025}
1026
1027
1028/**
1029 * Return sockaddr for this network handle
1030 *
1031 * @param desc wrapper to process
1032 * @return sockaddr
1033 */
1034struct sockaddr*
1035GNUNET_NETWORK_get_addr (const struct GNUNET_NETWORK_Handle *desc)
1036{
1037 return desc->addr;
1038}
1039
1040
1041/**
1042 * Return sockaddr length for this network handle
1043 *
1044 * @param desc wrapper to process
1045 * @return socklen_t for sockaddr
1046 */
1047socklen_t
1048GNUNET_NETWORK_get_addrlen (const struct GNUNET_NETWORK_Handle *desc)
1049{
1050 return desc->addrlen;
1051}
1052
1053
1054/**
1055 * Copy a native fd set
1056 *
1057 * @param to destination
1058 * @param from native source set
1059 * @param nfds the biggest socket number in from + 1
1060 */
1061void
1062GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
1063 const fd_set *from,
1064 int nfds)
1065{
1066 FD_COPY (from,
1067 &to->sds);
1068 to->nsds = nfds;
1069}
1070
1071
1072/**
1073 * Set a native fd in a set
1074 *
1075 * @param to destination
1076 * @param nfd native FD to set
1077 */
1078void
1079GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to,
1080 int nfd)
1081{
1082 GNUNET_assert ((nfd >= 0) && (nfd < FD_SETSIZE));
1083 FD_SET (nfd, &to->sds);
1084 to->nsds = GNUNET_MAX (nfd + 1,
1085 to->nsds);
1086}
1087
1088
1089/**
1090 * Test native fd in a set
1091 *
1092 * @param to set to test, NULL for empty set
1093 * @param nfd native FD to test, or -1 for none
1094 * @return #GNUNET_YES if FD is set in the set
1095 */
1096int
1097GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to,
1098 int nfd)
1099{
1100 if ((-1 == nfd) ||
1101 (NULL == to))
1102 return GNUNET_NO;
1103 return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO;
1104}
1105
1106
1107/**
1108 * Add a file handle to the fd set
1109 * @param fds fd set
1110 * @param h the file handle to add
1111 */
1112void
1113GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
1114 const struct GNUNET_DISK_FileHandle *h)
1115{
1116 int fd;
1117
1118 GNUNET_assert (GNUNET_OK ==
1119 GNUNET_DISK_internal_file_handle_ (h,
1120 &fd,
1121 sizeof(int)));
1122 FD_SET (fd,
1123 &fds->sds);
1124 fds->nsds = GNUNET_MAX (fd + 1,
1125 fds->nsds);
1126}
1127
1128
1129/**
1130 * Add a file handle to the fd set
1131 * @param fds fd set
1132 * @param h the file handle to add
1133 */
1134void
1135GNUNET_NETWORK_fdset_handle_set_first (struct GNUNET_NETWORK_FDSet *fds,
1136 const struct GNUNET_DISK_FileHandle *h)
1137{
1138 GNUNET_NETWORK_fdset_handle_set (fds, h);
1139}
1140
1141
1142/**
1143 * Check if a file handle is part of an fd set
1144 *
1145 * @param fds fd set
1146 * @param h file handle
1147 * @return #GNUNET_YES if the file handle is part of the set
1148 */
1149int
1150GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
1151 const struct GNUNET_DISK_FileHandle *h)
1152{
1153 return FD_ISSET (h->fd,
1154 &fds->sds);
1155}
1156
1157
1158/**
1159 * Checks if two fd sets overlap
1160 *
1161 * @param fds1 first fd set
1162 * @param fds2 second fd set
1163 * @return #GNUNET_YES if they do overlap, #GNUNET_NO otherwise
1164 */
1165int
1166GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
1167 const struct GNUNET_NETWORK_FDSet *fds2)
1168{
1169 int nfds;
1170
1171 nfds = GNUNET_MIN (fds1->nsds,
1172 fds2->nsds);
1173 while (nfds > 0)
1174 {
1175 nfds--;
1176 if ((FD_ISSET (nfds,
1177 &fds1->sds)) &&
1178 (FD_ISSET (nfds,
1179 &fds2->sds)))
1180 return GNUNET_YES;
1181 }
1182 return GNUNET_NO;
1183}
1184
1185
1186/**
1187 * Creates an fd set
1188 *
1189 * @return a new fd set
1190 */
1191struct GNUNET_NETWORK_FDSet *
1192GNUNET_NETWORK_fdset_create ()
1193{
1194 struct GNUNET_NETWORK_FDSet *fds;
1195
1196 fds = GNUNET_new (struct GNUNET_NETWORK_FDSet);
1197 GNUNET_NETWORK_fdset_zero (fds);
1198 return fds;
1199}
1200
1201
1202/**
1203 * Releases the associated memory of an fd set
1204 *
1205 * @param fds fd set
1206 */
1207void
1208GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
1209{
1210 GNUNET_free (fds);
1211}
1212
1213
1214/**
1215 * Test if the given @a port is available.
1216 *
1217 * @param ipproto transport protocol to test (e.g. IPPROTO_TCP)
1218 * @param port port number to test
1219 * @return #GNUNET_OK if the port is available, #GNUNET_NO if not
1220 */
1221int
1222GNUNET_NETWORK_test_port_free (int ipproto,
1223 uint16_t port)
1224{
1225 struct GNUNET_NETWORK_Handle *socket;
1226 int bind_status;
1227 int socktype;
1228 char open_port_str[6];
1229 struct addrinfo hint;
1230 struct addrinfo *ret;
1231 struct addrinfo *ai;
1232
1233 GNUNET_snprintf (open_port_str,
1234 sizeof(open_port_str),
1235 "%u",
1236 (unsigned int) port);
1237 socktype = (IPPROTO_TCP == ipproto) ? SOCK_STREAM : SOCK_DGRAM;
1238 ret = NULL;
1239 memset (&hint, 0, sizeof(hint));
1240 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
1241 hint.ai_socktype = socktype;
1242 hint.ai_protocol = ipproto;
1243 hint.ai_addrlen = 0;
1244 hint.ai_addr = NULL;
1245 hint.ai_canonname = NULL;
1246 hint.ai_next = NULL;
1247 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
1248 GNUNET_assert (0 == getaddrinfo (NULL,
1249 open_port_str,
1250 &hint,
1251 &ret));
1252 bind_status = GNUNET_NO;
1253 for (ai = ret; NULL != ai; ai = ai->ai_next)
1254 {
1255 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
1256 ai->ai_socktype,
1257 ai->ai_protocol);
1258 if (NULL == socket)
1259 continue;
1260 bind_status = GNUNET_NETWORK_socket_bind (socket,
1261 ai->ai_addr,
1262 ai->ai_addrlen);
1263 GNUNET_NETWORK_socket_close (socket);
1264 if (GNUNET_OK != bind_status)
1265 break;
1266 }
1267 freeaddrinfo (ret);
1268 return bind_status;
1269}
1270
1271
1272/**
1273 * Check if sockets or pipes meet certain conditions
1274 *
1275 * @param rfds set of sockets or pipes to be checked for readability
1276 * @param wfds set of sockets or pipes to be checked for writability
1277 * @param efds set of sockets or pipes to be checked for exceptions
1278 * @param timeout relative value when to return
1279 * @return number of selected sockets or pipes, #GNUNET_SYSERR on error
1280 */
1281int
1282GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1283 struct GNUNET_NETWORK_FDSet *wfds,
1284 struct GNUNET_NETWORK_FDSet *efds,
1285 const struct GNUNET_TIME_Relative timeout)
1286{
1287 int nfds;
1288 struct timeval tv;
1289
1290 if (NULL != rfds)
1291 nfds = rfds->nsds;
1292 else
1293 nfds = 0;
1294 if (NULL != wfds)
1295 nfds = GNUNET_MAX (nfds,
1296 wfds->nsds);
1297 if (NULL != efds)
1298 nfds = GNUNET_MAX (nfds,
1299 efds->nsds);
1300 if ((0 == nfds) &&
1301 (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us))
1302 {
1303 GNUNET_break (0);
1304 LOG (GNUNET_ERROR_TYPE_ERROR,
1305 _ (
1306 "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),
1307 "select");
1308 }
1309 if (timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us > (unsigned
1310 long long)
1311 LONG_MAX)
1312 {
1313 tv.tv_sec = LONG_MAX;
1314 tv.tv_usec = 999999L;
1315 }
1316 else
1317 {
1318 tv.tv_sec = (long) (timeout.rel_value_us
1319 / GNUNET_TIME_UNIT_SECONDS.rel_value_us);
1320 tv.tv_usec =
1321 (timeout.rel_value_us
1322 - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value_us));
1323 }
1324 return select (nfds,
1325 (NULL != rfds) ? &rfds->sds : NULL,
1326 (NULL != wfds) ? &wfds->sds : NULL,
1327 (NULL != efds) ? &efds->sds : NULL,
1328 (timeout.rel_value_us ==
1329 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) ? NULL : &tv);
1330}
1331
1332
1333/* end of network.c */
diff --git a/src/util/op.c b/src/util/op.c
deleted file mode 100644
index 647fedb53..000000000
--- a/src/util/op.c
+++ /dev/null
@@ -1,334 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 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
23 * Asynchronous operations; register callbacks for operations and call them when a response arrives.
24 *
25 * @author Gabor X Toth
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_util_lib.h"
32
33#define LOG(kind, ...) GNUNET_log_from (kind, "util-op", __VA_ARGS__)
34
35struct OperationListItem
36{
37 struct OperationListItem *prev;
38 struct OperationListItem *next;
39
40 /**
41 * Operation ID.
42 */
43 uint64_t op_id;
44
45 /**
46 * Continuation to invoke with the result of an operation.
47 */
48 GNUNET_ResultCallback result_cb;
49
50 /**
51 * Closure for @a result_cb.
52 */
53 void *cls;
54
55 /**
56 * User context.
57 */
58 void *ctx;
59};
60
61
62/**
63 * Operations handle.
64 */
65
66struct GNUNET_OP_Handle
67{
68 /**
69 * First operation in the linked list.
70 */
71 struct OperationListItem *op_head;
72
73 /**
74 * Last operation in the linked list.
75 */
76 struct OperationListItem *op_tail;
77
78 /**
79 * Last operation ID used.
80 */
81 uint64_t last_op_id;
82};
83
84
85/**
86 * Create new operations handle.
87 */
88struct GNUNET_OP_Handle *
89GNUNET_OP_create ()
90{
91 return GNUNET_new (struct GNUNET_OP_Handle);
92}
93
94
95/**
96 * Destroy operations handle.
97 */
98void
99GNUNET_OP_destroy (struct GNUNET_OP_Handle *h)
100{
101 GNUNET_free (h);
102}
103
104
105/**
106 * Get a unique operation ID to distinguish between asynchronous requests.
107 *
108 * @param h
109 * Operations handle.
110 *
111 * @return Operation ID to use.
112 */
113uint64_t
114GNUNET_OP_get_next_id (struct GNUNET_OP_Handle *h)
115{
116 return ++h->last_op_id;
117}
118
119
120/**
121 * Find operation by ID.
122 *
123 * @param h
124 * Operations handle.
125 * @param op_id
126 * Operation ID to look up.
127 *
128 * @return Operation, or NULL if not found.
129 */
130static struct OperationListItem *
131op_find (struct GNUNET_OP_Handle *h,
132 uint64_t op_id)
133{
134 struct OperationListItem *op;
135
136 for (op = h->op_head; NULL != op; op = op->next)
137 if (op->op_id == op_id)
138 return op;
139 return NULL;
140}
141
142
143/**
144 * Find operation by ID.
145 *
146 * @param h
147 * Operations handle.
148 * @param op_id
149 * Operation ID to look up.
150 * @param[out] result_cb
151 * If an operation was found, its result callback is returned here.
152 * @param[out] cls
153 * If an operation was found, its closure is returned here.
154 * @param[out] ctx
155 * If an operation was found, its user context is returned here.
156 *
157 * @return #GNUNET_YES if an operation was found,
158 * #GNUNET_NO if not found.
159 */
160int
161GNUNET_OP_get (struct GNUNET_OP_Handle *h,
162 uint64_t op_id,
163 GNUNET_ResultCallback *result_cb,
164 void **cls,
165 void **ctx)
166{
167 struct OperationListItem *op = op_find (h, op_id);
168
169 if (NULL != op)
170 {
171 if (NULL != result_cb)
172 *result_cb = op->result_cb;
173 if (NULL != cls)
174 *cls = op->cls;
175 if (NULL != ctx)
176 *ctx = op->ctx;
177 return GNUNET_YES;
178 }
179 return GNUNET_NO;
180}
181
182
183/**
184 * Add a new operation.
185 *
186 * @param h
187 * Operations handle.
188 * @param result_cb
189 * Function to call with the result of the operation.
190 * @param cls
191 * Closure for @a result_cb.
192 * @param ctx
193 * User context.
194 *
195 * @return ID of the new operation.
196 */
197uint64_t
198GNUNET_OP_add (struct GNUNET_OP_Handle *h,
199 GNUNET_ResultCallback result_cb,
200 void *cls,
201 void *ctx)
202{
203 struct OperationListItem *op;
204
205 op = GNUNET_new (struct OperationListItem);
206 op->op_id = GNUNET_OP_get_next_id (h);
207 op->result_cb = result_cb;
208 op->cls = cls;
209 op->ctx = ctx;
210 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
211 h->op_tail,
212 op);
213 LOG (GNUNET_ERROR_TYPE_DEBUG,
214 "%p Added operation #%" PRIu64 "\n",
215 h, op->op_id);
216 return op->op_id;
217}
218
219
220/**
221 * Remove an operation, and call its result callback (unless it was cancelled).
222 *
223 *
224 * @param h
225 * Operations handle.
226 * @param op_id
227 * Operation ID.
228 * @param result_code
229 * Result of the operation.
230 * @param data
231 * Data result of the operation.
232 * @param data_size
233 * Size of @a data.
234 * @param[out] ctx
235 * User context.
236 * @param cancel
237 * Is the operation cancelled?
238 * #GNUNET_NO Not cancelled, result callback is called.
239 * #GNUNET_YES Cancelled, result callback is not called.
240 *
241 * @return #GNUNET_YES if the operation was found and removed,
242 * #GNUNET_NO if the operation was not found.
243 */
244static int
245op_result (struct GNUNET_OP_Handle *h,
246 uint64_t op_id,
247 int64_t result_code,
248 const void *data,
249 uint16_t data_size,
250 void **ctx,
251 uint8_t cancel)
252{
253 if (0 == op_id)
254 return GNUNET_NO;
255
256 struct OperationListItem *op = op_find (h, op_id);
257 if (NULL == op)
258 {
259 LOG (GNUNET_ERROR_TYPE_WARNING,
260 "Could not find operation #%" PRIu64 "\n", op_id);
261 return GNUNET_NO;
262 }
263
264 if (NULL != ctx)
265 *ctx = op->ctx;
266
267 GNUNET_CONTAINER_DLL_remove (h->op_head,
268 h->op_tail,
269 op);
270
271 if ((GNUNET_YES != cancel) &&
272 (NULL != op->result_cb))
273 op->result_cb (op->cls,
274 result_code, data,
275 data_size);
276 GNUNET_free (op);
277 return GNUNET_YES;
278}
279
280
281/**
282 * Call the result callback of an operation and remove it.
283 *
284 * @param h
285 * Operations handle.
286 * @param op_id
287 * Operation ID.
288 * @param result_code
289 * Result of the operation.
290 * @param data
291 * Data result of the operation.
292 * @param data_size
293 * Size of @a data.
294 * @param[out] ctx
295 * User context.
296 *
297 * @return #GNUNET_YES if the operation was found and removed,
298 * #GNUNET_NO if the operation was not found.
299 */
300int
301GNUNET_OP_result (struct GNUNET_OP_Handle *h,
302 uint64_t op_id,
303 int64_t result_code,
304 const void *data,
305 uint16_t data_size,
306 void **ctx)
307{
308 LOG (GNUNET_ERROR_TYPE_DEBUG,
309 "%p Received result for operation #%" PRIu64 ": %" PRId64 " (size: %u)\n",
310 h, op_id, result_code, data_size);
311 return op_result (h, op_id, result_code, data, data_size, ctx, GNUNET_NO);
312}
313
314
315/**
316 * Remove / cancel an operation.
317 *
318 * @param h
319 * Operations handle.
320 * @param op_id
321 * Operation ID.
322 *
323 * @return #GNUNET_YES if the operation was found and removed,
324 * #GNUNET_NO if the operation was not found.
325 */
326int
327GNUNET_OP_remove (struct GNUNET_OP_Handle *h,
328 uint64_t op_id)
329{
330 LOG (GNUNET_ERROR_TYPE_DEBUG,
331 "%p Cancelling operation #%" PRIu64 "\n",
332 h, op_id);
333 return op_result (h, op_id, 0, NULL, 0, NULL, GNUNET_YES);
334}
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
deleted file mode 100644
index 171bb5baa..000000000
--- a/src/util/os_installation.c
+++ /dev/null
@@ -1,828 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006-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 src/util/os_installation.c
23 * @brief get paths used by the program
24 * @author Milan
25 * @author Christian Fuchs
26 * @author Christian Grothoff
27 * @author Matthias Wachs
28 * @author Heikki Lindholm
29 * @author LRN
30 */
31#include <sys/stat.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35#include <unistr.h> /* for u16_to_u8 */
36
37#include "platform.h"
38#include "gnunet_util_lib.h"
39#if DARWIN
40#include <mach-o/ldsyms.h>
41#include <mach-o/dyld.h>
42#endif
43
44
45#define LOG(kind, ...) \
46 GNUNET_log_from (kind, "util-os-installation", __VA_ARGS__)
47
48#define LOG_STRERROR_FILE(kind, syscall, filename) \
49 GNUNET_log_from_strerror_file (kind, \
50 "util-os-installation", \
51 syscall, \
52 filename)
53
54
55/**
56 * Default project data used for installation path detection
57 * for GNUnet (core).
58 */
59static const struct GNUNET_OS_ProjectData default_pd = {
60 .libname = "libgnunetutil",
61 .project_dirname = "gnunet",
62 .binary_name = "gnunet-arm",
63 .version = PACKAGE_VERSION " " VCS_VERSION,
64 .env_varname = "GNUNET_PREFIX",
65 .base_config_varname = "GNUNET_BASE_CONFIG",
66 .bug_email = "gnunet-developers@gnu.org",
67 .homepage = "http://www.gnu.org/s/gnunet/",
68 .config_file = "gnunet.conf",
69 .user_config_file = "~/.config/gnunet.conf",
70 .is_gnu = 1,
71 .gettext_domain = "gnunet",
72 .gettext_path = NULL,
73 .agpl_url = GNUNET_AGPL_URL,
74};
75
76/**
77 * Which project data do we currently use for installation
78 * path detection? Never NULL.
79 */
80static const struct GNUNET_OS_ProjectData *current_pd = &default_pd;
81
82/**
83 * Whether or not gettext has been initialized for the library.
84 * Note that the gettext initialization done within
85 * GNUNET_PROGRAM_run2 is for the specific application.
86 */
87static int gettextinit = 0;
88
89/**
90 * Return default project data used by 'libgnunetutil' for GNUnet.
91 */
92const struct GNUNET_OS_ProjectData *
93GNUNET_OS_project_data_default (void)
94{
95 return &default_pd;
96}
97
98
99/**
100 * @return current project data.
101 */
102const struct GNUNET_OS_ProjectData *
103GNUNET_OS_project_data_get ()
104{
105 if (0 == gettextinit)
106 {
107 char *path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
108 if (NULL != path)
109 bindtextdomain (PACKAGE, path);
110 GNUNET_free (path);
111 gettextinit = 1;
112 }
113 return current_pd;
114}
115
116
117/**
118 * Setup OS subsystem with project data.
119 *
120 * @param pd project data used to determine paths
121 */
122void
123GNUNET_OS_init (const struct GNUNET_OS_ProjectData *pd)
124{
125 if (0 == gettextinit)
126 {
127 char *path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
128 if (NULL != path)
129 bindtextdomain (PACKAGE, path);
130 GNUNET_free (path);
131 gettextinit = 1;
132 }
133 GNUNET_assert (NULL != pd);
134 current_pd = pd;
135}
136
137
138#ifdef __linux__
139/**
140 * Try to determine path by reading /proc/PID/exe
141 *
142 * @return NULL on error
143 */
144static char *
145get_path_from_proc_maps (void)
146{
147 char fn[64];
148 char line[1024];
149 char dir[1024];
150 FILE *f;
151 char *lgu;
152
153 if (NULL == current_pd->libname)
154 return NULL;
155 GNUNET_snprintf (fn,
156 sizeof(fn),
157 "/proc/%u/maps",
158 getpid ());
159 if (NULL == (f = fopen (fn, "r")))
160 return NULL;
161 while (NULL != fgets (line, sizeof(line), f))
162 {
163 if ((1 == sscanf (line,
164 "%*p-%*p %*c%*c%*c%*c %*x %*x:%*x %*u%*[ ]%1023s",
165 dir)) &&
166 (NULL != (lgu = strstr (dir,
167 current_pd->libname))))
168 {
169 lgu[0] = '\0';
170 fclose (f);
171 return GNUNET_strdup (dir);
172 }
173 }
174 fclose (f);
175 return NULL;
176}
177
178
179/**
180 * Try to determine path by reading /proc/PID/exe
181 *
182 * @return NULL on error
183 */
184static char *
185get_path_from_proc_exe (void)
186{
187 char fn[64];
188 char lnk[1024];
189 ssize_t size;
190 char *lep;
191
192 GNUNET_snprintf (fn, sizeof(fn), "/proc/%u/exe", getpid ());
193 size = readlink (fn, lnk, sizeof(lnk) - 1);
194 if (size <= 0)
195 {
196 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
197 return NULL;
198 }
199 GNUNET_assert (((size_t) size) < sizeof(lnk));
200 lnk[size] = '\0';
201 while ((lnk[size] != '/') && (size > 0))
202 size--;
203 GNUNET_asprintf (&lep, "/%s/libexec/", current_pd->project_dirname);
204 /* test for being in lib/gnunet/libexec/ or lib/MULTIARCH/gnunet/libexec */
205 if ((((size_t) size) > strlen (lep)) &&
206 (0 == strcmp (lep, &lnk[size - strlen (lep)])))
207 size -= strlen (lep) - 1;
208 GNUNET_free (lep);
209 if ((size < 4) || (lnk[size - 4] != '/'))
210 {
211 /* not installed in "/bin/" -- binary path probably useless */
212 return NULL;
213 }
214 lnk[size] = '\0';
215 return GNUNET_strdup (lnk);
216}
217
218
219#endif
220
221
222#if DARWIN
223/**
224 * Signature of the '_NSGetExecutablePath" function.
225 *
226 * @param buf where to write the path
227 * @param number of bytes available in @a buf
228 * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
229 */
230typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t *bufsize);
231
232
233/**
234 * Try to obtain the path of our executable using '_NSGetExecutablePath'.
235 *
236 * @return NULL on error
237 */
238static char *
239get_path_from_NSGetExecutablePath (void)
240{
241 static char zero = '\0';
242 char *path;
243 size_t len;
244 MyNSGetExecutablePathProto func;
245
246 path = NULL;
247 if (NULL ==
248 (func = (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT,
249 "_NSGetExecutablePath")))
250 return NULL;
251 path = &zero;
252 len = 0;
253 /* get the path len, including the trailing \0 */
254 (void) func (path, &len);
255 if (0 == len)
256 return NULL;
257 path = GNUNET_malloc (len);
258 if (0 != func (path, &len))
259 {
260 GNUNET_free (path);
261 return NULL;
262 }
263 len = strlen (path);
264 while ((path[len] != '/') && (len > 0))
265 len--;
266 path[len] = '\0';
267 return path;
268}
269
270
271/**
272 * Try to obtain the path of our executable using '_dyld_image' API.
273 *
274 * @return NULL on error
275 */
276static char *
277get_path_from_dyld_image (void)
278{
279 const char *path;
280 char *p;
281 char *s;
282 unsigned int i;
283 int c;
284
285 c = _dyld_image_count ();
286 for (i = 0; i < c; i++)
287 {
288 if (((const void *) _dyld_get_image_header (i)) !=
289 ((const void *) &_mh_dylib_header))
290 continue;
291 path = _dyld_get_image_name (i);
292 if ((NULL == path) || (0 == strlen (path)))
293 continue;
294 p = GNUNET_strdup (path);
295 s = p + strlen (p);
296 while ((s > p) && ('/' != *s))
297 s--;
298 s++;
299 *s = '\0';
300 return p;
301 }
302 return NULL;
303}
304
305
306#endif
307
308
309/**
310 * Return the actual path to a file found in the current
311 * PATH environment variable.
312 *
313 * @param binary the name of the file to find
314 * @return path to binary, NULL if not found
315 */
316static char *
317get_path_from_PATH (const char *binary)
318{
319 char *path;
320 char *pos;
321 char *end;
322 char *buf;
323 const char *p;
324
325 if (NULL == (p = getenv ("PATH")))
326 return NULL;
327
328 path = GNUNET_strdup (p); /* because we write on it */
329
330 buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
331 pos = path;
332 while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
333 {
334 *end = '\0';
335 sprintf (buf, "%s/%s", pos, binary);
336 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
337 {
338 pos = GNUNET_strdup (pos);
339 GNUNET_free (buf);
340 GNUNET_free (path);
341 return pos;
342 }
343 pos = end + 1;
344 }
345 sprintf (buf, "%s/%s", pos, binary);
346 if (GNUNET_YES == GNUNET_DISK_file_test (buf))
347 {
348 pos = GNUNET_strdup (pos);
349 GNUNET_free (buf);
350 GNUNET_free (path);
351 return pos;
352 }
353 GNUNET_free (buf);
354 GNUNET_free (path);
355 return NULL;
356}
357
358
359/**
360 * Try to obtain the installation path using the "GNUNET_PREFIX" environment
361 * variable.
362 *
363 * @return NULL on error (environment variable not set)
364 */
365static char *
366get_path_from_GNUNET_PREFIX (void)
367{
368 const char *p;
369
370 if ((NULL != current_pd->env_varname) &&
371 (NULL != (p = getenv (current_pd->env_varname))))
372 return GNUNET_strdup (p);
373 if ((NULL != current_pd->env_varname_alt) &&
374 (NULL != (p = getenv (current_pd->env_varname_alt))))
375 return GNUNET_strdup (p);
376 return NULL;
377}
378
379
380/**
381 * @brief get the path to GNUnet bin/ or lib/, preferring the lib/ path
382 * @author Milan
383 *
384 * @return a pointer to the executable path, or NULL on error
385 */
386static char *
387os_get_gnunet_path (void)
388{
389 char *ret;
390
391 if (NULL != (ret = get_path_from_GNUNET_PREFIX ()))
392 return ret;
393#ifdef __linux__
394 if (NULL != (ret = get_path_from_proc_maps ()))
395 return ret;
396 /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
397 if ((NULL != current_pd->binary_name) &&
398 (NULL != (ret = get_path_from_PATH (current_pd->binary_name))))
399 return ret;
400 if (NULL != (ret = get_path_from_proc_exe ()))
401 return ret;
402#endif
403#if DARWIN
404 if (NULL != (ret = get_path_from_dyld_image ()))
405 return ret;
406 if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
407 return ret;
408#endif
409 if ((NULL != current_pd->binary_name) &&
410 (NULL != (ret = get_path_from_PATH (current_pd->binary_name))))
411 return ret;
412 /* other attempts here */
413 LOG (GNUNET_ERROR_TYPE_ERROR,
414 _ (
415 "Could not determine installation path for %s. Set `%s' environment variable.\n"),
416 current_pd->project_dirname,
417 current_pd->env_varname);
418 return NULL;
419}
420
421
422/**
423 * @brief get the path to current app's bin/
424 * @return a pointer to the executable path, or NULL on error
425 */
426static char *
427os_get_exec_path ()
428{
429 char *ret = NULL;
430
431#ifdef __linux__
432 if (NULL != (ret = get_path_from_proc_exe ()))
433 return ret;
434#endif
435#if DARWIN
436 if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
437 return ret;
438#endif
439 /* other attempts here */
440 return ret;
441}
442
443
444/**
445 * @brief get the path to a specific GNUnet installation directory or,
446 * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory
447 * @return a pointer to the dir path (to be freed by the caller)
448 */
449char *
450GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
451{
452 size_t n;
453 char *dirname;
454 char *execpath = NULL;
455 char *tmp;
456 char *multiarch;
457 char *libdir;
458 int isbasedir;
459
460 /* if wanted, try to get the current app's bin/ */
461 if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
462 execpath = os_get_exec_path ();
463
464 /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
465 * guess for the current app */
466 if (NULL == execpath)
467 execpath = os_get_gnunet_path ();
468 if (NULL == execpath)
469 return NULL;
470
471 n = strlen (execpath);
472 if (0 == n)
473 {
474 /* should never happen, but better safe than sorry */
475 GNUNET_free (execpath);
476 return NULL;
477 }
478 /* remove filename itself */
479 while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
480 execpath[--n] = '\0';
481
482 isbasedir = 1;
483 if ((n > 6) && ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
484 (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
485 {
486 if ((GNUNET_OS_IPK_LIBDIR != dirkind) &&
487 (GNUNET_OS_IPK_LIBEXECDIR != dirkind))
488 {
489 /* strip '/lib32' or '/lib64' */
490 execpath[n - 6] = '\0';
491 n -= 6;
492 }
493 else
494 isbasedir = 0;
495 }
496 else if ((n > 4) && ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
497 (0 == strcasecmp (&execpath[n - 4], "/lib"))))
498 {
499 /* strip '/bin' or '/lib' */
500 execpath[n - 4] = '\0';
501 n -= 4;
502 }
503 multiarch = NULL;
504 if (NULL != (libdir = strstr (execpath, "/lib/")))
505 {
506 /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
507 here we need to re-add 'multiarch' to lib and libexec paths later! */
508 multiarch = &libdir[5];
509 if (NULL == strchr (multiarch, '/'))
510 libdir[0] =
511 '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
512 else
513 multiarch =
514 NULL; /* maybe not, multiarch still has a '/', which is not OK */
515 }
516 /* in case this was a directory named foo-bin, remove "foo-" */
517 while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
518 execpath[--n] = '\0';
519 switch (dirkind)
520 {
521 case GNUNET_OS_IPK_PREFIX:
522 case GNUNET_OS_IPK_SELF_PREFIX:
523 dirname = GNUNET_strdup (DIR_SEPARATOR_STR);
524 break;
525
526 case GNUNET_OS_IPK_BINDIR:
527 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR);
528 break;
529
530 case GNUNET_OS_IPK_LIBDIR:
531 if (isbasedir)
532 {
533 GNUNET_asprintf (&tmp,
534 "%s%s%s%s%s%s%s",
535 execpath,
536 DIR_SEPARATOR_STR "lib",
537 (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
538 (NULL != multiarch) ? multiarch : "",
539 DIR_SEPARATOR_STR,
540 current_pd->project_dirname,
541 DIR_SEPARATOR_STR);
542 if (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES))
543 {
544 GNUNET_free (execpath);
545 return tmp;
546 }
547 GNUNET_free (tmp);
548 tmp = NULL;
549 dirname = NULL;
550 if (4 == sizeof(void *))
551 {
552 GNUNET_asprintf (&dirname,
553 DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR
554 "%s" DIR_SEPARATOR_STR,
555 current_pd->project_dirname);
556 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
557 }
558 if (8 == sizeof(void *))
559 {
560 GNUNET_asprintf (&dirname,
561 DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR
562 "%s" DIR_SEPARATOR_STR,
563 current_pd->project_dirname);
564 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
565 }
566
567 if ((NULL != tmp) &&
568 (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES)))
569 {
570 GNUNET_free (execpath);
571 GNUNET_free (dirname);
572 return tmp;
573 }
574 GNUNET_free (tmp);
575 GNUNET_free (dirname);
576 }
577 GNUNET_asprintf (&dirname,
578 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR,
579 current_pd->project_dirname);
580 break;
581
582 case GNUNET_OS_IPK_DATADIR:
583 GNUNET_asprintf (&dirname,
584 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
585 "%s" DIR_SEPARATOR_STR,
586 current_pd->project_dirname);
587 break;
588
589 case GNUNET_OS_IPK_LOCALEDIR:
590 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
591 "locale" DIR_SEPARATOR_STR);
592 break;
593
594 case GNUNET_OS_IPK_ICONDIR:
595 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
596 "icons" DIR_SEPARATOR_STR);
597 break;
598
599 case GNUNET_OS_IPK_DOCDIR:
600 GNUNET_asprintf (&dirname,
601 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
602 "doc" DIR_SEPARATOR_STR
603 "%s" DIR_SEPARATOR_STR,
604 current_pd->project_dirname);
605 break;
606
607 case GNUNET_OS_IPK_LIBEXECDIR:
608 if (isbasedir)
609 {
610 GNUNET_asprintf (&dirname,
611 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR
612 "libexec" DIR_SEPARATOR_STR,
613 current_pd->project_dirname);
614 GNUNET_asprintf (&tmp,
615 "%s%s%s%s",
616 execpath,
617 DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
618 (NULL != multiarch) ? multiarch : "",
619 dirname);
620 GNUNET_free (dirname);
621 if (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES))
622 {
623 GNUNET_free (execpath);
624 return tmp;
625 }
626 GNUNET_free (tmp);
627 tmp = NULL;
628 dirname = NULL;
629 if (4 == sizeof(void *))
630 {
631 GNUNET_asprintf (&dirname,
632 DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR
633 "%s" DIR_SEPARATOR_STR
634 "libexec" DIR_SEPARATOR_STR,
635 current_pd->project_dirname);
636 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
637 }
638 if (8 == sizeof(void *))
639 {
640 GNUNET_asprintf (&dirname,
641 DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR
642 "%s" DIR_SEPARATOR_STR
643 "libexec" DIR_SEPARATOR_STR,
644 current_pd->project_dirname);
645 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
646 }
647 if ((NULL != tmp) &&
648 (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES)))
649 {
650 GNUNET_free (execpath);
651 GNUNET_free (dirname);
652 return tmp;
653 }
654 GNUNET_free (tmp);
655 GNUNET_free (dirname);
656 }
657 GNUNET_asprintf (&dirname,
658 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR
659 "libexec" DIR_SEPARATOR_STR,
660 current_pd->project_dirname);
661 break;
662
663 default:
664 GNUNET_free (execpath);
665 return NULL;
666 }
667 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
668 GNUNET_free (dirname);
669 GNUNET_free (execpath);
670 return tmp;
671}
672
673
674/**
675 * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon
676 * binary, try to prefix it with the libexec/-directory to get the
677 * full path.
678 *
679 * @param progname name of the binary
680 * @return full path to the binary, if possible, otherwise copy of 'progname'
681 */
682char *
683GNUNET_OS_get_libexec_binary_path (const char *progname)
684{
685 static char *cache;
686 char *libexecdir;
687 char *binary;
688
689 if ((DIR_SEPARATOR == progname[0]) ||
690 (GNUNET_YES ==
691 GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)))
692 return GNUNET_strdup (progname);
693 if (NULL != cache)
694 libexecdir = cache;
695 else
696 libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
697 if (NULL == libexecdir)
698 return GNUNET_strdup (progname);
699 GNUNET_asprintf (&binary, "%s%s", libexecdir, progname);
700 cache = libexecdir;
701 return binary;
702}
703
704
705/**
706 * Given the name of a helper, service or daemon binary construct the full
707 * path to the binary using the SUID_BINARY_PATH in the PATHS section of the
708 * configuration. If that option is not present, fall back to
709 * GNUNET_OS_get_libexec_binary_path. If @a progname is an absolute path, a
710 * copy of this path is returned.
711 *
712 * @param cfg configuration to inspect
713 * @param progname name of the binary
714 * @return full path to the binary, if possible, a copy of @a progname
715 * otherwise
716 */
717char *
718GNUNET_OS_get_suid_binary_path (const struct GNUNET_CONFIGURATION_Handle *cfg,
719 const char *progname)
720{
721 static char *cache;
722 char *binary = NULL;
723 char *path = NULL;
724 size_t path_len;
725
726 if (GNUNET_YES ==
727 GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL))
728 {
729 return GNUNET_strdup (progname);
730 }
731 if (NULL != cache)
732 path = cache;
733 else
734 GNUNET_CONFIGURATION_get_value_string (cfg,
735 "PATHS",
736 "SUID_BINARY_PATH",
737 &path);
738 if ((NULL == path) || (0 == strlen (path)))
739 {
740 if (NULL != path)
741 GNUNET_free (path);
742 cache = NULL;
743 return GNUNET_OS_get_libexec_binary_path (progname);
744 }
745 path_len = strlen (path);
746 GNUNET_asprintf (&binary,
747 "%s%s%s",
748 path,
749 (path[path_len - 1] == DIR_SEPARATOR) ? ""
750 : DIR_SEPARATOR_STR,
751 progname);
752 cache = path;
753 return binary;
754}
755
756
757enum GNUNET_GenericReturnValue
758GNUNET_OS_check_helper_binary (const char *binary,
759 bool check_suid,
760 const char *params)
761{
762 struct stat statbuf;
763 char *p;
764 char *pf;
765
766 if ((GNUNET_YES ==
767 GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO, NULL, NULL)) ||
768 (0 == strncmp (binary, "./", 2)))
769 {
770 p = GNUNET_strdup (binary);
771 }
772 else
773 {
774 p = get_path_from_PATH (binary);
775 if (NULL != p)
776 {
777 GNUNET_asprintf (&pf, "%s/%s", p, binary);
778 GNUNET_free (p);
779 p = pf;
780 }
781 }
782
783 if (NULL == p)
784 {
785 LOG (GNUNET_ERROR_TYPE_INFO,
786 _ ("Could not find binary `%s' in PATH!\n"),
787 binary);
788 return GNUNET_SYSERR;
789 }
790 if (0 != access (p, X_OK))
791 {
792 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p);
793 GNUNET_free (p);
794 return GNUNET_SYSERR;
795 }
796
797 if (0 == getuid ())
798 {
799 /* as we run as root, we don't insist on SUID */
800 GNUNET_free (p);
801 return GNUNET_YES;
802 }
803
804 if (0 != stat (p, &statbuf))
805 {
806 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p);
807 GNUNET_free (p);
808 return GNUNET_SYSERR;
809 }
810 if (check_suid)
811 {
812 (void) params;
813 if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
814 {
815 GNUNET_free (p);
816 return GNUNET_YES;
817 }
818 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
819 _ ("Binary `%s' exists, but is not SUID\n"),
820 p);
821 /* binary exists, but not SUID */
822 }
823 GNUNET_free (p);
824 return GNUNET_NO;
825}
826
827
828/* end of os_installation.c */
diff --git a/src/util/os_network.c b/src/util/os_network.c
deleted file mode 100644
index 9ee26f0a9..000000000
--- a/src/util/os_network.c
+++ /dev/null
@@ -1,443 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2004, 2005, 2006, 2015 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 util/os_network.c
23 * @brief function to determine available network interfaces
24 * @author Nils Durner
25 * @author Heikki Lindholm
26 * @author Jake Dust
27 * @author LRN
28 * @author Christian Grothoff
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "util-os-network", __VA_ARGS__)
35#define LOG_STRERROR_FILE(kind, syscall, \
36 filename) GNUNET_log_from_strerror_file (kind, \
37 "util-os-network", \
38 syscall, \
39 filename)
40
41
42#if ! (HAVE_GETIFADDRS && HAVE_FREEIFADDRS)
43/**
44 * Try to enumerate all network interfaces using 'ifconfig'.
45 *
46 * @param proc the callback function
47 * @param proc_cls closure for @a proc
48 * @return #GNUNET_OK if it worked
49 */
50static int
51try_ifconfig (GNUNET_OS_NetworkInterfaceProcessor proc,
52 void *proc_cls)
53{
54 int i;
55 char line[1024];
56 char *replace;
57 const char *start;
58 char ifc[12];
59 char addrstr[128];
60 char bcstr[128];
61 char netmaskstr[128];
62 FILE *f;
63 int have_ifc;
64 struct sockaddr_in a4;
65 struct sockaddr_in6 a6;
66 struct in_addr v4;
67 struct in6_addr v6;
68 struct sockaddr_in bcaddr;
69 struct sockaddr_in netmask;
70 struct sockaddr_in6 netmask6;
71 struct sockaddr *pass_bcaddr;
72 struct sockaddr *pass_netmask;
73 int prefixlen;
74 static char *pcall;
75
76 if (NULL == pcall)
77 {
78 const char *sbin_ifconfig;
79
80#ifdef IFCONFIG
81 if (0 == access (IFCONFIG, X_OK))
82 sbin_ifconfig = IFCONFIG;
83 else
84#endif
85 if (0 == access ("/sbin/ifconfig", X_OK))
86 sbin_ifconfig = "/sbin/ifconfig";
87 else if (0 == access ("/usr/sbin/ifconfig", X_OK))
88 sbin_ifconfig = "/usr/sbin/ifconfig";
89 else
90 sbin_ifconfig = "ifconfig";
91 GNUNET_asprintf (&pcall,
92 "%s -a 2> /dev/null",
93 sbin_ifconfig);
94 }
95 f = popen (pcall, "r");
96 if (NULL == f)
97 {
98 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
99 "popen",
100 "ifconfig");
101
102 return GNUNET_SYSERR;
103 }
104
105 have_ifc = GNUNET_NO;
106 ifc[11] = '\0';
107 while (NULL != fgets (line, sizeof(line), f))
108 {
109 if (strlen (line) == 0)
110 {
111 have_ifc = GNUNET_NO;
112 continue;
113 }
114 if (! isspace (line[0]))
115 {
116 have_ifc = (1 == sscanf (line, "%11s", ifc)) ? GNUNET_YES : GNUNET_NO;
117 /* would end with ':' on OSX, fix it! */
118 if (ifc[strlen (ifc) - 1] == ':')
119 ifc[strlen (ifc) - 1] = '\0';
120 continue;
121 }
122 if (! have_ifc)
123 continue; /* strange input, hope for the best */
124
125 /* make parsing of ipv6 addresses easier */
126 for (replace = line; *replace != '\0'; replace++)
127 {
128 if (*replace == '/')
129 *replace = ' ';
130 }
131 prefixlen = -1;
132
133 start = line;
134 while (('\0' != *start) && (isspace (*start)))
135 start++;
136
137 /* Zero-out stack allocated values */
138 memset (addrstr, 0, 128);
139 memset (netmaskstr, 0, 128);
140 memset (bcstr, 0, 128);
141 prefixlen = 0;
142
143 if ( /* Linux */
144 (3 == sscanf (start, "inet addr:%127s Bcast:%127s Mask:%127s", addrstr,
145 bcstr, netmaskstr)) ||
146 (2 == sscanf (start, "inet addr:%127s Mask:%127s", addrstr,
147 netmaskstr)) ||
148 (2 == sscanf (start, "inet6 addr:%127s %d", addrstr, &prefixlen)) ||
149 /* Solaris, OS X */
150 (1 == sscanf (start, "inet %127s", addrstr)) ||
151 (1 == sscanf (start, "inet6 %127s", addrstr)))
152 {
153 /* IPv4 */
154 if (1 == inet_pton (AF_INET, addrstr, &v4))
155 {
156 memset (&a4, 0, sizeof(a4));
157 a4.sin_family = AF_INET;
158#if HAVE_SOCKADDR_IN_SIN_LEN
159 a4.sin_len = (u_char) sizeof(struct sockaddr_in);
160#endif
161 a4.sin_addr = v4;
162
163 pass_bcaddr = NULL;
164 pass_netmask = NULL;
165 if (1 == inet_pton (AF_INET, bcstr, &v4))
166 {
167 memset (&bcaddr, 0, sizeof(bcaddr));
168 bcaddr.sin_family = AF_INET;
169#if HAVE_SOCKADDR_IN_SIN_LEN
170 bcaddr.sin_len = (u_char) sizeof(struct sockaddr_in);
171#endif
172 bcaddr.sin_addr = v4;
173 pass_bcaddr = (struct sockaddr *) &bcaddr;
174 }
175 if (1 == inet_pton (AF_INET, netmaskstr, &v4))
176 {
177 memset (&netmask, 0, sizeof(netmask));
178 netmask.sin_family = AF_INET;
179#if HAVE_SOCKADDR_IN_SIN_LEN
180 netmask.sin_len = (u_char) sizeof(struct sockaddr_in);
181#endif
182 netmask.sin_addr = v4;
183 pass_netmask = (struct sockaddr *) &netmask;
184 }
185
186
187 if (GNUNET_OK !=
188 proc (proc_cls, ifc,(0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE)),
189 (const struct sockaddr *) &a4,
190 pass_bcaddr, pass_netmask, sizeof(a4)))
191 break;
192 continue;
193 }
194 /* IPv6 */
195 if (1 == inet_pton (AF_INET6, addrstr, &v6))
196 {
197 memset (&a6, 0, sizeof(a6));
198 a6.sin6_family = AF_INET6;
199#if HAVE_SOCKADDR_IN_SIN_LEN
200 a6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
201#endif
202 a6.sin6_addr = v6;
203
204 pass_netmask = NULL;
205 if (prefixlen != -1)
206 {
207 memset (v6.s6_addr, 0, sizeof(v6.s6_addr));
208 for (i = 0; i < prefixlen; i++)
209 {
210 v6.s6_addr[i >> 3] |= 1 << (i & 7);
211 }
212 memset (&netmask6, 0, sizeof(netmask6));
213 netmask6.sin6_family = AF_INET6;
214#if HAVE_SOCKADDR_IN_SIN_LEN
215 netmask6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
216#endif
217 netmask6.sin6_addr = v6;
218
219 pass_netmask = (struct sockaddr *) &netmask6;
220 }
221
222 if (GNUNET_OK !=
223 proc (proc_cls, ifc,(0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE)),
224 (const struct sockaddr *) &a6,
225 NULL, pass_netmask, sizeof(a6)))
226 break;
227 continue;
228 }
229 }
230 }
231 pclose (f);
232 return GNUNET_OK;
233}
234
235
236/**
237 * Try to enumerate all network interfaces using 'ip'.
238 *
239 * @param proc the callback function
240 * @param proc_cls closure for @a proc
241 * @return #GNUNET_OK if it worked
242 */
243static int
244try_ip (GNUNET_OS_NetworkInterfaceProcessor proc,
245 void *proc_cls)
246{
247 char line[1024];
248 char *replace;
249 char ifname[64];
250 char afstr[6];
251 char addrstr[128];
252 FILE *f;
253 struct sockaddr_in a4;
254 struct sockaddr_in6 a6;
255 struct in_addr v4;
256 struct in6_addr v6;
257 struct sockaddr_in netmask;
258 struct sockaddr_in6 netmask6;
259 unsigned int i;
260 unsigned int prefixlen;
261 static char *pcall;
262
263 if (NULL == pcall)
264 {
265 const char *sbin_ip;
266
267#ifdef IFCONFIG
268 if (0 == access (PATH_TO_IP, X_OK))
269 sbin_ip = PATH_TO_IP;
270 else
271#endif
272 if (0 == access ("/sbin/ip", X_OK))
273 sbin_ip = "/sbin/ip";
274 else if (0 == access ("/usr/sbin/ip", X_OK))
275 sbin_ip = "/usr/sbin/ip";
276 else
277 sbin_ip = "if";
278 GNUNET_asprintf (&pcall,
279 "%s -o add 2> /dev/null",
280 sbin_ip);
281 }
282 f = popen (pcall, "r");
283 if (! f)
284 {
285 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
286 "popen",
287 "ip");
288 return GNUNET_SYSERR;
289 }
290
291 while (NULL != fgets (line, sizeof(line), f))
292 {
293 /* make parsing easier */
294 for (replace = line; *replace != '\0'; replace++)
295 {
296 if (*replace == '/')
297 *replace = ' ';
298 }
299 /* Zero-out stack allocated values */
300 memset (ifname, 0, 64);
301 memset (afstr, 0, 6);
302 memset (addrstr, 0, 128);
303 if (4 != sscanf (line,
304 "%*u: %63s %5s %127s %6u",
305 ifname,
306 afstr,
307 addrstr,
308 &prefixlen))
309 continue;
310 /* IPv4 */
311 if ((0 == strcasecmp ("inet",
312 afstr)) &&
313 (1 == inet_pton (AF_INET,
314 addrstr,
315 &v4)))
316 {
317 memset (&a4, 0, sizeof(a4));
318 a4.sin_family = AF_INET;
319#if HAVE_SOCKADDR_IN_SIN_LEN
320 a4.sin_len = (u_char) sizeof(struct sockaddr_in);
321#endif
322 a4.sin_addr = v4;
323
324 memset (&v4.s_addr, 0, sizeof(v4.s_addr));
325 for (i = 0; i < prefixlen; i++)
326 v4.s_addr |= 1 << (i & 7);
327 memset (&netmask, 0, sizeof(netmask));
328 netmask.sin_family = AF_INET;
329#if HAVE_SOCKADDR_IN_SIN_LEN
330 netmask.sin_len = (u_char) sizeof(struct sockaddr_in);
331#endif
332 netmask.sin_addr = v4;
333
334 if (GNUNET_OK !=
335 proc (proc_cls,
336 ifname,
337 (0 == strcmp (ifname,
338 GNUNET_DEFAULT_INTERFACE)),
339 (const struct sockaddr *) &a4,
340 NULL,
341 (const struct sockaddr *) &netmask,
342 sizeof(a4)))
343 break;
344 }
345 /* IPv6 */
346 if ((0 == strcasecmp ("inet6",
347 afstr)) &&
348 (1 == inet_pton (AF_INET6,
349 addrstr,
350 &v6)))
351 {
352 memset (&a6, 0, sizeof(a6));
353 a6.sin6_family = AF_INET6;
354#if HAVE_SOCKADDR_IN_SIN_LEN
355 a6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
356#endif
357 a6.sin6_addr = v6;
358
359 memset (v6.s6_addr, 0, sizeof(v6.s6_addr));
360 for (i = 0; i < prefixlen; i++)
361 v6.s6_addr[i >> 3] |= 1 << (i & 7);
362 memset (&netmask6, 0, sizeof(netmask6));
363 netmask6.sin6_family = AF_INET6;
364#if HAVE_SOCKADDR_IN_SIN_LEN
365 netmask6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
366#endif
367 netmask6.sin6_addr = v6;
368
369 if (GNUNET_OK !=
370 proc (proc_cls,
371 ifname,
372 (0 == strcmp (ifname,
373 GNUNET_DEFAULT_INTERFACE)),
374 (const struct sockaddr *) &a6,
375 NULL,
376 (const struct sockaddr *) &netmask6,
377 sizeof(a6)))
378 break;
379 }
380 }
381 pclose (f);
382 return GNUNET_OK;
383}
384
385
386#endif
387
388
389/**
390 * @brief Enumerate all network interfaces
391 *
392 * @param proc the callback function
393 * @param proc_cls closure for @a proc
394 */
395void
396GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc,
397 void *proc_cls)
398{
399#if HAVE_GETIFADDRS && HAVE_FREEIFADDRS
400 struct ifaddrs *ifa_first;
401 struct ifaddrs *ifa_ptr;
402 socklen_t alen;
403
404 if (getifaddrs (&ifa_first) == 0)
405 {
406 for (ifa_ptr = ifa_first; ifa_ptr != NULL; ifa_ptr = ifa_ptr->ifa_next)
407 {
408 if ((ifa_ptr->ifa_name != NULL) && (ifa_ptr->ifa_addr != NULL) &&
409 ( (ifa_ptr->ifa_flags & IFF_UP) != 0) )
410 {
411 if ((ifa_ptr->ifa_addr->sa_family != AF_INET) &&
412 (ifa_ptr->ifa_addr->sa_family != AF_INET6))
413 continue;
414 if (ifa_ptr->ifa_addr->sa_family == AF_INET)
415 alen = sizeof(struct sockaddr_in);
416 else
417 alen = sizeof(struct sockaddr_in6);
418 if (GNUNET_OK !=
419 proc (proc_cls, ifa_ptr->ifa_name,
420 (0 == strcmp (ifa_ptr->ifa_name, GNUNET_DEFAULT_INTERFACE)),
421 ifa_ptr->ifa_addr, ifa_ptr->ifa_broadaddr,
422 ifa_ptr->ifa_netmask, alen))
423 break;
424 }
425 }
426 freeifaddrs (ifa_first);
427 }
428#else
429 if (GNUNET_OK ==
430 try_ip (proc,
431 proc_cls))
432 return;
433 if (GNUNET_OK ==
434 try_ifconfig (proc,
435 proc_cls))
436 return;
437 LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
438 "Failed to enumerate network interfaces\n");
439#endif
440}
441
442
443/* end of os_network.c */
diff --git a/src/util/os_priority.c b/src/util/os_priority.c
deleted file mode 100644
index 08320b291..000000000
--- a/src/util/os_priority.c
+++ /dev/null
@@ -1,1186 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2011 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 util/os_priority.c
23 * @brief Methods to set process priority
24 * @author Nils Durner
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "disk.h"
30#include <unistr.h>
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util-os-priority", __VA_ARGS__)
33
34#define LOG_STRERROR(kind, syscall) \
35 GNUNET_log_from_strerror (kind, "util-os-priority", syscall)
36
37#define LOG_STRERROR_FILE(kind, syscall, filename) \
38 GNUNET_log_from_strerror_file (kind, "util-os-priority", syscall, filename)
39
40#define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
41
42
43struct GNUNET_OS_Process
44{
45 /**
46 * PID of the process.
47 */
48 pid_t pid;
49
50 /**
51 * Pipe we use to signal the process.
52 * NULL if unused, or if process was deemed uncontrollable.
53 */
54 struct GNUNET_DISK_FileHandle *control_pipe;
55};
56
57
58/**
59 * Handle for 'this' process.
60 */
61static struct GNUNET_OS_Process current_process;
62
63/**
64 * Handle for the #parent_control_handler() Task.
65 */
66static struct GNUNET_SCHEDULER_Task *pch;
67
68/**
69 * Handle for the #shutdown_pch() Task.
70 */
71static struct GNUNET_SCHEDULER_Task *spch;
72
73
74/**
75 * This handler is called on shutdown to remove the #pch.
76 *
77 * @param cls the `struct GNUNET_DISK_FileHandle` of the control pipe
78 */
79static void
80shutdown_pch (void *cls)
81{
82 struct GNUNET_DISK_FileHandle *control_pipe = cls;
83
84 GNUNET_SCHEDULER_cancel (pch);
85 pch = NULL;
86 GNUNET_DISK_file_close (control_pipe);
87 control_pipe = NULL;
88}
89
90
91/**
92 * This handler is called when there are control data to be read on the pipe
93 *
94 * @param cls the `struct GNUNET_DISK_FileHandle` of the control pipe
95 */
96static void
97parent_control_handler (void *cls)
98{
99 struct GNUNET_DISK_FileHandle *control_pipe = cls;
100 char sig;
101 char *pipe_fd;
102 ssize_t ret;
103
104 pch = NULL;
105 ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof(sig));
106 if (sizeof(sig) != ret)
107 {
108 if (-1 == ret)
109 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
110 LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
111 GNUNET_DISK_file_close (control_pipe);
112 control_pipe = NULL;
113 GNUNET_SCHEDULER_cancel (spch);
114 spch = NULL;
115 return;
116 }
117 pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
118 GNUNET_assert ((NULL == pipe_fd) || (strlen (pipe_fd) <= 0));
119 LOG (GNUNET_ERROR_TYPE_DEBUG,
120 "Got control code %d from parent via pipe %s\n",
121 sig,
122 pipe_fd);
123 pch = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
124 control_pipe,
125 &parent_control_handler,
126 control_pipe);
127 GNUNET_SIGNAL_raise ((int) sig);
128}
129
130
131/**
132 * Task that connects this process to its parent via pipe;
133 * essentially, the parent control handler will read signal numbers
134 * from the #GNUNET_OS_CONTROL_PIPE (as given in an environment
135 * variable) and raise those signals.
136 *
137 * @param cls closure (unused)
138 */
139void
140GNUNET_OS_install_parent_control_handler (void *cls)
141{
142 const char *env_buf;
143 char *env_buf_end;
144 struct GNUNET_DISK_FileHandle *control_pipe;
145 uint64_t pipe_fd;
146
147 (void) cls;
148 if (NULL != pch)
149 {
150 /* already done, we've been called twice... */
151 GNUNET_break (0);
152 return;
153 }
154 env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
155 if ((NULL == env_buf) || (strlen (env_buf) <= 0))
156 {
157 LOG (GNUNET_ERROR_TYPE_DEBUG,
158 "Not installing a handler because $%s is empty\n",
159 GNUNET_OS_CONTROL_PIPE);
160 putenv (GNUNET_OS_CONTROL_PIPE "=");
161 return;
162 }
163 errno = 0;
164 pipe_fd = strtoull (env_buf, &env_buf_end, 16);
165 if ((0 != errno) || (env_buf == env_buf_end))
166 {
167 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
168 putenv (GNUNET_OS_CONTROL_PIPE "=");
169 return;
170 }
171 if (pipe_fd >= FD_SETSIZE)
172 {
173 LOG (GNUNET_ERROR_TYPE_ERROR,
174 "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
175 env_buf);
176 putenv (GNUNET_OS_CONTROL_PIPE "=");
177 return;
178 }
179
180 control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
181
182 if (NULL == control_pipe)
183 {
184 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
185 putenv (GNUNET_OS_CONTROL_PIPE "=");
186 return;
187 }
188 LOG (GNUNET_ERROR_TYPE_DEBUG,
189 "Adding parent control handler pipe `%s' to the scheduler\n",
190 env_buf);
191 pch = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
192 control_pipe,
193 &parent_control_handler,
194 control_pipe);
195 spch = GNUNET_SCHEDULER_add_shutdown (&shutdown_pch, control_pipe);
196 putenv (GNUNET_OS_CONTROL_PIPE "=");
197}
198
199
200/**
201 * Get process structure for current process
202 *
203 * The pointer it returns points to static memory location and must
204 * not be deallocated/closed.
205 *
206 * @return pointer to the process sturcutre for this process
207 */
208struct GNUNET_OS_Process *
209GNUNET_OS_process_current ()
210{
211 current_process.pid = 0;
212 return &current_process;
213}
214
215
216/**
217 * Sends a signal to the process
218 *
219 * @param proc pointer to process structure
220 * @param sig signal
221 * @return 0 on success, -1 on error
222 */
223int
224GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
225{
226 int ret;
227 char csig;
228
229 csig = (char) sig;
230 if (NULL != proc->control_pipe)
231 {
232 LOG (GNUNET_ERROR_TYPE_DEBUG,
233 "Sending signal %d to pid: %u via pipe\n",
234 sig,
235 proc->pid);
236 ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof(csig));
237 if (sizeof(csig) == ret)
238 return 0;
239 }
240 /* pipe failed or non-existent, try other methods */
241 switch (sig)
242 {
243 case SIGHUP:
244 case SIGINT:
245 case SIGKILL:
246 case SIGTERM:
247#if (SIGTERM != GNUNET_TERM_SIG)
248 case GNUNET_TERM_SIG:
249#endif
250 LOG (GNUNET_ERROR_TYPE_DEBUG,
251 "Sending signal %d to pid: %u via system call\n",
252 sig,
253 proc->pid);
254 return kill (proc->pid, sig);
255 default:
256 LOG (GNUNET_ERROR_TYPE_DEBUG,
257 "Sending signal %d to pid: %u via system call\n",
258 sig,
259 proc->pid);
260 return kill (proc->pid, sig);
261 }
262}
263
264
265/**
266 * Get the pid of the process in question
267 *
268 * @param proc the process to get the pid of
269 *
270 * @return the current process id
271 */
272pid_t
273GNUNET_OS_process_get_pid (struct GNUNET_OS_Process *proc)
274{
275 return proc->pid;
276}
277
278
279/**
280 * Cleans up process structure contents (OS-dependent) and deallocates
281 * it.
282 *
283 * @param proc pointer to process structure
284 */
285void
286GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
287{
288 if (NULL != proc->control_pipe)
289 GNUNET_DISK_file_close (proc->control_pipe);
290
291 GNUNET_free (proc);
292}
293
294
295/**
296 * Open '/dev/null' and make the result the given
297 * file descriptor.
298 *
299 * @param target_fd desired FD to point to /dev/null
300 * @param flags open flags (O_RDONLY, O_WRONLY)
301 */
302static void
303open_dev_null (int target_fd,
304 int flags)
305{
306 int fd;
307
308 fd = open ("/dev/null", flags);
309 if (-1 == fd)
310 {
311 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
312 return;
313 }
314 if (fd == target_fd)
315 return;
316 if (-1 == dup2 (fd, target_fd))
317 {
318 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
319 GNUNET_break (0 == close (fd));
320 return;
321 }
322 GNUNET_break (0 == close (fd));
323}
324
325
326/**
327 * Start a process.
328 *
329 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
330 * std handles of the parent are inherited by the child.
331 * pipe_stdin and pipe_stdout take priority over std_inheritance
332 * (when they are non-NULL).
333 * @param pipe_stdin pipe to use to send input to child process (or NULL)
334 * @param pipe_stdout pipe to use to get output from child process (or NULL)
335 * @param pipe_stderr pipe to use for stderr for child process (or NULL)
336 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
337 * must be NULL on platforms where dup is not supported
338 * @param filename name of the binary
339 * @param argv NULL-terminated list of arguments to the process
340 * @return process ID of the new process, -1 on error
341 */
342static struct GNUNET_OS_Process *
343start_process (enum GNUNET_OS_InheritStdioFlags std_inheritance,
344 struct GNUNET_DISK_PipeHandle *pipe_stdin,
345 struct GNUNET_DISK_PipeHandle *pipe_stdout,
346 struct GNUNET_DISK_PipeHandle *pipe_stderr,
347 const int *lsocks,
348 const char *filename,
349 char *const argv[])
350{
351 pid_t ret;
352 char fds[16];
353 struct GNUNET_OS_Process *gnunet_proc;
354 struct GNUNET_DISK_FileHandle *childpipe_read;
355 struct GNUNET_DISK_FileHandle *childpipe_write;
356 int childpipe_read_fd;
357 int i;
358 int j;
359 int k;
360 int tgt;
361 int flags;
362 int *lscp;
363 unsigned int ls;
364 int fd_stdout_write;
365 int fd_stdout_read;
366 int fd_stderr_write;
367 int fd_stderr_read;
368 int fd_stdin_read;
369 int fd_stdin_write;
370
371 if (GNUNET_SYSERR ==
372 GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
373 return NULL; /* not executable */
374 if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
375 {
376 struct GNUNET_DISK_PipeHandle *childpipe;
377 int dup_childpipe_read_fd = -1;
378
379 childpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
380 if (NULL == childpipe)
381 return NULL;
382 childpipe_read =
383 GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_READ);
384 childpipe_write =
385 GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_WRITE);
386 GNUNET_DISK_pipe_close (childpipe);
387 if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
388 (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
389 &childpipe_read_fd,
390 sizeof(int))) ||
391 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
392 {
393 if (NULL != childpipe_read)
394 GNUNET_DISK_file_close (childpipe_read);
395 if (NULL != childpipe_write)
396 GNUNET_DISK_file_close (childpipe_write);
397 if (0 <= dup_childpipe_read_fd)
398 GNUNET_break (0 == close (dup_childpipe_read_fd));
399 return NULL;
400 }
401 childpipe_read_fd = dup_childpipe_read_fd;
402 GNUNET_DISK_file_close (childpipe_read);
403 }
404 else
405 {
406 childpipe_write = NULL;
407 childpipe_read_fd = -1;
408 }
409 if (NULL != pipe_stdin)
410 {
411 GNUNET_assert (
412 GNUNET_OK ==
413 GNUNET_DISK_internal_file_handle_ (
414 GNUNET_DISK_pipe_handle (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
415 &fd_stdin_read,
416 sizeof(int)));
417 GNUNET_assert (
418 GNUNET_OK ==
419 GNUNET_DISK_internal_file_handle_ (
420 GNUNET_DISK_pipe_handle (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
421 &fd_stdin_write,
422 sizeof(int)));
423 }
424 if (NULL != pipe_stdout)
425 {
426 GNUNET_assert (
427 GNUNET_OK ==
428 GNUNET_DISK_internal_file_handle_ (
429 GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE),
430 &fd_stdout_write,
431 sizeof(int)));
432 GNUNET_assert (
433 GNUNET_OK ==
434 GNUNET_DISK_internal_file_handle_ (
435 GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
436 &fd_stdout_read,
437 sizeof(int)));
438 }
439 if (NULL != pipe_stderr)
440 {
441 GNUNET_assert (
442 GNUNET_OK ==
443 GNUNET_DISK_internal_file_handle_ (
444 GNUNET_DISK_pipe_handle (pipe_stderr, GNUNET_DISK_PIPE_END_READ),
445 &fd_stderr_read,
446 sizeof(int)));
447 GNUNET_assert (
448 GNUNET_OK ==
449 GNUNET_DISK_internal_file_handle_ (
450 GNUNET_DISK_pipe_handle (pipe_stderr, GNUNET_DISK_PIPE_END_WRITE),
451 &fd_stderr_write,
452 sizeof(int)));
453 }
454 lscp = NULL;
455 ls = 0;
456 if (NULL != lsocks)
457 {
458 i = 0;
459 while (-1 != (k = lsocks[i++]))
460 GNUNET_array_append (lscp, ls, k);
461 GNUNET_array_append (lscp, ls, -1);
462 }
463#if DARWIN
464 /* see https://web.archive.org/web/20150924082249/gnunet.org/vfork */
465 ret = vfork ();
466#else
467 ret = fork ();
468#endif
469 if (-1 == ret)
470 {
471 int eno = errno;
472 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
473 GNUNET_array_grow (lscp, ls, 0);
474 if (NULL != childpipe_write)
475 GNUNET_DISK_file_close (childpipe_write);
476 if (0 <= childpipe_read_fd)
477 GNUNET_break (0 == close (childpipe_read_fd));
478 errno = eno;
479 return NULL;
480 }
481 if (0 != ret)
482 {
483 unsetenv (GNUNET_OS_CONTROL_PIPE);
484 gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
485 gnunet_proc->pid = ret;
486 gnunet_proc->control_pipe = childpipe_write;
487 if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
488 {
489 GNUNET_break (0 == close (childpipe_read_fd));
490 }
491 GNUNET_array_grow (lscp, ls, 0);
492 return gnunet_proc;
493 }
494 if (0 <= childpipe_read_fd)
495 {
496 char fdbuf[100];
497#ifndef DARWIN
498 /* due to vfork, we must NOT free memory on DARWIN! */
499 GNUNET_DISK_file_close (childpipe_write);
500#endif
501 snprintf (fdbuf, 100, "%x", childpipe_read_fd);
502 setenv (GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
503 }
504 else
505 unsetenv (GNUNET_OS_CONTROL_PIPE);
506 if (NULL != pipe_stdin)
507 {
508 GNUNET_break (0 == close (fd_stdin_write));
509 if (-1 == dup2 (fd_stdin_read, 0))
510 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
511 GNUNET_break (0 == close (fd_stdin_read));
512 }
513 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
514 {
515 GNUNET_break (0 == close (0));
516 open_dev_null (0, O_RDONLY);
517 }
518 if (NULL != pipe_stdout)
519 {
520 GNUNET_break (0 == close (fd_stdout_read));
521 if (-1 == dup2 (fd_stdout_write, 1))
522 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
523 GNUNET_break (0 == close (fd_stdout_write));
524 }
525 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
526 {
527 GNUNET_break (0 == close (1));
528 open_dev_null (1, O_WRONLY);
529 }
530 if (NULL != pipe_stderr)
531 {
532 GNUNET_break (0 == close (fd_stderr_read));
533 if (-1 == dup2 (fd_stderr_write, 2))
534 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
535 GNUNET_break (0 == close (fd_stderr_write));
536 }
537 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
538 {
539 GNUNET_break (0 == close (2));
540 open_dev_null (2, O_WRONLY);
541 }
542 if (NULL != lscp)
543 {
544 /* read systemd documentation... */
545 i = 0;
546 tgt = 3;
547 while (-1 != lscp[i])
548 {
549 j = i + 1;
550 while (-1 != lscp[j])
551 {
552 if (lscp[j] == tgt)
553 {
554 /* dup away */
555 k = dup (lscp[j]);
556 GNUNET_assert (-1 != k);
557 GNUNET_assert (0 == close (lscp[j]));
558 lscp[j] = k;
559 break;
560 }
561 j++;
562 }
563 if (lscp[i] != tgt)
564 {
565 /* Bury any existing FD, no matter what; they should all be closed
566 * on exec anyway and the important ones have been dup'ed away */
567 GNUNET_break (0 == close (tgt));
568 GNUNET_assert (-1 != dup2 (lscp[i], tgt));
569 }
570 /* unset close-on-exec flag */
571 flags = fcntl (tgt, F_GETFD);
572 GNUNET_assert (flags >= 0);
573 flags &= ~FD_CLOEXEC;
574 fflush (stderr);
575 (void) fcntl (tgt, F_SETFD, flags);
576 tgt++;
577 i++;
578 }
579 GNUNET_snprintf (fds, sizeof(fds), "%u", i);
580 setenv ("LISTEN_FDS", fds, 1);
581 }
582#ifndef DARWIN
583 /* due to vfork, we must NOT free memory on DARWIN! */
584 GNUNET_array_grow (lscp, ls, 0);
585#endif
586 execvp (filename, argv);
587 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
588 _exit (1);
589}
590
591
592/**
593 * Start a process.
594 *
595 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
596 * @param pipe_stdin pipe to use to send input to child process (or NULL)
597 * @param pipe_stdout pipe to use to get output from child process (or NULL)
598 * @param pipe_stderr pipe to use to get output from child process (or NULL)
599 * @param filename name of the binary
600 * @param argv NULL-terminated array of arguments to the process
601 * @return pointer to process structure of the new process, NULL on error
602 */
603struct GNUNET_OS_Process *
604GNUNET_OS_start_process_vap (enum GNUNET_OS_InheritStdioFlags std_inheritance,
605 struct GNUNET_DISK_PipeHandle *pipe_stdin,
606 struct GNUNET_DISK_PipeHandle *pipe_stdout,
607 struct GNUNET_DISK_PipeHandle *pipe_stderr,
608 const char *filename,
609 char *const argv[])
610{
611 return start_process (std_inheritance,
612 pipe_stdin,
613 pipe_stdout,
614 pipe_stderr,
615 NULL,
616 filename,
617 argv);
618}
619
620
621/**
622 * Start a process.
623 *
624 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
625 * @param pipe_stdin pipe to use to send input to child process (or NULL)
626 * @param pipe_stdout pipe to use to get output from child process (or NULL)
627 * @param pipe_stderr pipe to use to get output from child process (or NULL)
628 * @param filename name of the binary
629 * @param va NULL-terminated list of arguments to the process
630 * @return pointer to process structure of the new process, NULL on error
631 */
632struct GNUNET_OS_Process *
633GNUNET_OS_start_process_va (enum GNUNET_OS_InheritStdioFlags std_inheritance,
634 struct GNUNET_DISK_PipeHandle *pipe_stdin,
635 struct GNUNET_DISK_PipeHandle *pipe_stdout,
636 struct GNUNET_DISK_PipeHandle *pipe_stderr,
637 const char *filename,
638 va_list va)
639{
640 struct GNUNET_OS_Process *ret;
641 va_list ap;
642 char **argv;
643 int argc;
644
645 argc = 0;
646 va_copy (ap, va);
647 while (NULL != va_arg (ap, char *))
648 argc++;
649 va_end (ap);
650 argv = GNUNET_malloc (sizeof(char *) * (argc + 1));
651 argc = 0;
652 va_copy (ap, va);
653 while (NULL != (argv[argc] = va_arg (ap, char *)))
654 argc++;
655 va_end (ap);
656 ret = GNUNET_OS_start_process_vap (std_inheritance,
657 pipe_stdin,
658 pipe_stdout,
659 pipe_stderr,
660 filename,
661 argv);
662 GNUNET_free (argv);
663 return ret;
664}
665
666
667/**
668 * Start a process.
669 *
670 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
671 * @param pipe_stdin pipe to use to send input to child process (or NULL)
672 * @param pipe_stdout pipe to use to get output from child process (or NULL)
673 * @param filename name of the binary
674 * @param ... NULL-terminated list of arguments to the process
675 * @return pointer to process structure of the new process, NULL on error
676 */
677struct GNUNET_OS_Process *
678GNUNET_OS_start_process (enum GNUNET_OS_InheritStdioFlags std_inheritance,
679 struct GNUNET_DISK_PipeHandle *pipe_stdin,
680 struct GNUNET_DISK_PipeHandle *pipe_stdout,
681 struct GNUNET_DISK_PipeHandle *pipe_stderr,
682 const char *filename,
683 ...)
684{
685 struct GNUNET_OS_Process *ret;
686 va_list ap;
687
688 va_start (ap, filename);
689 ret = GNUNET_OS_start_process_va (std_inheritance,
690 pipe_stdin,
691 pipe_stdout,
692 pipe_stderr,
693 filename,
694 ap);
695 va_end (ap);
696 return ret;
697}
698
699
700/**
701 * Start a process.
702 *
703 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags controlling which
704 * std handles of the parent are inherited by the child.
705 * pipe_stdin and pipe_stdout take priority over std_inheritance
706 * (when they are non-NULL).
707 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
708 * must be NULL on platforms where dup is not supported
709 * @param filename name of the binary
710 * @param argv NULL-terminated list of arguments to the process
711 * @return process ID of the new process, -1 on error
712 */
713struct GNUNET_OS_Process *
714GNUNET_OS_start_process_v (enum GNUNET_OS_InheritStdioFlags std_inheritance,
715 const int *lsocks,
716 const char *filename,
717 char *const argv[])
718{
719 return start_process (std_inheritance,
720 NULL,
721 NULL,
722 NULL,
723 lsocks,
724 filename,
725 argv);
726}
727
728
729/**
730 * Start a process. This function is similar to the GNUNET_OS_start_process_*
731 * except that the filename and arguments can have whole strings which contain
732 * the arguments. These arguments are to be separated by spaces and are parsed
733 * in the order they appear. Arguments containing spaces can be used by
734 * quoting them with @em ".
735 *
736 * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
737 * @param lsocks array of listen sockets to dup systemd-style (or NULL);
738 * must be NULL on platforms where dup is not supported
739 * @param filename name of the binary. It is valid to have the arguments
740 * in this string when they are separated by spaces.
741 * @param ... more arguments. Should be of type `char *`. It is valid
742 * to have the arguments in these strings when they are separated by
743 * spaces. The last argument MUST be NULL.
744 * @return pointer to process structure of the new process, NULL on error
745 */
746struct GNUNET_OS_Process *
747GNUNET_OS_start_process_s (enum GNUNET_OS_InheritStdioFlags std_inheritance,
748 const int *lsocks,
749 const char *filename,
750 ...)
751{
752 va_list ap;
753 char **argv;
754 unsigned int argv_size;
755 const char *arg;
756 const char *rpos;
757 char *pos;
758 char *cp;
759 const char *last;
760 struct GNUNET_OS_Process *proc;
761 char *binary_path;
762 int quote_on;
763 unsigned int i;
764 size_t len;
765
766 argv_size = 1;
767 va_start (ap, filename);
768 arg = filename;
769 last = NULL;
770 do
771 {
772 rpos = arg;
773 quote_on = 0;
774 while ('\0' != *rpos)
775 {
776 if ('"' == *rpos)
777 {
778 if (1 == quote_on)
779 quote_on = 0;
780 else
781 quote_on = 1;
782 }
783 if ((' ' == *rpos) && (0 == quote_on))
784 {
785 if (NULL != last)
786 argv_size++;
787 last = NULL;
788 rpos++;
789 while (' ' == *rpos)
790 rpos++;
791 }
792 if ((NULL == last) && ('\0' != *rpos)) // FIXME: == or !=?
793 last = rpos;
794 if ('\0' != *rpos)
795 rpos++;
796 }
797 if (NULL != last)
798 argv_size++;
799 }
800 while (NULL != (arg = (va_arg (ap, const char *))));
801 va_end (ap);
802
803 argv = GNUNET_malloc (argv_size * sizeof(char *));
804 argv_size = 0;
805 va_start (ap, filename);
806 arg = filename;
807 last = NULL;
808 do
809 {
810 cp = GNUNET_strdup (arg);
811 quote_on = 0;
812 pos = cp;
813 while ('\0' != *pos)
814 {
815 if ('"' == *pos)
816 {
817 if (1 == quote_on)
818 quote_on = 0;
819 else
820 quote_on = 1;
821 }
822 if ((' ' == *pos) && (0 == quote_on))
823 {
824 *pos = '\0';
825 if (NULL != last)
826 argv[argv_size++] = GNUNET_strdup (last);
827 last = NULL;
828 pos++;
829 while (' ' == *pos)
830 pos++;
831 }
832 if ((NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
833 last = pos;
834 if ('\0' != *pos)
835 pos++;
836 }
837 if (NULL != last)
838 argv[argv_size++] = GNUNET_strdup (last);
839 last = NULL;
840 GNUNET_free (cp);
841 }
842 while (NULL != (arg = (va_arg (ap, const char *))));
843 va_end (ap);
844 argv[argv_size] = NULL;
845
846 for (i = 0; i < argv_size; i++)
847 {
848 len = strlen (argv[i]);
849 if ((argv[i][0] == '"') && (argv[i][len - 1] == '"'))
850 {
851 memmove (&argv[i][0], &argv[i][1], len - 2);
852 argv[i][len - 2] = '\0';
853 }
854 }
855 binary_path = argv[0];
856 proc = GNUNET_OS_start_process_v (std_inheritance,
857 lsocks,
858 binary_path,
859 argv);
860 while (argv_size > 0)
861 GNUNET_free_nz (argv[--argv_size]);
862 GNUNET_free (argv);
863 return proc;
864}
865
866
867/**
868 * Retrieve the status of a process, waiting on it if dead.
869 * Nonblocking version.
870 *
871 * @param proc process ID
872 * @param type status type
873 * @param code return code/signal number
874 * @param options WNOHANG if non-blocking is desired
875 * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
876 */
877static int
878process_status (struct GNUNET_OS_Process *proc,
879 enum GNUNET_OS_ProcessStatusType *type,
880 unsigned long *code,
881 int options)
882{
883 int status;
884 int ret;
885
886 GNUNET_assert (0 != proc);
887 ret = waitpid (proc->pid, &status, options);
888 if (ret < 0)
889 {
890 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
891 return GNUNET_SYSERR;
892 }
893 if (0 == ret)
894 {
895 *type = GNUNET_OS_PROCESS_RUNNING;
896 *code = 0;
897 return GNUNET_NO;
898 }
899 if (proc->pid != ret)
900 {
901 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
902 return GNUNET_SYSERR;
903 }
904 if (WIFEXITED (status))
905 {
906 *type = GNUNET_OS_PROCESS_EXITED;
907 *code = WEXITSTATUS (status);
908 }
909 else if (WIFSIGNALED (status))
910 {
911 *type = GNUNET_OS_PROCESS_SIGNALED;
912 *code = WTERMSIG (status);
913 }
914 else if (WIFSTOPPED (status))
915 {
916 *type = GNUNET_OS_PROCESS_SIGNALED;
917 *code = WSTOPSIG (status);
918 }
919#ifdef WIFCONTINUED
920 else if (WIFCONTINUED (status))
921 {
922 *type = GNUNET_OS_PROCESS_RUNNING;
923 *code = 0;
924 }
925#endif
926 else
927 {
928 *type = GNUNET_OS_PROCESS_UNKNOWN;
929 *code = 0;
930 }
931
932 return GNUNET_OK;
933}
934
935
936/**
937 * Retrieve the status of a process.
938 * Nonblocking version.
939 *
940 * @param proc process ID
941 * @param type status type
942 * @param code return code/signal number
943 * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
944 */
945int
946GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
947 enum GNUNET_OS_ProcessStatusType *type,
948 unsigned long *code)
949{
950 return process_status (proc, type, code, WNOHANG);
951}
952
953
954/**
955 * Retrieve the status of a process, waiting on it if dead.
956 * Blocking version.
957 *
958 * @param proc pointer to process structure
959 * @param type status type
960 * @param code return code/signal number
961 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
962 */
963int
964GNUNET_OS_process_wait_status (struct GNUNET_OS_Process *proc,
965 enum GNUNET_OS_ProcessStatusType *type,
966 unsigned long *code)
967{
968 return process_status (proc, type, code, 0);
969}
970
971
972/**
973 * Wait for a process to terminate. The return code is discarded.
974 * You must not use #GNUNET_OS_process_status() on the same process
975 * after calling this function! This function is blocking and should
976 * thus only be used if the child process is known to have terminated
977 * or to terminate very soon.
978 *
979 * @param proc pointer to process structure
980 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
981 */
982int
983GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
984{
985 pid_t pid = proc->pid;
986 pid_t ret;
987
988 while ((pid != (ret = waitpid (pid, NULL, 0))) && (EINTR == errno))
989 ;
990 if (pid != ret)
991 {
992 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
993 return GNUNET_SYSERR;
994 }
995 return GNUNET_OK;
996}
997
998
999/**
1000 * Handle to a command.
1001 */
1002struct GNUNET_OS_CommandHandle
1003{
1004 /**
1005 * Process handle.
1006 */
1007 struct GNUNET_OS_Process *eip;
1008
1009 /**
1010 * Handle to the output pipe.
1011 */
1012 struct GNUNET_DISK_PipeHandle *opipe;
1013
1014 /**
1015 * Read-end of output pipe.
1016 */
1017 const struct GNUNET_DISK_FileHandle *r;
1018
1019 /**
1020 * Function to call on each line of output.
1021 */
1022 GNUNET_OS_LineProcessor proc;
1023
1024 /**
1025 * Closure for @e proc.
1026 */
1027 void *proc_cls;
1028
1029 /**
1030 * Buffer for the output.
1031 */
1032 char buf[1024];
1033
1034 /**
1035 * Task reading from pipe.
1036 */
1037 struct GNUNET_SCHEDULER_Task *rtask;
1038
1039 /**
1040 * When to time out.
1041 */
1042 struct GNUNET_TIME_Absolute timeout;
1043
1044 /**
1045 * Current read offset in buf.
1046 */
1047 size_t off;
1048};
1049
1050
1051/**
1052 * Stop/kill a command. Must ONLY be called either from
1053 * the callback after 'NULL' was passed for 'line' *OR*
1054 * from an independent task (not within the line processor).
1055 *
1056 * @param cmd handle to the process
1057 */
1058void
1059GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
1060{
1061 if (NULL != cmd->proc)
1062 {
1063 GNUNET_assert (NULL != cmd->rtask);
1064 GNUNET_SCHEDULER_cancel (cmd->rtask);
1065 }
1066 (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1067 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
1068 GNUNET_OS_process_destroy (cmd->eip);
1069 GNUNET_DISK_pipe_close (cmd->opipe);
1070 GNUNET_free (cmd);
1071}
1072
1073
1074/**
1075 * Read from the process and call the line processor.
1076 *
1077 * @param cls the `struct GNUNET_OS_CommandHandle *`
1078 */
1079static void
1080cmd_read (void *cls)
1081{
1082 struct GNUNET_OS_CommandHandle *cmd = cls;
1083 const struct GNUNET_SCHEDULER_TaskContext *tc;
1084 GNUNET_OS_LineProcessor proc;
1085 char *end;
1086 ssize_t ret;
1087
1088 cmd->rtask = NULL;
1089 tc = GNUNET_SCHEDULER_get_task_context ();
1090 if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
1091 {
1092 /* timeout */
1093 proc = cmd->proc;
1094 cmd->proc = NULL;
1095 proc (cmd->proc_cls, NULL);
1096 return;
1097 }
1098 ret = GNUNET_DISK_file_read (cmd->r,
1099 &cmd->buf[cmd->off],
1100 sizeof(cmd->buf) - cmd->off);
1101 if (ret <= 0)
1102 {
1103 if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1104 {
1105 cmd->buf[cmd->off] = '\0';
1106 cmd->proc (cmd->proc_cls, cmd->buf);
1107 }
1108 proc = cmd->proc;
1109 cmd->proc = NULL;
1110 proc (cmd->proc_cls, NULL);
1111 return;
1112 }
1113 end = memchr (&cmd->buf[cmd->off], '\n', ret);
1114 cmd->off += ret;
1115 while (NULL != end)
1116 {
1117 *end = '\0';
1118 cmd->proc (cmd->proc_cls, cmd->buf);
1119 memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1120 cmd->off -= (end + 1 - cmd->buf);
1121 end = memchr (cmd->buf, '\n', cmd->off);
1122 }
1123 cmd->rtask =
1124 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining (
1125 cmd->timeout),
1126 cmd->r,
1127 &cmd_read,
1128 cmd);
1129}
1130
1131
1132/**
1133 * Run the given command line and call the given function
1134 * for each line of the output.
1135 *
1136 * @param proc function to call for each line of the output
1137 * @param proc_cls closure for @a proc
1138 * @param timeout when to time out
1139 * @param binary command to run
1140 * @param ... arguments to command
1141 * @return NULL on error
1142 */
1143struct GNUNET_OS_CommandHandle *
1144GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc,
1145 void *proc_cls,
1146 struct GNUNET_TIME_Relative timeout,
1147 const char *binary,
1148 ...)
1149{
1150 struct GNUNET_OS_CommandHandle *cmd;
1151 struct GNUNET_OS_Process *eip;
1152 struct GNUNET_DISK_PipeHandle *opipe;
1153 va_list ap;
1154
1155 opipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
1156 if (NULL == opipe)
1157 return NULL;
1158 va_start (ap, binary);
1159 /* redirect stdout, don't inherit stderr/stdin */
1160 eip =
1161 GNUNET_OS_start_process_va (GNUNET_OS_INHERIT_STD_NONE,
1162 NULL,
1163 opipe,
1164 NULL,
1165 binary,
1166 ap);
1167 va_end (ap);
1168 if (NULL == eip)
1169 {
1170 GNUNET_DISK_pipe_close (opipe);
1171 return NULL;
1172 }
1173 GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
1174 cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
1175 cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1176 cmd->eip = eip;
1177 cmd->opipe = opipe;
1178 cmd->proc = proc;
1179 cmd->proc_cls = proc_cls;
1180 cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
1181 cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1182 return cmd;
1183}
1184
1185
1186/* end of os_priority.c */
diff --git a/src/util/peer.c b/src/util/peer.c
deleted file mode 100644
index 257922f36..000000000
--- a/src/util/peer.c
+++ /dev/null
@@ -1,253 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2006, 2008, 2009 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 util/peer.c
23 * @brief peer-ID table that assigns integer IDs to peer-IDs to save memory
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_peer_lib.h"
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "util-peer", __VA_ARGS__)
30
31
32struct PeerEntry
33{
34 /**
35 * The identifier itself
36 */
37 struct GNUNET_PeerIdentity id;
38
39 /**
40 * Short version of the identifier; if the RC==0, then index of next
41 * free slot in table, otherwise equal to this slot in the table.
42 */
43 GNUNET_PEER_Id pid;
44
45 /**
46 * Reference counter, 0 if this slot is not used.
47 */
48 unsigned int rc;
49};
50
51
52/**
53 * Table with our interned peer IDs.
54 */
55static struct PeerEntry **table;
56
57/**
58 * Peermap of PeerIdentities to "struct PeerEntry"
59 * (for fast lookup). NULL until the library
60 * is actually being used.
61 */
62static struct GNUNET_CONTAINER_MultiPeerMap *map;
63
64/**
65 * Size of the "table".
66 */
67static unsigned int size;
68
69/**
70 * Index of the beginning of the free list in the table; set to "size"
71 * if no slots are free in the table.
72 */
73static unsigned int free_list_start;
74
75
76/**
77 * Search for a peer identity. The reference counter is not changed.
78 *
79 * @param pid identity to find
80 * @return the interned identity or 0.
81 */
82GNUNET_PEER_Id
83GNUNET_PEER_search (const struct GNUNET_PeerIdentity *pid)
84{
85 struct PeerEntry *e;
86
87 if (NULL == pid)
88 return 0;
89 if (NULL == map)
90 return 0;
91 e = GNUNET_CONTAINER_multipeermap_get (map, pid);
92 if (NULL == e)
93 return 0;
94 GNUNET_assert (e->rc > 0);
95 return e->pid;
96}
97
98
99/**
100 * Intern an peer identity. If the identity is already known, its
101 * reference counter will be increased by one.
102 *
103 * @param pid identity to intern
104 * @return the interned identity.
105 */
106GNUNET_PEER_Id
107GNUNET_PEER_intern (const struct GNUNET_PeerIdentity *pid)
108{
109 GNUNET_PEER_Id ret;
110 struct PeerEntry *e;
111
112 if (NULL == pid)
113 return 0;
114 if (NULL == map)
115 map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
116 e = GNUNET_CONTAINER_multipeermap_get (map, pid);
117 if (NULL != e)
118 {
119 GNUNET_assert (e->rc > 0);
120 e->rc++;
121 return e->pid;
122 }
123 ret = free_list_start;
124 if (ret == size)
125 {
126 GNUNET_array_grow (table, size, size + 16);
127 for (unsigned int i = ret; i < size; i++)
128 {
129 table[i] = GNUNET_new (struct PeerEntry);
130 table[i]->pid = i + 1;
131 }
132 }
133 if (0 == ret)
134 {
135 memset (&table[0]->id, 0, sizeof(struct GNUNET_PeerIdentity));
136 table[0]->pid = 0;
137 table[0]->rc = 1;
138 ret = 1;
139 }
140 GNUNET_assert (ret < size);
141 GNUNET_assert (0 == table[ret]->rc);
142 free_list_start = table[ret]->pid;
143 table[ret]->id = *pid;
144 table[ret]->rc = 1;
145 table[ret]->pid = ret;
146 GNUNET_break (GNUNET_OK ==
147 GNUNET_CONTAINER_multipeermap_put (map,
148 &table[ret]->id,
149 table[ret],
150 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
151 return ret;
152}
153
154
155/**
156 * Decrement multiple RCs of peer identities by one.
157 *
158 * @param ids array of PIDs to decrement the RCs of
159 * @param count size of the ids array
160 */
161void
162GNUNET_PEER_decrement_rcs (const GNUNET_PEER_Id *ids, unsigned int count)
163{
164 int i;
165 GNUNET_PEER_Id id;
166
167 if (0 == count)
168 return;
169 for (i = count - 1; i >= 0; i--)
170 {
171 id = ids[i];
172 if (0 == id)
173 continue;
174 GNUNET_assert (id < size);
175 GNUNET_assert (table[id]->rc > 0);
176 table[id]->rc--;
177 if (0 == table[id]->rc)
178 {
179 GNUNET_break (GNUNET_OK ==
180 GNUNET_CONTAINER_multipeermap_remove (map,
181 &table[id]->id,
182 table[id]));
183 table[id]->pid = free_list_start;
184 free_list_start = id;
185 }
186 }
187}
188
189
190/**
191 * Change the reference counter of an interned PID.
192 *
193 * @param id identity to change the RC of
194 * @param delta how much to change the RC
195 */
196void
197GNUNET_PEER_change_rc (GNUNET_PEER_Id id, int delta)
198{
199 if (0 == id)
200 return;
201 GNUNET_assert (id < size);
202 GNUNET_assert (table[id]->rc > 0);
203 GNUNET_assert ((delta >= 0) ||
204 (table[id]->rc >= (unsigned int) (-delta)));
205 table[id]->rc += delta;
206 if (0 == table[id]->rc)
207 {
208 GNUNET_break (GNUNET_OK ==
209 GNUNET_CONTAINER_multipeermap_remove (map,
210 &table[id]->id,
211 table[id]));
212 table[id]->pid = free_list_start;
213 free_list_start = id;
214 }
215}
216
217
218/**
219 * Convert an interned PID to a normal peer identity.
220 *
221 * @param id interned PID to convert
222 * @param pid where to write the normal peer identity
223 */
224void
225GNUNET_PEER_resolve (GNUNET_PEER_Id id, struct GNUNET_PeerIdentity *pid)
226{
227 if (0 == id)
228 {
229 memset (pid, 0, sizeof(struct GNUNET_PeerIdentity));
230 return;
231 }
232 GNUNET_assert (id < size);
233 GNUNET_assert (table[id]->rc > 0);
234 *pid = table[id]->id;
235}
236
237
238/**
239 * Convert an interned PID to a normal peer identity.
240 *
241 * @param id interned PID to convert
242 * @return pointer to peer identity, valid as long 'id' is valid
243 */
244const struct GNUNET_PeerIdentity *
245GNUNET_PEER_resolve2 (GNUNET_PEER_Id id)
246{
247 GNUNET_assert (id < size);
248 GNUNET_assert (table[id]->rc > 0);
249 return &table[id]->id;
250}
251
252
253/* end of peer.c */
diff --git a/src/util/perf_crypto_asymmetric.c b/src/util/perf_crypto_asymmetric.c
deleted file mode 100644
index 8533351e1..000000000
--- a/src/util/perf_crypto_asymmetric.c
+++ /dev/null
@@ -1,132 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015 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 * @author Bart Polot
23 * @file util/perf_crypto_asymmetric.c
24 * @brief measure performance of public key functions
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gauger.h>
29
30static struct GNUNET_TIME_Absolute start;
31
32#define l 500
33
34struct TestSig
35{
36 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
37 struct GNUNET_HashCode h;
38 struct GNUNET_CRYPTO_EddsaSignature sig;
39};
40
41
42static void
43log_duration (const char *cryptosystem,
44 const char *description)
45{
46 struct GNUNET_TIME_Relative t;
47 char s[64];
48
49 sprintf (s, "%6s %15s", cryptosystem, description);
50 t = GNUNET_TIME_absolute_get_duration (start);
51 t = GNUNET_TIME_relative_divide (t, l);
52 fprintf (stdout,
53 "%s: %10s\n",
54 s,
55 GNUNET_STRINGS_relative_time_to_string (t,
56 GNUNET_NO));
57 GAUGER ("UTIL", s, t.rel_value_us, "us");
58}
59
60
61int
62main (int argc, char *argv[])
63{
64 int i;
65 struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe[l];
66 struct GNUNET_CRYPTO_EcdhePublicKey dhpub[l];
67 struct GNUNET_CRYPTO_EddsaPrivateKey eddsa[l];
68 struct GNUNET_CRYPTO_EddsaPublicKey dspub[l];
69 struct TestSig sig[l];
70
71 start = GNUNET_TIME_absolute_get ();
72 for (i = 0; i < l; i++)
73 {
74 sig[i].purp.purpose = 0;
75 sig[i].purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
76 + sizeof(struct GNUNET_HashCode));
77 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
78 &sig[i].h,
79 sizeof(sig[i].h));
80 }
81 log_duration ("", "Init");
82
83 start = GNUNET_TIME_absolute_get ();
84 for (i = 0; i < l; i++)
85 GNUNET_CRYPTO_eddsa_key_create (&eddsa[i]);
86 log_duration ("EdDSA", "create key");
87
88 start = GNUNET_TIME_absolute_get ();
89 for (i = 0; i < l; i++)
90 GNUNET_CRYPTO_eddsa_key_get_public (&eddsa[i], &dspub[i]);
91 log_duration ("EdDSA", "get public");
92
93 start = GNUNET_TIME_absolute_get ();
94 for (i = 0; i < l; i++)
95 GNUNET_assert (GNUNET_OK ==
96 GNUNET_CRYPTO_eddsa_sign_ (&eddsa[i],
97 &sig[i].purp,
98 &sig[i].sig));
99 log_duration ("EdDSA", "sign HashCode");
100
101 start = GNUNET_TIME_absolute_get ();
102 for (i = 0; i < l; i++)
103 GNUNET_assert (GNUNET_OK ==
104 GNUNET_CRYPTO_eddsa_verify_ (0,
105 &sig[i].purp,
106 &sig[i].sig,
107 &dspub[i]));
108 log_duration ("EdDSA", "verify HashCode");
109
110 start = GNUNET_TIME_absolute_get ();
111 for (i = 0; i < l; i++)
112 GNUNET_CRYPTO_ecdhe_key_create (&ecdhe[i]);
113 log_duration ("ECDH", "create key");
114
115 start = GNUNET_TIME_absolute_get ();
116 for (i = 0; i < l; i++)
117 GNUNET_CRYPTO_ecdhe_key_get_public (&ecdhe[i], &dhpub[i]);
118 log_duration ("ECDH", "get public");
119
120 start = GNUNET_TIME_absolute_get ();
121 for (i = 0; i < l - 1; i += 2)
122 {
123 GNUNET_CRYPTO_ecc_ecdh (&ecdhe[i], &dhpub[i + 1], &sig[i].h);
124 GNUNET_CRYPTO_ecc_ecdh (&ecdhe[i + 1], &dhpub[i], &sig[i + 1].h);
125 }
126 log_duration ("ECDH", "do DH");
127
128 return 0;
129}
130
131
132/* end of perf_crypto_asymmetric.c */
diff --git a/src/util/perf_crypto_ecc_dlog.c b/src/util/perf_crypto_ecc_dlog.c
deleted file mode 100644
index f32ffbd67..000000000
--- a/src/util/perf_crypto_ecc_dlog.c
+++ /dev/null
@@ -1,183 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015 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 util/perf_crypto_ecc_dlog.c
23 * @brief benchmark for ECC DLOG calculation
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gcrypt.h>
29#include <gauger.h>
30
31
32/**
33 * Name of the curve we are using. Note that we have hard-coded
34 * structs that use 256 bits, so using a bigger curve will require
35 * changes that break stuff badly. The name of the curve given here
36 * must be agreed by all peers and be supported by libgcrypt.
37 */
38#define CURVE "Ed25519"
39
40/**
41 * Maximum value we benchmark dlog for.
42 */
43#define MAX_FACT (1024 * 1024)
44
45/**
46 * Maximum memory to use, sqrt(MAX_FACT) is a good choice.
47 */
48#define MAX_MEM 1024
49
50/**
51 * How many values do we test?
52 */
53#define TEST_ITER 10
54
55
56/**
57 * Do some DLOG operations for testing.
58 *
59 * @param edc context for ECC operations
60 * @param do_dlog true if we want to actually do the bencharked operation
61 */
62static void
63test_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc,
64 bool do_dlog)
65{
66 for (unsigned int i = 0; i < TEST_ITER; i++)
67 {
68 struct GNUNET_CRYPTO_EccScalar fact;
69 struct GNUNET_CRYPTO_EccScalar n;
70 struct GNUNET_CRYPTO_EccPoint q;
71 int x;
72
73 fprintf (stderr, ".");
74 x = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
75 MAX_FACT);
76 memset (&n,
77 0,
78 sizeof (n));
79 for (unsigned int j = 0; j < x; j++)
80 sodium_increment (n.v,
81 sizeof (n.v));
82 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
83 2))
84 {
85 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
86 "Trying negative %d\n",
87 -x);
88 crypto_core_ed25519_scalar_negate (fact.v,
89 n.v);
90 x = -x;
91 }
92 else
93 {
94 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
95 "Trying positive %d\n",
96 x);
97 fact = n;
98 }
99 if (0 == x)
100 {
101 /* libsodium does not like to multiply with zero; make sure
102 'q' is a valid point (g) first, then use q = q - q to get
103 the product with zero */
104 sodium_increment (fact.v,
105 sizeof (fact.v));
106 GNUNET_assert (0 ==
107 crypto_scalarmult_ed25519_base_noclamp (q.v,
108 fact.v));
109 GNUNET_assert (
110 0 ==
111 crypto_core_ed25519_sub (q.v,
112 q.v,
113 q.v));
114 }
115 else
116 GNUNET_assert (0 ==
117 crypto_scalarmult_ed25519_base_noclamp (q.v,
118 fact.v));
119 if (do_dlog)
120 {
121 int iret;
122
123 if (x !=
124 (iret = GNUNET_CRYPTO_ecc_dlog (edc,
125 &q)))
126 {
127 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
128 "DLOG failed for value %d (got: %d)\n",
129 x,
130 iret);
131 GNUNET_assert (0);
132 }
133 }
134 }
135 fprintf (stderr,
136 "\n");
137}
138
139
140int
141main (int argc, char *argv[])
142{
143 struct GNUNET_CRYPTO_EccDlogContext *edc;
144 struct GNUNET_TIME_Absolute start;
145 struct GNUNET_TIME_Relative delta;
146
147 GNUNET_log_setup ("perf-crypto-ecc-dlog",
148 "WARNING",
149 NULL);
150 start = GNUNET_TIME_absolute_get ();
151 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_FACT,
152 MAX_MEM);
153 printf ("DLOG precomputation 1M/1K took %s\n",
154 GNUNET_STRINGS_relative_time_to_string (
155 GNUNET_TIME_absolute_get_duration (start),
156 GNUNET_YES));
157 GAUGER ("UTIL", "ECC DLOG initialization",
158 GNUNET_TIME_absolute_get_duration
159 (start).rel_value_us / 1000LL, "ms/op");
160 start = GNUNET_TIME_absolute_get ();
161 /* first do a baseline run without the DLOG */
162 test_dlog (edc, false);
163 delta = GNUNET_TIME_absolute_get_duration (start);
164 start = GNUNET_TIME_absolute_get ();
165 test_dlog (edc, true);
166 delta = GNUNET_TIME_relative_subtract (GNUNET_TIME_absolute_get_duration (
167 start),
168 delta);
169 printf ("%u DLOG calculations took %s\n",
170 TEST_ITER,
171 GNUNET_STRINGS_relative_time_to_string (delta,
172 GNUNET_YES));
173 GAUGER ("UTIL",
174 "ECC DLOG operations",
175 delta.rel_value_us / 1000LL / TEST_ITER,
176 "ms/op");
177
178 GNUNET_CRYPTO_ecc_dlog_release (edc);
179 return 0;
180}
181
182
183/* end of perf_crypto_ecc_dlog.c */
diff --git a/src/util/perf_crypto_hash.c b/src/util/perf_crypto_hash.c
deleted file mode 100644
index 3bd483639..000000000
--- a/src/util/perf_crypto_hash.c
+++ /dev/null
@@ -1,114 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002, 2003, 2004, 2006 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 * @author Christian Grothoff
23 * @file util/perf_crypto_hash.c
24 * @brief measure performance of hash function
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gauger.h>
29#include <gcrypt.h>
30
31
32static void
33perfHash ()
34{
35 struct GNUNET_HashCode hc;
36 unsigned int i;
37 char buf[64 * 1024];
38
39 memset (buf, 1, sizeof(buf));
40 for (i = 0; i < 1024; i++)
41 GNUNET_CRYPTO_hash (buf, sizeof(buf), &hc);
42}
43
44
45static void
46perfHashSmall ()
47{
48 struct GNUNET_HashCode hc;
49 unsigned int i;
50 char buf[64];
51
52 memset (buf, 1, sizeof(buf));
53 for (i = 0; i < 1024; i++)
54 GNUNET_CRYPTO_hash (buf, sizeof(buf), &hc);
55}
56
57
58static void
59perfHKDF ()
60{
61 unsigned int i;
62 char res[128];
63 char buf[128];
64 char skm[64];
65
66 memset (buf, 1, sizeof(buf));
67 memset (skm, 2, sizeof(skm));
68 for (i = 0; i < 1024; i++)
69 GNUNET_CRYPTO_hkdf (res, sizeof(res),
70 GCRY_MD_SHA512, GCRY_MD_SHA256,
71 buf, sizeof(buf),
72 skm, sizeof(skm),
73 "test", (size_t) 4,
74 NULL, 0);
75}
76
77
78int
79main (int argc, char *argv[])
80{
81 struct GNUNET_TIME_Absolute start;
82
83 start = GNUNET_TIME_absolute_get ();
84 perfHashSmall ();
85 printf ("1024x 64-byte Hash perf took %s\n",
86 GNUNET_STRINGS_relative_time_to_string (
87 GNUNET_TIME_absolute_get_duration (start),
88 GNUNET_YES));
89
90 start = GNUNET_TIME_absolute_get ();
91 perfHash ();
92 printf ("1024x 64k Hash perf took %s\n",
93 GNUNET_STRINGS_relative_time_to_string (
94 GNUNET_TIME_absolute_get_duration (start),
95 GNUNET_YES));
96 GAUGER ("UTIL", "Cryptographic hashing",
97 64 * 1024 / (1
98 + GNUNET_TIME_absolute_get_duration
99 (start).rel_value_us / 1000LL), "kb/ms");
100 start = GNUNET_TIME_absolute_get ();
101 perfHKDF ();
102 printf ("HKDF perf took %s\n",
103 GNUNET_STRINGS_relative_time_to_string (
104 GNUNET_TIME_absolute_get_duration (start),
105 GNUNET_YES));
106 GAUGER ("UTIL", "Cryptographic HKDF",
107 64 * 1024 / (1
108 + GNUNET_TIME_absolute_get_duration
109 (start).rel_value_us / 1000LL), "kb/ms");
110 return 0;
111}
112
113
114/* end of perf_crypto_hash.c */
diff --git a/src/util/perf_crypto_paillier.c b/src/util/perf_crypto_paillier.c
deleted file mode 100644
index 35e6cce16..000000000
--- a/src/util/perf_crypto_paillier.c
+++ /dev/null
@@ -1,95 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014 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 * @author Christian Grothoff
23 * @file util/perf_crypto_paillier.c
24 * @brief measure performance of Paillier encryption
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gauger.h>
29
30
31int
32main (int argc, char *argv[])
33{
34 struct GNUNET_TIME_Absolute start;
35 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
36 struct GNUNET_CRYPTO_PaillierPrivateKey private_key;
37 struct GNUNET_CRYPTO_PaillierCiphertext c1;
38 gcry_mpi_t m1;
39 unsigned int i;
40
41 start = GNUNET_TIME_absolute_get ();
42 for (i = 0; i < 10; i++)
43 GNUNET_CRYPTO_paillier_create (&public_key,
44 &private_key);
45 printf ("10x key generation took %s\n",
46 GNUNET_STRINGS_relative_time_to_string (
47 GNUNET_TIME_absolute_get_duration (start),
48 GNUNET_YES));
49 GAUGER ("UTIL", "Paillier key generation",
50 64 * 1024 / (1
51 + GNUNET_TIME_absolute_get_duration
52 (start).rel_value_us / 1000LL), "keys/ms");
53
54 m1 = gcry_mpi_new (0);
55 m1 = gcry_mpi_set_ui (m1, 1);
56 /* m1 = m1 * 2 ^ (GCPB - 3) */
57 gcry_mpi_mul_2exp (m1,
58 m1,
59 GNUNET_CRYPTO_PAILLIER_BITS - 3);
60 start = GNUNET_TIME_absolute_get ();
61 for (i = 0; i < 10; i++)
62 GNUNET_CRYPTO_paillier_encrypt (&public_key,
63 m1,
64 2,
65 &c1);
66 printf ("10x encryption took %s\n",
67 GNUNET_STRINGS_relative_time_to_string (
68 GNUNET_TIME_absolute_get_duration (start),
69 GNUNET_YES));
70 GAUGER ("UTIL", "Paillier encryption",
71 64 * 1024 / (1
72 + GNUNET_TIME_absolute_get_duration
73 (start).rel_value_us / 1000LL), "ops/ms");
74
75 start = GNUNET_TIME_absolute_get ();
76 for (i = 0; i < 10; i++)
77 GNUNET_CRYPTO_paillier_decrypt (&private_key,
78 &public_key,
79 &c1,
80 m1);
81 printf ("10x decryption took %s\n",
82 GNUNET_STRINGS_relative_time_to_string (
83 GNUNET_TIME_absolute_get_duration (start),
84 GNUNET_YES));
85 GAUGER ("UTIL", "Paillier decryption",
86 64 * 1024 / (1
87 + GNUNET_TIME_absolute_get_duration
88 (start).rel_value_us / 1000LL), "ops/ms");
89
90
91 return 0;
92}
93
94
95/* end of perf_crypto_paillier.c */
diff --git a/src/util/perf_crypto_rsa.c b/src/util/perf_crypto_rsa.c
deleted file mode 100644
index aba61786f..000000000
--- a/src/util/perf_crypto_rsa.c
+++ /dev/null
@@ -1,211 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014 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 * @author Christian Grothoff
23 * @file util/perf_crypto_rsa.c
24 * @brief measure performance of RSA signing
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gauger.h>
29
30
31/**
32 * Evaluate RSA performance.
33 *
34 * @param len keylength to evaluate with
35 */
36static void
37eval (unsigned int len)
38{
39 struct GNUNET_TIME_Absolute start;
40 struct GNUNET_CRYPTO_RsaSignature *sig;
41 struct GNUNET_CRYPTO_RsaSignature *rsig;
42 struct GNUNET_CRYPTO_RsaPublicKey *public_key;
43 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
44 struct GNUNET_CRYPTO_RsaBlindingKeySecret bsec[10];
45 unsigned int i;
46 char sbuf[128];
47 void *bbuf;
48 size_t bbuf_len;
49 struct GNUNET_HashCode hc;
50
51 start = GNUNET_TIME_absolute_get ();
52 for (i = 0; i < 10; i++)
53 {
54 private_key = GNUNET_CRYPTO_rsa_private_key_create (len);
55 GNUNET_CRYPTO_rsa_private_key_free (private_key);
56 }
57 printf ("10x %u-key generation took %s\n",
58 len,
59 GNUNET_STRINGS_relative_time_to_string (
60 GNUNET_TIME_absolute_get_duration (start),
61 GNUNET_YES));
62 GNUNET_snprintf (sbuf,
63 sizeof(sbuf),
64 "RSA %u-key generation",
65 len);
66 GAUGER ("UTIL", sbuf,
67 64 * 1024 / (1
68 + GNUNET_TIME_absolute_get_duration
69 (start).rel_value_us / 1000LL), "keys/ms");
70 private_key = GNUNET_CRYPTO_rsa_private_key_create (len);
71 public_key = GNUNET_CRYPTO_rsa_private_key_get_public (private_key);
72 for (i = 0; i < 10; i++)
73 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
74 &bsec[i], sizeof(bsec[0]));
75 /*
76 start = GNUNET_TIME_absolute_get ();
77 for (i=0;i<10;i++)
78 rsa_blinding_key_derive(public_key, &bsec[i]);
79 printf ("10x %u-blinding key generation took %s\n",
80 len,
81 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start),
82 GNUNET_YES));
83 GNUNET_snprintf (sbuf,
84 sizeof (sbuf),
85 "RSA %u-blinding key generation",
86 len);
87 GAUGER ("UTIL", sbuf,
88 64 * 1024 / (1 +
89 GNUNET_TIME_absolute_get_duration
90 (start).rel_value_us / 1000LL), "keys/ms");
91 */
92 start = GNUNET_TIME_absolute_get ();
93 GNUNET_CRYPTO_hash ("test", 4, &hc);
94 for (i = 0; i < 10; i++)
95 {
96 GNUNET_CRYPTO_rsa_blind (&hc,
97 &bsec[i],
98 public_key,
99 &bbuf,
100 &bbuf_len);
101 GNUNET_free (bbuf);
102 }
103 printf ("10x %u-blinding took %s\n",
104 len,
105 GNUNET_STRINGS_relative_time_to_string (
106 GNUNET_TIME_absolute_get_duration (start),
107 GNUNET_YES));
108 GNUNET_snprintf (sbuf,
109 sizeof(sbuf),
110 "RSA %u-blinding",
111 len);
112 GAUGER ("UTIL",
113 sbuf,
114 64 * 1024 / (1
115 + GNUNET_TIME_absolute_get_duration
116 (start).rel_value_us / 1000LL), "ops/ms");
117 GNUNET_CRYPTO_rsa_blind (&hc,
118 &bsec[0],
119 public_key,
120 &bbuf,
121 &bbuf_len);
122 start = GNUNET_TIME_absolute_get ();
123 for (i = 0; i < 10; i++)
124 {
125 sig = GNUNET_CRYPTO_rsa_sign_blinded (private_key,
126 bbuf,
127 bbuf_len);
128 GNUNET_CRYPTO_rsa_signature_free (sig);
129 }
130 printf ("10x %u-signing took %s\n",
131 len,
132 GNUNET_STRINGS_relative_time_to_string (
133 GNUNET_TIME_absolute_get_duration (start),
134 GNUNET_YES));
135 GNUNET_snprintf (sbuf,
136 sizeof(sbuf),
137 "RSA %u-signing",
138 len);
139 GAUGER ("UTIL",
140 sbuf,
141 64 * 1024 / (1
142 + GNUNET_TIME_absolute_get_duration
143 (start).rel_value_us / 1000LL), "ops/ms");
144 sig = GNUNET_CRYPTO_rsa_sign_blinded (private_key,
145 bbuf,
146 bbuf_len);
147 start = GNUNET_TIME_absolute_get ();
148 for (i = 0; i < 10; i++)
149 {
150 rsig = GNUNET_CRYPTO_rsa_unblind (sig,
151 &bsec[0],
152 public_key);
153 GNUNET_CRYPTO_rsa_signature_free (rsig);
154 }
155 printf ("10x %u-unblinding took %s\n",
156 len,
157 GNUNET_STRINGS_relative_time_to_string (
158 GNUNET_TIME_absolute_get_duration (start),
159 GNUNET_YES));
160 GNUNET_snprintf (sbuf,
161 sizeof(sbuf),
162 "RSA %u-unblinding",
163 len);
164 GAUGER ("UTIL",
165 sbuf,
166 64 * 1024 / (1
167 + GNUNET_TIME_absolute_get_duration
168 (start).rel_value_us / 1000LL), "ops/ms");
169 rsig = GNUNET_CRYPTO_rsa_unblind (sig,
170 &bsec[0],
171 public_key);
172 start = GNUNET_TIME_absolute_get ();
173 for (i = 0; i < 10; i++)
174 {
175 GNUNET_assert (GNUNET_OK ==
176 GNUNET_CRYPTO_rsa_verify (&hc,
177 rsig,
178 public_key));
179 }
180 printf ("10x %u-verifying took %s\n",
181 len,
182 GNUNET_STRINGS_relative_time_to_string (
183 GNUNET_TIME_absolute_get_duration (start),
184 GNUNET_YES));
185 GNUNET_snprintf (sbuf,
186 sizeof(sbuf),
187 "RSA %u-verification",
188 len);
189 GAUGER ("UTIL",
190 sbuf,
191 64 * 1024 / (1
192 + GNUNET_TIME_absolute_get_duration
193 (start).rel_value_us / 1000LL), "ops/ms");
194 GNUNET_CRYPTO_rsa_signature_free (sig);
195 GNUNET_CRYPTO_rsa_public_key_free (public_key);
196 GNUNET_CRYPTO_rsa_private_key_free (private_key);
197 GNUNET_free (bbuf);
198}
199
200
201int
202main (int argc, char *argv[])
203{
204 eval (1024);
205 eval (2048);
206 /* eval (4096); */
207 return 0;
208}
209
210
211/* end of perf_crypto_rsa.c */
diff --git a/src/util/perf_crypto_symmetric.c b/src/util/perf_crypto_symmetric.c
deleted file mode 100644
index 8176361ba..000000000
--- a/src/util/perf_crypto_symmetric.c
+++ /dev/null
@@ -1,77 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002, 2003, 2004, 2006 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 * @author Christian Grothoff
23 * @file util/perf_crypto_symmetric.c
24 * @brief measure performance of encryption function
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gauger.h>
29
30
31static void
32perfEncrypt ()
33{
34 unsigned int i;
35 char buf[64 * 1024];
36 char rbuf[64 * 1024];
37 struct GNUNET_CRYPTO_SymmetricSessionKey sk;
38 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
39
40 GNUNET_CRYPTO_symmetric_create_session_key (&sk);
41
42 memset (buf, 1, sizeof(buf));
43 for (i = 0; i < 1024; i++)
44 {
45 memset (&iv, (int8_t) i, sizeof(iv));
46 GNUNET_CRYPTO_symmetric_encrypt (buf, sizeof(buf),
47 &sk, &iv,
48 rbuf);
49 GNUNET_CRYPTO_symmetric_decrypt (rbuf, sizeof(buf),
50 &sk, &iv,
51 buf);
52 }
53 memset (rbuf, 1, sizeof(rbuf));
54 GNUNET_assert (0 == memcmp (rbuf, buf, sizeof(buf)));
55}
56
57
58int
59main (int argc, char *argv[])
60{
61 struct GNUNET_TIME_Absolute start;
62
63 start = GNUNET_TIME_absolute_get ();
64 perfEncrypt ();
65 printf ("Encrypt perf took %s\n",
66 GNUNET_STRINGS_relative_time_to_string (
67 GNUNET_TIME_absolute_get_duration (start),
68 GNUNET_YES));
69 GAUGER ("UTIL", "Symmetric encryption",
70 64 * 1024 / (1
71 + GNUNET_TIME_absolute_get_duration
72 (start).rel_value_us / 1000LL), "kb/ms");
73 return 0;
74}
75
76
77/* end of perf_crypto_aes.c */
diff --git a/src/util/perf_malloc.c b/src/util/perf_malloc.c
deleted file mode 100644
index ea25148ec..000000000
--- a/src/util/perf_malloc.c
+++ /dev/null
@@ -1,97 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012 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 * @author Christian Grothoff
23 * @file util/perf_malloc.c
24 * @brief measure performance of allocation functions
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gauger.h>
29
30static uint64_t
31perf_malloc ()
32{
33 uint64_t ret;
34
35 ret = 0;
36 for (size_t i = 1; i < 1024 * 1024; i += 1024)
37 {
38 ret += i;
39 GNUNET_free_nz (GNUNET_malloc (i));
40 }
41 return ret;
42}
43
44
45static uint64_t
46perf_realloc ()
47{
48 uint64_t ret;
49
50 ret = 0;
51 for (size_t i = 10; i < 1024 * 1024 / 5; i += 1024)
52 {
53 char *ptr;
54
55 ret += i;
56 ptr = GNUNET_malloc (i);
57 memset (ptr, 1, i);
58 ptr = GNUNET_realloc (ptr, i + 5);
59 for (size_t j = 0; j<i; j++)
60 GNUNET_assert (1 == ptr[j]);
61 memset (ptr, 6, i + 5);
62 ptr = GNUNET_realloc (ptr, i - 5);
63 for (size_t j = 0; j<i - 5; j++)
64 GNUNET_assert (6 == ptr[j]);
65 GNUNET_free (ptr);
66 }
67 return ret;
68}
69
70
71int
72main (int argc, char *argv[])
73{
74 struct GNUNET_TIME_Absolute start;
75 uint64_t kb;
76
77 start = GNUNET_TIME_absolute_get ();
78 kb = perf_malloc ();
79 printf ("Malloc perf took %s\n",
80 GNUNET_STRINGS_relative_time_to_string (
81 GNUNET_TIME_absolute_get_duration (start),
82 GNUNET_YES));
83 GAUGER ("UTIL", "Allocation",
84 kb / 1024 / (1
85 + GNUNET_TIME_absolute_get_duration
86 (start).rel_value_us / 1000LL), "kb/ms");
87 start = GNUNET_TIME_absolute_get ();
88 kb = perf_realloc ();
89 printf ("Realloc perf took %s\n",
90 GNUNET_STRINGS_relative_time_to_string (
91 GNUNET_TIME_absolute_get_duration (start),
92 GNUNET_YES));
93 return 0;
94}
95
96
97/* end of perf_malloc.c */
diff --git a/src/util/perf_mq.c b/src/util/perf_mq.c
deleted file mode 100644
index f6e3d78e2..000000000
--- a/src/util/perf_mq.c
+++ /dev/null
@@ -1,300 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2018, 2020 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 util/perf_mq.c
23 * @brief benchmark for mq
24 * @author Florian Dold
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include <gauger.h>
30
31#define NUM_TRANSMISSIONS 1000000
32
33/**
34 * How long does the receiver take per message?
35 */
36#define RECEIVER_THROTTLE GNUNET_TIME_relative_multiply ( \
37 GNUNET_TIME_UNIT_MILLISECONDS, 1)
38
39static unsigned int received_cnt;
40
41
42GNUNET_NETWORK_STRUCT_BEGIN
43
44struct MyMessage
45{
46 struct GNUNET_MessageHeader header;
47 uint32_t x GNUNET_PACKED;
48};
49
50GNUNET_NETWORK_STRUCT_END
51
52static int global_ret;
53
54static struct GNUNET_SCHEDULER_Task *task;
55
56static struct GNUNET_MQ_Handle *cmq;
57
58
59static void
60do_shutdown (void *cls)
61{
62 (void) cls;
63 if (NULL != task)
64 {
65 GNUNET_SCHEDULER_cancel (task);
66 task = NULL;
67 }
68 if (NULL != cmq)
69 {
70 GNUNET_MQ_destroy (cmq);
71 cmq = NULL;
72 }
73}
74
75
76/**
77 * Generic error handler, called with the appropriate
78 * error code and the same closure specified at the creation of
79 * the message queue.
80 * Not every message queue implementation supports an error handler.
81 *
82 * @param cls closure
83 * @param error error code
84 */
85static void
86error_cb (void *cls,
87 enum GNUNET_MQ_Error error)
88{
89 GNUNET_break (0);
90 global_ret = 3;
91 GNUNET_SCHEDULER_shutdown ();
92}
93
94
95static void
96handle_dummy (void *cls,
97 const struct MyMessage *msg)
98{
99 struct GNUNET_SERVICE_Client *c = cls;
100
101 GNUNET_SERVICE_client_continue (c);
102 if (received_cnt != ntohl (msg->x))
103 {
104 GNUNET_break (0);
105 global_ret = 4;
106 GNUNET_SCHEDULER_shutdown ();
107 }
108 received_cnt++;
109}
110
111
112static void
113handle_dummy2 (void *cls,
114 const struct MyMessage *msg)
115{
116 struct GNUNET_SERVICE_Client *c = cls;
117
118 GNUNET_SERVICE_client_continue (c);
119 if (NUM_TRANSMISSIONS != received_cnt)
120 {
121 GNUNET_break (0);
122 global_ret = 5;
123 }
124 GNUNET_SCHEDULER_shutdown ();
125}
126
127
128static void
129do_send (void *cls);
130
131
132/**
133 * Function called whenever MQ has sent a message.
134 */
135static void
136notify_sent_cb (void *cls)
137{
138 static unsigned int seen;
139 unsigned int *cnt = cls;
140
141 if (seen != *cnt)
142 {
143 GNUNET_break (0);
144 global_ret = 6;
145 GNUNET_SCHEDULER_shutdown ();
146 }
147 seen++;
148 GNUNET_free (cnt);
149 task = GNUNET_SCHEDULER_add_now (&do_send,
150 NULL);
151}
152
153
154static void
155do_send (void *cls)
156{
157 static unsigned int i = 0;
158 unsigned int *cnt;
159 struct GNUNET_MQ_Envelope *env;
160 struct MyMessage *m;
161
162 task = NULL;
163 if (NUM_TRANSMISSIONS == i)
164 {
165 env = GNUNET_MQ_msg (m,
166 GNUNET_MESSAGE_TYPE_DUMMY2);
167 GNUNET_MQ_send (cmq,
168 env);
169 return;
170 }
171 cnt = GNUNET_new (unsigned int);
172 *cnt = i;
173 env = GNUNET_MQ_msg (m,
174 GNUNET_MESSAGE_TYPE_DUMMY);
175 GNUNET_MQ_notify_sent (env,
176 &notify_sent_cb,
177 cnt);
178 m->x = htonl (i);
179 GNUNET_MQ_send (cmq,
180 env);
181 i++;
182}
183
184
185/**
186 * Start running the actual test.
187 *
188 * @param cls closure passed to #GNUNET_SERVICE_MAIN
189 * @param cfg configuration to use for this service
190 * @param sh handle to the newly create service
191 */
192static void
193run (void *cls,
194 const struct GNUNET_CONFIGURATION_Handle *cfg,
195 struct GNUNET_SERVICE_Handle *sh)
196{
197 struct GNUNET_MQ_MessageHandler ch[] = {
198 GNUNET_MQ_handler_end ()
199 };
200
201 (void) cls;
202 (void) sh;
203 cmq = GNUNET_CLIENT_connect (cfg,
204 "test_client",
205 ch,
206 &error_cb,
207 NULL);
208 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
209 NULL);
210 task = GNUNET_SCHEDULER_add_now (&do_send,
211 NULL);
212}
213
214
215/**
216 * Callback to be called when a client connects to the service.
217 *
218 * @param cls closure for the service
219 * @param c the new client that connected to the service
220 * @param mq the message queue used to send messages to the client
221 * @return the client-specific (`internal') closure
222 */
223static void *
224connect_cb (void *cls,
225 struct GNUNET_SERVICE_Client *c,
226 struct GNUNET_MQ_Handle *mq)
227{
228 (void) cls;
229 (void) mq;
230 return c;
231}
232
233
234/**
235 * Callback to be called when a client disconnected from the service
236 *
237 * @param cls closure for the service
238 * @param c the client that disconnected
239 * @param internal_cls the client-specific (`internal') closure
240 */
241static void
242disconnect_cb (void *cls,
243 struct GNUNET_SERVICE_Client *c,
244 void *internal_cls)
245{
246 (void) cls;
247 (void) c;
248 (void) internal_cls;
249}
250
251
252int
253main (int argc, char **argv)
254{
255 struct GNUNET_TIME_Absolute start;
256 char *test_argv[] = {
257 (char *) "test_client",
258 "-c",
259 "test_client_data.conf",
260 NULL
261 };
262 struct GNUNET_MQ_MessageHandler mh[] = {
263 GNUNET_MQ_hd_fixed_size (dummy,
264 GNUNET_MESSAGE_TYPE_DUMMY,
265 struct MyMessage,
266 NULL),
267 GNUNET_MQ_hd_fixed_size (dummy2,
268 GNUNET_MESSAGE_TYPE_DUMMY2,
269 struct MyMessage,
270 NULL),
271 GNUNET_MQ_handler_end ()
272 };
273
274 (void) argc;
275 (void) argv;
276 GNUNET_log_setup ("perf-mq",
277 "INFO",
278 NULL);
279 start = GNUNET_TIME_absolute_get ();
280 if (0 !=
281 GNUNET_SERVICE_run_ (3,
282 test_argv,
283 "test_client",
284 GNUNET_SERVICE_OPTION_NONE,
285 &run,
286 &connect_cb,
287 &disconnect_cb,
288 NULL,
289 mh))
290 return 1;
291 printf ("Scheduler perf took %s\n",
292 GNUNET_STRINGS_relative_time_to_string (
293 GNUNET_TIME_absolute_get_duration (start),
294 GNUNET_YES));
295 GAUGER ("UTIL", "Scheduler",
296 received_cnt / 1024 / (1
297 + GNUNET_TIME_absolute_get_duration
298 (start).rel_value_us / 1000LL), "kmsg/ms");
299 return global_ret;
300}
diff --git a/src/util/perf_scheduler.c b/src/util/perf_scheduler.c
deleted file mode 100644
index 4d4d0a228..000000000
--- a/src/util/perf_scheduler.c
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 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 * @author Christian Grothoff
22 * @file util/perf_scheduler.c
23 * @brief measure performance of scheduler functions
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include <gauger.h>
28
29#define RUNS (1024 * 1024)
30
31static struct GNUNET_SCHEDULER_Task *task;
32
33
34static void
35run (void *cls)
36{
37 uint64_t *count = cls;
38
39 task = NULL;
40 (*count)++;
41 if (*count >= RUNS)
42 {
43 GNUNET_SCHEDULER_shutdown ();
44 return;
45 }
46 task = GNUNET_SCHEDULER_add_now (&run,
47 count);
48}
49
50
51static void
52do_shutdown (void *cls)
53{
54 if (NULL != task)
55 GNUNET_SCHEDULER_cancel (task);
56}
57
58
59static void
60first (void *cls)
61{
62 uint64_t *count = cls;
63
64 (*count)++;
65 task = GNUNET_SCHEDULER_add_now (&run,
66 count);
67 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
68 NULL);
69}
70
71
72static uint64_t
73perf_scheduler ()
74{
75 uint64_t count = 0;
76
77 GNUNET_SCHEDULER_run (&first,
78 &count);
79 return count;
80}
81
82
83int
84main (int argc, char *argv[])
85{
86 struct GNUNET_TIME_Absolute start;
87 uint64_t tasks;
88
89 start = GNUNET_TIME_absolute_get ();
90 tasks = perf_scheduler ();
91 printf ("Scheduler perf took %s\n",
92 GNUNET_STRINGS_relative_time_to_string (
93 GNUNET_TIME_absolute_get_duration (start),
94 GNUNET_YES));
95 GAUGER ("UTIL", "Scheduler",
96 tasks / 1024 / (1
97 + GNUNET_TIME_absolute_get_duration
98 (start).rel_value_us / 1000LL), "tasks/ms");
99 return 0;
100}
101
102
103/* end of perf_scheduler.c */
diff --git a/src/util/plugin.c b/src/util/plugin.c
deleted file mode 100644
index 39874a588..000000000
--- a/src/util/plugin.c
+++ /dev/null
@@ -1,460 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002-2013 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 util/plugin.c
23 * @brief Methods to access plugins
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include <ltdl.h>
29#include "gnunet_util_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-plugin", __VA_ARGS__)
32
33/**
34 * Linked list of active plugins.
35 */
36struct PluginList
37{
38 /**
39 * This is a linked list.
40 */
41 struct PluginList *next;
42
43 /**
44 * Name of the library.
45 */
46 char *name;
47
48 /**
49 * System handle.
50 */
51 void *handle;
52};
53
54
55/**
56 * Have we been initialized?
57 */
58static int initialized;
59
60/**
61 * Libtool search path before we started.
62 */
63static char *old_dlsearchpath;
64
65/**
66 * List of plugins we have loaded.
67 */
68static struct PluginList *plugins;
69
70
71/**
72 * Setup libtool paths.
73 */
74static void
75plugin_init (void)
76{
77 int err;
78 const char *opath;
79 char *path;
80 char *cpath;
81
82 err = lt_dlinit ();
83 if (err > 0)
84 {
85 fprintf (stderr,
86 _ ("Initialization of plugin mechanism failed: %s!\n"),
87 lt_dlerror ());
88 return;
89 }
90 opath = lt_dlgetsearchpath ();
91 if (NULL != opath)
92 old_dlsearchpath = GNUNET_strdup (opath);
93 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
94 if (NULL != path)
95 {
96 if (NULL != opath)
97 {
98 GNUNET_asprintf (&cpath,
99 "%s:%s",
100 opath,
101 path);
102 lt_dlsetsearchpath (cpath);
103 GNUNET_free (path);
104 GNUNET_free (cpath);
105 }
106 else
107 {
108 lt_dlsetsearchpath (path);
109 GNUNET_free (path);
110 }
111 }
112}
113
114
115/**
116 * Shutdown libtool.
117 */
118static void
119plugin_fini (void)
120{
121 lt_dlsetsearchpath (old_dlsearchpath);
122 if (NULL != old_dlsearchpath)
123 {
124 GNUNET_free (old_dlsearchpath);
125 old_dlsearchpath = NULL;
126 }
127 lt_dlexit ();
128}
129
130
131/**
132 * Lookup a function in the plugin.
133 *
134 * @param plug the plugin to check
135 * @param name name of the symbol to look for
136 * @return NULL if the symbol was not found
137 */
138static GNUNET_PLUGIN_Callback
139resolve_function (struct PluginList *plug,
140 const char *name)
141{
142 char *initName;
143 void *mptr;
144
145 GNUNET_asprintf (&initName,
146 "_%s_%s",
147 plug->name,
148 name);
149 mptr = lt_dlsym (plug->handle,
150 &initName[1]);
151 if (NULL == mptr)
152 mptr = lt_dlsym (plug->handle,
153 initName);
154 if (NULL == mptr)
155 LOG (GNUNET_ERROR_TYPE_ERROR,
156 _ ("`%s' failed to resolve method '%s' with error: %s\n"),
157 "lt_dlsym",
158 &initName[1],
159 lt_dlerror ());
160 GNUNET_free (initName);
161 return mptr;
162}
163
164
165/**
166 * Test if a plugin exists.
167 *
168 * Note that the library must export a symbol called
169 * `library_name_init` for the test to succeed.
170 *
171 * @param library_name name of the plugin to test if it is installed
172 * @return #GNUNET_YES if the plugin exists, #GNUNET_NO if not
173 */
174int
175GNUNET_PLUGIN_test (const char *library_name)
176{
177 void *libhandle;
178 GNUNET_PLUGIN_Callback init;
179 struct PluginList plug;
180
181 if (! initialized)
182 {
183 initialized = GNUNET_YES;
184 plugin_init ();
185 }
186 libhandle = lt_dlopenext (library_name);
187 if (NULL == libhandle)
188 return GNUNET_NO;
189 plug.handle = libhandle;
190 plug.name = (char *) library_name;
191 init = resolve_function (&plug,
192 "init");
193 if (NULL == init)
194 {
195 GNUNET_break (0);
196 lt_dlclose (libhandle);
197 return GNUNET_NO;
198 }
199 lt_dlclose (libhandle);
200 return GNUNET_YES;
201}
202
203
204/**
205 * Setup plugin (runs the `init` callback and returns whatever `init`
206 * returned). If `init` returns NULL, the plugin is unloaded.
207 *
208 * Note that the library must export symbols called
209 * `library_name_init` and `library_name_done`. These will be called
210 * when the library is loaded and unloaded respectively.
211 *
212 * @param library_name name of the plugin to load
213 * @param arg argument to the plugin initialization function
214 * @return whatever the initialization function returned
215 */
216void *
217GNUNET_PLUGIN_load (const char *library_name,
218 void *arg)
219{
220 void *libhandle;
221 struct PluginList *plug;
222 GNUNET_PLUGIN_Callback init;
223 void *ret;
224
225 if (! initialized)
226 {
227 initialized = GNUNET_YES;
228 plugin_init ();
229 }
230 libhandle = lt_dlopenext (library_name);
231 if (NULL == libhandle)
232 {
233 LOG (GNUNET_ERROR_TYPE_ERROR,
234 _ ("`%s' failed for library `%s' with error: %s\n"),
235 "lt_dlopenext",
236 library_name,
237 lt_dlerror ());
238 return NULL;
239 }
240 plug = GNUNET_new (struct PluginList);
241 plug->handle = libhandle;
242 plug->name = GNUNET_strdup (library_name);
243 plug->next = plugins;
244 plugins = plug;
245 init = resolve_function (plug,
246 "init");
247 if ( (NULL == init) ||
248 (NULL == (ret = init (arg))) )
249 {
250 lt_dlclose (libhandle);
251 GNUNET_free (plug->name);
252 plugins = plug->next;
253 GNUNET_free (plug);
254 return NULL;
255 }
256 return ret;
257}
258
259
260/**
261 * Unload plugin (runs the `done` callback and returns whatever `done`
262 * returned). The plugin is then unloaded.
263 *
264 * @param library_name name of the plugin to unload
265 * @param arg argument to the plugin shutdown function
266 * @return whatever the shutdown function returned
267 */
268void *
269GNUNET_PLUGIN_unload (const char *library_name,
270 void *arg)
271{
272 struct PluginList *pos;
273 struct PluginList *prev;
274 GNUNET_PLUGIN_Callback done;
275 void *ret;
276
277 prev = NULL;
278 pos = plugins;
279 while ( (NULL != pos) &&
280 (0 != strcmp (pos->name,
281 library_name)) )
282 {
283 prev = pos;
284 pos = pos->next;
285 }
286 if (NULL == pos)
287 return NULL;
288
289 done = resolve_function (pos,
290 "done");
291 ret = NULL;
292 if (NULL != done)
293 ret = done (arg);
294 if (NULL == prev)
295 plugins = pos->next;
296 else
297 prev->next = pos->next;
298 lt_dlclose (pos->handle);
299 GNUNET_free (pos->name);
300 GNUNET_free (pos);
301 if (NULL == plugins)
302 {
303 plugin_fini ();
304 initialized = GNUNET_NO;
305 }
306 return ret;
307}
308
309
310/**
311 * Closure for #find_libraries().
312 */
313struct LoadAllContext
314{
315 /**
316 * Prefix the plugin names we find have to match.
317 */
318 const char *basename;
319
320 /**
321 * Argument to give to 'init' when loading the plugin.
322 */
323 void *arg;
324
325 /**
326 * Function to call for each plugin.
327 */
328 GNUNET_PLUGIN_LoaderCallback cb;
329
330 /**
331 * Closure for @e cb
332 */
333 void *cb_cls;
334};
335
336
337/**
338 * Function called on each plugin in the directory. Loads
339 * the plugins that match the given basename.
340 *
341 * @param cls the `struct LoadAllContext` describing which
342 * plugins to load and what to do with them
343 * @param filename name of a plugin library to check
344 * @return #GNUNET_OK (continue loading)
345 */
346static int
347find_libraries (void *cls,
348 const char *filename)
349{
350 struct LoadAllContext *lac = cls;
351 const char *slashpos;
352 const char *libname;
353 char *basename;
354 char *dot;
355 void *lib_ret;
356 size_t n;
357
358 libname = filename;
359 while (NULL != (slashpos = strstr (libname,
360 DIR_SEPARATOR_STR)))
361 libname = slashpos + 1;
362 n = strlen (libname);
363 if (0 != strncmp (lac->basename,
364 libname,
365 strlen (lac->basename)))
366 return GNUNET_OK; /* wrong name */
367 if ( (n > 3) &&
368 (0 == strcmp (&libname[n - 3], ".la")) )
369 return GNUNET_OK; /* .la file */
370 basename = GNUNET_strdup (libname);
371 if (NULL != (dot = strstr (basename, ".")))
372 *dot = '\0';
373 lib_ret = GNUNET_PLUGIN_load (basename,
374 lac->arg);
375 if (NULL != lib_ret)
376 lac->cb (lac->cb_cls,
377 basename,
378 lib_ret);
379 GNUNET_free (basename);
380 return GNUNET_OK;
381}
382
383
384/**
385 * Load all compatible plugins with the given base name.
386 *
387 * Note that the library must export symbols called
388 * `basename_ANYTHING_init` and `basename_ANYTHING__done`. These will
389 * be called when the library is loaded and unloaded respectively.
390 *
391 * If you are writing a service to which third-party applications can connect,
392 * like GNUnet's own GNS service for example, you should use
393 * #GNUNET_PLUGIN_load_all_in_context instead of this function, passing your
394 * service's project data as context.
395 *
396 * @param basename basename of the plugins to load
397 * @param arg argument to the plugin initialization function
398 * @param cb function to call for each plugin found
399 * @param cb_cls closure for @a cb
400 */
401void
402GNUNET_PLUGIN_load_all (const char *basename,
403 void *arg,
404 GNUNET_PLUGIN_LoaderCallback cb,
405 void *cb_cls)
406{
407 struct LoadAllContext lac;
408 char *path;
409
410 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
411 if (NULL == path)
412 {
413 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
414 _ ("Could not determine plugin installation path.\n"));
415 return;
416 }
417 lac.basename = basename;
418 lac.arg = arg;
419 lac.cb = cb;
420 lac.cb_cls = cb_cls;
421 GNUNET_DISK_directory_scan (path,
422 &find_libraries,
423 &lac);
424 GNUNET_free (path);
425}
426
427
428/**
429 * Load all compatible plugins with the given base name while inside the given
430 * context (i.e. a specific project data structure.)
431 *
432 * Note that the library must export symbols called `basename_ANYTHING_init`
433 * and `basename_ANYTHING__done`. These will be called when the library is
434 * loaded and unloaded respectively.
435 *
436 * @param ctx the context used to find the plugins
437 * @param basename basename of the plugins to load
438 * @param arg argument to the plugin initialization function
439 * @param cb function to call for each plugin found
440 * @param cb_cls closure for @a cb
441 */
442void
443GNUNET_PLUGIN_load_all_in_context (const struct GNUNET_OS_ProjectData *ctx,
444 const char *basename,
445 void *arg,
446 GNUNET_PLUGIN_LoaderCallback cb,
447 void *cb_cls)
448{
449 const struct GNUNET_OS_ProjectData *cpd = GNUNET_OS_project_data_get ();
450
451 GNUNET_OS_init (ctx);
452 GNUNET_PLUGIN_load_all (basename,
453 arg,
454 cb,
455 cb_cls);
456 GNUNET_OS_init (cpd);
457}
458
459
460/* end of plugin.c */
diff --git a/src/util/proc_compat.c b/src/util/proc_compat.c
deleted file mode 100644
index 6e852cb35..000000000
--- a/src/util/proc_compat.c
+++ /dev/null
@@ -1,49 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2004, 2005 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#include "platform.h"
21
22/**
23 * @author Martin Schanzenbach
24 *
25 * @file util/proc_compat.c
26 * Definitions for macOS and Win32
27 */
28
29
30/**
31 * memrchr as defined in glibc
32 *
33 * @param s pointer to memory
34 * @param c character to search for
35 * @param n search character limit
36 */
37void*
38GN_memrchr_ (const void *s,
39 int c,
40 size_t n)
41{
42 const unsigned char *ucs = s;
43 ssize_t i;
44
45 for (i = n - 1; i >= 0; i--)
46 if (c == (int) ucs[i])
47 return (void *) &ucs[i];
48 return NULL;
49}
diff --git a/src/util/program.c b/src/util/program.c
deleted file mode 100644
index fb7929b98..000000000
--- a/src/util/program.c
+++ /dev/null
@@ -1,418 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 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 PURPROSE. 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 util/program.c
23 * @brief standard code for GNUnet startup and shutdown
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_resolver_service.h"
30#include "gnunet_constants.h"
31#include "speedup.h"
32#include <gcrypt.h>
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "util-program", __VA_ARGS__)
35
36#define LOG_STRERROR_FILE(kind, syscall, filename) \
37 GNUNET_log_from_strerror_file (kind, "util-program", syscall, filename)
38
39/**
40 * Context for the command.
41 */
42struct CommandContext
43{
44 /**
45 * Argv argument.
46 */
47 char *const *args;
48
49 /**
50 * Name of the configuration file used, can be NULL!
51 */
52 char *cfgfile;
53
54 /**
55 * Main function to run.
56 */
57 GNUNET_PROGRAM_Main task;
58
59 /**
60 * Closure for @e task.
61 */
62 void *task_cls;
63
64 /**
65 * Configuration to use.
66 */
67 const struct GNUNET_CONFIGURATION_Handle *cfg;
68};
69
70
71/**
72 * task run when the scheduler shuts down
73 */
74static void
75shutdown_task (void *cls)
76{
77 (void) cls;
78 GNUNET_SPEEDUP_stop_ ();
79}
80
81
82/**
83 * Initial task called by the scheduler for each
84 * program. Runs the program-specific main task.
85 */
86static void
87program_main (void *cls)
88{
89 struct CommandContext *cc = cls;
90
91 GNUNET_SPEEDUP_start_ (cc->cfg);
92 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
93 NULL);
94 GNUNET_RESOLVER_connect (cc->cfg);
95 cc->task (cc->task_cls,
96 cc->args,
97 cc->cfgfile,
98 cc->cfg);
99}
100
101
102/**
103 * Compare function for 'qsort' to sort command-line arguments by the
104 * short option.
105 *
106 * @param a1 first command line option
107 * @param a2 second command line option
108 */
109static int
110cmd_sorter (const void *a1,
111 const void *a2)
112{
113 const struct GNUNET_GETOPT_CommandLineOption *c1 = a1;
114 const struct GNUNET_GETOPT_CommandLineOption *c2 = a2;
115
116 if (toupper ((unsigned char) c1->shortName) >
117 toupper ((unsigned char) c2->shortName))
118 return 1;
119 if (toupper ((unsigned char) c1->shortName) <
120 toupper ((unsigned char) c2->shortName))
121 return -1;
122 if (c1->shortName > c2->shortName)
123 return 1;
124 if (c1->shortName < c2->shortName)
125 return -1;
126 return 0;
127}
128
129
130enum GNUNET_GenericReturnValue
131GNUNET_PROGRAM_run2 (int argc,
132 char *const *argv,
133 const char *binaryName,
134 const char *binaryHelp,
135 const struct GNUNET_GETOPT_CommandLineOption *options,
136 GNUNET_PROGRAM_Main task,
137 void *task_cls,
138 int run_without_scheduler)
139{
140 struct CommandContext cc;
141
142#if ENABLE_NLS
143 char *path;
144#endif
145 char *loglev;
146 char *logfile;
147 char *cfg_fn;
148 enum GNUNET_GenericReturnValue ret;
149 int iret;
150 unsigned int cnt;
151 unsigned long long skew_offset;
152 unsigned long long skew_variance;
153 long long clock_offset;
154 struct GNUNET_CONFIGURATION_Handle *cfg;
155 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
156 const struct GNUNET_GETOPT_CommandLineOption defoptions[] = {
157 GNUNET_GETOPT_option_cfgfile (&cc.cfgfile),
158 GNUNET_GETOPT_option_help (binaryHelp),
159 GNUNET_GETOPT_option_loglevel (&loglev),
160 GNUNET_GETOPT_option_logfile (&logfile),
161 GNUNET_GETOPT_option_version (pd->version)
162 };
163 unsigned int deflen = sizeof(defoptions) / sizeof(defoptions[0]);
164 struct GNUNET_GETOPT_CommandLineOption *allopts;
165 const char *gargs;
166 char *lpfx;
167 char *spc;
168
169 logfile = NULL;
170 gargs = getenv ("GNUNET_ARGS");
171 if (NULL != gargs)
172 {
173 char **gargv;
174 unsigned int gargc;
175 char *cargs;
176
177 gargv = NULL;
178 gargc = 0;
179 for (int i = 0; i < argc; i++)
180 GNUNET_array_append (gargv,
181 gargc,
182 GNUNET_strdup (argv[i]));
183 cargs = GNUNET_strdup (gargs);
184 for (char *tok = strtok (cargs, " ");
185 NULL != tok;
186 tok = strtok (NULL, " "))
187 GNUNET_array_append (gargv, gargc, GNUNET_strdup (tok));
188 GNUNET_free (cargs);
189 GNUNET_array_append (gargv, gargc, NULL);
190 argv = (char *const *) gargv;
191 argc = gargc - 1;
192 }
193 memset (&cc, 0, sizeof(cc));
194 loglev = NULL;
195 cc.task = task;
196 cc.task_cls = task_cls;
197 cc.cfg = cfg = GNUNET_CONFIGURATION_create ();
198 /* prepare */
199#if ENABLE_NLS
200 if (NULL != pd->gettext_domain)
201 {
202 setlocale (LC_ALL, "");
203 path = (NULL == pd->gettext_path)
204 ? GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR)
205 : GNUNET_strdup (pd->gettext_path);
206 if (NULL != path)
207 {
208 bindtextdomain (pd->gettext_domain, path);
209 GNUNET_free (path);
210 }
211 textdomain (pd->gettext_domain);
212 }
213#endif
214 cnt = 0;
215 while (NULL != options[cnt].name)
216 cnt++;
217 allopts = GNUNET_new_array (cnt + deflen + 1,
218 struct GNUNET_GETOPT_CommandLineOption);
219 GNUNET_memcpy (allopts,
220 options,
221 cnt * sizeof(struct GNUNET_GETOPT_CommandLineOption));
222 {
223 unsigned int xtra = 0;
224
225 for (unsigned int i = 0;
226 i<sizeof (defoptions) / sizeof(struct GNUNET_GETOPT_CommandLineOption);
227 i++)
228 {
229 bool found = false;
230
231 for (unsigned int j = 0; j<cnt; j++)
232 {
233 found |= ( (options[j].shortName == defoptions[i].shortName) &&
234 (0 != options[j].shortName) );
235 found |= ( (NULL != options[j].name) &&
236 (NULL != defoptions[i].name) &&
237 (0 == strcmp (options[j].name,
238 defoptions[i].name)) );
239 if (found)
240 break;
241 }
242 if (found)
243 continue;
244 GNUNET_memcpy (&allopts[cnt + xtra],
245 &defoptions[i],
246 sizeof (struct GNUNET_GETOPT_CommandLineOption));
247 xtra++;
248 }
249 cnt += xtra;
250 }
251 qsort (allopts,
252 cnt,
253 sizeof(struct GNUNET_GETOPT_CommandLineOption),
254 &cmd_sorter);
255 loglev = NULL;
256 if ((NULL != pd->config_file) && (NULL != pd->user_config_file))
257 cfg_fn = GNUNET_CONFIGURATION_default_filename ();
258 else
259 cfg_fn = NULL;
260 lpfx = GNUNET_strdup (binaryName);
261 if (NULL != (spc = strstr (lpfx, " ")))
262 *spc = '\0';
263 iret = GNUNET_GETOPT_run (binaryName,
264 allopts,
265 (unsigned int) argc,
266 argv);
267 if ((GNUNET_OK > iret) ||
268 (GNUNET_OK != GNUNET_log_setup (lpfx,
269 loglev,
270 logfile)))
271 {
272 GNUNET_free (allopts);
273 GNUNET_free (lpfx);
274 ret = (enum GNUNET_GenericReturnValue) iret;
275 goto cleanup;
276 }
277 if (NULL != cc.cfgfile)
278 {
279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280 "Loading configuration from entry point specified as option (%s)\n",
281 cc.cfgfile);
282 if (GNUNET_YES !=
283 GNUNET_DISK_file_test (cc.cfgfile))
284 {
285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
286 _ ("Unreadable configuration file `%s', exiting ...\n"),
287 cc.cfgfile);
288 ret = GNUNET_SYSERR;
289 GNUNET_free (allopts);
290 GNUNET_free (lpfx);
291 goto cleanup;
292 }
293 if (GNUNET_SYSERR ==
294 GNUNET_CONFIGURATION_load (cfg,
295 cc.cfgfile))
296 {
297 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
298 _ ("Malformed configuration file `%s', exiting ...\n"),
299 cc.cfgfile);
300 ret = GNUNET_SYSERR;
301 GNUNET_free (allopts);
302 GNUNET_free (lpfx);
303 goto cleanup;
304 }
305 }
306 else
307 {
308 if ( (NULL != cfg_fn) &&
309 (GNUNET_YES !=
310 GNUNET_DISK_file_test (cfg_fn)) )
311 {
312 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
313 _ ("Unreadable configuration file `%s'. Exiting ...\n"),
314 cfg_fn);
315 ret = GNUNET_SYSERR;
316 GNUNET_free (allopts);
317 GNUNET_free (lpfx);
318 goto cleanup;
319 }
320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321 "Loading configuration from entry point `%s'\n",
322 cc.cfgfile);
323 if (GNUNET_SYSERR ==
324 GNUNET_CONFIGURATION_load (cfg,
325 cfg_fn))
326 {
327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328 _ ("Malformed configuration. Exiting ...\n"));
329 ret = GNUNET_SYSERR;
330 GNUNET_free (allopts);
331 GNUNET_free (lpfx);
332 goto cleanup;
333 }
334 }
335 GNUNET_free (allopts);
336 GNUNET_free (lpfx);
337 if ((GNUNET_OK ==
338 GNUNET_CONFIGURATION_get_value_number (cc.cfg,
339 "testing",
340 "skew_offset",
341 &skew_offset)) &&
342 (GNUNET_OK ==
343 GNUNET_CONFIGURATION_get_value_number (cc.cfg,
344 "testing",
345 "skew_variance",
346 &skew_variance)))
347 {
348 clock_offset = skew_offset - skew_variance;
349 GNUNET_TIME_set_offset (clock_offset);
350 }
351 /* ARM needs to know which configuration file to use when starting
352 services. If we got a command-line option *and* if nothing is
353 specified in the configuration, remember the command-line option
354 in "cfg". This is typically really only having an effect if we
355 are running code in src/arm/, as obviously the rest of the code
356 has little business with ARM-specific options. */
357 if (GNUNET_YES !=
358 GNUNET_CONFIGURATION_have_value (cfg,
359 "arm",
360 "CONFIG"))
361 {
362 if (NULL != cc.cfgfile)
363 GNUNET_CONFIGURATION_set_value_string (cfg,
364 "arm",
365 "CONFIG",
366 cc.cfgfile);
367 else if (NULL != cfg_fn)
368 GNUNET_CONFIGURATION_set_value_string (cfg,
369 "arm",
370 "CONFIG",
371 cfg_fn);
372 }
373
374 /* run */
375 cc.args = &argv[iret];
376 if ((NULL == cc.cfgfile) && (NULL != cfg_fn))
377 cc.cfgfile = GNUNET_strdup (cfg_fn);
378 if (GNUNET_NO == run_without_scheduler)
379 {
380 GNUNET_SCHEDULER_run (&program_main, &cc);
381 }
382 else
383 {
384 GNUNET_RESOLVER_connect (cc.cfg);
385 cc.task (cc.task_cls, cc.args, cc.cfgfile, cc.cfg);
386 }
387 ret = GNUNET_OK;
388cleanup:
389 GNUNET_CONFIGURATION_destroy (cfg);
390 GNUNET_free (cc.cfgfile);
391 GNUNET_free (cfg_fn);
392 GNUNET_free (loglev);
393 GNUNET_free (logfile);
394 return ret;
395}
396
397
398enum GNUNET_GenericReturnValue
399GNUNET_PROGRAM_run (int argc,
400 char *const *argv,
401 const char *binaryName,
402 const char *binaryHelp,
403 const struct GNUNET_GETOPT_CommandLineOption *options,
404 GNUNET_PROGRAM_Main task,
405 void *task_cls)
406{
407 return GNUNET_PROGRAM_run2 (argc,
408 argv,
409 binaryName,
410 binaryHelp,
411 options,
412 task,
413 task_cls,
414 GNUNET_NO);
415}
416
417
418/* end of program.c */
diff --git a/src/util/regex.c b/src/util/regex.c
deleted file mode 100644
index fed325cd6..000000000
--- a/src/util/regex.c
+++ /dev/null
@@ -1,846 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2013, 2015 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 * @file src/tun/regex.c
22 * @brief functions to convert IP networks to regexes
23 * @author Maximilian Szengel
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_tun_lib.h"
29
30/**
31 * 'wildcard', matches all possible values (for HEX encoding).
32 */
33#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"
34
35
36/**
37 * Create a regex in @a rxstr from the given @a ip and @a netmask.
38 *
39 * @param ip IPv4 representation.
40 * @param port destination port
41 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN
42 * bytes long.
43 */
44void
45GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip,
46 uint16_t port,
47 char *rxstr)
48{
49 GNUNET_snprintf (rxstr,
50 GNUNET_TUN_IPV4_REGEXLEN,
51 "4-%04X-%08X",
52 (unsigned int) port,
53 ntohl (ip->s_addr));
54}
55
56
57/**
58 * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen.
59 *
60 * @param ipv6 IPv6 representation.
61 * @param port destination port
62 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN
63 * bytes long.
64 */
65void
66GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6,
67 uint16_t port,
68 char *rxstr)
69{
70 const uint32_t *addr;
71
72 addr = (const uint32_t *) ipv6;
73 GNUNET_snprintf (rxstr,
74 GNUNET_TUN_IPV6_REGEXLEN,
75 "6-%04X-%08X%08X%08X%08X",
76 (unsigned int) port,
77 ntohl (addr[0]),
78 ntohl (addr[1]),
79 ntohl (addr[2]),
80 ntohl (addr[3]));
81}
82
83
84/**
85 * Convert the given 4-bit (!) number to a regex.
86 *
87 * @param value the value, only the lowest 4 bits will be looked at
88 * @param mask which bits in value are wildcards (any value)?
89 */
90static char *
91nibble_to_regex (uint8_t value,
92 uint8_t mask)
93{
94 char *ret;
95
96 value &= mask;
97 switch (mask)
98 {
99 case 0:
100 return GNUNET_strdup (DOT);
101
102 case 8:
103 GNUNET_asprintf (&ret,
104 "(%X|%X|%X|%X|%X|%X|%X|%X)",
105 value,
106 value + 1,
107 value + 2,
108 value + 3,
109 value + 4,
110 value + 5,
111 value + 6,
112 value + 7);
113 return ret;
114
115 case 12:
116 GNUNET_asprintf (&ret,
117 "(%X|%X|%X|%X)",
118 value,
119 value + 1,
120 value + 2,
121 value + 3);
122 return ret;
123
124 case 14:
125 GNUNET_asprintf (&ret,
126 "(%X|%X)",
127 value,
128 value + 1);
129 return ret;
130
131 case 15:
132 GNUNET_asprintf (&ret,
133 "%X",
134 value);
135 return ret;
136
137 default:
138 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
139 _ ("Bad mask: %d\n"),
140 mask);
141 GNUNET_break (0);
142 return NULL;
143 }
144}
145
146
147/**
148 * Convert the given 16-bit number to a regex.
149 *
150 * @param value the value
151 * @param mask which bits in value are wildcards (any value)?
152 */
153static char *
154num_to_regex (uint16_t value,
155 uint16_t mask)
156{
157 const uint8_t *v = (const uint8_t *) &value;
158 const uint8_t *m = (const uint8_t *) &mask;
159 char *a;
160 char *b;
161 char *c;
162 char *d;
163 char *ret;
164
165 a = nibble_to_regex (v[0] >> 4, m[0] >> 4);
166 b = nibble_to_regex (v[0] & 15, m[0] & 15);
167 c = nibble_to_regex (v[1] >> 4, m[1] >> 4);
168 d = nibble_to_regex (v[1] & 15, m[1] & 15);
169 ret = NULL;
170 if ((NULL != a) &&
171 (NULL != b) &&
172 (NULL != c) &&
173 (NULL != d))
174 GNUNET_asprintf (&ret,
175 "%s%s%s%s",
176 a, b, c, d);
177 GNUNET_free (a);
178 GNUNET_free (b);
179 GNUNET_free (c);
180 GNUNET_free (d);
181 return ret;
182}
183
184
185/**
186 * Do we need to put parents around the given argument?
187 *
188 * @param arg part of a regular expression
189 * @return #GNUNET_YES if we should parens,
190 * #GNUNET_NO if not
191 */
192static int
193needs_parens (const char *arg)
194{
195 size_t off;
196 size_t len;
197 unsigned int op;
198
199 op = 0;
200 len = strlen (arg);
201 for (off = 0; off < len; off++)
202 {
203 switch (arg[off])
204 {
205 case '(':
206 op++;
207 break;
208
209 case ')':
210 GNUNET_assert (op > 0);
211 op--;
212 break;
213
214 case '|':
215 if (0 == op)
216 return GNUNET_YES;
217 break;
218
219 default:
220 break;
221 }
222 }
223 return GNUNET_NO;
224}
225
226
227/**
228 * Compute port policy for the given range of
229 * port numbers.
230 *
231 * @param start starting offset
232 * @param end end offset
233 * @param step increment level (power of 16)
234 * @param pp port policy to convert
235 * @return corresponding regex
236 */
237static char *
238compute_policy (unsigned int start,
239 unsigned int end,
240 unsigned int step,
241 const struct GNUNET_STRINGS_PortPolicy *pp)
242{
243 unsigned int i;
244 char before[36]; /* 16 * 2 + 3 dots + 0-terminator */
245 char middlel[33]; /* 16 * 2 + 0-terminator */
246 char middleh[33]; /* 16 * 2 + 0-terminator */
247 char after[36]; /* 16 * 2 + 3 dots + 0-terminator */
248 char beforep[36 + 2]; /* 16 * 2 + 3 dots + 0-terminator + ()*/
249 char middlehp[33 + 2]; /* 16 * 2 + 0-terminator + () */
250 char middlelp[33 + 2]; /* 16 * 2 + 0-terminator + () */
251 char afterp[36 + 2]; /* 16 * 2 + 3 dots + 0-terminator + () */
252 char dots[5 * strlen (DOT)];
253 char buf[3];
254 char *middle;
255 char *ret;
256 unsigned int xstep;
257 char *recl;
258 char *rech;
259 char *reclp;
260 char *rechp;
261 unsigned int start_port;
262 unsigned int end_port;
263
264 GNUNET_assert (GNUNET_YES == pp->negate_portrange);
265 start_port = pp->start_port;
266 if (1 == start_port)
267 start_port = 0;
268 end_port = pp->end_port;
269 GNUNET_assert ((end - start) / step <= 0xF);
270 before[0] = '\0';
271 middlel[0] = '\0';
272 middleh[0] = '\0';
273 after[0] = '\0';
274 for (i = start; i <= end; i += step)
275 {
276 GNUNET_snprintf (buf,
277 sizeof(buf),
278 "%X|",
279 (i - start) / step);
280 if (i / step < start_port / step)
281 strcat (before, buf);
282 else if (i / step > end_port / step)
283 strcat (after, buf);
284 else if (i / step == start_port / step)
285 strcat (middlel, buf);
286 else if (i / step == end_port / step)
287 strcat (middleh, buf);
288 }
289 if (strlen (before) > 0)
290 before[strlen (before) - 1] = '\0';
291 if (strlen (middlel) > 0)
292 middlel[strlen (middlel) - 1] = '\0';
293 if (strlen (middleh) > 0)
294 middleh[strlen (middleh) - 1] = '\0';
295 if (strlen (after) > 0)
296 after[strlen (after) - 1] = '\0';
297 if (needs_parens (before))
298 GNUNET_snprintf (beforep,
299 sizeof(beforep),
300 "(%s)",
301 before);
302 else
303 strcpy (beforep, before);
304 if (needs_parens (middlel))
305 GNUNET_snprintf (middlelp,
306 sizeof(middlelp),
307 "(%s)",
308 middlel);
309 else
310 strcpy (middlelp, middlel);
311 if (needs_parens (middleh))
312 GNUNET_snprintf (middlehp,
313 sizeof(middlehp),
314 "(%s)",
315 middleh);
316 else
317 strcpy (middlehp, middleh);
318 if (needs_parens (after))
319 GNUNET_snprintf (afterp,
320 sizeof(afterp),
321 "(%s)",
322 after);
323 else
324 strcpy (afterp, after);
325 dots[0] = '\0';
326 for (xstep = step / 16; xstep > 0; xstep /= 16)
327 strcat (dots, DOT);
328 if (step >= 16)
329 {
330 if (strlen (middlel) > 0)
331 recl = compute_policy ((start_port / step) * step,
332 (start_port / step) * step + step - 1,
333 step / 16,
334 pp);
335 else
336 recl = GNUNET_strdup ("");
337 if (strlen (middleh) > 0)
338 rech = compute_policy ((end_port / step) * step,
339 (end_port / step) * step + step - 1,
340 step / 16,
341 pp);
342 else
343 rech = GNUNET_strdup ("");
344 }
345 else
346 {
347 recl = GNUNET_strdup ("");
348 rech = GNUNET_strdup ("");
349 middlel[0] = '\0';
350 middlelp[0] = '\0';
351 middleh[0] = '\0';
352 middlehp[0] = '\0';
353 }
354 if (needs_parens (recl))
355 GNUNET_asprintf (&reclp,
356 "(%s)",
357 recl);
358 else
359 reclp = GNUNET_strdup (recl);
360 if (needs_parens (rech))
361 GNUNET_asprintf (&rechp,
362 "(%s)",
363 rech);
364 else
365 rechp = GNUNET_strdup (rech);
366
367 if ((strlen (middleh) > 0) &&
368 (strlen (rech) > 0) &&
369 (strlen (middlel) > 0) &&
370 (strlen (recl) > 0))
371 {
372 GNUNET_asprintf (&middle,
373 "%s%s|%s%s",
374 middlel,
375 reclp,
376 middleh,
377 rechp);
378 }
379 else if ((strlen (middleh) > 0) &&
380 (strlen (rech) > 0))
381 {
382 GNUNET_asprintf (&middle,
383 "%s%s",
384 middleh,
385 rechp);
386 }
387 else if ((strlen (middlel) > 0) &&
388 (strlen (recl) > 0))
389 {
390 GNUNET_asprintf (&middle,
391 "%s%s",
392 middlel,
393 reclp);
394 }
395 else
396 {
397 middle = GNUNET_strdup ("");
398 }
399 if ((strlen (before) > 0) &&
400 (strlen (after) > 0))
401 {
402 if (strlen (dots) > 0)
403 {
404 if (strlen (middle) > 0)
405 GNUNET_asprintf (&ret,
406 "(%s%s|%s|%s%s)",
407 beforep, dots,
408 middle,
409 afterp, dots);
410 else
411 GNUNET_asprintf (&ret,
412 "(%s|%s)%s",
413 beforep,
414 afterp,
415 dots);
416 }
417 else
418 {
419 if (strlen (middle) > 0)
420 GNUNET_asprintf (&ret,
421 "(%s|%s|%s)",
422 before,
423 middle,
424 after);
425 else if (1 == step)
426 GNUNET_asprintf (&ret,
427 "%s|%s",
428 before,
429 after);
430 else
431 GNUNET_asprintf (&ret,
432 "(%s|%s)",
433 before,
434 after);
435 }
436 }
437 else if (strlen (before) > 0)
438 {
439 if (strlen (dots) > 0)
440 {
441 if (strlen (middle) > 0)
442 GNUNET_asprintf (&ret,
443 "(%s%s|%s)",
444 beforep, dots,
445 middle);
446 else
447 GNUNET_asprintf (&ret,
448 "%s%s",
449 beforep, dots);
450 }
451 else
452 {
453 if (strlen (middle) > 0)
454 GNUNET_asprintf (&ret,
455 "(%s|%s)",
456 before,
457 middle);
458 else
459 GNUNET_asprintf (&ret,
460 "%s",
461 before);
462 }
463 }
464 else if (strlen (after) > 0)
465 {
466 if (strlen (dots) > 0)
467 {
468 if (strlen (middle) > 0)
469 GNUNET_asprintf (&ret,
470 "(%s|%s%s)",
471 middle,
472 afterp, dots);
473 else
474 GNUNET_asprintf (&ret,
475 "%s%s",
476 afterp, dots);
477 }
478 else
479 {
480 if (strlen (middle) > 0)
481 GNUNET_asprintf (&ret,
482 "%s|%s",
483 middle,
484 after);
485 else
486 GNUNET_asprintf (&ret,
487 "%s",
488 after);
489 }
490 }
491 else if (strlen (middle) > 0)
492 {
493 GNUNET_asprintf (&ret,
494 "%s",
495 middle);
496 }
497 else
498 {
499 ret = GNUNET_strdup ("");
500 }
501 GNUNET_free (middle);
502 GNUNET_free (reclp);
503 GNUNET_free (rechp);
504 GNUNET_free (recl);
505 GNUNET_free (rech);
506 return ret;
507}
508
509
510/**
511 * Convert a port policy to a regular expression. Note: this is a
512 * very simplistic implementation, we might want to consider doing
513 * something more sophisiticated (resulting in smaller regular
514 * expressions) at a later time.
515 *
516 * @param pp port policy to convert
517 * @return NULL on error
518 */
519static char *
520port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
521{
522 char *reg;
523 char *ret;
524 char *pos;
525 unsigned int i;
526 unsigned int cnt;
527
528 if ((0 == pp->start_port) ||
529 ((1 == pp->start_port) &&
530 (0xFFFF == pp->end_port) &&
531 (GNUNET_NO == pp->negate_portrange)))
532 return GNUNET_strdup (DOT DOT DOT DOT);
533 if ((pp->start_port == pp->end_port) &&
534 (GNUNET_NO == pp->negate_portrange))
535 {
536 GNUNET_asprintf (&ret,
537 "%04X",
538 pp->start_port);
539 return ret;
540 }
541 if (pp->end_port < pp->start_port)
542 return NULL;
543
544 if (GNUNET_YES == pp->negate_portrange)
545 {
546 ret = compute_policy (0, 0xFFFF, 0x1000, pp);
547 }
548 else
549 {
550 cnt = pp->end_port - pp->start_port + 1;
551 reg = GNUNET_malloc (cnt * 5 + 1);
552 pos = reg;
553 for (i = 1; i <= 0xFFFF; i++)
554 {
555 if ((i >= pp->start_port) && (i <= pp->end_port))
556 {
557 if (pos == reg)
558 {
559 GNUNET_snprintf (pos,
560 5,
561 "%04X",
562 i);
563 }
564 else
565 {
566 GNUNET_snprintf (pos,
567 6,
568 "|%04X",
569 i);
570 }
571 pos += strlen (pos);
572 }
573 }
574 GNUNET_asprintf (&ret,
575 "(%s)",
576 reg);
577 GNUNET_free (reg);
578 }
579 return ret;
580}
581
582
583/**
584 * Convert an address (IPv4 or IPv6) to a regex.
585 *
586 * @param addr address
587 * @param mask network mask
588 * @param len number of bytes in @a addr and @a mask
589 * @return NULL on error, otherwise regex for the address
590 */
591static char *
592address_to_regex (const void *addr,
593 const void *mask,
594 size_t len)
595{
596 const uint16_t *a = addr;
597 const uint16_t *m = mask;
598 char *ret;
599 char *tmp;
600 char *reg;
601 unsigned int i;
602
603 ret = NULL;
604 GNUNET_assert (1 != (len % 2));
605 for (i = 0; i < len / 2; i++)
606 {
607 reg = num_to_regex (a[i], m[i]);
608 if (NULL == reg)
609 {
610 GNUNET_free (ret);
611 return NULL;
612 }
613 if (NULL == ret)
614 {
615 ret = reg;
616 }
617 else
618 {
619 GNUNET_asprintf (&tmp,
620 "%s%s",
621 ret, reg);
622 GNUNET_free (ret);
623 GNUNET_free (reg);
624 ret = tmp;
625 }
626 }
627 return ret;
628}
629
630
631/**
632 * Convert a single line of an IPv4 policy to a regular expression.
633 *
634 * @param v4 line to convert
635 * @return NULL on error
636 */
637static char *
638ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
639{
640 char *reg;
641 char *pp;
642 char *ret;
643
644 reg = address_to_regex (&v4->network,
645 &v4->netmask,
646 sizeof(struct in_addr));
647 if (NULL == reg)
648 return NULL;
649 pp = port_to_regex (&v4->pp);
650 if (NULL == pp)
651 {
652 GNUNET_free (reg);
653 return NULL;
654 }
655 GNUNET_asprintf (&ret,
656 "4-%s-%s",
657 pp, reg);
658 GNUNET_free (pp);
659 GNUNET_free (reg);
660 return ret;
661}
662
663
664/**
665 * Convert a single line of an IPv4 policy to a regular expression.
666 *
667 * @param v6 line to convert
668 * @return NULL on error
669 */
670static char *
671ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
672{
673 char *reg;
674 char *pp;
675 char *ret;
676
677 reg = address_to_regex (&v6->network,
678 &v6->netmask,
679 sizeof(struct in6_addr));
680 if (NULL == reg)
681 return NULL;
682 pp = port_to_regex (&v6->pp);
683 if (NULL == pp)
684 {
685 GNUNET_free (reg);
686 return NULL;
687 }
688 GNUNET_asprintf (&ret,
689 "6-%s-%s",
690 pp, reg);
691 GNUNET_free (pp);
692 GNUNET_free (reg);
693 return ret;
694}
695
696
697/**
698 * Convert an exit policy to a regular expression. The exit policy
699 * specifies a set of subnets this peer is willing to serve as an
700 * exit for; the resulting regular expression will match the
701 * IPv4 address strings as returned by #GNUNET_TUN_ipv4toregexsearch().
702 *
703 * @param policy exit policy specification
704 * @return regular expression, NULL on error
705 */
706char *
707GNUNET_TUN_ipv4policy2regex (const char *policy)
708{
709 struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
710 char *reg;
711 char *tmp;
712 char *line;
713 unsigned int i;
714
715 np = GNUNET_STRINGS_parse_ipv4_policy (policy);
716 if (NULL == np)
717 return NULL;
718 reg = NULL;
719 for (i = 0; (0 == i) || (0 != np[i].network.s_addr); i++)
720 {
721 line = ipv4_to_regex (&np[i]);
722 if (NULL == line)
723 {
724 GNUNET_free (reg);
725 GNUNET_free (np);
726 return NULL;
727 }
728 if (NULL == reg)
729 {
730 reg = line;
731 }
732 else
733 {
734 GNUNET_asprintf (&tmp,
735 "%s|(%s)",
736 reg, line);
737 GNUNET_free (reg);
738 GNUNET_free (line);
739 reg = tmp;
740 }
741 if (0 == np[i].network.s_addr)
742 break;
743 }
744 GNUNET_free (np);
745 return reg;
746}
747
748
749/**
750 * Convert an exit policy to a regular expression. The exit policy
751 * specifies a set of subnets this peer is willing to serve as an
752 * exit for; the resulting regular expression will match the
753 * IPv6 address strings as returned by #GNUNET_TUN_ipv6toregexsearch().
754 *
755 * @param policy exit policy specification
756 * @return regular expression, NULL on error
757 */
758char *
759GNUNET_TUN_ipv6policy2regex (const char *policy)
760{
761 struct in6_addr zero;
762 struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
763 char *reg;
764 char *tmp;
765 char *line;
766 unsigned int i;
767
768 np = GNUNET_STRINGS_parse_ipv6_policy (policy);
769 if (NULL == np)
770 return NULL;
771 reg = NULL;
772 memset (&zero, 0, sizeof(struct in6_addr));
773 for (i = 0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof(struct
774 in6_addr)));
775 i++)
776 {
777 line = ipv6_to_regex (&np[i]);
778 if (NULL == line)
779 {
780 GNUNET_free (reg);
781 GNUNET_free (np);
782 return NULL;
783 }
784 if (NULL == reg)
785 {
786 reg = line;
787 }
788 else
789 {
790 GNUNET_asprintf (&tmp,
791 "%s|(%s)",
792 reg, line);
793 GNUNET_free (reg);
794 GNUNET_free (line);
795 reg = tmp;
796 }
797 if (0 == memcmp (&zero, &np[i].network, sizeof(struct in6_addr)))
798 break;
799 }
800 GNUNET_free (np);
801 return reg;
802}
803
804
805/**
806 * Hash the service name of a hosted service to the
807 * hash code that is used to identify the service on
808 * the network.
809 *
810 * @param service_name a string
811 * @param hc corresponding hash
812 */
813void
814GNUNET_TUN_service_name_to_hash (const char *service_name,
815 struct GNUNET_HashCode *hc)
816{
817 GNUNET_CRYPTO_hash (service_name,
818 strlen (service_name),
819 hc);
820}
821
822
823/**
824 * Compute the CADET port given a service descriptor
825 * (returned from #GNUNET_TUN_service_name_to_hash) and
826 * a TCP/UDP port @a ip_port.
827 *
828 * @param desc service shared secret
829 * @param ip_port TCP/UDP port, use 0 for ICMP
830 * @param[out] cadet_port CADET port to use
831 */
832void
833GNUNET_TUN_compute_service_cadet_port (const struct GNUNET_HashCode *desc,
834 uint16_t ip_port,
835 struct GNUNET_HashCode *cadet_port)
836{
837 uint16_t be_port = htons (ip_port);
838
839 *cadet_port = *desc;
840 GNUNET_memcpy (cadet_port,
841 &be_port,
842 sizeof(uint16_t));
843}
844
845
846/* end of regex.c */
diff --git a/src/util/resolver.conf.in b/src/util/resolver.conf.in
deleted file mode 100644
index 6e2b9a869..000000000
--- a/src/util/resolver.conf.in
+++ /dev/null
@@ -1,20 +0,0 @@
1[resolver]
2START_ON_DEMAND = @START_ON_DEMAND@
3@JAVAPORT@PORT = 2089
4HOSTNAME = localhost
5BINARY = gnunet-service-resolver
6ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver.sock
9UNIX_MATCH_UID = NO
10UNIX_MATCH_GID = NO
11# DISABLE_SOCKET_FORWARDING = NO
12# USERNAME =
13# MAXBUF =
14# TIMEOUT =
15# DISABLEV6 =
16# BINDTO =
17# REJECT_FROM =
18# REJECT_FROM6 =
19# PREFIX =
20
diff --git a/src/util/resolver.h b/src/util/resolver.h
deleted file mode 100644
index e487f6e6f..000000000
--- a/src/util/resolver.h
+++ /dev/null
@@ -1,93 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 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 * @author Christian Grothoff
23 * @file util/resolver.h
24 */
25#ifndef RESOLVER_H
26#define RESOLVER_H
27
28#include "gnunet_common.h"
29
30GNUNET_NETWORK_STRUCT_BEGIN
31
32/**
33 * Request for the resolver. Followed by either the "struct sockaddr"
34 * or the 0-terminated hostname.
35 *
36 * The response will be one or more messages of type
37 * RESOLVER_RESPONSE, each with the message header immediately
38 * followed by the requested data (0-terminated hostname or struct
39 * in[6]_addr, depending on direction). The last RESOLVER_RESPONSE
40 * will just be a header without any data (used to indicate the end of
41 * the list).
42 */
43struct GNUNET_RESOLVER_GetMessage
44{
45 /**
46 * Type: #GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST
47 */
48 struct GNUNET_MessageHeader header;
49
50 /**
51 * GNUNET_YES to get hostname from IP,
52 * GNUNET_NO to get IP from hostname.
53 */
54 int32_t direction GNUNET_PACKED;
55
56 /**
57 * Address family to use (AF_INET, AF_INET6 or AF_UNSPEC).
58 */
59 int32_t af GNUNET_PACKED;
60
61 /**
62 * identifies the request and is contained in the response message. The
63 * client has to match response to request by this identifier.
64 */
65 uint32_t client_id GNUNET_PACKED;
66
67 /* followed by 0-terminated string for A/AAAA-lookup or
68 by 'struct in_addr' / 'struct in6_addr' for reverse lookup */
69};
70
71
72struct GNUNET_RESOLVER_ResponseMessage
73{
74 /**
75 * Type: #GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE
76 */
77 struct GNUNET_MessageHeader header;
78
79 /**
80 * identifies the request this message responds to. The client
81 * has to match response to request by this identifier.
82 */
83 uint32_t client_id GNUNET_PACKED;
84
85 /* followed by 0-terminated string for response to a reverse lookup
86 * or by 'struct in_addr' / 'struct in6_addr' for response to
87 * A/AAAA-lookup
88 */
89};
90
91GNUNET_NETWORK_STRUCT_END
92
93#endif
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c
deleted file mode 100644
index d38c700e4..000000000
--- a/src/util/resolver_api.c
+++ /dev/null
@@ -1,1294 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-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 util/resolver_api.c
23 * @brief resolver for writing a tool
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_resolver_service.h"
30#include "resolver.h"
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util-resolver-api", __VA_ARGS__)
33
34#define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \
35 "util-resolver-api", \
36 syscall)
37
38/**
39 * Maximum supported length for a hostname
40 */
41#define MAX_HOSTNAME 1024
42
43
44/**
45 * Possible hostnames for "loopback".
46 */
47static const char *loopback[] = {
48 "localhost",
49 "ip6-localnet",
50 NULL
51};
52
53
54/**
55 * Configuration.
56 */
57static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg;
58
59/**
60 * Our connection to the resolver service, created on-demand, but then
61 * persists until error or shutdown.
62 */
63static struct GNUNET_MQ_Handle *mq;
64
65/**
66 * Head of DLL of requests.
67 */
68static struct GNUNET_RESOLVER_RequestHandle *req_head;
69
70/**
71 * Tail of DLL of requests.
72 */
73static struct GNUNET_RESOLVER_RequestHandle *req_tail;
74
75/**
76 * ID of the last request we sent to the service
77 */
78static uint32_t last_request_id;
79
80/**
81 * How long should we wait to reconnect?
82 */
83static struct GNUNET_TIME_Relative backoff;
84
85/**
86 * Task for reconnecting.
87 */
88static struct GNUNET_SCHEDULER_Task *r_task;
89
90/**
91 * Task ID of shutdown task; only present while we have a
92 * connection to the resolver service.
93 */
94static struct GNUNET_SCHEDULER_Task *s_task;
95
96
97/**
98 * Handle to a request given to the resolver. Can be used to cancel
99 * the request prior to the timeout or successful execution. Also
100 * used to track our internal state for the request.
101 */
102struct GNUNET_RESOLVER_RequestHandle
103{
104 /**
105 * Next entry in DLL of requests.
106 */
107 struct GNUNET_RESOLVER_RequestHandle *next;
108
109 /**
110 * Previous entry in DLL of requests.
111 */
112 struct GNUNET_RESOLVER_RequestHandle *prev;
113
114 /**
115 * Callback if this is an name resolution request,
116 * otherwise NULL.
117 */
118 GNUNET_RESOLVER_AddressCallback addr_callback;
119
120 /**
121 * Callback if this is a reverse lookup request,
122 * otherwise NULL.
123 */
124 GNUNET_RESOLVER_HostnameCallback name_callback;
125
126 /**
127 * Closure for the callbacks.
128 */
129 void *cls;
130
131 /**
132 * When should this request time out?
133 */
134 struct GNUNET_TIME_Absolute timeout;
135
136 /**
137 * Task handle for making reply callbacks in numeric lookups
138 * asynchronous, and for timeout handling.
139 */
140 struct GNUNET_SCHEDULER_Task *task;
141
142 /**
143 * Desired address family.
144 */
145 int af;
146
147 /**
148 * Identifies the request. The response will contain this id.
149 */
150 uint32_t id;
151
152 /**
153 * Has this request been transmitted to the service?
154 * #GNUNET_YES if transmitted
155 * #GNUNET_NO if not transmitted
156 * #GNUNET_SYSERR when request was canceled
157 */
158 int was_transmitted;
159
160 /**
161 * Did we add this request to the queue?
162 */
163 int was_queued;
164
165 /**
166 * Desired direction (IP to name or name to IP)
167 */
168 int direction;
169
170 /**
171 * #GNUNET_YES if a response was received
172 */
173 int received_response;
174
175 /**
176 * Length of the data that follows this struct.
177 */
178 size_t data_len;
179};
180
181
182/**
183 * Check that the resolver service runs on localhost
184 * (or equivalent).
185 *
186 * @return #GNUNET_OK if the resolver is properly configured,
187 * #GNUNET_SYSERR otherwise.
188 */
189static int
190check_config ()
191{
192 char *hostname;
193 struct sockaddr_in v4;
194 struct sockaddr_in6 v6;
195
196 if (GNUNET_OK ==
197 GNUNET_CONFIGURATION_have_value (resolver_cfg,
198 "resolver",
199 "UNIXPATH"))
200 return GNUNET_OK;
201 memset (&v4, 0, sizeof(v4));
202 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
203 v4.sin_family = AF_INET;
204#if HAVE_SOCKADDR_IN_SIN_LEN
205 v4.sin_len = sizeof(v4);
206#endif
207 memset (&v6, 0, sizeof(v6));
208 v6.sin6_family = AF_INET6;
209#if HAVE_SOCKADDR_IN_SIN_LEN
210 v6.sin6_len = sizeof(v6);
211#endif
212 if (GNUNET_OK !=
213 GNUNET_CONFIGURATION_get_value_string (resolver_cfg,
214 "resolver",
215 "HOSTNAME",
216 &hostname))
217 {
218 LOG (GNUNET_ERROR_TYPE_INFO,
219 _ (
220 "Missing `%s' for `%s' in configuration, DNS resolution will be unavailable.\n"),
221 "HOSTNAME",
222 "resolver");
223 return GNUNET_SYSERR;
224 }
225 if ((1 == inet_pton (AF_INET, hostname, &v4)) ||
226 (1 == inet_pton (AF_INET6, hostname, &v6)))
227 {
228 GNUNET_free (hostname);
229 return GNUNET_OK;
230 }
231 for (unsigned int i = 0;
232 NULL != loopback[i];
233 i++)
234 if (0 == strcasecmp (loopback[i],
235 hostname))
236 {
237 GNUNET_free (hostname);
238 return GNUNET_OK;
239 }
240 LOG (GNUNET_ERROR_TYPE_INFO,
241 _ (
242 "Missing `%s' or numeric IP address for `%s' of `%s' in configuration, DNS resolution will be unavailable.\n"),
243 "localhost",
244 "HOSTNAME",
245 "resolver");
246 GNUNET_free (hostname);
247 return GNUNET_SYSERR;
248}
249
250
251/**
252 * Create the connection to the resolver service.
253 *
254 * @param cfg configuration to use
255 */
256void
257GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
258{
259 GNUNET_assert (NULL != cfg);
260 backoff = GNUNET_TIME_UNIT_MILLISECONDS;
261 resolver_cfg = cfg;
262}
263
264
265/**
266 * Destroy the connection to the resolver service.
267 */
268void
269GNUNET_RESOLVER_disconnect ()
270{
271 struct GNUNET_RESOLVER_RequestHandle *rh;
272
273 while (NULL != (rh = req_head))
274 {
275 GNUNET_assert (GNUNET_SYSERR == rh->was_transmitted);
276 GNUNET_CONTAINER_DLL_remove (req_head,
277 req_tail,
278 rh);
279 GNUNET_free (rh);
280 }
281 if (NULL != mq)
282 {
283 LOG (GNUNET_ERROR_TYPE_DEBUG,
284 "Disconnecting from DNS service\n");
285 GNUNET_MQ_destroy (mq);
286 mq = NULL;
287 }
288 if (NULL != r_task)
289 {
290 GNUNET_SCHEDULER_cancel (r_task);
291 r_task = NULL;
292 }
293 if (NULL != s_task)
294 {
295 GNUNET_SCHEDULER_cancel (s_task);
296 s_task = NULL;
297 }
298}
299
300
301/**
302 * Task executed on system shutdown.
303 */
304static void
305shutdown_task (void *cls)
306{
307 (void) cls;
308 s_task = NULL;
309 GNUNET_RESOLVER_disconnect ();
310 backoff = GNUNET_TIME_UNIT_MILLISECONDS;
311}
312
313
314/**
315 * Consider disconnecting if we have no further requests pending.
316 */
317static void
318check_disconnect ()
319{
320 for (struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
321 NULL != rh;
322 rh = rh->next)
323 if (GNUNET_SYSERR != rh->was_transmitted)
324 return;
325 if (NULL != r_task)
326 {
327 GNUNET_SCHEDULER_cancel (r_task);
328 r_task = NULL;
329 }
330 if (NULL != s_task)
331 return;
332 s_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
333 &shutdown_task,
334 NULL);
335}
336
337
338/**
339 * Convert IP address to string without DNS resolution.
340 *
341 * @param af address family
342 * @param ip the address
343 * @param ip_len number of bytes in @a ip
344 * @return address as a string, NULL on error
345 */
346static char *
347no_resolve (int af,
348 const void *ip,
349 socklen_t ip_len)
350{
351 char buf[INET6_ADDRSTRLEN];
352
353 switch (af)
354 {
355 case AF_INET:
356 if (ip_len != sizeof(struct in_addr))
357 return NULL;
358 if (NULL ==
359 inet_ntop (AF_INET,
360 ip,
361 buf,
362 sizeof(buf)))
363 {
364 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
365 "inet_ntop");
366 return NULL;
367 }
368 break;
369
370 case AF_INET6:
371 if (ip_len != sizeof(struct in6_addr))
372 return NULL;
373 if (NULL ==
374 inet_ntop (AF_INET6,
375 ip,
376 buf,
377 sizeof(buf)))
378 {
379 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
380 "inet_ntop");
381 return NULL;
382 }
383 break;
384
385 default:
386 GNUNET_break (0);
387 return NULL;
388 }
389 return GNUNET_strdup (buf);
390}
391
392
393/**
394 * Adjust exponential back-off and reconnect to the service.
395 */
396static void
397reconnect (void);
398
399
400/**
401 * Generic error handler, called with the appropriate error code and
402 * the same closure specified at the creation of the message queue.
403 * Not every message queue implementation supports an error handler.
404 *
405 * @param cls NULL
406 * @param error error code
407 */
408static void
409mq_error_handler (void *cls,
410 enum GNUNET_MQ_Error error)
411{
412 (void) cls;
413 GNUNET_MQ_destroy (mq);
414 mq = NULL;
415 LOG (GNUNET_ERROR_TYPE_DEBUG,
416 "MQ error %d, reconnecting\n",
417 error);
418 reconnect ();
419}
420
421
422/**
423 * Process pending requests to the resolver.
424 */
425static void
426process_requests ()
427{
428 struct GNUNET_RESOLVER_GetMessage *msg;
429 struct GNUNET_MQ_Envelope *env;
430 struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
431
432 if (NULL == mq)
433 {
434 reconnect ();
435 return;
436 }
437 if (NULL == rh)
438 {
439 /* nothing to do, release socket really soon if there is nothing
440 * else happening... */
441 if (NULL == s_task)
442 s_task =
443 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
444 &shutdown_task,
445 NULL);
446 return;
447 }
448 if (GNUNET_NO != rh->was_transmitted)
449 return; /* waiting for reply */
450 env = GNUNET_MQ_msg_extra (msg,
451 rh->data_len,
452 GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
453 msg->direction = htonl (rh->direction);
454 msg->af = htonl (rh->af);
455 msg->client_id = rh->id;
456 GNUNET_memcpy (&msg[1],
457 &rh[1],
458 rh->data_len);
459 LOG (GNUNET_ERROR_TYPE_DEBUG,
460 "Transmitting DNS resolution request (ID %u) to DNS service\n",
461 rh->id);
462 GNUNET_MQ_send (mq,
463 env);
464 rh->was_transmitted = GNUNET_YES;
465}
466
467
468/**
469 * Check validity of response with a hostname for a DNS lookup.
470 *
471 * @param cls NULL
472 * @param msg message with the hostname
473 */
474static int
475check_response (void *cls,
476 const struct GNUNET_RESOLVER_ResponseMessage *msg)
477{
478 (void) cls;
479 (void) msg;
480
481 /* implemented in #handle_response() for now */
482 return GNUNET_OK;
483}
484
485
486/**
487 * Check validity of response with a hostname for a DNS lookup.
488 * NOTE: right now rather messy, might want to use different
489 * message types for different response formats in the future.
490 *
491 * @param cls NULL
492 * @param msg message with the response
493 */
494static void
495handle_response (void *cls,
496 const struct GNUNET_RESOLVER_ResponseMessage *msg)
497{
498 struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
499 uint16_t size;
500 char *nret;
501 uint32_t client_request_id = msg->client_id;
502
503 for (; rh != NULL; rh = rh->next)
504 {
505 if (rh->id == client_request_id)
506 break;
507 }
508
509 (void) cls;
510 if (NULL == rh)
511 {
512 /* Resolver service sent extra replies to query (after terminator)? Bad! */
513 GNUNET_break (0);
514 GNUNET_MQ_destroy (mq);
515 mq = NULL;
516 reconnect ();
517 return;
518 }
519 size = ntohs (msg->header.size);
520 if (size == sizeof(struct GNUNET_RESOLVER_ResponseMessage))
521 {
522 LOG (GNUNET_ERROR_TYPE_DEBUG,
523 "Received empty response from DNS service\n");
524 /* message contains not data, just header; end of replies */
525 /* check if request was canceled */
526 if (GNUNET_SYSERR != rh->was_transmitted)
527 {
528 /* no reverse lookup was successful, return IP as string */
529 if (NULL != rh->name_callback)
530 {
531 if (GNUNET_NO == rh->received_response)
532 {
533 nret = no_resolve (rh->af,
534 &rh[1],
535 rh->data_len);
536 rh->name_callback (rh->cls, nret);
537 GNUNET_free (nret);
538 }
539 /* finally, make termination call */
540 if (GNUNET_SYSERR != rh->was_transmitted)
541 rh->name_callback (rh->cls,
542 NULL);
543 }
544 if ((NULL != rh->addr_callback) &&
545 (GNUNET_SYSERR != rh->was_transmitted))
546 rh->addr_callback (rh->cls,
547 NULL,
548 0);
549 }
550 rh->was_transmitted = GNUNET_NO;
551 GNUNET_RESOLVER_request_cancel (rh);
552 process_requests ();
553 return;
554 }
555 /* return reverse lookup results to caller */
556 if (NULL != rh->name_callback)
557 {
558 const char *hostname;
559
560 hostname = (const char *) &msg[1];
561 if (hostname[size - sizeof(struct GNUNET_RESOLVER_ResponseMessage) - 1] !=
562 '\0')
563 {
564 GNUNET_break (0);
565 if (GNUNET_SYSERR != rh->was_transmitted)
566 rh->name_callback (rh->cls,
567 NULL);
568 rh->was_transmitted = GNUNET_NO;
569 GNUNET_RESOLVER_request_cancel (rh);
570 GNUNET_MQ_destroy (mq);
571 mq = NULL;
572 reconnect ();
573 return;
574 }
575 LOG (GNUNET_ERROR_TYPE_DEBUG,
576 "Resolver returns `%s' for IP `%s'.\n",
577 hostname,
578 GNUNET_a2s ((const void *) &rh[1],
579 rh->data_len));
580 if (rh->was_transmitted != GNUNET_SYSERR)
581 rh->name_callback (rh->cls,
582 hostname);
583 rh->received_response = GNUNET_YES;
584 }
585 /* return lookup results to caller */
586 if (NULL != rh->addr_callback)
587 {
588 struct sockaddr_in v4;
589 struct sockaddr_in6 v6;
590 const struct sockaddr *sa;
591 socklen_t salen;
592 const void *ip;
593 size_t ip_len;
594
595 ip = &msg[1];
596 ip_len = size - sizeof(struct GNUNET_RESOLVER_ResponseMessage);
597 if (ip_len == sizeof(struct in_addr))
598 {
599 memset (&v4, 0, sizeof(v4));
600 v4.sin_family = AF_INET;
601 v4.sin_addr = *(struct in_addr*) ip;
602#if HAVE_SOCKADDR_IN_SIN_LEN
603 v4.sin_len = sizeof(v4);
604#endif
605 salen = sizeof(v4);
606 sa = (const struct sockaddr *) &v4;
607 }
608 else if (ip_len == sizeof(struct in6_addr))
609 {
610 memset (&v6, 0, sizeof(v6));
611 v6.sin6_family = AF_INET6;
612 v6.sin6_addr = *(struct in6_addr*) ip;
613#if HAVE_SOCKADDR_IN_SIN_LEN
614 v6.sin6_len = sizeof(v6);
615#endif
616 salen = sizeof(v6);
617 sa = (const struct sockaddr *) &v6;
618 }
619 else
620 {
621 GNUNET_break (0);
622 if (GNUNET_SYSERR != rh->was_transmitted)
623 rh->addr_callback (rh->cls,
624 NULL,
625 0);
626 rh->was_transmitted = GNUNET_NO;
627 GNUNET_RESOLVER_request_cancel (rh);
628 GNUNET_MQ_destroy (mq);
629 mq = NULL;
630 reconnect ();
631 return;
632 }
633 LOG (GNUNET_ERROR_TYPE_DEBUG,
634 "Received IP from DNS service\n");
635 if (GNUNET_SYSERR != rh->was_transmitted)
636 rh->addr_callback (rh->cls,
637 sa,
638 salen);
639 }
640}
641
642
643/**
644 * We've been asked to lookup the address for a hostname and were
645 * given a valid numeric string. Perform the callbacks for the
646 * numeric addresses.
647 *
648 * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
649 */
650static void
651numeric_resolution (void *cls)
652{
653 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
654 struct sockaddr_in v4;
655 struct sockaddr_in6 v6;
656 const char *hostname;
657
658 rh->task = NULL;
659 memset (&v4, 0, sizeof(v4));
660 v4.sin_family = AF_INET;
661#if HAVE_SOCKADDR_IN_SIN_LEN
662 v4.sin_len = sizeof(v4);
663#endif
664 memset (&v6, 0, sizeof(v6));
665 v6.sin6_family = AF_INET6;
666#if HAVE_SOCKADDR_IN_SIN_LEN
667 v6.sin6_len = sizeof(v6);
668#endif
669 hostname = (const char *) &rh[1];
670 if (((rh->af == AF_UNSPEC) ||
671 (rh->af == AF_INET)) &&
672 (1 == inet_pton (AF_INET,
673 hostname,
674 &v4.sin_addr)))
675 {
676 rh->addr_callback (rh->cls,
677 (const struct sockaddr *) &v4,
678 sizeof(v4));
679 if ((rh->af == AF_UNSPEC) &&
680 (GNUNET_SYSERR != rh->was_transmitted) &&
681 (1 == inet_pton (AF_INET6,
682 hostname,
683 &v6.sin6_addr)))
684 {
685 /* this can happen on some systems IF "hostname" is "localhost" */
686 rh->addr_callback (rh->cls,
687 (const struct sockaddr *) &v6,
688 sizeof(v6));
689 }
690 if (GNUNET_SYSERR != rh->was_transmitted)
691 rh->addr_callback (rh->cls,
692 NULL,
693 0);
694 GNUNET_free (rh);
695 return;
696 }
697 if (((rh->af == AF_UNSPEC) ||
698 (rh->af == AF_INET6)) &&
699 (1 == inet_pton (AF_INET6,
700 hostname,
701 &v6.sin6_addr)))
702 {
703 rh->addr_callback (rh->cls,
704 (const struct sockaddr *) &v6,
705 sizeof(v6));
706 if (GNUNET_SYSERR != rh->was_transmitted)
707 rh->addr_callback (rh->cls,
708 NULL,
709 0);
710 GNUNET_free (rh);
711 return;
712 }
713 /* why are we here? this task should not have been scheduled! */
714 GNUNET_assert (0);
715 GNUNET_free (rh);
716}
717
718
719/**
720 * We've been asked to lookup the address for a hostname and were
721 * given a variant of "loopback". Perform the callbacks for the
722 * respective loopback numeric addresses.
723 *
724 * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
725 */
726static void
727loopback_resolution (void *cls)
728{
729 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
730 struct sockaddr_in v4;
731 struct sockaddr_in6 v6;
732
733 rh->task = NULL;
734 memset (&v4, 0, sizeof(v4));
735 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
736 v4.sin_family = AF_INET;
737#if HAVE_SOCKADDR_IN_SIN_LEN
738 v4.sin_len = sizeof(v4);
739#endif
740 memset (&v6, 0, sizeof(v6));
741 v6.sin6_family = AF_INET6;
742#if HAVE_SOCKADDR_IN_SIN_LEN
743 v6.sin6_len = sizeof(v6);
744#endif
745 v6.sin6_addr = in6addr_loopback;
746 switch (rh->af)
747 {
748 case AF_INET:
749 rh->addr_callback (rh->cls,
750 (const struct sockaddr *) &v4,
751 sizeof(v4));
752 break;
753
754 case AF_INET6:
755 rh->addr_callback (rh->cls,
756 (const struct sockaddr *) &v6,
757 sizeof(v6));
758 break;
759
760 case AF_UNSPEC:
761 rh->addr_callback (rh->cls,
762 (const struct sockaddr *) &v6,
763 sizeof(v6));
764 rh->addr_callback (rh->cls,
765 (const struct sockaddr *) &v4,
766 sizeof(v4));
767
768 break;
769
770 default:
771 GNUNET_break (0);
772 break;
773 }
774 if (GNUNET_SYSERR != rh->was_transmitted)
775 rh->addr_callback (rh->cls,
776 NULL,
777 0);
778 LOG (GNUNET_ERROR_TYPE_DEBUG,
779 "Finished resolving hostname `%s'.\n",
780 (const char *) &rh[1]);
781 GNUNET_free (rh);
782}
783
784
785/**
786 * Now try to reconnect to the resolver service.
787 *
788 * @param cls NULL
789 */
790static void
791reconnect_task (void *cls)
792{
793 struct GNUNET_MQ_MessageHandler handlers[] = {
794 GNUNET_MQ_hd_var_size (response,
795 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE,
796 struct GNUNET_RESOLVER_ResponseMessage,
797 NULL),
798 GNUNET_MQ_handler_end ()
799 };
800
801 (void) cls;
802 r_task = NULL;
803 if (NULL == req_head)
804 return; /* no work pending */
805 LOG (GNUNET_ERROR_TYPE_DEBUG,
806 "Trying to connect to DNS service\n");
807 mq = GNUNET_CLIENT_connect (resolver_cfg,
808 "resolver",
809 handlers,
810 &mq_error_handler,
811 NULL);
812 if (NULL == mq)
813 {
814 LOG (GNUNET_ERROR_TYPE_DEBUG,
815 "Failed to connect, will try again later\n");
816 reconnect ();
817 return;
818 }
819 process_requests ();
820}
821
822
823/**
824 * Adjust exponential back-off and reconnect to the service.
825 */
826static void
827reconnect ()
828{
829 struct GNUNET_RESOLVER_RequestHandle *rh;
830
831 if (NULL != r_task)
832 return;
833 GNUNET_assert (NULL == mq);
834 if (NULL != (rh = req_head))
835 {
836 switch (rh->was_transmitted)
837 {
838 case GNUNET_NO:
839 /* nothing more to do */
840 break;
841
842 case GNUNET_YES:
843 /* disconnected, transmit again! */
844 rh->was_transmitted = GNUNET_NO;
845 break;
846
847 case GNUNET_SYSERR:
848 /* request was cancelled, remove entirely */
849 GNUNET_CONTAINER_DLL_remove (req_head,
850 req_tail,
851 rh);
852 GNUNET_free (rh);
853 check_disconnect ();
854 break;
855
856 default:
857 GNUNET_assert (0);
858 break;
859 }
860 }
861 LOG (GNUNET_ERROR_TYPE_DEBUG,
862 "Will try to connect to DNS service in %s\n",
863 GNUNET_STRINGS_relative_time_to_string (backoff,
864 GNUNET_YES));
865 GNUNET_assert (NULL != resolver_cfg);
866 r_task = GNUNET_SCHEDULER_add_delayed (backoff,
867 &reconnect_task,
868 NULL);
869 backoff = GNUNET_TIME_STD_BACKOFF (backoff);
870}
871
872
873/**
874 * A DNS resolution timed out. Notify the application.
875 *
876 * @param cls the `struct GNUNET_RESOLVER_RequestHandle *`
877 */
878static void
879handle_lookup_timeout (void *cls)
880{
881 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
882
883 rh->task = NULL;
884 if (GNUNET_NO == rh->direction)
885 {
886 LOG (GNUNET_ERROR_TYPE_INFO,
887 _ ("Timeout trying to resolve hostname `%s'.\n"),
888 (const char *) &rh[1]);
889 if (NULL != rh->addr_callback)
890 rh->addr_callback (rh->cls,
891 NULL,
892 0);
893 }
894 else
895 {
896#if ! defined(GNUNET_CULL_LOGGING)
897 char buf[INET6_ADDRSTRLEN];
898
899 LOG (GNUNET_ERROR_TYPE_INFO,
900 _ ("Timeout trying to resolve IP address `%s'.\n"),
901 inet_ntop (rh->af,
902 (const void *) &rh[1],
903 buf,
904 sizeof(buf)));
905#endif
906 if (GNUNET_NO == rh->received_response)
907 {
908 char *nret;
909
910 nret = no_resolve (rh->af,
911 &rh[1],
912 rh->data_len);
913 if (NULL != rh->name_callback)
914 rh->name_callback (rh->cls, nret);
915 GNUNET_free (nret);
916 }
917 /* finally, make termination call */
918 if (NULL != rh->name_callback)
919 rh->name_callback (rh->cls,
920 NULL);
921 }
922 rh->was_transmitted = GNUNET_NO;
923 GNUNET_RESOLVER_request_cancel (rh);
924 process_requests ();
925}
926
927
928/**
929 * Convert a string to one or more IP addresses.
930 *
931 * @param hostname the hostname to resolve
932 * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
933 * @param callback function to call with addresses
934 * @param callback_cls closure for @a callback
935 * @param timeout how long to try resolving
936 * @return handle that can be used to cancel the request, NULL on error
937 */
938struct GNUNET_RESOLVER_RequestHandle *
939GNUNET_RESOLVER_ip_get (const char *hostname,
940 int af,
941 struct GNUNET_TIME_Relative timeout,
942 GNUNET_RESOLVER_AddressCallback callback,
943 void *callback_cls)
944{
945 struct GNUNET_RESOLVER_RequestHandle *rh;
946 size_t slen;
947 struct in_addr v4;
948 struct in6_addr v6;
949
950 slen = strlen (hostname) + 1;
951 if (slen + sizeof(struct GNUNET_RESOLVER_GetMessage) >=
952 GNUNET_MAX_MESSAGE_SIZE)
953 {
954 GNUNET_break (0);
955 return NULL;
956 }
957 LOG (GNUNET_ERROR_TYPE_DEBUG,
958 "Trying to resolve hostname `%s'.\n",
959 hostname);
960 rh = GNUNET_malloc (sizeof(struct GNUNET_RESOLVER_RequestHandle) + slen);
961 rh->af = af;
962 rh->id = ++last_request_id;
963 rh->addr_callback = callback;
964 rh->cls = callback_cls;
965 GNUNET_memcpy (&rh[1],
966 hostname,
967 slen);
968 rh->data_len = slen;
969 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
970 rh->direction = GNUNET_NO;
971 /* first, check if this is a numeric address */
972 if (((1 == inet_pton (AF_INET,
973 hostname,
974 &v4)) &&
975 ((af == AF_INET) ||
976 (af == AF_UNSPEC))) ||
977 ((1 == inet_pton (AF_INET6,
978 hostname,
979 &v6)) &&
980 ((af == AF_INET6) ||
981 (af == AF_UNSPEC))))
982 {
983 rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution,
984 rh);
985 return rh;
986 }
987 /* then, check if this is a loopback address */
988 for (unsigned int i = 0;
989 NULL != loopback[i];
990 i++)
991 if (0 == strcasecmp (loopback[i],
992 hostname))
993 {
994 rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution,
995 rh);
996 return rh;
997 }
998 if (GNUNET_OK != check_config ())
999 {
1000 GNUNET_free (rh);
1001 return NULL;
1002 }
1003 rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
1004 &handle_lookup_timeout,
1005 rh);
1006 GNUNET_CONTAINER_DLL_insert_tail (req_head,
1007 req_tail,
1008 rh);
1009 rh->was_queued = GNUNET_YES;
1010 if (NULL != s_task)
1011 {
1012 GNUNET_SCHEDULER_cancel (s_task);
1013 s_task = NULL;
1014 }
1015 process_requests ();
1016 return rh;
1017}
1018
1019
1020/**
1021 * We've been asked to convert an address to a string without
1022 * a reverse lookup, either because the client asked for it
1023 * or because the DNS lookup hit a timeout. Do the numeric
1024 * conversion and invoke the callback.
1025 *
1026 * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
1027 */
1028static void
1029numeric_reverse (void *cls)
1030{
1031 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
1032 char *result;
1033
1034 rh->task = NULL;
1035 result = no_resolve (rh->af,
1036 &rh[1],
1037 rh->data_len);
1038 LOG (GNUNET_ERROR_TYPE_DEBUG,
1039 "Resolver returns `%s'.\n",
1040 result);
1041 if (NULL != result)
1042 {
1043 rh->name_callback (rh->cls,
1044 result);
1045 GNUNET_free (result);
1046 }
1047 rh->name_callback (rh->cls,
1048 NULL);
1049 if (NULL != rh->task)
1050 {
1051 GNUNET_SCHEDULER_cancel (rh->task);
1052 rh->task = NULL;
1053 }
1054 GNUNET_free (rh);
1055}
1056
1057
1058/**
1059 * Get an IP address as a string.
1060 *
1061 * @param sa host address
1062 * @param salen length of host address in @a sa
1063 * @param do_resolve use #GNUNET_NO to return numeric hostname
1064 * @param timeout how long to try resolving
1065 * @param callback function to call with hostnames
1066 * last callback is NULL when finished
1067 * @param cls closure for @a callback
1068 * @return handle that can be used to cancel the request
1069 */
1070struct GNUNET_RESOLVER_RequestHandle *
1071GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa,
1072 socklen_t salen,
1073 int do_resolve,
1074 struct GNUNET_TIME_Relative timeout,
1075 GNUNET_RESOLVER_HostnameCallback callback,
1076 void *cls)
1077{
1078 struct GNUNET_RESOLVER_RequestHandle *rh;
1079 size_t ip_len;
1080 const void *ip;
1081
1082 if (GNUNET_OK != check_config ())
1083 {
1084 LOG (GNUNET_ERROR_TYPE_ERROR,
1085 _ ("Resolver not configured correctly.\n"));
1086 return NULL;
1087 }
1088
1089 switch (sa->sa_family)
1090 {
1091 case AF_INET:
1092 GNUNET_assert (salen == sizeof(struct sockaddr_in));
1093 ip_len = sizeof(struct in_addr);
1094 ip = &((const struct sockaddr_in*) sa)->sin_addr;
1095 break;
1096
1097 case AF_INET6:
1098 GNUNET_assert (salen == sizeof(struct sockaddr_in6));
1099 ip_len = sizeof(struct in6_addr);
1100 ip = &((const struct sockaddr_in6*) sa)->sin6_addr;
1101 break;
1102
1103 default:
1104 GNUNET_break (0);
1105 return NULL;
1106 }
1107 rh = GNUNET_malloc (sizeof(struct GNUNET_RESOLVER_RequestHandle) + salen);
1108 rh->name_callback = callback;
1109 rh->cls = cls;
1110 rh->af = sa->sa_family;
1111 rh->id = ++last_request_id;
1112 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1113 GNUNET_memcpy (&rh[1],
1114 ip,
1115 ip_len);
1116 rh->data_len = ip_len;
1117 rh->direction = GNUNET_YES;
1118 rh->received_response = GNUNET_NO;
1119 if (GNUNET_NO == do_resolve)
1120 {
1121 rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse,
1122 rh);
1123 return rh;
1124 }
1125 rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
1126 &handle_lookup_timeout,
1127 rh);
1128 GNUNET_CONTAINER_DLL_insert_tail (req_head,
1129 req_tail,
1130 rh);
1131 rh->was_queued = GNUNET_YES;
1132 if (NULL != s_task)
1133 {
1134 GNUNET_SCHEDULER_cancel (s_task);
1135 s_task = NULL;
1136 }
1137 process_requests ();
1138 return rh;
1139}
1140
1141
1142/**
1143 * Get local fully qualified af name
1144 *
1145 * @return fqdn
1146 */
1147char *
1148GNUNET_RESOLVER_local_fqdn_get ()
1149{
1150 char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1151
1152 if (0 != gethostname (hostname,
1153 sizeof(hostname) - 1))
1154 {
1155 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1156 "gethostname");
1157 return NULL;
1158 }
1159 LOG (GNUNET_ERROR_TYPE_DEBUG,
1160 "Resolving our FQDN `%s'\n",
1161 hostname);
1162#if HAVE_GETADDRINFO
1163 {
1164 struct addrinfo *ai;
1165 int ret;
1166 char *rval;
1167
1168 if (0 != (ret = getaddrinfo (hostname,
1169 NULL,
1170 NULL,
1171 &ai)))
1172 {
1173 LOG (GNUNET_ERROR_TYPE_ERROR,
1174 _ ("Could not resolve our FQDN: %s\n"),
1175 gai_strerror (ret));
1176 return NULL;
1177 }
1178 if (NULL != ai->ai_canonname)
1179 rval = GNUNET_strdup (ai->ai_canonname);
1180 else
1181 rval = GNUNET_strdup (hostname);
1182 freeaddrinfo (ai);
1183 return rval;
1184 }
1185#elif HAVE_GETHOSTBYNAME2
1186 {
1187 struct hostent *host;
1188
1189 host = gethostbyname2 (hostname,
1190 AF_INET);
1191 if (NULL == host)
1192 host = gethostbyname2 (hostname,
1193 AF_INET6);
1194 if (NULL == host)
1195 {
1196 LOG (GNUNET_ERROR_TYPE_ERROR,
1197 _ ("Could not resolve our FQDN: %s\n"),
1198 hstrerror (h_errno));
1199 return NULL;
1200 }
1201 return GNUNET_strdup (host->h_name);
1202 }
1203#elif HAVE_GETHOSTBYNAME
1204 {
1205 struct hostent *host;
1206
1207 host = gethostbyname (hostname);
1208 if (NULL == host)
1209 {
1210 LOG (GNUNET_ERROR_TYPE_ERROR,
1211 _ ("Could not resolve our FQDN: %s\n"),
1212 hstrerror (h_errno));
1213 return NULL;
1214 }
1215 return GNUNET_strdup (host->h_name);
1216 }
1217#else
1218 /* fallback: just hope name is already FQDN */
1219 return GNUNET_strdup (hostname);
1220#endif
1221}
1222
1223
1224/**
1225 * Looking our own hostname.
1226 *
1227 * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
1228 * @param timeout how long to try resolving
1229 * @param callback function to call with addresses
1230 * @param cls closure for @a callback
1231 * @return handle that can be used to cancel the request, NULL on error
1232 */
1233struct GNUNET_RESOLVER_RequestHandle *
1234GNUNET_RESOLVER_hostname_resolve (int af,
1235 struct GNUNET_TIME_Relative timeout,
1236 GNUNET_RESOLVER_AddressCallback callback,
1237 void *cls)
1238{
1239 char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1240
1241 if (0 != gethostname (hostname, sizeof(hostname) - 1))
1242 {
1243 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1244 "gethostname");
1245 return NULL;
1246 }
1247 LOG (GNUNET_ERROR_TYPE_DEBUG,
1248 "Resolving our hostname `%s'\n",
1249 hostname);
1250 return GNUNET_RESOLVER_ip_get (hostname,
1251 af,
1252 timeout,
1253 callback,
1254 cls);
1255}
1256
1257
1258/**
1259 * Cancel a request that is still pending with the resolver.
1260 * Note that a client MUST NOT cancel a request that has
1261 * been completed (i.e, the callback has been called to
1262 * signal timeout or the final result).
1263 *
1264 * @param rh handle of request to cancel
1265 */
1266void
1267GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh)
1268{
1269 if (GNUNET_NO == rh->direction)
1270 LOG (GNUNET_ERROR_TYPE_DEBUG,
1271 "Asked to cancel request to resolve hostname `%s'.\n",
1272 (const char *) &rh[1]);
1273 if (NULL != rh->task)
1274 {
1275 GNUNET_SCHEDULER_cancel (rh->task);
1276 rh->task = NULL;
1277 }
1278 if (GNUNET_NO == rh->was_transmitted)
1279 {
1280 if (GNUNET_YES == rh->was_queued)
1281 GNUNET_CONTAINER_DLL_remove (req_head,
1282 req_tail,
1283 rh);
1284 GNUNET_free (rh);
1285 check_disconnect ();
1286 return;
1287 }
1288 GNUNET_assert (GNUNET_YES == rh->was_transmitted);
1289 rh->was_transmitted = GNUNET_SYSERR; /* mark as cancelled */
1290 check_disconnect ();
1291}
1292
1293
1294/* end of resolver_api.c */
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
deleted file mode 100644
index 03a7c0dfb..000000000
--- a/src/util/scheduler.c
+++ /dev/null
@@ -1,2570 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009-2017 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 * @file util/scheduler.c
22 * @brief schedule computations using continuation passing style
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "disk.h"
28// DEBUG
29#include <inttypes.h>
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__)
32
33#define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \
34 "util-scheduler", \
35 syscall)
36
37
38#if HAVE_EXECINFO_H
39#include "execinfo.h"
40
41/**
42 * Use lsof to generate file descriptor reports on select error?
43 * (turn off for stable releases).
44 */
45#define USE_LSOF GNUNET_NO
46
47/**
48 * Obtain trace information for all scheduler calls that schedule tasks.
49 */
50#define EXECINFO GNUNET_NO
51
52/**
53 * Check each file descriptor before adding
54 */
55#define DEBUG_FDS GNUNET_NO
56
57/**
58 * Depth of the traces collected via EXECINFO.
59 */
60#define MAX_TRACE_DEPTH 50
61#endif
62
63/**
64 * Should we figure out which tasks are delayed for a while
65 * before they are run? (Consider using in combination with EXECINFO).
66 */
67#define PROFILE_DELAYS GNUNET_NO
68
69/**
70 * Task that were in the queue for longer than this are reported if
71 * PROFILE_DELAYS is active.
72 */
73#define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS
74
75
76/**
77 * Argument to be passed from the driver to
78 * #GNUNET_SCHEDULER_do_work(). Contains the
79 * scheduler's internal state.
80 */
81struct GNUNET_SCHEDULER_Handle
82{
83 /**
84 * Passed here to avoid constantly allocating/deallocating
85 * this element, but generally we want to get rid of this.
86 * @deprecated
87 */
88 struct GNUNET_NETWORK_FDSet *rs;
89
90 /**
91 * Passed here to avoid constantly allocating/deallocating
92 * this element, but generally we want to get rid of this.
93 * @deprecated
94 */
95 struct GNUNET_NETWORK_FDSet *ws;
96
97 /**
98 * context of the SIGINT handler
99 */
100 struct GNUNET_SIGNAL_Context *shc_int;
101
102 /**
103 * context of the SIGTERM handler
104 */
105 struct GNUNET_SIGNAL_Context *shc_term;
106
107#if (SIGTERM != GNUNET_TERM_SIG)
108 /**
109 * context of the TERM_SIG handler
110 */
111 struct GNUNET_SIGNAL_Context *shc_gterm;
112#endif
113
114 /**
115 * context of the SIGQUIT handler
116 */
117 struct GNUNET_SIGNAL_Context *shc_quit;
118
119 /**
120 * context of the SIGHUP handler
121 */
122 struct GNUNET_SIGNAL_Context *shc_hup;
123
124 /**
125 * context of the SIGPIPE handler
126 */
127 struct GNUNET_SIGNAL_Context *shc_pipe;
128};
129
130
131/**
132 * Entry in list of pending tasks.
133 */
134struct GNUNET_SCHEDULER_Task
135{
136 /**
137 * This is a linked list.
138 */
139 struct GNUNET_SCHEDULER_Task *next;
140
141 /**
142 * This is a linked list.
143 */
144 struct GNUNET_SCHEDULER_Task *prev;
145
146 /**
147 * Function to run when ready.
148 */
149 GNUNET_SCHEDULER_TaskCallback callback;
150
151 /**
152 * Closure for the @e callback.
153 */
154 void *callback_cls;
155
156 /**
157 * Information about which FDs are ready for this task (and why).
158 */
159 struct GNUNET_SCHEDULER_FdInfo *fds;
160
161 /**
162 * Storage location used for @e fds if we want to avoid
163 * a separate malloc() call in the common case that this
164 * task is only about a single FD.
165 */
166 struct GNUNET_SCHEDULER_FdInfo fdx;
167
168 /**
169 * Size of the @e fds array.
170 */
171 unsigned int fds_len;
172
173 /**
174 * Do we own the network and file handles referenced by the FdInfo
175 * structs in the fds array. This will only be GNUNET_YES if the
176 * task was created by the #GNUNET_SCHEDULER_add_select function.
177 */
178 int own_handles;
179
180 /**
181 * Absolute timeout value for the task, or
182 * #GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
183 */
184 struct GNUNET_TIME_Absolute timeout;
185
186#if PROFILE_DELAYS
187 /**
188 * When was the task scheduled?
189 */
190 struct GNUNET_TIME_Absolute start_time;
191#endif
192
193 /**
194 * Why is the task ready? Set after task is added to ready queue.
195 * Initially set to zero. All reasons that have already been
196 * satisfied (e.g. read or write ready) will be set over time.
197 */
198 enum GNUNET_SCHEDULER_Reason reason;
199
200 /**
201 * Task priority.
202 */
203 enum GNUNET_SCHEDULER_Priority priority;
204
205 /**
206 * Set if we only wait for reading from a single FD, otherwise -1.
207 */
208 int read_fd;
209
210 /**
211 * Set if we only wait for writing to a single FD, otherwise -1.
212 */
213 int write_fd;
214
215 /**
216 * Should the existence of this task in the queue be counted as
217 * reason to not shutdown the scheduler?
218 */
219 int lifeness;
220
221 /**
222 * Is this task run on shutdown?
223 */
224 int on_shutdown;
225
226 /**
227 * Is this task in the ready list?
228 */
229 int in_ready_list;
230
231#if EXECINFO
232 /**
233 * Array of strings which make up a backtrace from the point when this
234 * task was scheduled (essentially, who scheduled the task?)
235 */
236 char **backtrace_strings;
237
238 /**
239 * Size of the backtrace_strings array
240 */
241 int num_backtrace_strings;
242#endif
243
244 /**
245 * Asynchronous scope of the task that scheduled this scope,
246 */
247 struct GNUNET_AsyncScopeSave scope;
248};
249
250
251/**
252 * A struct representing an event the select driver is waiting for
253 */
254struct Scheduled
255{
256 struct Scheduled *prev;
257
258 struct Scheduled *next;
259
260 /**
261 * the task, the event is related to
262 */
263 struct GNUNET_SCHEDULER_Task *task;
264
265 /**
266 * information about the network socket / file descriptor where
267 * the event is expected to occur
268 */
269 struct GNUNET_SCHEDULER_FdInfo *fdi;
270
271 /**
272 * the event types (multiple event types can be ORed) the select
273 * driver is expected to wait for
274 */
275 enum GNUNET_SCHEDULER_EventType et;
276};
277
278
279/**
280 * Driver context used by GNUNET_SCHEDULER_run
281 */
282struct DriverContext
283{
284 /**
285 * the head of a DLL containing information about the events the
286 * select driver is waiting for
287 */
288 struct Scheduled *scheduled_head;
289
290 /**
291 * the tail of a DLL containing information about the events the
292 * select driver is waiting for
293 */
294 struct Scheduled *scheduled_tail;
295
296 /**
297 * the time when the select driver will wake up again (after
298 * calling select)
299 */
300 struct GNUNET_TIME_Absolute timeout;
301};
302
303
304/**
305 * The driver used for the event loop. Will be handed over to
306 * the scheduler in #GNUNET_SCHEDULER_do_work(), persisted
307 * there in this variable for later use in functions like
308 * #GNUNET_SCHEDULER_add_select(), #add_without_sets() and
309 * #GNUNET_SCHEDULER_cancel().
310 */
311static const struct GNUNET_SCHEDULER_Driver *scheduler_driver;
312
313/**
314 * Head of list of tasks waiting for an event.
315 */
316static struct GNUNET_SCHEDULER_Task *pending_head;
317
318/**
319 * Tail of list of tasks waiting for an event.
320 */
321static struct GNUNET_SCHEDULER_Task *pending_tail;
322
323/**
324 * Head of list of tasks waiting for shutdown.
325 */
326static struct GNUNET_SCHEDULER_Task *shutdown_head;
327
328/**
329 * Tail of list of tasks waiting for shutdown.
330 */
331static struct GNUNET_SCHEDULER_Task *shutdown_tail;
332
333/**
334 * List of tasks waiting ONLY for a timeout event.
335 * Sorted by timeout (earliest first). Used so that
336 * we do not traverse the list of these tasks when
337 * building select sets (we just look at the head
338 * to determine the respective timeout ONCE).
339 */
340static struct GNUNET_SCHEDULER_Task *pending_timeout_head;
341
342/**
343 * List of tasks waiting ONLY for a timeout event.
344 * Sorted by timeout (earliest first). Used so that
345 * we do not traverse the list of these tasks when
346 * building select sets (we just look at the head
347 * to determine the respective timeout ONCE).
348 */
349static struct GNUNET_SCHEDULER_Task *pending_timeout_tail;
350
351/**
352 * Last inserted task waiting ONLY for a timeout event.
353 * Used to (heuristically) speed up insertion.
354 */
355static struct GNUNET_SCHEDULER_Task *pending_timeout_last;
356
357/**
358 * ID of the task that is running right now.
359 */
360static struct GNUNET_SCHEDULER_Task *active_task;
361
362/**
363 * Head of list of tasks ready to run right now, grouped by importance.
364 */
365static struct
366GNUNET_SCHEDULER_Task *ready_head[GNUNET_SCHEDULER_PRIORITY_COUNT];
367
368/**
369 * Tail of list of tasks ready to run right now, grouped by importance.
370 */
371static struct
372GNUNET_SCHEDULER_Task *ready_tail[GNUNET_SCHEDULER_PRIORITY_COUNT];
373
374/**
375 * Task for installing parent control handlers (it might happen that the
376 * scheduler is shutdown before this task is executed, so
377 * GNUNET_SCHEDULER_shutdown must cancel it in that case)
378 */
379static struct GNUNET_SCHEDULER_Task *install_parent_control_task;
380
381/**
382 * Task for reading from a pipe that signal handlers will use to initiate
383 * shutdown
384 */
385static struct GNUNET_SCHEDULER_Task *shutdown_pipe_task;
386
387/**
388 * Number of tasks on the ready list.
389 */
390static unsigned int ready_count;
391
392/**
393 * Priority of the task running right now. Only
394 * valid while a task is running.
395 */
396static enum GNUNET_SCHEDULER_Priority current_priority;
397
398/**
399 * Priority of the highest task added in the current select
400 * iteration.
401 */
402static enum GNUNET_SCHEDULER_Priority max_priority_added;
403
404/**
405 * Value of the 'lifeness' flag for the current task.
406 */
407static int current_lifeness;
408
409/**
410 * Priority used currently in #GNUNET_SCHEDULER_do_work().
411 */
412static enum GNUNET_SCHEDULER_Priority work_priority;
413
414/**
415 * Function to use as a select() in the scheduler.
416 * If NULL, we use GNUNET_NETWORK_socket_select().
417 */
418static GNUNET_SCHEDULER_select scheduler_select;
419
420/**
421 * Task context of the current task.
422 */
423static struct GNUNET_SCHEDULER_TaskContext tc;
424
425/**
426 * Closure for #scheduler_select.
427 */
428static void *scheduler_select_cls;
429
430
431/**
432 * Sets the select function to use in the scheduler (scheduler_select).
433 *
434 * @param new_select new select function to use
435 * @param new_select_cls closure for @a new_select
436 * @return previously used select function, NULL for default
437 */
438void
439GNUNET_SCHEDULER_set_select (GNUNET_SCHEDULER_select new_select,
440 void *new_select_cls)
441{
442 scheduler_select = new_select;
443 scheduler_select_cls = new_select_cls;
444}
445
446
447/**
448 * Check that the given priority is legal (and return it).
449 *
450 * @param p priority value to check
451 * @return p on success, 0 on error
452 */
453static enum GNUNET_SCHEDULER_Priority
454check_priority (enum GNUNET_SCHEDULER_Priority p)
455{
456 if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT))
457 return p;
458 GNUNET_assert (0);
459 return 0; /* make compiler happy */
460}
461
462
463/**
464 * chooses the nearest timeout from all pending tasks, to be used
465 * to tell the driver the next wakeup time (using its set_wakeup
466 * callback)
467 */
468struct GNUNET_TIME_Absolute
469get_timeout ()
470{
471 struct GNUNET_SCHEDULER_Task *pos;
472 struct GNUNET_TIME_Absolute now;
473 struct GNUNET_TIME_Absolute timeout;
474
475 pos = pending_timeout_head;
476 now = GNUNET_TIME_absolute_get ();
477 timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
478 if (NULL != pos)
479 {
480 if (0 != pos->reason)
481 {
482 return now;
483 }
484 else
485 {
486 timeout = pos->timeout;
487 }
488 }
489 for (pos = pending_head; NULL != pos; pos = pos->next)
490 {
491 if (0 != pos->reason)
492 {
493 return now;
494 }
495 else if ((pos->timeout.abs_value_us !=
496 GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) &&
497 (timeout.abs_value_us > pos->timeout.abs_value_us))
498 {
499 timeout = pos->timeout;
500 }
501 }
502 return timeout;
503}
504
505
506/**
507 * Put a task that is ready for execution into the ready queue.
508 *
509 * @param task task ready for execution
510 */
511static void
512queue_ready_task (struct GNUNET_SCHEDULER_Task *task)
513{
514 enum GNUNET_SCHEDULER_Priority p = check_priority (task->priority);
515
516 GNUNET_CONTAINER_DLL_insert_tail (ready_head[p],
517 ready_tail[p],
518 task);
519 task->in_ready_list = GNUNET_YES;
520 ready_count++;
521}
522
523
524/**
525 * Request the shutdown of a scheduler. Marks all tasks
526 * awaiting shutdown as ready. Note that tasks
527 * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call
528 * will be delayed until the next shutdown signal.
529 */
530void
531GNUNET_SCHEDULER_shutdown ()
532{
533 struct GNUNET_SCHEDULER_Task *pos;
534
535 LOG (GNUNET_ERROR_TYPE_DEBUG,
536 "GNUNET_SCHEDULER_shutdown\n");
537 if (NULL != install_parent_control_task)
538 {
539 GNUNET_SCHEDULER_cancel (install_parent_control_task);
540 install_parent_control_task = NULL;
541 }
542 if (NULL != shutdown_pipe_task)
543 {
544 GNUNET_SCHEDULER_cancel (shutdown_pipe_task);
545 shutdown_pipe_task = NULL;
546 }
547 while (NULL != (pos = shutdown_head))
548 {
549 GNUNET_CONTAINER_DLL_remove (shutdown_head,
550 shutdown_tail,
551 pos);
552 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
553 queue_ready_task (pos);
554 }
555}
556
557
558/**
559 * Output stack trace of task @a t.
560 *
561 * @param t task to dump stack trace of
562 */
563static void
564dump_backtrace (struct GNUNET_SCHEDULER_Task *t)
565{
566#if EXECINFO
567 for (unsigned int i = 0; i < t->num_backtrace_strings; i++)
568 LOG (GNUNET_ERROR_TYPE_WARNING,
569 "Task %p trace %u: %s\n",
570 t,
571 i,
572 t->backtrace_strings[i]);
573#else
574 (void) t;
575#endif
576}
577
578
579/**
580 * Destroy a task (release associated resources)
581 *
582 * @param t task to destroy
583 */
584static void
585destroy_task (struct GNUNET_SCHEDULER_Task *t)
586{
587 LOG (GNUNET_ERROR_TYPE_DEBUG,
588 "destroying task %p\n",
589 t);
590
591 if (GNUNET_YES == t->own_handles)
592 {
593 for (unsigned int i = 0; i != t->fds_len; ++i)
594 {
595 const struct GNUNET_NETWORK_Handle *fd = t->fds[i].fd;
596 const struct GNUNET_DISK_FileHandle *fh = t->fds[i].fh;
597 if (fd)
598 {
599 GNUNET_NETWORK_socket_free_memory_only_ (
600 (struct GNUNET_NETWORK_Handle *) fd);
601 }
602 if (fh)
603 {
604 // FIXME: on WIN32 this is not enough! A function
605 // GNUNET_DISK_file_free_memory_only would be nice
606 GNUNET_free_nz ((void *) fh);
607 }
608 }
609 }
610 if (t->fds_len > 1)
611 {
612 GNUNET_array_grow (t->fds, t->fds_len, 0);
613 }
614#if EXECINFO
615 GNUNET_free (t->backtrace_strings);
616#endif
617 GNUNET_free (t);
618}
619
620
621/**
622 * Pipe used to communicate shutdown via signal.
623 */
624static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle;
625
626/**
627 * Process ID of this process at the time we installed the various
628 * signal handlers.
629 */
630static pid_t my_pid;
631
632/**
633 * Signal handler called for SIGPIPE.
634 */
635static void
636sighandler_pipe ()
637{
638 return;
639}
640
641
642///**
643// * Wait for a short time.
644// * Sleeps for @a ms ms (as that should be long enough for virtually all
645// * modern systems to context switch and allow another process to do
646// * some 'real' work).
647// *
648// * @param ms how many ms to wait
649// */
650// static void
651// short_wait (unsigned int ms)
652// {
653// struct GNUNET_TIME_Relative timeout;
654//
655// timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ms);
656// (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
657// }
658
659
660/**
661 * Signal handler called for signals that should cause us to shutdown.
662 */
663static void
664sighandler_shutdown ()
665{
666 static char c;
667 int old_errno = errno; /* backup errno */
668
669 if (getpid () != my_pid)
670 _exit (1); /* we have fork'ed since the signal handler was created,
671 * ignore the signal, see https://gnunet.org/vfork discussion */
672 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
673 (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE),
674 &c, sizeof(c));
675 errno = old_errno;
676}
677
678
679static void
680shutdown_if_no_lifeness ()
681{
682 struct GNUNET_SCHEDULER_Task *t;
683
684 if (ready_count > 0)
685 return;
686 for (t = pending_head; NULL != t; t = t->next)
687 if (GNUNET_YES == t->lifeness)
688 return;
689 for (t = shutdown_head; NULL != t; t = t->next)
690 if (GNUNET_YES == t->lifeness)
691 return;
692 for (t = pending_timeout_head; NULL != t; t = t->next)
693 if (GNUNET_YES == t->lifeness)
694 return;
695 /* No lifeness! */
696 GNUNET_SCHEDULER_shutdown ();
697}
698
699
700static int
701select_loop (struct GNUNET_SCHEDULER_Handle *sh,
702 struct DriverContext *context);
703
704
705/**
706 * Initialize and run scheduler. This function will return when all
707 * tasks have completed. On systems with signals, receiving a SIGTERM
708 * (and other similar signals) will cause #GNUNET_SCHEDULER_shutdown()
709 * to be run after the active task is complete. As a result, SIGTERM
710 * causes all active tasks to be scheduled with reason
711 * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added
712 * afterwards will execute normally!). Note that any particular signal
713 * will only shut down one scheduler; applications should always only
714 * create a single scheduler.
715 *
716 * @param task task to run immediately
717 * @param task_cls closure of @a task
718 */
719void
720GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task,
721 void *task_cls)
722{
723 struct GNUNET_SCHEDULER_Handle *sh;
724 struct GNUNET_SCHEDULER_Driver *driver;
725 struct DriverContext context = {
726 .scheduled_head = NULL,
727 .scheduled_tail = NULL,
728 .timeout = GNUNET_TIME_absolute_get ()
729 };
730
731 driver = GNUNET_SCHEDULER_driver_select ();
732 driver->cls = &context;
733 sh = GNUNET_SCHEDULER_driver_init (driver);
734 GNUNET_SCHEDULER_add_with_reason_and_priority (task,
735 task_cls,
736 GNUNET_SCHEDULER_REASON_STARTUP,
737 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
738 select_loop (sh,
739 &context);
740 GNUNET_SCHEDULER_driver_done (sh);
741 GNUNET_free (driver);
742}
743
744
745/**
746 * Obtain the task context, giving the reason why the current task was
747 * started.
748 *
749 * @return current tasks' scheduler context
750 */
751const struct GNUNET_SCHEDULER_TaskContext *
752GNUNET_SCHEDULER_get_task_context ()
753{
754 GNUNET_assert (NULL != active_task);
755 return &tc;
756}
757
758
759/**
760 * Get information about the current load of this scheduler. Use this
761 * function to determine if an elective task should be added or simply
762 * dropped (if the decision should be made based on the number of
763 * tasks ready to run).
764 *
765 * @param p priority level to look at
766 * @return number of tasks pending right now
767 */
768unsigned int
769GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p)
770{
771 unsigned int ret;
772
773 GNUNET_assert (NULL != active_task);
774 if (p == GNUNET_SCHEDULER_PRIORITY_COUNT)
775 return ready_count;
776 if (p == GNUNET_SCHEDULER_PRIORITY_KEEP)
777 p = current_priority;
778 ret = 0;
779 for (struct GNUNET_SCHEDULER_Task *pos = ready_head[check_priority (p)];
780 NULL != pos;
781 pos = pos->next)
782 ret++;
783 return ret;
784}
785
786
787void
788init_fd_info (struct GNUNET_SCHEDULER_Task *t,
789 const struct GNUNET_NETWORK_Handle *const *read_nh,
790 unsigned int read_nh_len,
791 const struct GNUNET_NETWORK_Handle *const *write_nh,
792 unsigned int write_nh_len,
793 const struct GNUNET_DISK_FileHandle *const *read_fh,
794 unsigned int read_fh_len,
795 const struct GNUNET_DISK_FileHandle *const *write_fh,
796 unsigned int write_fh_len)
797{
798 // FIXME: if we have exactly two network handles / exactly two file handles
799 // and they are equal, we can make one FdInfo with both
800 // GNUNET_SCHEDULER_ET_IN and GNUNET_SCHEDULER_ET_OUT set.
801 struct GNUNET_SCHEDULER_FdInfo *fdi;
802
803 t->fds_len = read_nh_len + write_nh_len + read_fh_len + write_fh_len;
804 if (1 == t->fds_len)
805 {
806 fdi = &t->fdx;
807 t->fds = fdi;
808 if (1 == read_nh_len)
809 {
810 GNUNET_assert (NULL != read_nh);
811 GNUNET_assert (NULL != *read_nh);
812 fdi->fd = *read_nh;
813 fdi->et = GNUNET_SCHEDULER_ET_IN;
814 fdi->sock = GNUNET_NETWORK_get_fd (*read_nh);
815 t->read_fd = fdi->sock;
816 t->write_fd = -1;
817 }
818 else if (1 == write_nh_len)
819 {
820 GNUNET_assert (NULL != write_nh);
821 GNUNET_assert (NULL != *write_nh);
822 fdi->fd = *write_nh;
823 fdi->et = GNUNET_SCHEDULER_ET_OUT;
824 fdi->sock = GNUNET_NETWORK_get_fd (*write_nh);
825 t->read_fd = -1;
826 t->write_fd = fdi->sock;
827 }
828 else if (1 == read_fh_len)
829 {
830 GNUNET_assert (NULL != read_fh);
831 GNUNET_assert (NULL != *read_fh);
832 fdi->fh = *read_fh;
833 fdi->et = GNUNET_SCHEDULER_ET_IN;
834 fdi->sock = (*read_fh)->fd; // FIXME: does not work under WIN32
835 t->read_fd = fdi->sock;
836 t->write_fd = -1;
837 }
838 else
839 {
840 GNUNET_assert (NULL != write_fh);
841 GNUNET_assert (NULL != *write_fh);
842 fdi->fh = *write_fh;
843 fdi->et = GNUNET_SCHEDULER_ET_OUT;
844 fdi->sock = (*write_fh)->fd; // FIXME: does not work under WIN32
845 t->read_fd = -1;
846 t->write_fd = fdi->sock;
847 }
848 }
849 else
850 {
851 fdi = GNUNET_new_array (t->fds_len, struct GNUNET_SCHEDULER_FdInfo);
852 t->fds = fdi;
853 t->read_fd = -1;
854 t->write_fd = -1;
855 unsigned int i;
856 for (i = 0; i != read_nh_len; ++i)
857 {
858 fdi->fd = read_nh[i];
859 GNUNET_assert (NULL != fdi->fd);
860 fdi->et = GNUNET_SCHEDULER_ET_IN;
861 fdi->sock = GNUNET_NETWORK_get_fd (read_nh[i]);
862 ++fdi;
863 }
864 for (i = 0; i != write_nh_len; ++i)
865 {
866 fdi->fd = write_nh[i];
867 GNUNET_assert (NULL != fdi->fd);
868 fdi->et = GNUNET_SCHEDULER_ET_OUT;
869 fdi->sock = GNUNET_NETWORK_get_fd (write_nh[i]);
870 ++fdi;
871 }
872 for (i = 0; i != read_fh_len; ++i)
873 {
874 fdi->fh = read_fh[i];
875 GNUNET_assert (NULL != fdi->fh);
876 fdi->et = GNUNET_SCHEDULER_ET_IN;
877 fdi->sock = (read_fh[i])->fd; // FIXME: does not work under WIN32
878 ++fdi;
879 }
880 for (i = 0; i != write_fh_len; ++i)
881 {
882 fdi->fh = write_fh[i];
883 GNUNET_assert (NULL != fdi->fh);
884 fdi->et = GNUNET_SCHEDULER_ET_OUT;
885 fdi->sock = (write_fh[i])->fd; // FIXME: does not work under WIN32
886 ++fdi;
887 }
888 }
889}
890
891
892/**
893 * calls the given function @a func on each FdInfo related to @a t.
894 * Optionally updates the event type field in each FdInfo after calling
895 * @a func.
896 *
897 * @param t the task
898 * @param driver_func the function to call with each FdInfo contained in
899 * in @a t
900 * @param if_not_ready only call @a driver_func on FdInfos that are not
901 * ready
902 * @param et the event type to be set in each FdInfo after calling
903 * @a driver_func on it, or -1 if no updating not desired.
904 */
905static void
906driver_add_multiple (struct GNUNET_SCHEDULER_Task *t)
907{
908 struct GNUNET_SCHEDULER_FdInfo *fdi;
909 int success = GNUNET_YES;
910
911 for (unsigned int i = 0; i != t->fds_len; ++i)
912 {
913 fdi = &t->fds[i];
914 success = scheduler_driver->add (scheduler_driver->cls,
915 t,
916 fdi) && success;
917 fdi->et = GNUNET_SCHEDULER_ET_NONE;
918 }
919 if (GNUNET_YES != success)
920 {
921 LOG (GNUNET_ERROR_TYPE_ERROR,
922 "driver could not add task\n");
923 }
924}
925
926
927static void
928install_parent_control_handler (void *cls)
929{
930 (void) cls;
931 install_parent_control_task = NULL;
932 GNUNET_OS_install_parent_control_handler (NULL);
933}
934
935
936static void
937shutdown_pipe_cb (void *cls)
938{
939 char c;
940 const struct GNUNET_DISK_FileHandle *pr;
941
942 (void) cls;
943 shutdown_pipe_task = NULL;
944 pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
945 GNUNET_DISK_PIPE_END_READ);
946 GNUNET_assert (! GNUNET_DISK_handle_invalid (pr));
947 /* consume the signal */
948 GNUNET_DISK_file_read (pr, &c, sizeof(c));
949 /* mark all active tasks as ready due to shutdown */
950 GNUNET_SCHEDULER_shutdown ();
951 shutdown_pipe_task =
952 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
953 pr,
954 &shutdown_pipe_cb,
955 NULL);
956}
957
958
959/**
960 * Cancel the task with the specified identifier.
961 * The task must not yet have run. Only allowed to be called as long as the
962 * scheduler is running, that is one of the following conditions is met:
963 *
964 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
965 * - #GNUNET_SCHEDULER_driver_init has been run and
966 * #GNUNET_SCHEDULER_driver_done has not been called yet
967 *
968 * @param task id of the task to cancel
969 * @return original closure of the task
970 */
971void *
972GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task)
973{
974 enum GNUNET_SCHEDULER_Priority p;
975 int is_fd_task;
976 void *ret;
977
978 LOG (GNUNET_ERROR_TYPE_DEBUG,
979 "canceling task %p\n",
980 task);
981
982 /* scheduler must be running */
983 GNUNET_assert (NULL != scheduler_driver);
984 is_fd_task = (NULL != task->fds);
985 if (is_fd_task)
986 {
987 int del_result = scheduler_driver->del (scheduler_driver->cls, task);
988 if (GNUNET_OK != del_result)
989 {
990 LOG (GNUNET_ERROR_TYPE_ERROR,
991 "driver could not delete task\n");
992 GNUNET_assert (0);
993 }
994 }
995 if (! task->in_ready_list)
996 {
997 if (is_fd_task)
998 {
999 GNUNET_CONTAINER_DLL_remove (pending_head,
1000 pending_tail,
1001 task);
1002 }
1003 else if (GNUNET_YES == task->on_shutdown)
1004 {
1005 GNUNET_CONTAINER_DLL_remove (shutdown_head,
1006 shutdown_tail,
1007 task);
1008 }
1009 else
1010 {
1011 GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
1012 pending_timeout_tail,
1013 task);
1014 if (pending_timeout_last == task)
1015 pending_timeout_last = NULL;
1016 }
1017 }
1018 else
1019 {
1020 p = check_priority (task->priority);
1021 GNUNET_CONTAINER_DLL_remove (ready_head[p],
1022 ready_tail[p],
1023 task);
1024 ready_count--;
1025 }
1026 ret = task->callback_cls;
1027 destroy_task (task);
1028 return ret;
1029}
1030
1031
1032/**
1033 * Initialize backtrace data for task @a t
1034 *
1035 * @param t task to initialize
1036 */
1037static void
1038init_backtrace (struct GNUNET_SCHEDULER_Task *t)
1039{
1040#if EXECINFO
1041 void *backtrace_array[MAX_TRACE_DEPTH];
1042
1043 t->num_backtrace_strings
1044 = backtrace (backtrace_array, MAX_TRACE_DEPTH);
1045 t->backtrace_strings =
1046 backtrace_symbols (backtrace_array,
1047 t->num_backtrace_strings);
1048 dump_backtrace (t);
1049#else
1050 (void) t;
1051#endif
1052}
1053
1054
1055/**
1056 * Continue the current execution with the given function. This is
1057 * similar to the other "add" functions except that there is no delay
1058 * and the reason code can be specified.
1059 *
1060 * @param task main function of the task
1061 * @param task_cls closure for @a task
1062 * @param reason reason for task invocation
1063 * @param priority priority to use for the task
1064 */
1065void
1066GNUNET_SCHEDULER_add_with_reason_and_priority (GNUNET_SCHEDULER_TaskCallback
1067 task,
1068 void *task_cls,
1069 enum GNUNET_SCHEDULER_Reason
1070 reason,
1071 enum GNUNET_SCHEDULER_Priority
1072 priority)
1073{
1074 struct GNUNET_SCHEDULER_Task *t;
1075
1076 /* scheduler must be running */
1077 GNUNET_assert (NULL != scheduler_driver);
1078 GNUNET_assert (NULL != task);
1079 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1080 t->read_fd = -1;
1081 t->write_fd = -1;
1082 t->callback = task;
1083 t->callback_cls = task_cls;
1084#if PROFILE_DELAYS
1085 t->start_time = GNUNET_TIME_absolute_get ();
1086#endif
1087 t->reason = reason;
1088 t->priority = check_priority (priority);
1089 t->lifeness = current_lifeness;
1090 LOG (GNUNET_ERROR_TYPE_DEBUG,
1091 "Adding continuation task %p\n",
1092 t);
1093 init_backtrace (t);
1094 queue_ready_task (t);
1095}
1096
1097
1098/**
1099 * Schedule a new task to be run at the specified time. The task
1100 * will be scheduled for execution at time @a at.
1101 *
1102 * @param at time when the operation should run
1103 * @param priority priority to use for the task
1104 * @param task main function of the task
1105 * @param task_cls closure of @a task
1106 * @return unique task identifier for the job
1107 * only valid until @a task is started!
1108 */
1109struct GNUNET_SCHEDULER_Task *
1110GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at,
1111 enum GNUNET_SCHEDULER_Priority priority,
1112 GNUNET_SCHEDULER_TaskCallback task,
1113 void *task_cls)
1114{
1115 struct GNUNET_SCHEDULER_Task *t;
1116 struct GNUNET_SCHEDULER_Task *pos;
1117 struct GNUNET_SCHEDULER_Task *prev;
1118 struct GNUNET_TIME_Relative left;
1119
1120 /* scheduler must be running */
1121 GNUNET_assert (NULL != scheduler_driver);
1122 GNUNET_assert (NULL != task);
1123 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1124 GNUNET_async_scope_get (&t->scope);
1125 t->callback = task;
1126 t->callback_cls = task_cls;
1127 t->read_fd = -1;
1128 t->write_fd = -1;
1129#if PROFILE_DELAYS
1130 t->start_time = GNUNET_TIME_absolute_get ();
1131#endif
1132 t->timeout = at;
1133 t->priority = check_priority (priority);
1134 t->lifeness = current_lifeness;
1135 init_backtrace (t);
1136
1137 left = GNUNET_TIME_absolute_get_remaining (at);
1138 if (0 == left.rel_value_us)
1139 {
1140 queue_ready_task (t);
1141 if (priority > work_priority)
1142 work_priority = priority;
1143 return t;
1144 }
1145
1146 /* try tail first (optimization in case we are
1147 * appending to a long list of tasks with timeouts) */
1148 if ((NULL == pending_timeout_head) ||
1149 (at.abs_value_us < pending_timeout_head->timeout.abs_value_us))
1150 {
1151 GNUNET_CONTAINER_DLL_insert (pending_timeout_head,
1152 pending_timeout_tail,
1153 t);
1154 }
1155 else
1156 {
1157 /* first move from heuristic start backwards to before start time */
1158 prev = pending_timeout_last;
1159 while ((NULL != prev) &&
1160 (prev->timeout.abs_value_us > t->timeout.abs_value_us))
1161 prev = prev->prev;
1162 /* now, move from heuristic start (or head of list) forward to insertion point */
1163 if (NULL == prev)
1164 pos = pending_timeout_head;
1165 else
1166 pos = prev->next;
1167 while ((NULL != pos) && (pos->timeout.abs_value_us <=
1168 t->timeout.abs_value_us))
1169 {
1170 prev = pos;
1171 pos = pos->next;
1172 }
1173 GNUNET_CONTAINER_DLL_insert_after (pending_timeout_head,
1174 pending_timeout_tail,
1175 prev,
1176 t);
1177 }
1178 /* finally, update heuristic insertion point to last insertion... */
1179 pending_timeout_last = t;
1180 LOG (GNUNET_ERROR_TYPE_DEBUG,
1181 "Adding task %p\n",
1182 t);
1183 return t;
1184}
1185
1186
1187/**
1188 * Schedule a new task to be run with a specified delay. The task
1189 * will be scheduled for execution once the delay has expired.
1190 *
1191 * @param delay when should this operation time out?
1192 * @param priority priority to use for the task
1193 * @param task main function of the task
1194 * @param task_cls closure of @a task
1195 * @return unique task identifier for the job
1196 * only valid until @a task is started!
1197 */
1198struct GNUNET_SCHEDULER_Task *
1199GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
1200 enum GNUNET_SCHEDULER_Priority
1201 priority,
1202 GNUNET_SCHEDULER_TaskCallback task,
1203 void *task_cls)
1204{
1205 return GNUNET_SCHEDULER_add_at_with_priority (
1206 GNUNET_TIME_relative_to_absolute (delay),
1207 priority,
1208 task,
1209 task_cls);
1210}
1211
1212
1213/**
1214 * Schedule a new task to be run with a specified priority.
1215 *
1216 * @param prio how important is the new task?
1217 * @param task main function of the task
1218 * @param task_cls closure of @a task
1219 * @return unique task identifier for the job
1220 * only valid until @a task is started!
1221 */
1222struct GNUNET_SCHEDULER_Task *
1223GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
1224 GNUNET_SCHEDULER_TaskCallback task,
1225 void *task_cls)
1226{
1227 return GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_ZERO,
1228 prio,
1229 task,
1230 task_cls);
1231}
1232
1233
1234/**
1235 * Schedule a new task to be run at the specified time. The task
1236 * will be scheduled for execution once specified time has been
1237 * reached. It will be run with the DEFAULT priority.
1238 *
1239 * @param at time at which this operation should run
1240 * @param task main function of the task
1241 * @param task_cls closure of @a task
1242 * @return unique task identifier for the job
1243 * only valid until @a task is started!
1244 */
1245struct GNUNET_SCHEDULER_Task *
1246GNUNET_SCHEDULER_add_at (struct GNUNET_TIME_Absolute at,
1247 GNUNET_SCHEDULER_TaskCallback task,
1248 void *task_cls)
1249{
1250 return GNUNET_SCHEDULER_add_at_with_priority (at,
1251 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1252 task,
1253 task_cls);
1254}
1255
1256
1257/**
1258 * Schedule a new task to be run with a specified delay. The task
1259 * will be scheduled for execution once the delay has expired. It
1260 * will be run with the DEFAULT priority.
1261 *
1262 * @param delay when should this operation time out?
1263 * @param task main function of the task
1264 * @param task_cls closure of @a task
1265 * @return unique task identifier for the job
1266 * only valid until @a task is started!
1267 */
1268struct GNUNET_SCHEDULER_Task *
1269GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
1270 GNUNET_SCHEDULER_TaskCallback task,
1271 void *task_cls)
1272{
1273 return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
1274 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1275 task,
1276 task_cls);
1277}
1278
1279
1280/**
1281 * Schedule a new task to be run as soon as possible. Note that this
1282 * does not guarantee that this will be the next task that is being
1283 * run, as other tasks with higher priority (or that are already ready
1284 * to run) might get to run first. Just as with delays, clients must
1285 * not rely on any particular order of execution between tasks
1286 * scheduled concurrently.
1287 *
1288 * The task will be run with the DEFAULT priority.
1289 *
1290 * @param task main function of the task
1291 * @param task_cls closure of @a task
1292 * @return unique task identifier for the job
1293 * only valid until @a task is started!
1294 */
1295struct GNUNET_SCHEDULER_Task *
1296GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task,
1297 void *task_cls)
1298{
1299 struct GNUNET_SCHEDULER_Task *t;
1300
1301 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1302 GNUNET_async_scope_get (&t->scope);
1303 t->callback = task;
1304 t->callback_cls = task_cls;
1305 t->read_fd = -1;
1306 t->write_fd = -1;
1307#if PROFILE_DELAYS
1308 t->start_time = GNUNET_TIME_absolute_get ();
1309#endif
1310 t->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1311 t->priority = current_priority;
1312 t->on_shutdown = GNUNET_YES;
1313 t->lifeness = current_lifeness;
1314 queue_ready_task (t);
1315 init_backtrace (t);
1316 return t;
1317}
1318
1319
1320/**
1321 * Schedule a new task to be run on shutdown, that is when a CTRL-C
1322 * signal is received, or when #GNUNET_SCHEDULER_shutdown() is being
1323 * invoked.
1324 *
1325 * @param task main function of the task
1326 * @param task_cls closure of @a task
1327 * @return unique task identifier for the job
1328 * only valid until @a task is started!
1329 */
1330struct GNUNET_SCHEDULER_Task *
1331GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task,
1332 void *task_cls)
1333{
1334 struct GNUNET_SCHEDULER_Task *t;
1335
1336 /* scheduler must be running */
1337 GNUNET_assert (NULL != scheduler_driver);
1338 GNUNET_assert (NULL != task);
1339 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1340 GNUNET_async_scope_get (&t->scope);
1341 t->callback = task;
1342 t->callback_cls = task_cls;
1343 t->read_fd = -1;
1344 t->write_fd = -1;
1345#if PROFILE_DELAYS
1346 t->start_time = GNUNET_TIME_absolute_get ();
1347#endif
1348 t->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1349 t->priority = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN;
1350 t->on_shutdown = GNUNET_YES;
1351 t->lifeness = GNUNET_NO;
1352 GNUNET_CONTAINER_DLL_insert (shutdown_head,
1353 shutdown_tail,
1354 t);
1355 LOG (GNUNET_ERROR_TYPE_DEBUG,
1356 "Adding shutdown task %p\n",
1357 t);
1358 init_backtrace (t);
1359 return t;
1360}
1361
1362
1363/**
1364 * Schedule a new task to be run as soon as possible with the
1365 * (transitive) ignore-shutdown flag either explicitly set or
1366 * explicitly enabled. This task (and all tasks created from it,
1367 * other than by another call to this function) will either count or
1368 * not count for the "lifeness" of the process. This API is only
1369 * useful in a few special cases.
1370 *
1371 * @param lifeness #GNUNET_YES if the task counts for lifeness, #GNUNET_NO if not.
1372 * @param task main function of the task
1373 * @param task_cls closure of @a task
1374 * @return unique task identifier for the job
1375 * only valid until @a task is started!
1376 */
1377struct GNUNET_SCHEDULER_Task *
1378GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
1379 GNUNET_SCHEDULER_TaskCallback task,
1380 void *task_cls)
1381{
1382 struct GNUNET_SCHEDULER_Task *ret;
1383
1384 ret = GNUNET_SCHEDULER_add_now (task, task_cls);
1385 ret->lifeness = lifeness;
1386 return ret;
1387}
1388
1389
1390#if DEBUG_FDS
1391/**
1392 * check a raw file descriptor and abort if it is bad (for debugging purposes)
1393 *
1394 * @param t the task related to the file descriptor
1395 * @param raw_fd the raw file descriptor to check
1396 */
1397void
1398check_fd (struct GNUNET_SCHEDULER_Task *t, int raw_fd)
1399{
1400 if (-1 != raw_fd)
1401 {
1402 int flags = fcntl (raw_fd, F_GETFD);
1403
1404 if ((flags == -1) && (errno == EBADF))
1405 {
1406 LOG (GNUNET_ERROR_TYPE_ERROR,
1407 "Got invalid file descriptor %d!\n",
1408 raw_fd);
1409 init_backtrace (t);
1410 GNUNET_assert (0);
1411 }
1412 }
1413}
1414
1415
1416#endif
1417
1418
1419/**
1420 * Schedule a new task to be run with a specified delay or when any of
1421 * the specified file descriptor sets is ready. The delay can be used
1422 * as a timeout on the socket(s) being ready. The task will be
1423 * scheduled for execution once either the delay has expired or any of
1424 * the socket operations is ready. This is the most general
1425 * function of the "add" family. Note that the "prerequisite_task"
1426 * must be satisfied in addition to any of the other conditions. In
1427 * other words, the task will be started when
1428 * <code>
1429 * (prerequisite-run)
1430 * && (delay-ready
1431 * || any-rs-ready
1432 * || any-ws-ready)
1433 * </code>
1434 *
1435 * @param delay how long should we wait?
1436 * @param priority priority to use
1437 * @param rfd file descriptor we want to read (can be -1)
1438 * @param wfd file descriptors we want to write (can be -1)
1439 * @param task main function of the task
1440 * @param task_cls closure of @a task
1441 * @return unique task identifier for the job
1442 * only valid until @a task is started!
1443 */
1444static struct GNUNET_SCHEDULER_Task *
1445add_without_sets (struct GNUNET_TIME_Relative delay,
1446 enum GNUNET_SCHEDULER_Priority priority,
1447 const struct GNUNET_NETWORK_Handle *read_nh,
1448 const struct GNUNET_NETWORK_Handle *write_nh,
1449 const struct GNUNET_DISK_FileHandle *read_fh,
1450 const struct GNUNET_DISK_FileHandle *write_fh,
1451 GNUNET_SCHEDULER_TaskCallback task,
1452 void *task_cls)
1453{
1454 struct GNUNET_SCHEDULER_Task *t;
1455
1456 /* scheduler must be running */
1457 GNUNET_assert (NULL != scheduler_driver);
1458 GNUNET_assert (NULL != task);
1459 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1460 GNUNET_async_scope_get (&t->scope);
1461 init_fd_info (t,
1462 &read_nh,
1463 read_nh ? 1 : 0,
1464 &write_nh,
1465 write_nh ? 1 : 0,
1466 &read_fh,
1467 read_fh ? 1 : 0,
1468 &write_fh,
1469 write_fh ? 1 : 0);
1470 t->callback = task;
1471 t->callback_cls = task_cls;
1472#if DEBUG_FDS
1473 check_fd (t, NULL != read_nh ? GNUNET_NETWORK_get_fd (read_nh) : -1);
1474 check_fd (t, NULL != write_nh ? GNUNET_NETWORK_get_fd (write_nh) : -1);
1475 check_fd (t, NULL != read_fh ? read_fh->fd : -1);
1476 check_fd (t, NULL != write_fh ? write_fh->fd : -1);
1477#endif
1478#if PROFILE_DELAYS
1479 t->start_time = GNUNET_TIME_absolute_get ();
1480#endif
1481 t->timeout = GNUNET_TIME_relative_to_absolute (delay);
1482 t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ?
1483 current_priority : priority);
1484 t->lifeness = current_lifeness;
1485 GNUNET_CONTAINER_DLL_insert (pending_head,
1486 pending_tail,
1487 t);
1488 driver_add_multiple (t);
1489 max_priority_added = GNUNET_MAX (max_priority_added,
1490 t->priority);
1491 init_backtrace (t);
1492 return t;
1493}
1494
1495
1496/**
1497 * Schedule a new task to be run with a specified delay or when the
1498 * specified file descriptor is ready for reading. The delay can be
1499 * used as a timeout on the socket being ready. The task will be
1500 * scheduled for execution once either the delay has expired or the
1501 * socket operation is ready. It will be run with the DEFAULT priority.
1502 * Only allowed to be called as long as the scheduler is running, that
1503 * is one of the following conditions is met:
1504 *
1505 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1506 * - #GNUNET_SCHEDULER_driver_init has been run and
1507 * #GNUNET_SCHEDULER_driver_done has not been called yet
1508 *
1509 * @param delay when should this operation time out?
1510 * @param rfd read file-descriptor
1511 * @param task main function of the task
1512 * @param task_cls closure of @a task
1513 * @return unique task identifier for the job
1514 * only valid until @a task is started!
1515 */
1516struct GNUNET_SCHEDULER_Task *
1517GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
1518 struct GNUNET_NETWORK_Handle *rfd,
1519 GNUNET_SCHEDULER_TaskCallback task,
1520 void *task_cls)
1521{
1522 return GNUNET_SCHEDULER_add_read_net_with_priority (delay,
1523 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1524 rfd, task, task_cls);
1525}
1526
1527
1528/**
1529 * Schedule a new task to be run with a specified priority and to be
1530 * run after the specified delay or when the specified file descriptor
1531 * is ready for reading. The delay can be used as a timeout on the
1532 * socket being ready. The task will be scheduled for execution once
1533 * either the delay has expired or the socket operation is ready. It
1534 * will be run with the DEFAULT priority.
1535 * Only allowed to be called as long as the scheduler is running, that
1536 * is one of the following conditions is met:
1537 *
1538 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1539 * - #GNUNET_SCHEDULER_driver_init has been run and
1540 * #GNUNET_SCHEDULER_driver_done has not been called yet
1541 *
1542 * @param delay when should this operation time out?
1543 * @param priority priority to use for the task
1544 * @param rfd read file-descriptor
1545 * @param task main function of the task
1546 * @param task_cls closure of @a task
1547 * @return unique task identifier for the job
1548 * only valid until @a task is started!
1549 */
1550struct GNUNET_SCHEDULER_Task *
1551GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay,
1552 enum GNUNET_SCHEDULER_Priority
1553 priority,
1554 struct GNUNET_NETWORK_Handle *rfd,
1555 GNUNET_SCHEDULER_TaskCallback task,
1556 void *task_cls)
1557{
1558 return GNUNET_SCHEDULER_add_net_with_priority (delay, priority,
1559 rfd,
1560 GNUNET_YES,
1561 GNUNET_NO,
1562 task, task_cls);
1563}
1564
1565
1566/**
1567 * Schedule a new task to be run with a specified delay or when the
1568 * specified file descriptor is ready for writing. The delay can be
1569 * used as a timeout on the socket being ready. The task will be
1570 * scheduled for execution once either the delay has expired or the
1571 * socket operation is ready. It will be run with the priority of
1572 * the calling task.
1573 * Only allowed to be called as long as the scheduler is running, that
1574 * is one of the following conditions is met:
1575 *
1576 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1577 * - #GNUNET_SCHEDULER_driver_init has been run and
1578 * #GNUNET_SCHEDULER_driver_done has not been called yet
1579 *
1580 * @param delay when should this operation time out?
1581 * @param wfd write file-descriptor
1582 * @param task main function of the task
1583 * @param task_cls closure of @a task
1584 * @return unique task identifier for the job
1585 * only valid until @a task is started!
1586 */
1587struct GNUNET_SCHEDULER_Task *
1588GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
1589 struct GNUNET_NETWORK_Handle *wfd,
1590 GNUNET_SCHEDULER_TaskCallback task,
1591 void *task_cls)
1592{
1593 return GNUNET_SCHEDULER_add_net_with_priority (delay,
1594 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1595 wfd,
1596 GNUNET_NO, GNUNET_YES,
1597 task, task_cls);
1598}
1599
1600
1601/**
1602 * Schedule a new task to be run with a specified delay or when the
1603 * specified file descriptor is ready. The delay can be
1604 * used as a timeout on the socket being ready. The task will be
1605 * scheduled for execution once either the delay has expired or the
1606 * socket operation is ready.
1607 * Only allowed to be called as long as the scheduler is running, that
1608 * is one of the following conditions is met:
1609 *
1610 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1611 * - #GNUNET_SCHEDULER_driver_init has been run and
1612 * #GNUNET_SCHEDULER_driver_done has not been called yet
1613 *
1614 * @param delay when should this operation time out?
1615 * @param priority priority of the task
1616 * @param fd file-descriptor
1617 * @param on_read whether to poll the file-descriptor for readability
1618 * @param on_write whether to poll the file-descriptor for writability
1619 * @param task main function of the task
1620 * @param task_cls closure of task
1621 * @return unique task identifier for the job
1622 * only valid until "task" is started!
1623 */
1624struct GNUNET_SCHEDULER_Task *
1625GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay,
1626 enum GNUNET_SCHEDULER_Priority priority,
1627 struct GNUNET_NETWORK_Handle *fd,
1628 int on_read,
1629 int on_write,
1630 GNUNET_SCHEDULER_TaskCallback task,
1631 void *task_cls)
1632{
1633 /* scheduler must be running */
1634 GNUNET_assert (NULL != scheduler_driver);
1635 GNUNET_assert (on_read || on_write);
1636 GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0);
1637 return add_without_sets (delay, priority,
1638 on_read ? fd : NULL,
1639 on_write ? fd : NULL,
1640 NULL,
1641 NULL,
1642 task, task_cls);
1643}
1644
1645
1646/**
1647 * Schedule a new task to be run with a specified delay or when the
1648 * specified file descriptor is ready for reading. The delay can be
1649 * used as a timeout on the socket being ready. The task will be
1650 * scheduled for execution once either the delay has expired or the
1651 * socket operation is ready. It will be run with the DEFAULT priority.
1652 * Only allowed to be called as long as the scheduler is running, that
1653 * is one of the following conditions is met:
1654 *
1655 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1656 * - #GNUNET_SCHEDULER_driver_init has been run and
1657 * #GNUNET_SCHEDULER_driver_done has not been called yet
1658 *
1659 * @param delay when should this operation time out?
1660 * @param rfd read file-descriptor
1661 * @param task main function of the task
1662 * @param task_cls closure of @a task
1663 * @return unique task identifier for the job
1664 * only valid until @a task is started!
1665 */
1666struct GNUNET_SCHEDULER_Task *
1667GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
1668 const struct GNUNET_DISK_FileHandle *rfd,
1669 GNUNET_SCHEDULER_TaskCallback task,
1670 void *task_cls)
1671{
1672 return GNUNET_SCHEDULER_add_file_with_priority (
1673 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1674 rfd, GNUNET_YES, GNUNET_NO,
1675 task, task_cls);
1676}
1677
1678
1679/**
1680 * Schedule a new task to be run with a specified delay or when the
1681 * specified file descriptor is ready for writing. The delay can be
1682 * used as a timeout on the socket being ready. The task will be
1683 * scheduled for execution once either the delay has expired or the
1684 * socket operation is ready. It will be run with the DEFAULT priority.
1685 * Only allowed to be called as long as the scheduler is running, that
1686 * is one of the following conditions is met:
1687 *
1688 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1689 * - #GNUNET_SCHEDULER_driver_init has been run and
1690 * #GNUNET_SCHEDULER_driver_done has not been called yet
1691 *
1692 * @param delay when should this operation time out?
1693 * @param wfd write file-descriptor
1694 * @param task main function of the task
1695 * @param task_cls closure of @a task
1696 * @return unique task identifier for the job
1697 * only valid until @a task is started!
1698 */
1699struct GNUNET_SCHEDULER_Task *
1700GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
1701 const struct GNUNET_DISK_FileHandle *wfd,
1702 GNUNET_SCHEDULER_TaskCallback task,
1703 void *task_cls)
1704{
1705 return GNUNET_SCHEDULER_add_file_with_priority (
1706 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1707 wfd, GNUNET_NO, GNUNET_YES,
1708 task, task_cls);
1709}
1710
1711
1712/**
1713 * Schedule a new task to be run with a specified delay or when the
1714 * specified file descriptor is ready. The delay can be
1715 * used as a timeout on the socket being ready. The task will be
1716 * scheduled for execution once either the delay has expired or the
1717 * socket operation is ready.
1718 * Only allowed to be called as long as the scheduler is running, that
1719 * is one of the following conditions is met:
1720 *
1721 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1722 * - #GNUNET_SCHEDULER_driver_init has been run and
1723 * #GNUNET_SCHEDULER_driver_done has not been called yet
1724 *
1725 * @param delay when should this operation time out?
1726 * @param priority priority of the task
1727 * @param fd file-descriptor
1728 * @param on_read whether to poll the file-descriptor for readability
1729 * @param on_write whether to poll the file-descriptor for writability
1730 * @param task main function of the task
1731 * @param task_cls closure of @a task
1732 * @return unique task identifier for the job
1733 * only valid until @a task is started!
1734 */
1735struct GNUNET_SCHEDULER_Task *
1736GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay,
1737 enum GNUNET_SCHEDULER_Priority
1738 priority,
1739 const struct
1740 GNUNET_DISK_FileHandle *fd,
1741 int on_read, int on_write,
1742 GNUNET_SCHEDULER_TaskCallback task,
1743 void *task_cls)
1744{
1745 /* scheduler must be running */
1746 GNUNET_assert (NULL != scheduler_driver);
1747 GNUNET_assert (on_read || on_write);
1748 GNUNET_assert (fd->fd >= 0);
1749 return add_without_sets (delay, priority,
1750 NULL,
1751 NULL,
1752 on_read ? fd : NULL,
1753 on_write ? fd : NULL,
1754 task, task_cls);
1755}
1756
1757
1758void
1759extract_handles (const struct GNUNET_NETWORK_FDSet *fdset,
1760 const struct GNUNET_NETWORK_Handle ***ntarget,
1761 unsigned int *extracted_nhandles,
1762 const struct GNUNET_DISK_FileHandle ***ftarget,
1763 unsigned int *extracted_fhandles)
1764{
1765 // FIXME: this implementation only works for unix, for WIN32 the file handles
1766 // in fdset must be handled separately
1767 const struct GNUNET_NETWORK_Handle **nhandles;
1768 const struct GNUNET_DISK_FileHandle **fhandles;
1769 unsigned int nhandles_len;
1770 unsigned int fhandles_len;
1771
1772 nhandles = NULL;
1773 fhandles = NULL;
1774 nhandles_len = 0;
1775 fhandles_len = 0;
1776 for (int sock = 0; sock != fdset->nsds; ++sock)
1777 {
1778 if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (fdset, sock))
1779 {
1780 struct GNUNET_NETWORK_Handle *nhandle;
1781 struct GNUNET_DISK_FileHandle *fhandle;
1782
1783 nhandle = GNUNET_NETWORK_socket_box_native (sock);
1784 if (NULL != nhandle)
1785 {
1786 GNUNET_array_append (nhandles, nhandles_len, nhandle);
1787 }
1788 else
1789 {
1790 fhandle = GNUNET_DISK_get_handle_from_int_fd (sock);
1791 if (NULL != fhandle)
1792 {
1793 GNUNET_array_append (fhandles, fhandles_len, fhandle);
1794 }
1795 else
1796 {
1797 GNUNET_assert (0);
1798 }
1799 }
1800 }
1801 }
1802 *ntarget = nhandles_len > 0 ? nhandles : NULL;
1803 *ftarget = fhandles_len > 0 ? fhandles : NULL;
1804 *extracted_nhandles = nhandles_len;
1805 *extracted_fhandles = fhandles_len;
1806}
1807
1808
1809/**
1810 * Schedule a new task to be run with a specified delay or when any of
1811 * the specified file descriptor sets is ready. The delay can be used
1812 * as a timeout on the socket(s) being ready. The task will be
1813 * scheduled for execution once either the delay has expired or any of
1814 * the socket operations is ready. This is the most general
1815 * function of the "add" family. Note that the "prerequisite_task"
1816 * must be satisfied in addition to any of the other conditions. In
1817 * other words, the task will be started when
1818 * <code>
1819 * (prerequisite-run)
1820 * && (delay-ready
1821 * || any-rs-ready
1822 * || any-ws-ready) )
1823 * </code>
1824 * Only allowed to be called as long as the scheduler is running, that
1825 * is one of the following conditions is met:
1826 *
1827 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1828 * - #GNUNET_SCHEDULER_driver_init has been run and
1829 * #GNUNET_SCHEDULER_driver_done has not been called yet
1830 *
1831 * @param prio how important is this task?
1832 * @param delay how long should we wait?
1833 * @param rs set of file descriptors we want to read (can be NULL)
1834 * @param ws set of file descriptors we want to write (can be NULL)
1835 * @param task main function of the task
1836 * @param task_cls closure of @a task
1837 * @return unique task identifier for the job
1838 * only valid until @a task is started!
1839 */
1840struct GNUNET_SCHEDULER_Task *
1841GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1842 struct GNUNET_TIME_Relative delay,
1843 const struct GNUNET_NETWORK_FDSet *rs,
1844 const struct GNUNET_NETWORK_FDSet *ws,
1845 GNUNET_SCHEDULER_TaskCallback task,
1846 void *task_cls)
1847{
1848 struct GNUNET_SCHEDULER_Task *t;
1849 const struct GNUNET_NETWORK_Handle **read_nhandles = NULL;
1850 const struct GNUNET_NETWORK_Handle **write_nhandles = NULL;
1851 const struct GNUNET_DISK_FileHandle **read_fhandles = NULL;
1852 const struct GNUNET_DISK_FileHandle **write_fhandles = NULL;
1853 unsigned int read_nhandles_len = 0;
1854 unsigned int write_nhandles_len = 0;
1855 unsigned int read_fhandles_len = 0;
1856 unsigned int write_fhandles_len = 0;
1857
1858 /* scheduler must be running */
1859 GNUNET_assert (NULL != scheduler_driver);
1860 GNUNET_assert (NULL != task);
1861 int no_rs = (NULL == rs);
1862 int no_ws = (NULL == ws);
1863 int empty_rs = (NULL != rs) && (0 == rs->nsds);
1864 int empty_ws = (NULL != ws) && (0 == ws->nsds);
1865 int no_fds = (no_rs && no_ws) ||
1866 (empty_rs && empty_ws) ||
1867 (no_rs && empty_ws) ||
1868 (no_ws && empty_rs);
1869 if (! no_fds)
1870 {
1871 if (NULL != rs)
1872 {
1873 extract_handles (rs,
1874 &read_nhandles,
1875 &read_nhandles_len,
1876 &read_fhandles,
1877 &read_fhandles_len);
1878 }
1879 if (NULL != ws)
1880 {
1881 extract_handles (ws,
1882 &write_nhandles,
1883 &write_nhandles_len,
1884 &write_fhandles,
1885 &write_fhandles_len);
1886 }
1887 }
1888 /**
1889 * here we consider the case that a GNUNET_NETWORK_FDSet might be empty
1890 * although its maximum FD number (nsds) is greater than 0. We handle
1891 * this case gracefully because some libraries such as libmicrohttpd
1892 * only provide a hint what the maximum FD number in an FD set might be
1893 * and not the exact FD number (see e.g. gnunet-rest-service.c)
1894 */int no_fds_extracted = (0 == read_nhandles_len) &&
1895 (0 == read_fhandles_len) &&
1896 (0 == write_nhandles_len) &&
1897 (0 == write_fhandles_len);
1898 if (no_fds || no_fds_extracted)
1899 return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
1900 prio,
1901 task,
1902 task_cls);
1903 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1904 GNUNET_async_scope_get (&t->scope);
1905 init_fd_info (t,
1906 read_nhandles,
1907 read_nhandles_len,
1908 write_nhandles,
1909 write_nhandles_len,
1910 read_fhandles,
1911 read_fhandles_len,
1912 write_fhandles,
1913 write_fhandles_len);
1914 t->callback = task;
1915 t->callback_cls = task_cls;
1916 t->own_handles = GNUNET_YES;
1917 /* free the arrays of pointers to network / file handles, the actual
1918 * handles will be freed in destroy_task */
1919 GNUNET_array_grow (read_nhandles, read_nhandles_len, 0);
1920 GNUNET_array_grow (write_nhandles, write_nhandles_len, 0);
1921 GNUNET_array_grow (read_fhandles, read_fhandles_len, 0);
1922 GNUNET_array_grow (write_fhandles, write_fhandles_len, 0);
1923#if PROFILE_DELAYS
1924 t->start_time = GNUNET_TIME_absolute_get ();
1925#endif
1926 t->timeout = GNUNET_TIME_relative_to_absolute (delay);
1927 t->priority =
1928 check_priority ((prio ==
1929 GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority :
1930 prio);
1931 t->lifeness = current_lifeness;
1932 GNUNET_CONTAINER_DLL_insert (pending_head,
1933 pending_tail,
1934 t);
1935 driver_add_multiple (t);
1936 max_priority_added = GNUNET_MAX (max_priority_added,
1937 t->priority);
1938 LOG (GNUNET_ERROR_TYPE_DEBUG,
1939 "Adding task %p\n",
1940 t);
1941 init_backtrace (t);
1942 return t;
1943}
1944
1945
1946/**
1947 * Function used by event-loop implementations to signal the scheduler
1948 * that a particular @a task is ready due to an event specified in the
1949 * et field of @a fdi.
1950 *
1951 * This function will then queue the task to notify the application
1952 * that the task is ready (with the respective priority).
1953 *
1954 * @param task the task that is ready
1955 * @param fdi information about the related FD
1956 */
1957void
1958GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task,
1959 struct GNUNET_SCHEDULER_FdInfo *fdi)
1960{
1961 enum GNUNET_SCHEDULER_Reason reason;
1962
1963 reason = task->reason;
1964 if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1965 (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)))
1966 reason |= GNUNET_SCHEDULER_REASON_READ_READY;
1967 if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
1968 (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)))
1969 reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
1970 reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
1971 task->reason = reason;
1972 if (GNUNET_NO == task->in_ready_list)
1973 {
1974 GNUNET_CONTAINER_DLL_remove (pending_head,
1975 pending_tail,
1976 task);
1977 queue_ready_task (task);
1978 }
1979}
1980
1981
1982/**
1983 * Function called by external event loop implementations to tell the
1984 * scheduler to run some of the tasks that are ready. Must be called
1985 * only after #GNUNET_SCHEDULER_driver_init has been called and before
1986 * #GNUNET_SCHEDULER_driver_done is called.
1987 * This function may return even though there are tasks left to run
1988 * just to give other tasks a chance as well. If we return #GNUNET_YES,
1989 * the event loop implementation should call this function again as
1990 * soon as possible, while if we return #GNUNET_NO it must block until
1991 * either the operating system has more work (the scheduler has no more
1992 * work to do right now) or the timeout set by the scheduler (using the
1993 * set_wakeup callback) is reached.
1994 *
1995 * @param sh scheduler handle that was returned by
1996 * #GNUNET_SCHEDULER_driver_init
1997 * @return #GNUNET_YES if there are more tasks that are ready,
1998 * and thus we would like to run more (yield to avoid
1999 * blocking other activities for too long) #GNUNET_NO
2000 * if we are done running tasks (yield to block)
2001 */
2002int
2003GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2004{
2005 struct GNUNET_SCHEDULER_Task *pos;
2006 struct GNUNET_TIME_Absolute now;
2007
2008 /* check for tasks that reached the timeout! */
2009 now = GNUNET_TIME_absolute_get ();
2010 pos = pending_timeout_head;
2011 while (NULL != pos)
2012 {
2013 struct GNUNET_SCHEDULER_Task *next = pos->next;
2014 if (now.abs_value_us >= pos->timeout.abs_value_us)
2015 pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
2016 if (0 == pos->reason)
2017 break;
2018 GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
2019 pending_timeout_tail,
2020 pos);
2021 if (pending_timeout_last == pos)
2022 pending_timeout_last = NULL;
2023 queue_ready_task (pos);
2024 pos = next;
2025 }
2026 pos = pending_head;
2027 while (NULL != pos)
2028 {
2029 struct GNUNET_SCHEDULER_Task *next = pos->next;
2030 if (now.abs_value_us >= pos->timeout.abs_value_us)
2031 {
2032 pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
2033 GNUNET_CONTAINER_DLL_remove (pending_head,
2034 pending_tail,
2035 pos);
2036 queue_ready_task (pos);
2037 }
2038 pos = next;
2039 }
2040
2041 if (0 == ready_count)
2042 {
2043 struct GNUNET_TIME_Absolute timeout = get_timeout ();
2044
2045 if (timeout.abs_value_us > now.abs_value_us)
2046 {
2047 /**
2048 * The event loop called this function before the current timeout was
2049 * reached (and no FD tasks are ready). This is acceptable if
2050 *
2051 * - the system time was changed while the driver was waiting for
2052 * the timeout
2053 * - an external event loop called GNUnet API functions outside of
2054 * the callbacks called in GNUNET_SCHEDULER_do_work and thus
2055 * wasn't notified about the new timeout
2056 *
2057 * It might also mean we are busy-waiting because of a programming
2058 * error in the external event loop.
2059 */
2060 LOG (GNUNET_ERROR_TYPE_DEBUG,
2061 "GNUNET_SCHEDULER_do_work did not find any ready "
2062 "tasks and timeout has not been reached yet.\n");
2063 }
2064 else
2065 {
2066 /**
2067 * the current timeout was reached but no ready tasks were found,
2068 * internal scheduler error!
2069 */
2070 GNUNET_assert (0);
2071 }
2072 }
2073 else
2074 {
2075 /* find out which task priority level we are going to
2076 process this time */
2077 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
2078 GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
2079 /* yes, p>0 is correct, 0 is "KEEP" which should
2080 * always be an empty queue (see assertion)! */
2081 for (work_priority = GNUNET_SCHEDULER_PRIORITY_COUNT - 1;
2082 work_priority > 0;
2083 work_priority--)
2084 {
2085 pos = ready_head[work_priority];
2086 if (NULL != pos)
2087 break;
2088 }
2089 GNUNET_assert (NULL != pos); /* ready_count wrong? */
2090
2091 /* process all tasks at this priority level, then yield */
2092 while (NULL != (pos = ready_head[work_priority]))
2093 {
2094 GNUNET_CONTAINER_DLL_remove (ready_head[work_priority],
2095 ready_tail[work_priority],
2096 pos);
2097 ready_count--;
2098 current_priority = pos->priority;
2099 current_lifeness = pos->lifeness;
2100 active_task = pos;
2101#if PROFILE_DELAYS
2102 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2103 DELAY_THRESHOLD.rel_value_us)
2104 {
2105 LOG (GNUNET_ERROR_TYPE_DEBUG,
2106 "Task %p took %s to be scheduled\n",
2107 pos,
2108 GNUNET_STRINGS_relative_time_to_string (
2109 GNUNET_TIME_absolute_get_duration (pos->start_time),
2110 GNUNET_YES));
2111 }
2112#endif
2113 tc.reason = pos->reason;
2114 GNUNET_NETWORK_fdset_zero (sh->rs);
2115 GNUNET_NETWORK_fdset_zero (sh->ws);
2116 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2117 tc.fds_len = pos->fds_len;
2118 tc.fds = pos->fds;
2119 for (unsigned int i = 0; i != pos->fds_len; ++i)
2120 {
2121 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i];
2122 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et))
2123 {
2124 GNUNET_NETWORK_fdset_set_native (sh->rs,
2125 fdi->sock);
2126 }
2127 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et))
2128 {
2129 GNUNET_NETWORK_fdset_set_native (sh->ws,
2130 fdi->sock);
2131 }
2132 }
2133 tc.read_ready = sh->rs;
2134 tc.write_ready = sh->ws;
2135 LOG (GNUNET_ERROR_TYPE_DEBUG,
2136 "Running task %p\n",
2137 pos);
2138 GNUNET_assert (NULL != pos->callback);
2139 {
2140 struct GNUNET_AsyncScopeSave old_scope;
2141 if (pos->scope.have_scope)
2142 GNUNET_async_scope_enter (&pos->scope.scope_id, &old_scope);
2143 else
2144 GNUNET_async_scope_get (&old_scope);
2145 pos->callback (pos->callback_cls);
2146 GNUNET_async_scope_restore (&old_scope);
2147 }
2148 if (NULL != pos->fds)
2149 {
2150 int del_result = scheduler_driver->del (scheduler_driver->cls, pos);
2151 if (GNUNET_OK != del_result)
2152 {
2153 LOG (GNUNET_ERROR_TYPE_ERROR,
2154 "driver could not delete task %p\n", pos);
2155 GNUNET_assert (0);
2156 }
2157 }
2158 active_task = NULL;
2159 dump_backtrace (pos);
2160 destroy_task (pos);
2161 }
2162 }
2163 shutdown_if_no_lifeness ();
2164 if (0 == ready_count)
2165 {
2166 scheduler_driver->set_wakeup (scheduler_driver->cls,
2167 get_timeout ());
2168 return GNUNET_NO;
2169 }
2170 scheduler_driver->set_wakeup (scheduler_driver->cls,
2171 GNUNET_TIME_absolute_get ());
2172 return GNUNET_YES;
2173}
2174
2175
2176/**
2177 * Function called by external event loop implementations to initialize
2178 * the scheduler. An external implementation has to provide @a driver
2179 * which contains callbacks for the scheduler (see definition of struct
2180 * #GNUNET_SCHEDULER_Driver). The callbacks are used to instruct the
2181 * external implementation to watch for events. If it detects any of
2182 * those events it is expected to call #GNUNET_SCHEDULER_do_work to let
2183 * the scheduler handle it. If an event is related to a specific task
2184 * (e.g. the scheduler gave instructions to watch a file descriptor),
2185 * the external implementation is expected to mark that task ready
2186 * before by calling #GNUNET_SCHEDULER_task_ready.
2187
2188 * This function has to be called before any tasks are scheduled and
2189 * before GNUNET_SCHEDULER_do_work is called for the first time. It
2190 * allocates resources that have to be freed again by calling
2191 * #GNUNET_SCHEDULER_driver_done.
2192 *
2193 * This function installs the same signal handlers as
2194 * #GNUNET_SCHEDULER_run. This means SIGTERM (and other similar signals)
2195 * will induce a call to #GNUNET_SCHEDULER_shutdown during the next
2196 * call to #GNUNET_SCHEDULER_do_work. As a result, SIGTERM causes all
2197 * active tasks to be scheduled with reason
2198 * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added afterwards
2199 * will execute normally!). Note that any particular signal will only
2200 * shut down one scheduler; applications should always only create a
2201 * single scheduler.
2202 *
2203 * @param driver to use for the event loop
2204 * @return handle to be passed to #GNUNET_SCHEDULER_do_work and
2205 * #GNUNET_SCHEDULER_driver_done
2206 */
2207struct GNUNET_SCHEDULER_Handle *
2208GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
2209{
2210 struct GNUNET_SCHEDULER_Handle *sh;
2211 const struct GNUNET_DISK_FileHandle *pr;
2212
2213 /* scheduler must not be running */
2214 GNUNET_assert (NULL == scheduler_driver);
2215 GNUNET_assert (NULL == shutdown_pipe_handle);
2216 /* general set-up */
2217 sh = GNUNET_new (struct GNUNET_SCHEDULER_Handle);
2218 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
2219 GNUNET_assert (NULL != shutdown_pipe_handle);
2220 pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
2221 GNUNET_DISK_PIPE_END_READ);
2222 my_pid = getpid ();
2223 scheduler_driver = driver;
2224
2225 /* install signal handlers */
2226 LOG (GNUNET_ERROR_TYPE_DEBUG,
2227 "Registering signal handlers\n");
2228 sh->shc_int = GNUNET_SIGNAL_handler_install (SIGINT,
2229 &sighandler_shutdown);
2230 sh->shc_term = GNUNET_SIGNAL_handler_install (SIGTERM,
2231 &sighandler_shutdown);
2232#if (SIGTERM != GNUNET_TERM_SIG)
2233 sh->shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG,
2234 &sighandler_shutdown);
2235#endif
2236 sh->shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE,
2237 &sighandler_pipe);
2238 sh->shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT,
2239 &sighandler_shutdown);
2240 sh->shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP,
2241 &sighandler_shutdown);
2242
2243 /* Setup initial tasks */
2244 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
2245 current_lifeness = GNUNET_NO;
2246 /* ensure this task runs first, by using a priority level reserved for
2247 the scheduler (not really shutdown, but start-up ;-) */
2248 install_parent_control_task =
2249 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_SHUTDOWN,
2250 &install_parent_control_handler,
2251 NULL);
2252 shutdown_pipe_task =
2253 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2254 pr,
2255 &shutdown_pipe_cb,
2256 NULL);
2257 current_lifeness = GNUNET_YES;
2258 scheduler_driver->set_wakeup (scheduler_driver->cls,
2259 get_timeout ());
2260 /* begin main event loop */
2261 sh->rs = GNUNET_NETWORK_fdset_create ();
2262 sh->ws = GNUNET_NETWORK_fdset_create ();
2263 GNUNET_NETWORK_fdset_handle_set (sh->rs, pr);
2264 return sh;
2265}
2266
2267
2268/**
2269 * Counter-part of #GNUNET_SCHEDULER_driver_init. Has to be called
2270 * by external event loop implementations after the scheduler has
2271 * shut down. This is the case if both of the following conditions
2272 * are met:
2273 *
2274 * - all tasks the scheduler has added through the driver's add
2275 * callback have been removed again through the driver's del
2276 * callback
2277 * - the timeout the scheduler has set through the driver's
2278 * add_wakeup callback is FOREVER
2279 *
2280 * @param sh the handle returned by #GNUNET_SCHEDULER_driver_init
2281 */
2282void
2283GNUNET_SCHEDULER_driver_done (struct GNUNET_SCHEDULER_Handle *sh)
2284{
2285 GNUNET_assert (NULL == pending_head);
2286 GNUNET_assert (NULL == pending_timeout_head);
2287 GNUNET_assert (NULL == shutdown_head);
2288 for (int i = 0; i != GNUNET_SCHEDULER_PRIORITY_COUNT; ++i)
2289 {
2290 GNUNET_assert (NULL == ready_head[i]);
2291 }
2292 GNUNET_NETWORK_fdset_destroy (sh->rs);
2293 GNUNET_NETWORK_fdset_destroy (sh->ws);
2294
2295 /* uninstall signal handlers */
2296 GNUNET_SIGNAL_handler_uninstall (sh->shc_int);
2297 GNUNET_SIGNAL_handler_uninstall (sh->shc_term);
2298#if (SIGTERM != GNUNET_TERM_SIG)
2299 GNUNET_SIGNAL_handler_uninstall (sh->shc_gterm);
2300#endif
2301 GNUNET_SIGNAL_handler_uninstall (sh->shc_pipe);
2302 GNUNET_SIGNAL_handler_uninstall (sh->shc_quit);
2303 GNUNET_SIGNAL_handler_uninstall (sh->shc_hup);
2304 GNUNET_DISK_pipe_close (shutdown_pipe_handle);
2305 shutdown_pipe_handle = NULL;
2306 scheduler_driver = NULL;
2307 GNUNET_free (sh);
2308}
2309
2310
2311static int
2312select_loop (struct GNUNET_SCHEDULER_Handle *sh,
2313 struct DriverContext *context)
2314{
2315 struct GNUNET_NETWORK_FDSet *rs;
2316 struct GNUNET_NETWORK_FDSet *ws;
2317 int select_result;
2318
2319 GNUNET_assert (NULL != context);
2320 rs = GNUNET_NETWORK_fdset_create ();
2321 ws = GNUNET_NETWORK_fdset_create ();
2322 while ((NULL != context->scheduled_head) ||
2323 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
2324 context->timeout.abs_value_us))
2325 {
2326 struct GNUNET_TIME_Relative time_remaining;
2327
2328 LOG (GNUNET_ERROR_TYPE_DEBUG,
2329 "select timeout = %s\n",
2330 GNUNET_STRINGS_absolute_time_to_string (context->timeout));
2331
2332 GNUNET_NETWORK_fdset_zero (rs);
2333 GNUNET_NETWORK_fdset_zero (ws);
2334
2335 for (struct Scheduled *pos = context->scheduled_head;
2336 NULL != pos;
2337 pos = pos->next)
2338 {
2339 if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et))
2340 {
2341 GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock);
2342 }
2343 if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et))
2344 {
2345 GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock);
2346 }
2347 }
2348 time_remaining = GNUNET_TIME_absolute_get_remaining (context->timeout);
2349 if (0 < ready_count)
2350 time_remaining = GNUNET_TIME_UNIT_ZERO;
2351 if (NULL == scheduler_select)
2352 {
2353 select_result = GNUNET_NETWORK_socket_select (rs,
2354 ws,
2355 NULL,
2356 time_remaining);
2357 }
2358 else
2359 {
2360 select_result = scheduler_select (scheduler_select_cls,
2361 rs,
2362 ws,
2363 NULL,
2364 time_remaining);
2365 }
2366 if (select_result == GNUNET_SYSERR)
2367 {
2368 if (errno == EINTR)
2369 continue;
2370
2371 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
2372 "select");
2373#if USE_LSOF
2374 char lsof[512];
2375
2376 snprintf (lsof,
2377 sizeof(lsof),
2378 "lsof -p %d",
2379 getpid ());
2380 (void) close (1);
2381 (void) dup2 (2, 1);
2382 if (0 != system (lsof))
2383 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
2384 "system");
2385#endif
2386#if DEBUG_FDS
2387 for (struct Scheduled *s = context->scheduled_head;
2388 NULL != s;
2389 s = s->next)
2390 {
2391 int flags = fcntl (s->fdi->sock,
2392 F_GETFD);
2393
2394 if ((flags == -1) &&
2395 (EBADF == errno))
2396 {
2397 LOG (GNUNET_ERROR_TYPE_ERROR,
2398 "Got invalid file descriptor %d!\n",
2399 s->fdi->sock);
2400#if EXECINFO
2401 dump_backtrace (s->task);
2402#endif
2403 }
2404 }
2405#endif
2406 GNUNET_assert (0);
2407 GNUNET_NETWORK_fdset_destroy (rs);
2408 GNUNET_NETWORK_fdset_destroy (ws);
2409 return GNUNET_SYSERR;
2410 }
2411 if (select_result > 0)
2412 {
2413 for (struct Scheduled *pos = context->scheduled_head;
2414 NULL != pos;
2415 pos = pos->next)
2416 {
2417 int is_ready = GNUNET_NO;
2418
2419 if ((0 != (GNUNET_SCHEDULER_ET_IN & pos->et)) &&
2420 (GNUNET_YES ==
2421 GNUNET_NETWORK_fdset_test_native (rs,
2422 pos->fdi->sock)) )
2423 {
2424 pos->fdi->et |= GNUNET_SCHEDULER_ET_IN;
2425 is_ready = GNUNET_YES;
2426 }
2427 if ((0 != (GNUNET_SCHEDULER_ET_OUT & pos->et)) &&
2428 (GNUNET_YES ==
2429 GNUNET_NETWORK_fdset_test_native (ws,
2430 pos->fdi->sock)) )
2431 {
2432 pos->fdi->et |= GNUNET_SCHEDULER_ET_OUT;
2433 is_ready = GNUNET_YES;
2434 }
2435 if (GNUNET_YES == is_ready)
2436 {
2437 GNUNET_SCHEDULER_task_ready (pos->task,
2438 pos->fdi);
2439 }
2440 }
2441 }
2442 if (GNUNET_YES == GNUNET_SCHEDULER_do_work (sh))
2443 {
2444 LOG (GNUNET_ERROR_TYPE_DEBUG,
2445 "scheduler has more tasks ready!\n");
2446 }
2447 }
2448 GNUNET_NETWORK_fdset_destroy (rs);
2449 GNUNET_NETWORK_fdset_destroy (ws);
2450 return GNUNET_OK;
2451}
2452
2453
2454static int
2455select_add (void *cls,
2456 struct GNUNET_SCHEDULER_Task *task,
2457 struct GNUNET_SCHEDULER_FdInfo *fdi)
2458{
2459 struct DriverContext *context = cls;
2460
2461 GNUNET_assert (NULL != context);
2462 GNUNET_assert (NULL != task);
2463 GNUNET_assert (NULL != fdi);
2464 GNUNET_assert (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et) ||
2465 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et));
2466
2467 if (! ((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0))
2468 {
2469 /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */
2470 return GNUNET_SYSERR;
2471 }
2472
2473 struct Scheduled *scheduled = GNUNET_new (struct Scheduled);
2474 scheduled->task = task;
2475 scheduled->fdi = fdi;
2476 scheduled->et = fdi->et;
2477
2478 GNUNET_CONTAINER_DLL_insert (context->scheduled_head,
2479 context->scheduled_tail,
2480 scheduled);
2481 return GNUNET_OK;
2482}
2483
2484
2485static int
2486select_del (void *cls,
2487 struct GNUNET_SCHEDULER_Task *task)
2488{
2489 struct DriverContext *context;
2490 struct Scheduled *pos;
2491 int ret;
2492
2493 GNUNET_assert (NULL != cls);
2494
2495 context = cls;
2496 ret = GNUNET_SYSERR;
2497 pos = context->scheduled_head;
2498 while (NULL != pos)
2499 {
2500 struct Scheduled *next = pos->next;
2501 if (pos->task == task)
2502 {
2503 GNUNET_CONTAINER_DLL_remove (context->scheduled_head,
2504 context->scheduled_tail,
2505 pos);
2506 GNUNET_free (pos);
2507 ret = GNUNET_OK;
2508 }
2509 pos = next;
2510 }
2511 return ret;
2512}
2513
2514
2515static void
2516select_set_wakeup (void *cls,
2517 struct GNUNET_TIME_Absolute dt)
2518{
2519 struct DriverContext *context = cls;
2520
2521 GNUNET_assert (NULL != context);
2522 context->timeout = dt;
2523}
2524
2525
2526/**
2527 * Obtain the driver for using select() as the event loop.
2528 *
2529 * @return NULL on error
2530 */
2531struct GNUNET_SCHEDULER_Driver *
2532GNUNET_SCHEDULER_driver_select ()
2533{
2534 struct GNUNET_SCHEDULER_Driver *select_driver;
2535
2536 select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver);
2537
2538 select_driver->add = &select_add;
2539 select_driver->del = &select_del;
2540 select_driver->set_wakeup = &select_set_wakeup;
2541
2542 return select_driver;
2543}
2544
2545
2546/**
2547 * Change the async scope for the currently executing task and (transitively)
2548 * for all tasks scheduled by the current task after calling this function.
2549 * Nested tasks can begin their own nested async scope.
2550 *
2551 * Once the current task is finished, the async scope ID is reset to
2552 * its previous value.
2553 *
2554 * Must only be called from a running task.
2555 *
2556 * @param aid the asynchronous scope id to enter
2557 */
2558void
2559GNUNET_SCHEDULER_begin_async_scope (struct GNUNET_AsyncScopeId *aid)
2560{
2561 struct GNUNET_AsyncScopeSave dummy_old_scope;
2562
2563 GNUNET_assert (NULL != active_task);
2564 /* Since we're in a task, the context will be automatically
2565 restored by the scheduler. */
2566 GNUNET_async_scope_enter (aid, &dummy_old_scope);
2567}
2568
2569
2570/* end of scheduler.c */
diff --git a/src/util/service.c b/src/util/service.c
deleted file mode 100644
index df4feb0ec..000000000
--- a/src/util/service.c
+++ /dev/null
@@ -1,2444 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 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 util/service.c
23 * @brief functions related to starting services (redesign)
24 * @author Christian Grothoff
25 * @author Florian Dold
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_constants.h"
31#include "gnunet_resolver_service.h"
32#include "speedup.h"
33
34#if HAVE_MALLINFO2
35#include <malloc.h>
36#include "gauger.h"
37#endif
38
39
40#define LOG(kind, ...) GNUNET_log_from (kind, "util-service", __VA_ARGS__)
41
42#define LOG_STRERROR(kind, syscall) \
43 GNUNET_log_from_strerror (kind, "util-service", syscall)
44
45#define LOG_STRERROR_FILE(kind, syscall, filename) \
46 GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)
47
48
49/**
50 * Information the service tracks per listen operation.
51 */
52struct ServiceListenContext
53{
54 /**
55 * Kept in a DLL.
56 */
57 struct ServiceListenContext *next;
58
59 /**
60 * Kept in a DLL.
61 */
62 struct ServiceListenContext *prev;
63
64 /**
65 * Service this listen context belongs to.
66 */
67 struct GNUNET_SERVICE_Handle *sh;
68
69 /**
70 * Socket we are listening on.
71 */
72 struct GNUNET_NETWORK_Handle *listen_socket;
73
74 /**
75 * Task scheduled to do the listening.
76 */
77 struct GNUNET_SCHEDULER_Task *listen_task;
78};
79
80
81/**
82 * Reasons why we might be suspended.
83 */
84enum SuspendReason
85{
86 /**
87 * We are running normally.
88 */
89 SUSPEND_STATE_NONE = 0,
90
91 /**
92 * Application requested it.
93 */
94 SUSPEND_STATE_APP = 1,
95
96 /**
97 * OS ran out of file descriptors.
98 */
99 SUSPEND_STATE_EMFILE = 2,
100
101 /**
102 * Both reasons, APP and EMFILE apply.
103 */
104 SUSPEND_STATE_APP_AND_EMFILE = 3,
105
106 /**
107 * Suspension because service was permanently shutdown.
108 */
109 SUSPEND_STATE_SHUTDOWN = 4
110};
111
112
113/**
114 * Handle to a service.
115 */
116struct GNUNET_SERVICE_Handle
117{
118 /**
119 * Our configuration.
120 */
121 const struct GNUNET_CONFIGURATION_Handle *cfg;
122
123 /**
124 * Name of our service.
125 */
126 const char *service_name;
127
128 /**
129 * Main service-specific task to run.
130 */
131 GNUNET_SERVICE_InitCallback service_init_cb;
132
133 /**
134 * Function to call when clients connect.
135 */
136 GNUNET_SERVICE_ConnectHandler connect_cb;
137
138 /**
139 * Function to call when clients disconnect / are disconnected.
140 */
141 GNUNET_SERVICE_DisconnectHandler disconnect_cb;
142
143 /**
144 * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb.
145 */
146 void *cb_cls;
147
148 /**
149 * DLL of listen sockets used to accept new connections.
150 */
151 struct ServiceListenContext *slc_head;
152
153 /**
154 * DLL of listen sockets used to accept new connections.
155 */
156 struct ServiceListenContext *slc_tail;
157
158 /**
159 * Our clients, kept in a DLL.
160 */
161 struct GNUNET_SERVICE_Client *clients_head;
162
163 /**
164 * Our clients, kept in a DLL.
165 */
166 struct GNUNET_SERVICE_Client *clients_tail;
167
168 /**
169 * Message handlers to use for all clients.
170 */
171 struct GNUNET_MQ_MessageHandler *handlers;
172
173 /**
174 * Closure for @e task.
175 */
176 void *task_cls;
177
178
179 /**
180 * IPv4 addresses that are not allowed to connect.
181 */
182 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
183
184 /**
185 * IPv6 addresses that are not allowed to connect.
186 */
187 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
188
189 /**
190 * IPv4 addresses that are allowed to connect (if not
191 * set, all are allowed).
192 */
193 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
194
195 /**
196 * IPv6 addresses that are allowed to connect (if not
197 * set, all are allowed).
198 */
199 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
200
201 /**
202 * Do we require a matching UID for UNIX domain socket connections?
203 * #GNUNET_NO means that the UID does not have to match (however,
204 * @e match_gid may still impose other access control checks).
205 */
206 int match_uid;
207
208 /**
209 * Do we require a matching GID for UNIX domain socket connections?
210 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
211 * checking that the client's UID is in our group OR that the
212 * client's GID is our GID. If both "match_gid" and @e match_uid are
213 * #GNUNET_NO, all users on the local system have access.
214 */
215 int match_gid;
216
217 /**
218 * Are we suspended, and if so, why?
219 */
220 enum SuspendReason suspend_state;
221
222 /**
223 * Our options.
224 */
225 enum GNUNET_SERVICE_Options options;
226
227 /**
228 * If we are daemonizing, this FD is set to the
229 * pipe to the parent. Send '.' if we started
230 * ok, '!' if not. -1 if we are not daemonizing.
231 */
232 int ready_confirm_fd;
233
234 /**
235 * Overall success/failure of the service start.
236 */
237 int ret;
238
239 /**
240 * If #GNUNET_YES, consider unknown message types an error where the
241 * client is disconnected.
242 */
243 int require_found;
244};
245
246
247/**
248 * Handle to a client that is connected to a service.
249 */
250struct GNUNET_SERVICE_Client
251{
252 /**
253 * Kept in a DLL.
254 */
255 struct GNUNET_SERVICE_Client *next;
256
257 /**
258 * Kept in a DLL.
259 */
260 struct GNUNET_SERVICE_Client *prev;
261
262 /**
263 * Service that this client belongs to.
264 */
265 struct GNUNET_SERVICE_Handle *sh;
266
267 /**
268 * Socket of this client.
269 */
270 struct GNUNET_NETWORK_Handle *sock;
271
272 /**
273 * Message queue for the client.
274 */
275 struct GNUNET_MQ_Handle *mq;
276
277 /**
278 * Tokenizer we use for processing incoming data.
279 */
280 struct GNUNET_MessageStreamTokenizer *mst;
281
282 /**
283 * Task that warns about missing calls to
284 * #GNUNET_SERVICE_client_continue().
285 */
286 struct GNUNET_SCHEDULER_Task *warn_task;
287
288 /**
289 * Task run to finish dropping the client after the stack has
290 * properly unwound.
291 */
292 struct GNUNET_SCHEDULER_Task *drop_task;
293
294 /**
295 * Task that receives data from the client to
296 * pass it to the handlers.
297 */
298 struct GNUNET_SCHEDULER_Task *recv_task;
299
300 /**
301 * Task that transmit data to the client.
302 */
303 struct GNUNET_SCHEDULER_Task *send_task;
304
305 /**
306 * Pointer to the message to be transmitted by @e send_task.
307 */
308 const struct GNUNET_MessageHeader *msg;
309
310 /**
311 * User context value, value returned from
312 * the connect callback.
313 */
314 void *user_context;
315
316 /**
317 * Time when we last gave a message from this client
318 * to the application.
319 */
320 struct GNUNET_TIME_Absolute warn_start;
321
322 /**
323 * Current position in @e msg at which we are transmitting.
324 */
325 size_t msg_pos;
326
327 /**
328 * Persist the file handle for this client no matter what happens,
329 * force the OS to close once the process actually dies. Should only
330 * be used in special cases!
331 */
332 int persist;
333
334 /**
335 * Is this client a 'monitor' client that should not be counted
336 * when deciding on destroying the server during soft shutdown?
337 * (see also #GNUNET_SERVICE_start)
338 */
339 int is_monitor;
340
341 /**
342 * Are we waiting for the application to call #GNUNET_SERVICE_client_continue()?
343 */
344 int needs_continue;
345
346 /**
347 * Type of last message processed (for warn_no_receive_done).
348 */
349 uint16_t warn_type;
350};
351
352
353/**
354 * Check if any of the clients we have left are unrelated to
355 * monitoring.
356 *
357 * @param sh service to check clients for
358 * @return #GNUNET_YES if we have non-monitoring clients left
359 */
360static int
361have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
362{
363 for (struct GNUNET_SERVICE_Client *client = sh->clients_head; NULL != client;
364 client = client->next)
365 {
366 if (client->is_monitor)
367 continue;
368 return GNUNET_YES;
369 }
370 return GNUNET_NO;
371}
372
373
374/**
375 * Suspend accepting connections from the listen socket temporarily.
376 * Resume activity using #do_resume.
377 *
378 * @param sh service to stop accepting connections.
379 * @param sr reason for suspending accepting connections
380 */
381static void
382do_suspend (struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
383{
384 struct ServiceListenContext *slc;
385
386 GNUNET_assert (0 == (sh->suspend_state & sr));
387 sh->suspend_state |= sr;
388 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
389 {
390 if (NULL != slc->listen_task)
391 {
392 GNUNET_SCHEDULER_cancel (slc->listen_task);
393 slc->listen_task = NULL;
394 }
395 }
396}
397
398
399/**
400 * Shutdown task triggered when a service should be terminated.
401 * This considers active clients and the service options to see
402 * how this specific service is to be terminated, and depending
403 * on this proceeds with the shutdown logic.
404 *
405 * @param cls our `struct GNUNET_SERVICE_Handle`
406 */
407static void
408service_shutdown (void *cls)
409{
410 struct GNUNET_SERVICE_Handle *sh = cls;
411
412 switch (sh->options & GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK)
413 {
414 case GNUNET_SERVICE_OPTION_NONE:
415 GNUNET_SERVICE_shutdown (sh);
416 break;
417 case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN:
418 /* This task should never be run if we are using
419 the manual shutdown. */
420 GNUNET_assert (0);
421 break;
422 case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN:
423 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
424 do_suspend (sh, SUSPEND_STATE_SHUTDOWN);
425 if (GNUNET_NO == have_non_monitor_clients (sh))
426 GNUNET_SERVICE_shutdown (sh);
427 break;
428 }
429}
430
431
432/**
433 * Check if the given IP address is in the list of IP addresses.
434 *
435 * @param list a list of networks
436 * @param add the IP to check (in network byte order)
437 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
438 */
439static int
440check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
441 const struct in_addr *add)
442{
443 unsigned int i;
444
445 if (NULL == list)
446 return GNUNET_NO;
447 i = 0;
448 while ((0 != list[i].network.s_addr) || (0 != list[i].netmask.s_addr))
449 {
450 if ((add->s_addr & list[i].netmask.s_addr) ==
451 (list[i].network.s_addr & list[i].netmask.s_addr))
452 return GNUNET_YES;
453 i++;
454 }
455 return GNUNET_NO;
456}
457
458
459/**
460 * Check if the given IP address is in the list of IP addresses.
461 *
462 * @param list a list of networks
463 * @param ip the IP to check (in network byte order)
464 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
465 */
466static int
467check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
468 const struct in6_addr *ip)
469{
470 unsigned int i;
471
472 if (NULL == list)
473 return GNUNET_NO;
474 i = 0;
475NEXT:
476 while (GNUNET_NO == GNUNET_is_zero (&list[i].network))
477 {
478 for (unsigned int j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++)
479 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
480 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
481 {
482 i++;
483 goto NEXT;
484 }
485 return GNUNET_YES;
486 }
487 return GNUNET_NO;
488}
489
490
491/**
492 * Task run when we are ready to transmit data to the
493 * client.
494 *
495 * @param cls the `struct GNUNET_SERVICE_Client *` to send to
496 */
497static void
498do_send (void *cls)
499{
500 struct GNUNET_SERVICE_Client *client = cls;
501 ssize_t ret;
502 size_t left;
503 const char *buf;
504
505 LOG (GNUNET_ERROR_TYPE_DEBUG,
506 "service: sending message with type %u\n",
507 ntohs (client->msg->type));
508 client->send_task = NULL;
509 buf = (const char *) client->msg;
510 left = ntohs (client->msg->size) - client->msg_pos;
511 ret = GNUNET_NETWORK_socket_send (client->sock,
512 &buf[client->msg_pos],
513 left);
514 GNUNET_assert (ret <= (ssize_t) left);
515 if (0 == ret)
516 {
517 LOG (GNUNET_ERROR_TYPE_DEBUG, "no data send");
518 GNUNET_MQ_inject_error (client->mq, GNUNET_MQ_ERROR_WRITE);
519 return;
520 }
521 if (-1 == ret)
522 {
523 if ((EAGAIN == errno) || (EINTR == errno))
524 {
525 /* ignore */
526 ret = 0;
527 }
528 else
529 {
530 if (EPIPE != errno)
531 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
532 LOG (GNUNET_ERROR_TYPE_DEBUG,
533 "socket send returned with error code %i",
534 errno);
535 GNUNET_MQ_inject_error (client->mq, GNUNET_MQ_ERROR_WRITE);
536 return;
537 }
538 }
539 if (0 == client->msg_pos)
540 {
541 GNUNET_MQ_impl_send_in_flight (client->mq);
542 }
543 client->msg_pos += ret;
544 if (left > (size_t) ret)
545 {
546 GNUNET_assert (NULL == client->drop_task);
547 client->send_task =
548 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
549 client->sock,
550 &do_send,
551 client);
552 return;
553 }
554 GNUNET_MQ_impl_send_continue (client->mq);
555}
556
557
558/**
559 * Signature of functions implementing the sending functionality of a
560 * message queue.
561 *
562 * @param mq the message queue
563 * @param msg the message to send
564 * @param impl_state our `struct GNUNET_SERVICE_Client *`
565 */
566static void
567service_mq_send (struct GNUNET_MQ_Handle *mq,
568 const struct GNUNET_MessageHeader *msg,
569 void *impl_state)
570{
571 struct GNUNET_SERVICE_Client *client = impl_state;
572
573 (void) mq;
574 if (NULL != client->drop_task)
575 return; /* we're going down right now, do not try to send */
576 GNUNET_assert (NULL == client->send_task);
577 LOG (GNUNET_ERROR_TYPE_DEBUG,
578 "Sending message of type %u and size %u to client\n",
579 ntohs (msg->type),
580 ntohs (msg->size));
581 client->msg = msg;
582 client->msg_pos = 0;
583 client->send_task = GNUNET_SCHEDULER_add_now (&do_send,
584 client);
585}
586
587
588/**
589 * Implementation function that cancels the currently sent message.
590 *
591 * @param mq message queue
592 * @param impl_state state specific to the implementation
593 */
594static void
595service_mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
596{
597 struct GNUNET_SERVICE_Client *client = impl_state;
598
599 (void) mq;
600 GNUNET_assert (0 == client->msg_pos);
601 client->msg = NULL;
602 GNUNET_SCHEDULER_cancel (client->send_task);
603 client->send_task = NULL;
604}
605
606
607/**
608 * Generic error handler, called with the appropriate
609 * error code and the same closure specified at the creation of
610 * the message queue.
611 * Not every message queue implementation supports an error handler.
612 *
613 * @param cls closure with our `struct GNUNET_SERVICE_Client`
614 * @param error error code
615 */
616static void
617service_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
618{
619 struct GNUNET_SERVICE_Client *client = cls;
620 struct GNUNET_SERVICE_Handle *sh = client->sh;
621
622 if ((GNUNET_MQ_ERROR_NO_MATCH == error) && (GNUNET_NO == sh->require_found))
623 {
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "No handler for message of type %u found\n",
626 (unsigned int) client->warn_type);
627 GNUNET_SERVICE_client_continue (client);
628 return; /* ignore error */
629 }
630 GNUNET_SERVICE_client_drop (client);
631}
632
633
634/**
635 * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue().
636 *
637 * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from
638 */
639static void
640warn_no_client_continue (void *cls)
641{
642 struct GNUNET_SERVICE_Client *client = cls;
643
644 GNUNET_break (
645 0 !=
646 client->warn_type); /* type should never be 0 here, as we don't use 0 */
647 client->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
648 &warn_no_client_continue,
649 client);
650 LOG (
651 GNUNET_ERROR_TYPE_WARNING,
652 _ (
653 "Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"),
654 (unsigned int) client->warn_type,
655 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (
656 client->warn_start),
657 GNUNET_YES));
658}
659
660
661/**
662 * Functions with this signature are called whenever a
663 * complete message is received by the tokenizer for a client.
664 *
665 * Do not call #GNUNET_MST_destroy() from within
666 * the scope of this callback.
667 *
668 * @param cls closure with the `struct GNUNET_SERVICE_Client *`
669 * @param message the actual message
670 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped
671 */
672static int
673service_client_mst_cb (void *cls, const struct GNUNET_MessageHeader *message)
674{
675 struct GNUNET_SERVICE_Client *client = cls;
676
677 LOG (GNUNET_ERROR_TYPE_DEBUG,
678 "Received message of type %u and size %u from client\n",
679 ntohs (message->type),
680 ntohs (message->size));
681 GNUNET_assert (GNUNET_NO == client->needs_continue);
682 client->needs_continue = GNUNET_YES;
683 client->warn_type = ntohs (message->type);
684 client->warn_start = GNUNET_TIME_absolute_get ();
685 GNUNET_assert (NULL == client->warn_task);
686 client->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
687 &warn_no_client_continue,
688 client);
689 GNUNET_MQ_inject_message (client->mq, message);
690 if (NULL != client->drop_task)
691 return GNUNET_SYSERR;
692 return GNUNET_OK;
693}
694
695
696/**
697 * A client sent us data. Receive and process it. If we are done,
698 * reschedule this task.
699 *
700 * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
701 */
702static void
703service_client_recv (void *cls)
704{
705 struct GNUNET_SERVICE_Client *client = cls;
706 int ret;
707
708 client->recv_task = NULL;
709 ret = GNUNET_MST_read (client->mst, client->sock, GNUNET_NO, GNUNET_YES);
710 if (GNUNET_SYSERR == ret)
711 {
712 /* client closed connection (or IO error) */
713 if (NULL == client->drop_task)
714 {
715 GNUNET_assert (GNUNET_NO == client->needs_continue);
716 GNUNET_SERVICE_client_drop (client);
717 }
718 return;
719 }
720 if (GNUNET_NO == ret)
721 return; /* more messages in buffer, wait for application
722 to be done processing */
723 GNUNET_assert (GNUNET_OK == ret);
724 if (GNUNET_YES == client->needs_continue)
725 return;
726 if (NULL != client->recv_task)
727 return;
728 /* MST needs more data, re-schedule read job */
729 client->recv_task =
730 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
731 client->sock,
732 &service_client_recv,
733 client);
734}
735
736
737/**
738 * We have successfully accepted a connection from a client. Now
739 * setup the client (with the scheduler) and tell the application.
740 *
741 * @param sh service that accepted the client
742 * @param sock socket associated with the client
743 */
744static void
745start_client (struct GNUNET_SERVICE_Handle *sh,
746 struct GNUNET_NETWORK_Handle *csock)
747{
748 struct GNUNET_SERVICE_Client *client;
749
750 client = GNUNET_new (struct GNUNET_SERVICE_Client);
751 GNUNET_CONTAINER_DLL_insert (sh->clients_head, sh->clients_tail, client);
752 client->sh = sh;
753 client->sock = csock;
754 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
755 NULL,
756 &service_mq_cancel,
757 client,
758 sh->handlers,
759 &service_mq_error_handler,
760 client);
761 client->mst = GNUNET_MST_create (&service_client_mst_cb, client);
762 if (NULL != sh->connect_cb)
763 client->user_context = sh->connect_cb (sh->cb_cls, client, client->mq);
764 GNUNET_MQ_set_handlers_closure (client->mq, client->user_context);
765 client->recv_task =
766 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
767 client->sock,
768 &service_client_recv,
769 client);
770}
771
772
773/**
774 * We have a client. Accept the incoming socket(s) (and reschedule
775 * the listen task).
776 *
777 * @param cls the `struct ServiceListenContext` of the ready listen socket
778 */
779static void
780accept_client (void *cls)
781{
782 struct ServiceListenContext *slc = cls;
783 struct GNUNET_SERVICE_Handle *sh = slc->sh;
784
785 slc->listen_task = NULL;
786 while (1)
787 {
788 struct GNUNET_NETWORK_Handle *sock;
789 const struct sockaddr_in *v4;
790 const struct sockaddr_in6 *v6;
791 struct sockaddr_storage sa;
792 socklen_t addrlen;
793 int ok;
794
795 addrlen = sizeof(sa);
796 sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
797 (struct sockaddr *) &sa,
798 &addrlen);
799 if (NULL == sock)
800 {
801 if (EMFILE == errno)
802 do_suspend (sh, SUSPEND_STATE_EMFILE);
803 else if (EAGAIN != errno)
804 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
805 break;
806 }
807 switch (sa.ss_family)
808 {
809 case AF_INET:
810 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
811 v4 = (const struct sockaddr_in *) &sa;
812 ok = (((NULL == sh->v4_allowed) ||
813 (check_ipv4_listed (sh->v4_allowed, &v4->sin_addr))) &&
814 ((NULL == sh->v4_denied) ||
815 (! check_ipv4_listed (sh->v4_denied, &v4->sin_addr))));
816 break;
817
818 case AF_INET6:
819 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
820 v6 = (const struct sockaddr_in6 *) &sa;
821 ok = (((NULL == sh->v6_allowed) ||
822 (check_ipv6_listed (sh->v6_allowed, &v6->sin6_addr))) &&
823 ((NULL == sh->v6_denied) ||
824 (! check_ipv6_listed (sh->v6_denied, &v6->sin6_addr))));
825 break;
826
827 case AF_UNIX:
828 ok = GNUNET_OK; /* controlled using file-system ACL now */
829 break;
830
831 default:
832 LOG (GNUNET_ERROR_TYPE_WARNING,
833 _ ("Unknown address family %d\n"),
834 sa.ss_family);
835 return;
836 }
837 if (! ok)
838 {
839 LOG (GNUNET_ERROR_TYPE_DEBUG,
840 "Service rejected incoming connection from %s due to policy.\n",
841 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
842 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
843 continue;
844 }
845 LOG (GNUNET_ERROR_TYPE_DEBUG,
846 "Service accepted incoming connection from %s.\n",
847 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
848 start_client (slc->sh, sock);
849 }
850 if (0 != sh->suspend_state)
851 return;
852 slc->listen_task =
853 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
854 slc->listen_socket,
855 &accept_client,
856 slc);
857}
858
859
860/**
861 * Resume accepting connections from the listen socket.
862 *
863 * @param sh service to resume accepting connections.
864 * @param sr reason that is no longer causing the suspension,
865 * or #SUSPEND_STATE_NONE on first startup
866 */
867static void
868do_resume (struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
869{
870 struct ServiceListenContext *slc;
871
872 GNUNET_assert ((SUSPEND_STATE_NONE == sr) || (0 != (sh->suspend_state & sr)));
873 sh->suspend_state -= sr;
874 if (SUSPEND_STATE_NONE != sh->suspend_state)
875 return;
876 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
877 {
878 GNUNET_assert (NULL == slc->listen_task);
879 slc->listen_task =
880 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
881 slc->listen_socket,
882 &accept_client,
883 slc);
884 }
885}
886
887
888/**
889 * First task run by any service. Initializes our shutdown task,
890 * starts the listening operation on our listen sockets and launches
891 * the custom logic of the application service.
892 *
893 * @param cls our `struct GNUNET_SERVICE_Handle`
894 */
895static void
896service_main (void *cls)
897{
898 struct GNUNET_SERVICE_Handle *sh = cls;
899
900 if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN !=
901 (sh->options & GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK))
902 GNUNET_SCHEDULER_add_shutdown (&service_shutdown, sh);
903 do_resume (sh, SUSPEND_STATE_NONE);
904
905 if (-1 != sh->ready_confirm_fd)
906 {
907 GNUNET_break (1 == write (sh->ready_confirm_fd, ".", 1));
908 GNUNET_break (0 == close (sh->ready_confirm_fd));
909 sh->ready_confirm_fd = -1;
910 }
911
912 if (NULL != sh->service_init_cb)
913 sh->service_init_cb (sh->cb_cls, sh->cfg, sh);
914}
915
916
917/**
918 * Parse an IPv4 access control list.
919 *
920 * @param ret location where to write the ACL (set)
921 * @param sh service context to use to get the configuration
922 * @param option name of the ACL option to parse
923 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
924 * no ACL configured)
925 */
926static int
927process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
928 struct GNUNET_SERVICE_Handle *sh,
929 const char *option)
930{
931 char *opt;
932
933 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
934 {
935 *ret = NULL;
936 return GNUNET_OK;
937 }
938 GNUNET_break (GNUNET_OK ==
939 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
940 sh->service_name,
941 option,
942 &opt));
943 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
944 {
945 LOG (GNUNET_ERROR_TYPE_WARNING,
946 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
947 opt,
948 sh->service_name,
949 option);
950 GNUNET_free (opt);
951 return GNUNET_SYSERR;
952 }
953 GNUNET_free (opt);
954 return GNUNET_OK;
955}
956
957
958/**
959 * Parse an IPv6 access control list.
960 *
961 * @param ret location where to write the ACL (set)
962 * @param sh service context to use to get the configuration
963 * @param option name of the ACL option to parse
964 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
965 * no ACL configured)
966 */
967static int
968process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
969 struct GNUNET_SERVICE_Handle *sh,
970 const char *option)
971{
972 char *opt;
973
974 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
975 {
976 *ret = NULL;
977 return GNUNET_OK;
978 }
979 GNUNET_break (GNUNET_OK ==
980 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
981 sh->service_name,
982 option,
983 &opt));
984 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
985 {
986 LOG (GNUNET_ERROR_TYPE_WARNING,
987 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
988 opt,
989 sh->service_name,
990 option);
991 GNUNET_free (opt);
992 return GNUNET_SYSERR;
993 }
994 GNUNET_free (opt);
995 return GNUNET_OK;
996}
997
998
999/**
1000 * Add the given UNIX domain path as an address to the
1001 * list (as the first entry).
1002 *
1003 * @param saddrs array to update
1004 * @param saddrlens where to store the address length
1005 * @param unixpath path to add
1006 */
1007static void
1008add_unixpath (struct sockaddr **saddrs,
1009 socklen_t *saddrlens,
1010 const char *unixpath)
1011{
1012#ifdef AF_UNIX
1013 struct sockaddr_un *un;
1014
1015 un = GNUNET_new (struct sockaddr_un);
1016 un->sun_family = AF_UNIX;
1017 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
1018#if HAVE_SOCKADDR_UN_SUN_LEN
1019 un->sun_len = (u_char) sizeof(struct sockaddr_un);
1020#endif
1021 *saddrs = (struct sockaddr *) un;
1022 *saddrlens = sizeof(struct sockaddr_un);
1023#else
1024 /* this function should never be called
1025 * unless AF_UNIX is defined! */
1026 GNUNET_assert (0);
1027#endif
1028}
1029
1030
1031/**
1032 * Get the list of addresses that a server for the given service
1033 * should bind to.
1034 *
1035 * @param service_name name of the service
1036 * @param cfg configuration (which specifies the addresses)
1037 * @param addrs set (call by reference) to an array of pointers to the
1038 * addresses the server should bind to and listen on; the
1039 * array will be NULL-terminated (on success)
1040 * @param addr_lens set (call by reference) to an array of the lengths
1041 * of the respective `struct sockaddr` struct in the @a addrs
1042 * array (on success)
1043 * @return number of addresses found on success,
1044 * #GNUNET_SYSERR if the configuration
1045 * did not specify reasonable finding information or
1046 * if it specified a hostname that could not be resolved;
1047 * #GNUNET_NO if the number of addresses configured is
1048 * zero (in this case, `*addrs` and `*addr_lens` will be
1049 * set to NULL).
1050 */
1051static int
1052get_server_addresses (const char *service_name,
1053 const struct GNUNET_CONFIGURATION_Handle *cfg,
1054 struct sockaddr ***addrs,
1055 socklen_t **addr_lens)
1056{
1057 int disablev6;
1058 struct GNUNET_NETWORK_Handle *desc;
1059 unsigned long long port;
1060 char *unixpath;
1061 struct addrinfo hints;
1062 struct addrinfo *res;
1063 struct addrinfo *pos;
1064 struct addrinfo *next;
1065 unsigned int i;
1066 int resi;
1067 int ret;
1068 struct sockaddr **saddrs;
1069 socklen_t *saddrlens;
1070 char *hostname;
1071
1072 *addrs = NULL;
1073 *addr_lens = NULL;
1074 desc = NULL;
1075 disablev6 = GNUNET_NO;
1076 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
1077 (GNUNET_YES ==
1078 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1079 disablev6 = GNUNET_YES;
1080
1081 port = 0;
1082 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1083 {
1084 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1085 service_name,
1086 "PORT",
1087 &port))
1088 {
1089 LOG (GNUNET_ERROR_TYPE_ERROR,
1090 _ ("Require valid port number for service `%s' in configuration!\n"),
1091 service_name);
1092 }
1093 if (port > 65535)
1094 {
1095 LOG (GNUNET_ERROR_TYPE_ERROR,
1096 _ ("Require valid port number for service `%s' in configuration!\n"),
1097 service_name);
1098 return GNUNET_SYSERR;
1099 }
1100 }
1101
1102 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1103 {
1104 GNUNET_break (GNUNET_OK ==
1105 GNUNET_CONFIGURATION_get_value_string (cfg,
1106 service_name,
1107 "BINDTO",
1108 &hostname));
1109 }
1110 else
1111 hostname = NULL;
1112
1113 unixpath = NULL;
1114#ifdef AF_UNIX
1115 if ((GNUNET_YES ==
1116 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1117 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1118 service_name,
1119 "UNIXPATH",
1120 &unixpath)) &&
1121 (0 < strlen (unixpath)))
1122 {
1123 /* probe UNIX support */
1124 struct sockaddr_un s_un;
1125
1126 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1127 {
1128 LOG (GNUNET_ERROR_TYPE_WARNING,
1129 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1130 unixpath,
1131 (unsigned long long) sizeof(s_un.sun_path));
1132 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1133 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1134 }
1135 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath))
1136 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1137 }
1138 if (NULL != unixpath)
1139 {
1140 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1141 if (NULL == desc)
1142 {
1143 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1144 (EACCES == errno))
1145 {
1146 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
1147 GNUNET_free (hostname);
1148 GNUNET_free (unixpath);
1149 return GNUNET_SYSERR;
1150 }
1151 LOG (GNUNET_ERROR_TYPE_INFO,
1152 _ (
1153 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1154 service_name,
1155 strerror (errno));
1156 GNUNET_free (unixpath);
1157 unixpath = NULL;
1158 }
1159 else
1160 {
1161 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1162 desc = NULL;
1163 }
1164 }
1165#endif
1166
1167 if ((0 == port) && (NULL == unixpath))
1168 {
1169 LOG (GNUNET_ERROR_TYPE_ERROR,
1170 _ (
1171 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1172 service_name);
1173 GNUNET_free (hostname);
1174 return GNUNET_SYSERR;
1175 }
1176 if (0 == port)
1177 {
1178 saddrs = GNUNET_new_array (2, struct sockaddr *);
1179 saddrlens = GNUNET_new_array (2, socklen_t);
1180 add_unixpath (saddrs, saddrlens, unixpath);
1181 GNUNET_free (unixpath);
1182 GNUNET_free (hostname);
1183 *addrs = saddrs;
1184 *addr_lens = saddrlens;
1185 return 1;
1186 }
1187
1188 if (NULL != hostname)
1189 {
1190 LOG (GNUNET_ERROR_TYPE_DEBUG,
1191 "Resolving `%s' since that is where `%s' will bind to.\n",
1192 hostname,
1193 service_name);
1194 memset (&hints, 0, sizeof(struct addrinfo));
1195 if (disablev6)
1196 hints.ai_family = AF_INET;
1197 hints.ai_protocol = IPPROTO_TCP;
1198 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1199 (NULL == res))
1200 {
1201 LOG (GNUNET_ERROR_TYPE_ERROR,
1202 _ ("Failed to resolve `%s': %s\n"),
1203 hostname,
1204 gai_strerror (ret));
1205 GNUNET_free (hostname);
1206 GNUNET_free (unixpath);
1207 return GNUNET_SYSERR;
1208 }
1209 next = res;
1210 i = 0;
1211 while (NULL != (pos = next))
1212 {
1213 next = pos->ai_next;
1214 if ((disablev6) && (pos->ai_family == AF_INET6))
1215 continue;
1216 i++;
1217 }
1218 if (0 == i)
1219 {
1220 LOG (GNUNET_ERROR_TYPE_ERROR,
1221 _ ("Failed to find %saddress for `%s'.\n"),
1222 disablev6 ? "IPv4 " : "",
1223 hostname);
1224 freeaddrinfo (res);
1225 GNUNET_free (hostname);
1226 GNUNET_free (unixpath);
1227 return GNUNET_SYSERR;
1228 }
1229 resi = i;
1230 if (NULL != unixpath)
1231 resi++;
1232 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1233 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1234 i = 0;
1235 if (NULL != unixpath)
1236 {
1237 add_unixpath (saddrs, saddrlens, unixpath);
1238 i++;
1239 }
1240 next = res;
1241 while (NULL != (pos = next))
1242 {
1243 next = pos->ai_next;
1244 if ((disablev6) && (AF_INET6 == pos->ai_family))
1245 continue;
1246 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1247 continue; /* not TCP */
1248 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1249 continue; /* huh? */
1250 LOG (GNUNET_ERROR_TYPE_DEBUG,
1251 "Service `%s' will bind to `%s'\n",
1252 service_name,
1253 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1254 if (AF_INET == pos->ai_family)
1255 {
1256 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1257 saddrlens[i] = pos->ai_addrlen;
1258 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1259 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1260 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1261 }
1262 else
1263 {
1264 GNUNET_assert (AF_INET6 == pos->ai_family);
1265 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1266 saddrlens[i] = pos->ai_addrlen;
1267 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1268 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1269 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1270 }
1271 i++;
1272 }
1273 GNUNET_free (hostname);
1274 freeaddrinfo (res);
1275 resi = i;
1276 }
1277 else
1278 {
1279 /* will bind against everything, just set port */
1280 if (disablev6)
1281 {
1282 /* V4-only */
1283 resi = 1;
1284 if (NULL != unixpath)
1285 resi++;
1286 i = 0;
1287 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1288 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1289 if (NULL != unixpath)
1290 {
1291 add_unixpath (saddrs, saddrlens, unixpath);
1292 i++;
1293 }
1294 saddrlens[i] = sizeof(struct sockaddr_in);
1295 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1296#if HAVE_SOCKADDR_IN_SIN_LEN
1297 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1298#endif
1299 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1300 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1301 }
1302 else
1303 {
1304 /* dual stack */
1305 resi = 2;
1306 if (NULL != unixpath)
1307 resi++;
1308 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1309 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1310 i = 0;
1311 if (NULL != unixpath)
1312 {
1313 add_unixpath (saddrs, saddrlens, unixpath);
1314 i++;
1315 }
1316 saddrlens[i] = sizeof(struct sockaddr_in6);
1317 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1318#if HAVE_SOCKADDR_IN_SIN_LEN
1319 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1320#endif
1321 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1322 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1323 i++;
1324 saddrlens[i] = sizeof(struct sockaddr_in);
1325 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1326#if HAVE_SOCKADDR_IN_SIN_LEN
1327 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1328#endif
1329 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1330 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1331 }
1332 }
1333 GNUNET_free (unixpath);
1334 *addrs = saddrs;
1335 *addr_lens = saddrlens;
1336 return resi;
1337}
1338
1339
1340/**
1341 * Create and initialize a listen socket for the server.
1342 *
1343 * @param server_addr address to listen on
1344 * @param socklen length of @a server_addr
1345 * @return NULL on error, otherwise the listen socket
1346 */
1347static struct GNUNET_NETWORK_Handle *
1348open_listen_socket (const struct sockaddr *server_addr,
1349 socklen_t socklen)
1350{
1351 struct GNUNET_NETWORK_Handle *sock;
1352 uint16_t port;
1353 int eno;
1354
1355 switch (server_addr->sa_family)
1356 {
1357 case AF_INET:
1358 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
1359 break;
1360 case AF_INET6:
1361 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
1362 break;
1363 case AF_UNIX:
1364 port = 0;
1365 break;
1366 default:
1367 GNUNET_break (0);
1368 port = 0;
1369 break;
1370 }
1371 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
1372 SOCK_STREAM,
1373 0);
1374 if (NULL == sock)
1375 {
1376 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1377 "socket");
1378 errno = 0;
1379 return NULL;
1380 }
1381 /* bind the socket */
1382 if (GNUNET_OK !=
1383 GNUNET_NETWORK_socket_bind (sock,
1384 server_addr,
1385 socklen))
1386 {
1387 eno = errno;
1388 if (EADDRINUSE != errno)
1389 {
1390 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
1391 * fail if we already took the port on IPv6; if both IPv4 and
1392 * IPv6 binds fail, then our caller will log using the
1393 * errno preserved in 'eno' */
1394 if (0 != port)
1395 LOG (GNUNET_ERROR_TYPE_ERROR,
1396 _ ("`%s' failed for port %d (%s).\n"),
1397 "bind",
1398 port,
1399 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1400 else
1401 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
1402 eno = 0;
1403 }
1404 else
1405 {
1406 if (0 != port)
1407 LOG (GNUNET_ERROR_TYPE_WARNING,
1408 _ ("`%s' failed for port %d (%s): address already in use\n"),
1409 "bind",
1410 port,
1411 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1412 else if (AF_UNIX == server_addr->sa_family)
1413 {
1414 LOG (GNUNET_ERROR_TYPE_WARNING,
1415 _ ("`%s' failed for `%s': address already in use\n"),
1416 "bind",
1417 GNUNET_a2s (server_addr, socklen));
1418 }
1419 }
1420 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1421 errno = eno;
1422 return NULL;
1423 }
1424 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1425 {
1426 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "listen");
1427 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1428 errno = 0;
1429 return NULL;
1430 }
1431 if (0 != port)
1432 LOG (GNUNET_ERROR_TYPE_DEBUG,
1433 "Server starts to listen on port %u.\n",
1434 port);
1435 return sock;
1436}
1437
1438
1439/**
1440 * Setup service handle
1441 *
1442 * Configuration may specify:
1443 * - PORT (where to bind to for TCP)
1444 * - UNIXPATH (where to bind to for UNIX domain sockets)
1445 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
1446 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
1447 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
1448 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
1449 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
1450 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
1451 *
1452 * @param sh service context to initialize
1453 * @return #GNUNET_OK if configuration succeeded
1454 */
1455static int
1456setup_service (struct GNUNET_SERVICE_Handle *sh)
1457{
1458 int tolerant;
1459 struct GNUNET_NETWORK_Handle **csocks = NULL;
1460 struct GNUNET_NETWORK_Handle **lsocks;
1461 const char *nfds;
1462 unsigned int cnt;
1463 int flags;
1464 char dummy[2];
1465
1466 if (GNUNET_CONFIGURATION_have_value (sh->cfg,
1467 sh->service_name,
1468 "TOLERANT"))
1469 {
1470 if (GNUNET_SYSERR ==
1471 (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1472 sh->service_name,
1473 "TOLERANT")))
1474 {
1475 LOG (GNUNET_ERROR_TYPE_ERROR,
1476 _ ("Specified value for `%s' of service `%s' is invalid\n"),
1477 "TOLERANT",
1478 sh->service_name);
1479 return GNUNET_SYSERR;
1480 }
1481 }
1482 else
1483 tolerant = GNUNET_NO;
1484
1485 lsocks = NULL;
1486 errno = 0;
1487 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1488 (1 == sscanf (nfds, "%u%1s", &cnt, dummy)) && (cnt > 0) &&
1489 (cnt < FD_SETSIZE) && (cnt + 4 < FD_SETSIZE))
1490 {
1491 lsocks = GNUNET_new_array (cnt + 1, struct GNUNET_NETWORK_Handle *);
1492 while (0 < cnt--)
1493 {
1494 flags = fcntl (3 + cnt, F_GETFD);
1495 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
1496 (NULL == (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1497 {
1498 LOG (GNUNET_ERROR_TYPE_ERROR,
1499 _ (
1500 "Could not access pre-bound socket %u, will try to bind myself\n"),
1501 (unsigned int) 3 + cnt);
1502 cnt++;
1503 while (NULL != lsocks[cnt])
1504 GNUNET_break (GNUNET_OK ==
1505 GNUNET_NETWORK_socket_close (lsocks[cnt++]));
1506 GNUNET_free (lsocks);
1507 lsocks = NULL;
1508 break;
1509 }
1510 }
1511 unsetenv ("LISTEN_FDS");
1512 }
1513 if ( (0 != (GNUNET_SERVICE_OPTION_CLOSE_LSOCKS & sh->options)) &&
1514 (NULL != lsocks) )
1515 {
1516 csocks = lsocks;
1517 lsocks = NULL;
1518 }
1519
1520 if (NULL != lsocks)
1521 {
1522 /* listen only on inherited sockets if we have any */
1523 for (struct GNUNET_NETWORK_Handle **ls = lsocks; NULL != *ls; ls++)
1524 {
1525 struct ServiceListenContext *slc;
1526
1527 slc = GNUNET_new (struct ServiceListenContext);
1528 slc->sh = sh;
1529 slc->listen_socket = *ls;
1530 GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1531 }
1532 GNUNET_free (lsocks);
1533 }
1534 else
1535 {
1536 struct sockaddr **addrs;
1537 socklen_t *addrlens;
1538 int num;
1539
1540 num = get_server_addresses (sh->service_name, sh->cfg, &addrs, &addrlens);
1541 if (GNUNET_SYSERR == num)
1542 return GNUNET_SYSERR;
1543
1544 for (int i = 0; i < num; i++)
1545 {
1546 struct ServiceListenContext *slc;
1547
1548 slc = GNUNET_new (struct ServiceListenContext);
1549 slc->sh = sh;
1550 slc->listen_socket = open_listen_socket (addrs[i], addrlens[i]);
1551 GNUNET_free (addrs[i]);
1552 if (NULL == slc->listen_socket)
1553 {
1554 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1555 GNUNET_free (slc);
1556 continue;
1557 }
1558 GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1559 }
1560 GNUNET_free (addrlens);
1561 GNUNET_free (addrs);
1562 if ((0 != num) && (NULL == sh->slc_head))
1563 {
1564 /* All attempts to bind failed, hard failure */
1565 GNUNET_log (
1566 GNUNET_ERROR_TYPE_ERROR,
1567 _ (
1568 "Could not bind to any of the ports I was supposed to, refusing to run!\n"));
1569 GNUNET_free (csocks);
1570 return GNUNET_SYSERR;
1571 }
1572 }
1573 if (NULL != csocks)
1574 {
1575 /* close inherited sockets to signal parent that we are ready */
1576 for (struct GNUNET_NETWORK_Handle **ls = csocks; NULL != *ls; ls++)
1577 GNUNET_NETWORK_socket_close (*ls);
1578 GNUNET_free (csocks);
1579 }
1580 sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1581 sh->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1582 sh->service_name,
1583 "UNIX_MATCH_UID");
1584 sh->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1585 sh->service_name,
1586 "UNIX_MATCH_GID");
1587 process_acl4 (&sh->v4_denied, sh, "REJECT_FROM");
1588 process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM");
1589 process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6");
1590 process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6");
1591 return GNUNET_OK;
1592}
1593
1594
1595/**
1596 * Get the name of the user that'll be used
1597 * to provide the service.
1598 *
1599 * @param sh service context
1600 * @return value of the 'USERNAME' option
1601 */
1602static char *
1603get_user_name (struct GNUNET_SERVICE_Handle *sh)
1604{
1605 char *un;
1606
1607 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1608 sh->service_name,
1609 "USERNAME",
1610 &un))
1611 return NULL;
1612 return un;
1613}
1614
1615
1616/**
1617 * Set user ID.
1618 *
1619 * @param sh service context
1620 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1621 */
1622static int
1623set_user_id (struct GNUNET_SERVICE_Handle *sh)
1624{
1625 char *user;
1626
1627 if (NULL == (user = get_user_name (sh)))
1628 return GNUNET_OK; /* keep */
1629
1630 struct passwd *pws;
1631
1632 errno = 0;
1633 pws = getpwnam (user);
1634 if (NULL == pws)
1635 {
1636 LOG (GNUNET_ERROR_TYPE_ERROR,
1637 _ ("Cannot obtain information about user `%s': %s\n"),
1638 user,
1639 errno == 0 ? _ ("No such user") : strerror (errno));
1640 GNUNET_free (user);
1641 return GNUNET_SYSERR;
1642 }
1643 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1644#if HAVE_INITGROUPS
1645 (0 != initgroups (user, pws->pw_gid)) ||
1646#endif
1647 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1648 {
1649 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1650 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1651 {
1652 LOG (GNUNET_ERROR_TYPE_ERROR,
1653 _ ("Cannot change user/group to `%s': %s\n"),
1654 user,
1655 strerror (errno));
1656 GNUNET_free (user);
1657 return GNUNET_SYSERR;
1658 }
1659 }
1660
1661 GNUNET_free (user);
1662 return GNUNET_OK;
1663}
1664
1665
1666/**
1667 * Get the name of the file where we will
1668 * write the PID of the service.
1669 *
1670 * @param sh service context
1671 * @return name of the file for the process ID
1672 */
1673static char *
1674get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
1675{
1676 char *pif;
1677
1678 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1679 sh->service_name,
1680 "PIDFILE",
1681 &pif))
1682 return NULL;
1683 return pif;
1684}
1685
1686
1687/**
1688 * Delete the PID file that was created by our parent.
1689 *
1690 * @param sh service context
1691 */
1692static void
1693pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
1694{
1695 char *pif = get_pid_file_name (sh);
1696
1697 if (NULL == pif)
1698 return; /* no PID file */
1699 if (0 != unlink (pif))
1700 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1701 GNUNET_free (pif);
1702}
1703
1704
1705/**
1706 * Detach from terminal.
1707 *
1708 * @param sh service context
1709 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1710 */
1711static int
1712detach_terminal (struct GNUNET_SERVICE_Handle *sh)
1713{
1714 pid_t pid;
1715 int nullfd;
1716 int filedes[2];
1717
1718 if (0 != pipe (filedes))
1719 {
1720 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1721 return GNUNET_SYSERR;
1722 }
1723 pid = fork ();
1724 if (pid < 0)
1725 {
1726 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1727 return GNUNET_SYSERR;
1728 }
1729 if (0 != pid)
1730 {
1731 /* Parent */
1732 char c;
1733
1734 GNUNET_break (0 == close (filedes[1]));
1735 c = 'X';
1736 if (1 != read (filedes[0], &c, sizeof(char)))
1737 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1738 fflush (stdout);
1739 switch (c)
1740 {
1741 case '.':
1742 exit (0);
1743
1744 case 'I':
1745 LOG (GNUNET_ERROR_TYPE_INFO,
1746 _ ("Service process failed to initialize\n"));
1747 break;
1748
1749 case 'S':
1750 LOG (GNUNET_ERROR_TYPE_INFO,
1751 _ ("Service process could not initialize server function\n"));
1752 break;
1753
1754 case 'X':
1755 LOG (GNUNET_ERROR_TYPE_INFO,
1756 _ ("Service process failed to report status\n"));
1757 break;
1758 }
1759 exit (1); /* child reported error */
1760 }
1761 GNUNET_break (0 == close (0));
1762 GNUNET_break (0 == close (1));
1763 GNUNET_break (0 == close (filedes[0]));
1764 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1765 if (nullfd < 0)
1766 return GNUNET_SYSERR;
1767 /* set stdin/stdout to /dev/null */
1768 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1769 {
1770 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1771 (void) close (nullfd);
1772 return GNUNET_SYSERR;
1773 }
1774 (void) close (nullfd);
1775 /* Detach from controlling terminal */
1776 pid = setsid ();
1777 if (-1 == pid)
1778 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1779 sh->ready_confirm_fd = filedes[1];
1780
1781 return GNUNET_OK;
1782}
1783
1784
1785/**
1786 * Tear down the service, closing the listen sockets and
1787 * freeing the ACLs.
1788 *
1789 * @param sh handle to the service to tear down.
1790 */
1791static void
1792teardown_service (struct GNUNET_SERVICE_Handle *sh)
1793{
1794 struct ServiceListenContext *slc;
1795
1796 GNUNET_free (sh->v4_denied);
1797 GNUNET_free (sh->v6_denied);
1798 GNUNET_free (sh->v4_allowed);
1799 GNUNET_free (sh->v6_allowed);
1800 while (NULL != (slc = sh->slc_head))
1801 {
1802 GNUNET_CONTAINER_DLL_remove (sh->slc_head, sh->slc_tail, slc);
1803 if (NULL != slc->listen_task)
1804 GNUNET_SCHEDULER_cancel (slc->listen_task);
1805 GNUNET_break (GNUNET_OK ==
1806 GNUNET_NETWORK_socket_close (slc->listen_socket));
1807 GNUNET_free (slc);
1808 }
1809}
1810
1811
1812/**
1813 * Function to return link to AGPL source upon request.
1814 *
1815 * @param cls closure with the identification of the client
1816 * @param msg AGPL request
1817 */
1818static void
1819return_agpl (void *cls, const struct GNUNET_MessageHeader *msg)
1820{
1821 struct GNUNET_SERVICE_Client *client = cls;
1822 struct GNUNET_MQ_Handle *mq;
1823 struct GNUNET_MQ_Envelope *env;
1824 struct GNUNET_MessageHeader *res;
1825 size_t slen;
1826 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1827
1828 (void) msg;
1829 slen = strlen (pd->agpl_url) + 1;
1830 env = GNUNET_MQ_msg_extra (res, GNUNET_MESSAGE_TYPE_RESPONSE_AGPL, slen);
1831 memcpy (&res[1], GNUNET_AGPL_URL, slen);
1832 mq = GNUNET_SERVICE_client_get_mq (client);
1833 GNUNET_MQ_send (mq, env);
1834 GNUNET_SERVICE_client_continue (client);
1835}
1836
1837
1838/**
1839 * Low-level function to start a service if the scheduler
1840 * is already running. Should only be used directly in
1841 * special cases.
1842 *
1843 * The function will launch the service with the name @a service_name
1844 * using the @a service_options to configure its shutdown
1845 * behavior. When clients connect or disconnect, the respective
1846 * @a connect_cb or @a disconnect_cb functions will be called. For
1847 * messages received from the clients, the respective @a handlers will
1848 * be invoked; for the closure of the handlers we use the return value
1849 * from the @a connect_cb invocation of the respective client.
1850 *
1851 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1852 * message to receive further messages from this client. If
1853 * #GNUNET_SERVICE_client_continue() is not called within a short
1854 * time, a warning will be logged. If delays are expected, services
1855 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1856 * disable the warning.
1857 *
1858 * Clients sending invalid messages (based on @a handlers) will be
1859 * dropped. Additionally, clients can be dropped at any time using
1860 * #GNUNET_SERVICE_client_drop().
1861 *
1862 * The service must be stopped using #GNUNET_SERVICE_stop().
1863 *
1864 * @param service_name name of the service to run
1865 * @param cfg configuration to use
1866 * @param connect_cb function to call whenever a client connects
1867 * @param disconnect_cb function to call whenever a client disconnects
1868 * @param cls closure argument for @a connect_cb and @a disconnect_cb
1869 * @param handlers NULL-terminated array of message handlers for the service,
1870 * the closure will be set to the value returned by
1871 * the @a connect_cb for the respective connection
1872 * @return NULL on error
1873 */
1874struct GNUNET_SERVICE_Handle *
1875GNUNET_SERVICE_start (const char *service_name,
1876 const struct GNUNET_CONFIGURATION_Handle *cfg,
1877 GNUNET_SERVICE_ConnectHandler connect_cb,
1878 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1879 void *cls,
1880 const struct GNUNET_MQ_MessageHandler *handlers)
1881{
1882 struct GNUNET_SERVICE_Handle *sh;
1883
1884 sh = GNUNET_new (struct GNUNET_SERVICE_Handle);
1885 sh->service_name = service_name;
1886 sh->cfg = cfg;
1887 sh->connect_cb = connect_cb;
1888 sh->disconnect_cb = disconnect_cb;
1889 sh->cb_cls = cls;
1890 sh->handlers = GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL);
1891 if (GNUNET_OK != setup_service (sh))
1892 {
1893 GNUNET_free (sh->handlers);
1894 GNUNET_free (sh);
1895 return NULL;
1896 }
1897 do_resume (sh, SUSPEND_STATE_NONE);
1898 return sh;
1899}
1900
1901
1902/**
1903 * Stops a service that was started with #GNUNET_SERVICE_start().
1904 *
1905 * @param srv service to stop
1906 */
1907void
1908GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
1909{
1910 struct GNUNET_SERVICE_Client *client;
1911
1912 GNUNET_SERVICE_suspend (srv);
1913 while (NULL != (client = srv->clients_head))
1914 GNUNET_SERVICE_client_drop (client);
1915 teardown_service (srv);
1916 GNUNET_free (srv->handlers);
1917 GNUNET_free (srv);
1918}
1919
1920
1921/**
1922 * Creates the "main" function for a GNUnet service. You
1923 * should almost always use the #GNUNET_SERVICE_MAIN macro
1924 * instead of calling this function directly (except
1925 * for ARM, which should call this function directly).
1926 *
1927 * The function will launch the service with the name @a service_name
1928 * using the @a service_options to configure its shutdown
1929 * behavior. Once the service is ready, the @a init_cb will be called
1930 * for service-specific initialization. @a init_cb will be given the
1931 * service handler which can be used to control the service's
1932 * availability. When clients connect or disconnect, the respective
1933 * @a connect_cb or @a disconnect_cb functions will be called. For
1934 * messages received from the clients, the respective @a handlers will
1935 * be invoked; for the closure of the handlers we use the return value
1936 * from the @a connect_cb invocation of the respective client.
1937 *
1938 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1939 * message to receive further messages from this client. If
1940 * #GNUNET_SERVICE_client_continue() is not called within a short
1941 * time, a warning will be logged. If delays are expected, services
1942 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1943 * disable the warning.
1944 *
1945 * Clients sending invalid messages (based on @a handlers) will be
1946 * dropped. Additionally, clients can be dropped at any time using
1947 * #GNUNET_SERVICE_client_drop().
1948 *
1949 * @param argc number of command-line arguments in @a argv
1950 * @param argv array of command-line arguments
1951 * @param service_name name of the service to run
1952 * @param options options controlling shutdown of the service
1953 * @param service_init_cb function to call once the service is ready
1954 * @param connect_cb function to call whenever a client connects
1955 * @param disconnect_cb function to call whenever a client disconnects
1956 * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
1957 * @param handlers NULL-terminated array of message handlers for the service,
1958 * the closure will be set to the value returned by
1959 * the @a connect_cb for the respective connection
1960 * @return 0 on success, non-zero on error
1961 */
1962int
1963GNUNET_SERVICE_run_ (int argc,
1964 char *const *argv,
1965 const char *service_name,
1966 enum GNUNET_SERVICE_Options options,
1967 GNUNET_SERVICE_InitCallback service_init_cb,
1968 GNUNET_SERVICE_ConnectHandler connect_cb,
1969 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1970 void *cls,
1971 const struct GNUNET_MQ_MessageHandler *handlers)
1972{
1973 struct GNUNET_SERVICE_Handle sh;
1974
1975#if ENABLE_NLS
1976 char *path;
1977#endif
1978 char *cfg_filename;
1979 char *opt_cfg_filename;
1980 char *loglev;
1981 const char *xdg;
1982 char *logfile;
1983 int do_daemonize;
1984 unsigned long long skew_offset;
1985 unsigned long long skew_variance;
1986 long long clock_offset;
1987 struct GNUNET_CONFIGURATION_Handle *cfg;
1988 int ret;
1989 int err;
1990 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1991 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1992 GNUNET_GETOPT_option_cfgfile (&opt_cfg_filename),
1993 GNUNET_GETOPT_option_flag ('d',
1994 "daemonize",
1995 gettext_noop (
1996 "do daemonize (detach from terminal)"),
1997 &do_daemonize),
1998 GNUNET_GETOPT_option_help (NULL),
1999 GNUNET_GETOPT_option_loglevel (&loglev),
2000 GNUNET_GETOPT_option_logfile (&logfile),
2001 GNUNET_GETOPT_option_version (pd->version),
2002 GNUNET_GETOPT_OPTION_END
2003 };
2004
2005 err = 1;
2006 memset (&sh, 0, sizeof(sh));
2007 xdg = getenv ("XDG_CONFIG_HOME");
2008 if (NULL != xdg)
2009 GNUNET_asprintf (&cfg_filename,
2010 "%s%s%s",
2011 xdg,
2012 DIR_SEPARATOR_STR,
2013 pd->config_file);
2014 else
2015 cfg_filename = GNUNET_strdup (pd->user_config_file);
2016 sh.ready_confirm_fd = -1;
2017 sh.options = options;
2018 sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
2019 sh.service_init_cb = service_init_cb;
2020 sh.connect_cb = connect_cb;
2021 sh.disconnect_cb = disconnect_cb;
2022 sh.cb_cls = cls;
2023 sh.handlers = (NULL == pd->agpl_url)
2024 ? GNUNET_MQ_copy_handlers (handlers)
2025 : GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL);
2026 sh.service_name = service_name;
2027 sh.ret = 0;
2028 /* setup subsystems */
2029 loglev = NULL;
2030 logfile = NULL;
2031 opt_cfg_filename = NULL;
2032 do_daemonize = 0;
2033#if ENABLE_NLS
2034 if (NULL != pd->gettext_domain)
2035 {
2036 setlocale (LC_ALL, "");
2037 path = (NULL == pd->gettext_path) ?
2038 GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR) :
2039 GNUNET_strdup (pd->gettext_path);
2040 if (NULL != path)
2041 {
2042 bindtextdomain (pd->gettext_domain, path);
2043 GNUNET_free (path);
2044 }
2045 textdomain (pd->gettext_domain);
2046 }
2047#endif
2048 ret = GNUNET_GETOPT_run (service_name,
2049 service_options,
2050 argc,
2051 argv);
2052 if (GNUNET_SYSERR == ret)
2053 goto shutdown;
2054 if (GNUNET_NO == ret)
2055 {
2056 err = 0;
2057 goto shutdown;
2058 }
2059 if (GNUNET_OK != GNUNET_log_setup (service_name,
2060 loglev,
2061 logfile))
2062 {
2063 GNUNET_break (0);
2064 goto shutdown;
2065 }
2066 if (NULL != opt_cfg_filename)
2067 {
2068 if ((GNUNET_YES != GNUNET_DISK_file_test (opt_cfg_filename)) ||
2069 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_filename)))
2070 {
2071 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2072 _ ("Malformed configuration file `%s', exit ...\n"),
2073 opt_cfg_filename);
2074 goto shutdown;
2075 }
2076 }
2077 else
2078 {
2079 if (GNUNET_YES == GNUNET_DISK_file_test (cfg_filename))
2080 {
2081 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cfg_filename))
2082 {
2083 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2084 _ ("Malformed configuration file `%s', exit ...\n"),
2085 cfg_filename);
2086 goto shutdown;
2087 }
2088 }
2089 else
2090 {
2091 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
2092 {
2093 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2094 _ ("Malformed configuration, exit ...\n"));
2095 goto shutdown;
2096 }
2097 }
2098 }
2099 if (GNUNET_OK != setup_service (&sh))
2100 goto shutdown;
2101 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sh)))
2102 {
2103 GNUNET_break (0);
2104 goto shutdown;
2105 }
2106 if (GNUNET_OK != set_user_id (&sh))
2107 goto shutdown;
2108 LOG (GNUNET_ERROR_TYPE_DEBUG,
2109 "Service `%s' runs with configuration from `%s'\n",
2110 service_name,
2111 (NULL != opt_cfg_filename) ? opt_cfg_filename : cfg_filename);
2112 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sh.cfg,
2113 "TESTING",
2114 "SKEW_OFFSET",
2115 &skew_offset)) &&
2116 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sh.cfg,
2117 "TESTING",
2118 "SKEW_VARIANCE",
2119 &skew_variance)))
2120 {
2121 clock_offset = skew_offset - skew_variance;
2122 GNUNET_TIME_set_offset (clock_offset);
2123 LOG (GNUNET_ERROR_TYPE_DEBUG,
2124 "Skewing clock by %lld ms\n",
2125 (long long) clock_offset);
2126 }
2127 GNUNET_RESOLVER_connect (sh.cfg);
2128
2129 /* actually run service */
2130 err = 0;
2131 GNUNET_SCHEDULER_run (&service_main, &sh);
2132 /* shutdown */
2133 if (1 == do_daemonize)
2134 pid_file_delete (&sh);
2135
2136shutdown:
2137 if (-1 != sh.ready_confirm_fd)
2138 {
2139 if (1 != write (sh.ready_confirm_fd, err ? "I" : "S", 1))
2140 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
2141 GNUNET_break (0 == close (sh.ready_confirm_fd));
2142 }
2143#if HAVE_MALLINFO2
2144 {
2145 char *counter;
2146
2147 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sh.cfg,
2148 service_name,
2149 "GAUGER_HEAP")) &&
2150 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sh.cfg,
2151 service_name,
2152 "GAUGER_HEAP",
2153 &counter)))
2154 {
2155 struct mallinfo2 mi;
2156
2157 mi = mallinfo2 ();
2158 GAUGER (service_name, counter, mi.usmblks, "blocks");
2159 GNUNET_free (counter);
2160 }
2161 }
2162#endif
2163 teardown_service (&sh);
2164 GNUNET_free (sh.handlers);
2165 GNUNET_SPEEDUP_stop_ ();
2166 GNUNET_CONFIGURATION_destroy (cfg);
2167 GNUNET_free (logfile);
2168 GNUNET_free (loglev);
2169 GNUNET_free (cfg_filename);
2170 GNUNET_free (opt_cfg_filename);
2171
2172 return err ? GNUNET_SYSERR : sh.ret;
2173}
2174
2175
2176/**
2177 * Suspend accepting connections from the listen socket temporarily.
2178 * Resume activity using #GNUNET_SERVICE_resume.
2179 *
2180 * @param sh service to stop accepting connections.
2181 */
2182void
2183GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
2184{
2185 do_suspend (sh, SUSPEND_STATE_APP);
2186}
2187
2188
2189/**
2190 * Resume accepting connections from the listen socket.
2191 *
2192 * @param sh service to resume accepting connections.
2193 */
2194void
2195GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
2196{
2197 do_resume (sh, SUSPEND_STATE_APP);
2198}
2199
2200
2201/**
2202 * Task run to resume receiving data from the client after
2203 * the client called #GNUNET_SERVICE_client_continue().
2204 *
2205 * @param cls our `struct GNUNET_SERVICE_Client`
2206 */
2207static void
2208resume_client_receive (void *cls)
2209{
2210 struct GNUNET_SERVICE_Client *c = cls;
2211 int ret;
2212
2213 c->recv_task = NULL;
2214 /* first, check if there is still something in the buffer */
2215 ret = GNUNET_MST_next (c->mst, GNUNET_YES);
2216 if (GNUNET_SYSERR == ret)
2217 {
2218 if (NULL == c->drop_task)
2219 GNUNET_SERVICE_client_drop (c);
2220 return;
2221 }
2222 if (GNUNET_NO == ret)
2223 return; /* done processing, wait for more later */
2224 GNUNET_assert (GNUNET_OK == ret);
2225 if (GNUNET_YES == c->needs_continue)
2226 return; /* #GNUNET_MST_next() did give a message to the client */
2227 /* need to receive more data from the network first */
2228 if (NULL != c->recv_task)
2229 return;
2230 c->recv_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2231 c->sock,
2232 &service_client_recv,
2233 c);
2234}
2235
2236
2237/**
2238 * Continue receiving further messages from the given client.
2239 * Must be called after each message received.
2240 *
2241 * @param c the client to continue receiving from
2242 */
2243void
2244GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
2245{
2246 GNUNET_assert (NULL == c->drop_task);
2247 GNUNET_assert (GNUNET_YES == c->needs_continue);
2248 GNUNET_assert (NULL == c->recv_task);
2249 c->needs_continue = GNUNET_NO;
2250 if (NULL != c->warn_task)
2251 {
2252 GNUNET_SCHEDULER_cancel (c->warn_task);
2253 c->warn_task = NULL;
2254 }
2255 c->recv_task = GNUNET_SCHEDULER_add_now (&resume_client_receive, c);
2256}
2257
2258
2259/**
2260 * Disable the warning the server issues if a message is not
2261 * acknowledged in a timely fashion. Use this call if a client is
2262 * intentionally delayed for a while. Only applies to the current
2263 * message.
2264 *
2265 * @param c client for which to disable the warning
2266 */
2267void
2268GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
2269{
2270 GNUNET_break (NULL != c->warn_task);
2271 if (NULL != c->warn_task)
2272 {
2273 GNUNET_SCHEDULER_cancel (c->warn_task);
2274 c->warn_task = NULL;
2275 }
2276}
2277
2278
2279/**
2280 * Asynchronously finish dropping the client.
2281 *
2282 * @param cls the `struct GNUNET_SERVICE_Client`.
2283 */
2284static void
2285finish_client_drop (void *cls)
2286{
2287 struct GNUNET_SERVICE_Client *c = cls;
2288 struct GNUNET_SERVICE_Handle *sh = c->sh;
2289
2290 c->drop_task = NULL;
2291 GNUNET_assert (NULL == c->send_task);
2292 GNUNET_assert (NULL == c->recv_task);
2293 GNUNET_assert (NULL == c->warn_task);
2294 GNUNET_MST_destroy (c->mst);
2295 GNUNET_MQ_destroy (c->mq);
2296 if (GNUNET_NO == c->persist)
2297 {
2298 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (c->sock));
2299 if ((0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) &&
2300 (0 == (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)))
2301 do_resume (sh, SUSPEND_STATE_EMFILE);
2302 }
2303 else
2304 {
2305 GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
2306 }
2307 GNUNET_free (c);
2308 if ((0 != (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)) &&
2309 (GNUNET_NO == have_non_monitor_clients (sh)))
2310 GNUNET_SERVICE_shutdown (sh);
2311}
2312
2313
2314/**
2315 * Ask the server to disconnect from the given client. This is the
2316 * same as returning #GNUNET_SYSERR within the check procedure when
2317 * handling a message, wexcept that it allows dropping of a client even
2318 * when not handling a message from that client. The `disconnect_cb`
2319 * will be called on @a c even if the application closes the connection
2320 * using this function.
2321 *
2322 * @param c client to disconnect now
2323 */
2324void
2325GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
2326{
2327 struct GNUNET_SERVICE_Handle *sh = c->sh;
2328
2329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2330 "Client dropped: %p (MQ: %p)\n",
2331 c,
2332 c->mq);
2333#if EXECINFO
2334 {
2335 void *backtrace_array[MAX_TRACE_DEPTH];
2336 int num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH);
2337 char **backtrace_strings =
2338 backtrace_symbols (backtrace_array, t->num_backtrace_strings);
2339 for (unsigned int i = 0; i < num_backtrace_strings; i++)
2340 LOG (GNUNET_ERROR_TYPE_DEBUG,
2341 "client drop trace %u: %s\n",
2342 i,
2343 backtrace_strings[i]);
2344 }
2345#endif
2346 if (NULL != c->drop_task)
2347 {
2348 /* asked to drop twice! */
2349 GNUNET_assert (0);
2350 return;
2351 }
2352 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
2353 sh->clients_tail,
2354 c);
2355 if (NULL != sh->disconnect_cb)
2356 sh->disconnect_cb (sh->cb_cls,
2357 c,
2358 c->user_context);
2359 if (NULL != c->warn_task)
2360 {
2361 GNUNET_SCHEDULER_cancel (c->warn_task);
2362 c->warn_task = NULL;
2363 }
2364 if (NULL != c->recv_task)
2365 {
2366 GNUNET_SCHEDULER_cancel (c->recv_task);
2367 c->recv_task = NULL;
2368 }
2369 if (NULL != c->send_task)
2370 {
2371 GNUNET_SCHEDULER_cancel (c->send_task);
2372 c->send_task = NULL;
2373 }
2374 c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop, c);
2375}
2376
2377
2378/**
2379 * Explicitly stops the service.
2380 *
2381 * @param sh server to shutdown
2382 */
2383void
2384GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
2385{
2386 struct GNUNET_SERVICE_Client *client;
2387
2388 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
2389 do_suspend (sh, SUSPEND_STATE_SHUTDOWN);
2390 while (NULL != (client = sh->clients_head))
2391 GNUNET_SERVICE_client_drop (client);
2392}
2393
2394
2395/**
2396 * Set the 'monitor' flag on this client. Clients which have been
2397 * marked as 'monitors' won't prevent the server from shutting down
2398 * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is
2399 * that for "normal" clients we likely want to allow them to process
2400 * their requests; however, monitor-clients are likely to 'never'
2401 * disconnect during shutdown and thus will not be considered when
2402 * determining if the server should continue to exist after
2403 * shutdown has been triggered.
2404 *
2405 * @param c client to mark as a monitor
2406 */
2407void
2408GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
2409{
2410 c->is_monitor = GNUNET_YES;
2411 if (((0 != (SUSPEND_STATE_SHUTDOWN & c->sh->suspend_state)) &&
2412 (GNUNET_NO == have_non_monitor_clients (c->sh))))
2413 GNUNET_SERVICE_shutdown (c->sh);
2414}
2415
2416
2417/**
2418 * Set the persist option on this client. Indicates that the
2419 * underlying socket or fd should never really be closed. Used for
2420 * indicating process death.
2421 *
2422 * @param c client to persist the socket (never to be closed)
2423 */
2424void
2425GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
2426{
2427 c->persist = GNUNET_YES;
2428}
2429
2430
2431/**
2432 * Obtain the message queue of @a c. Convenience function.
2433 *
2434 * @param c the client to continue receiving from
2435 * @return the message queue of @a c
2436 */
2437struct GNUNET_MQ_Handle *
2438GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
2439{
2440 return c->mq;
2441}
2442
2443
2444/* end of service.c */
diff --git a/src/util/signal.c b/src/util/signal.c
deleted file mode 100644
index 8b9a9a291..000000000
--- a/src/util/signal.c
+++ /dev/null
@@ -1,109 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2006 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 util/signal.c
23 * @brief code for installing and uninstalling signal handlers
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "util-signal", __VA_ARGS__)
31
32
33struct GNUNET_SIGNAL_Context
34{
35 struct GNUNET_SIGNAL_Context *next;
36
37 struct GNUNET_SIGNAL_Context *prev;
38
39 int sig;
40
41 GNUNET_SIGNAL_Handler method;
42
43 struct sigaction oldsig;
44};
45
46static struct GNUNET_SIGNAL_Context *sc_head;
47
48static struct GNUNET_SIGNAL_Context *sc_tail;
49
50struct GNUNET_SIGNAL_Context *
51GNUNET_SIGNAL_handler_install (int signum, GNUNET_SIGNAL_Handler handler)
52{
53 struct GNUNET_SIGNAL_Context *ret;
54
55 struct sigaction sig;
56
57 ret = GNUNET_new (struct GNUNET_SIGNAL_Context);
58 ret->sig = signum;
59 ret->method = handler;
60
61 memset (&sig, 0, sizeof(sig));
62 sig.sa_handler = (void *) handler;
63 sigemptyset (&sig.sa_mask);
64#ifdef SA_INTERRUPT
65 sig.sa_flags = SA_INTERRUPT; /* SunOS */
66#else
67 sig.sa_flags = SA_RESTART;
68#endif
69 sigaction (signum, &sig, &ret->oldsig);
70
71 GNUNET_CONTAINER_DLL_insert_tail (sc_head, sc_tail, ret);
72 return ret;
73}
74
75
76void
77GNUNET_SIGNAL_handler_uninstall (struct GNUNET_SIGNAL_Context *ctx)
78{
79 struct sigaction sig;
80
81 sigemptyset (&sig.sa_mask);
82 sigaction (ctx->sig, &ctx->oldsig, &sig);
83
84 GNUNET_CONTAINER_DLL_remove (sc_head, sc_tail, ctx);
85 GNUNET_free (ctx);
86}
87
88
89/**
90 * Raise the given signal by calling the installed signal handlers. This will
91 * not use the @em raise() system call but only calls the handlers registered
92 * through GNUNET_SIGNAL_handler_install().
93 *
94 * @param sig the signal to raise
95 */
96void
97GNUNET_SIGNAL_raise (const int sig)
98{
99 struct GNUNET_SIGNAL_Context *ctx;
100
101 for (ctx = sc_head; NULL != ctx; ctx = ctx->next)
102 {
103 if (sig != ctx->sig)
104 continue;
105 if (NULL == ctx->method)
106 continue;
107 ctx->method ();
108 }
109}
diff --git a/src/util/socks.c b/src/util/socks.c
deleted file mode 100644
index 5c9f8a5f8..000000000
--- a/src/util/socks.c
+++ /dev/null
@@ -1,689 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 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 util/socks.c
23 * @brief SOCKS5 connection support
24 * @author Jeffrey Burdges
25 *
26 * These routines should be called only on newly active connections.
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util-socks", __VA_ARGS__)
33
34#define LOG_STRERROR(kind, syscall) \
35 GNUNET_log_from_strerror (kind, "util-socks", syscall)
36
37
38/* SOCKS5 authentication methods */
39#define SOCKS5_AUTH_REJECT 0xFF /* No acceptable auth method */
40#define SOCKS5_AUTH_NOAUTH 0x00 /* without authentication */
41#define SOCKS5_AUTH_GSSAPI 0x01 /* GSSAPI */
42#define SOCKS5_AUTH_USERPASS 0x02 /* User/Password */
43#define SOCKS5_AUTH_CHAP 0x03 /* Challenge-Handshake Auth Proto. */
44#define SOCKS5_AUTH_EAP 0x05 /* Extensible Authentication Proto. */
45#define SOCKS5_AUTH_MAF 0x08 /* Multi-Authentication Framework */
46
47
48/* SOCKS5 connection responses */
49#define SOCKS5_REP_SUCCEEDED 0x00 /* succeeded */
50#define SOCKS5_REP_FAIL 0x01 /* general SOCKS serer failure */
51#define SOCKS5_REP_NALLOWED 0x02 /* connection not allowed by ruleset */
52#define SOCKS5_REP_NUNREACH 0x03 /* Network unreachable */
53#define SOCKS5_REP_HUNREACH 0x04 /* Host unreachable */
54#define SOCKS5_REP_REFUSED 0x05 /* connection refused */
55#define SOCKS5_REP_EXPIRED 0x06 /* TTL expired */
56#define SOCKS5_REP_CNOTSUP 0x07 /* Command not supported */
57#define SOCKS5_REP_ANOTSUP 0x08 /* Address not supported */
58#define SOCKS5_REP_INVADDR 0x09 /* Invalid address */
59
60const char *
61SOCKS5_REP_names (int rep)
62{
63 switch (rep)
64 {
65 case SOCKS5_REP_SUCCEEDED:
66 return "succeeded";
67
68 case SOCKS5_REP_FAIL:
69 return "general SOCKS server failure";
70
71 case SOCKS5_REP_NALLOWED:
72 return "connection not allowed by ruleset";
73
74 case SOCKS5_REP_NUNREACH:
75 return "Network unreachable";
76
77 case SOCKS5_REP_HUNREACH:
78 return "Host unreachable";
79
80 case SOCKS5_REP_REFUSED:
81 return "connection refused";
82
83 case SOCKS5_REP_EXPIRED:
84 return "TTL expired";
85
86 case SOCKS5_REP_CNOTSUP:
87 return "Command not supported";
88
89 case SOCKS5_REP_ANOTSUP:
90 return "Address not supported";
91
92 case SOCKS5_REP_INVADDR:
93 return "Invalid address";
94
95 default:
96 return NULL;
97 }
98};
99
100
101/**
102 * Encode a string for the SOCKS5 protocol by prefixing it a byte stating its
103 * length and stripping the trailing zero byte. Truncates any string longer
104 * than 255 bytes.
105 *
106 * @param b buffer to contain the encoded string
107 * @param s string to encode
108 * @return pointer to the end of the encoded string in the buffer
109 */
110unsigned char *
111SOCK5_proto_string (unsigned char *b, const char *s)
112{
113 size_t l = strlen (s);
114
115 if (l > 255)
116 {
117 LOG (GNUNET_ERROR_TYPE_WARNING,
118 "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
119 l = 255;
120 }
121 *(b++) = (unsigned char) l;
122 memcpy (b, s, l);
123 return b + l;
124}
125
126
127#define SOCKS5_step_greet 0
128#define SOCKS5_step_auth 1
129#define SOCKS5_step_cmd 2
130#define SOCKS5_step_done 3
131
132/**
133 * State of the SOCKS5 handshake.
134 */
135struct GNUNET_SOCKS_Handshake
136{
137 /**
138 * Connection handle used for SOCKS5
139 */
140 struct GNUNET_CONNECTION_Handle *socks5_connection;
141
142 /**
143 * Connection handle initially returned to client
144 */
145 struct GNUNET_CONNECTION_Handle *target_connection;
146
147 /**
148 * Transmission handle on socks5_connection.
149 */
150 struct GNUNET_CONNECTION_TransmitHandle *th;
151
152 /**
153 * Our stage in the SOCKS5 handshake
154 */
155 int step;
156
157 /**
158 * Precomputed SOCKS5 handshake output buffer
159 */
160 unsigned char outbuf[1024];
161
162 /**
163 * Pointers delineating protoocol steps in the output buffer
164 */
165 unsigned char *(outstep[4]);
166
167 /**
168 * SOCKS5 handshake input buffer
169 */
170 unsigned char inbuf[1024];
171
172 /**
173 * Pointers delimiting the current step in the input buffer
174 */
175 unsigned char *instart;
176 unsigned char *inend;
177};
178
179
180/* Registering prototypes */
181
182void
183register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want);
184
185/* In fact, the client sends first rule in GNUnet suggests one could take
186 * large mac read sizes without fear of screwing up the proxied protocol,
187 * but we make a proper SOCKS5 client. */
188#define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2)
189
190
191struct GNUNET_CONNECTION_TransmitHandle *
192register_sender (struct GNUNET_SOCKS_Handshake *ih);
193
194
195/**
196 * Conclude the SOCKS5 handshake successfully.
197 *
198 * @param ih SOCKS5 handshake, consumed here.
199 * @param c open unused connection, consumed here.
200 * @return Connection handle that becomes usable when the handshake completes.
201 */
202void
203SOCKS5_handshake_done (struct GNUNET_SOCKS_Handshake *ih)
204{
205 GNUNET_CONNECTION_acivate_proxied (ih->target_connection);
206}
207
208
209/**
210 * Read one step in the SOCKS5 handshake.
211 *
212 * @param ih SOCKS5 Handshake
213 */
214void
215SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
216{
217 unsigned char *b = ih->instart;
218 size_t available = ih->inend - b;
219
220 int want = register_reciever_wants (ih);
221
222 if (available < want)
223 {
224 register_reciever (ih, want - available);
225 return;
226 }
227 GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
228 switch (ih->step)
229 {
230 case SOCKS5_step_greet: /* SOCKS5 server's greeting */
231 if (b[0] != 5)
232 {
233 LOG (GNUNET_ERROR_TYPE_ERROR, "Not a SOCKS5 server\n");
234 GNUNET_assert (0);
235 }
236 switch (b[1])
237 {
238 case SOCKS5_AUTH_NOAUTH:
239 ih->step = SOCKS5_step_cmd; /* no authentication to do */
240 break;
241
242 case SOCKS5_AUTH_USERPASS:
243 ih->step = SOCKS5_step_auth;
244 break;
245
246 case SOCKS5_AUTH_REJECT:
247 LOG (GNUNET_ERROR_TYPE_ERROR, "No authentication method accepted\n");
248 return;
249
250 default:
251 LOG (GNUNET_ERROR_TYPE_ERROR,
252 "Not a SOCKS5 server / Nonsensical authentication\n");
253 return;
254 }
255 b += 2;
256 break;
257
258 case SOCKS5_step_auth: /* SOCKS5 server's response to authentication */
259 if (b[1] != 0)
260 {
261 LOG (GNUNET_ERROR_TYPE_ERROR, "SOCKS5 authentication failed\n");
262 GNUNET_assert (0);
263 }
264 ih->step = SOCKS5_step_cmd;
265 b += 2;
266 break;
267
268 case SOCKS5_step_cmd: /* SOCKS5 server's response to command */
269 if (b[0] != 5)
270 {
271 LOG (GNUNET_ERROR_TYPE_ERROR, "SOCKS5 protocol error\n");
272 GNUNET_assert (0);
273 }
274 if (0 != b[1])
275 {
276 LOG (GNUNET_ERROR_TYPE_ERROR,
277 "SOCKS5 connection error : %s\n",
278 SOCKS5_REP_names (b[1]));
279 return;
280 }
281 b += 3;
282 /* There is no reason to verify host and port afaik. */
283 switch (*(b++))
284 {
285 case 1: /* IPv4 */
286 b += sizeof(struct in_addr); /* 4 */
287 break;
288
289 case 4: /* IPv6 */
290 b += sizeof(struct in6_addr); /* 16 */
291 break;
292
293 case 3: /* hostname */
294 b += *b;
295 break;
296 }
297 b += 2; /* port */
298 if (b > ih->inend)
299 {
300 register_reciever (ih, b - ih->inend);
301 return;
302 }
303 ih->step = SOCKS5_step_done;
304 LOG (GNUNET_ERROR_TYPE_DEBUG,
305 "SOCKS5 server : %s\n",
306 SOCKS5_REP_names (b[1]));
307 ih->instart = b;
308 SOCKS5_handshake_done (ih);
309 return;
310
311 case SOCKS5_step_done:
312 GNUNET_assert (0);
313 }
314 ih->instart = b;
315 /* Do not reschedule the sender unless we're done reading.
316 * I imagine this lets us avoid ever cancelling the transmit handle. */
317 register_sender (ih);
318}
319
320
321/**
322 * Callback to read from the SOCKS5 proxy.
323 *
324 * @param client the service
325 * @param handler function to call with the message
326 * @param handler_cls closure for @a handler
327 */
328void
329receiver (void *cls,
330 const void *buf,
331 size_t available,
332 const struct sockaddr *addr,
333 socklen_t addrlen,
334 int errCode)
335{
336 struct GNUNET_SOCKS_Handshake *ih = cls;
337
338 GNUNET_assert (&ih->inend[available] < &ih->inbuf[1024]);
339 GNUNET_memcpy (ih->inend, buf, available);
340 ih->inend += available;
341 SOCKS5_handshake_step (ih);
342}
343
344
345/**
346 * Register callback to read from the SOCKS5 proxy.
347 *
348 * @param client the service
349 * @param handler function to call with the message
350 * @param handler_cls closure for @a handler
351 */
352void
353register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want)
354{
355 GNUNET_CONNECTION_receive (ih->socks5_connection,
356 want,
357 GNUNET_TIME_relative_get_minute_ (),
358 &receiver,
359 ih);
360}
361
362
363/**
364 * Register SOCKS5 handshake sender
365 *
366 * @param cls closure (SOCKS handshake)
367 * @param size number of bytes available in @a buf
368 * @param buf where the callee should write the message
369 * @return number of bytes written to @a buf
370 */
371size_t
372transmit_ready (void *cls, size_t size, void *buf)
373{
374 struct GNUNET_SOCKS_Handshake *ih = cls;
375
376 /* connection.c has many routines that call us with buf == NULL :
377 * signal_transmit_error() - DNS, etc. active
378 * connect_fail_continuation()
379 * connect_probe_continuation() - timeout
380 * try_connect_using_address() - DNS failure/timeout
381 * transmit_timeout() - retry failed?
382 * GNUNET_CONNECTION_notify_transmit_ready() can schedule :
383 * transmit_timeout() - DNS still working
384 * connect_error() - DNS done but no socket?
385 * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error()
386 * We'd need to dig into the scheduler to guess at the reason, as
387 * connection.c tells us nothing itself, but mostly its timouts.
388 * Initially, we'll simply ignore this and leave massive timeouts, but
389 * maybe that should change for error handling pruposes. It appears that
390 * successful operations, including DNS resolution, do not use this. */if (NULL == buf)
391 {
392 if (0 == ih->step)
393 {
394 LOG (GNUNET_ERROR_TYPE_WARNING,
395 "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
396 register_sender (ih);
397 }
398 else
399 {
400 LOG (GNUNET_ERROR_TYPE_ERROR,
401 "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n",
402 ih->step);
403 GNUNET_break (0);
404 }
405 return 0;
406 }
407
408 GNUNET_assert ((1024 >= size) && (size > 0));
409 GNUNET_assert ((SOCKS5_step_done > ih->step) && (ih->step >= 0));
410 unsigned char *b = ih->outstep[ih->step];
411 unsigned char *e = ih->outstep[ih->step + 1];
412 GNUNET_assert (e <= &ih->outbuf[1024]);
413 unsigned int l = e - b;
414 GNUNET_assert (size >= l);
415 GNUNET_memcpy (buf, b, l);
416 register_reciever (ih, register_reciever_wants (ih));
417 return l;
418}
419
420
421/**
422 * Register SOCKS5 handshake sender
423 *
424 * @param ih handshake
425 * @return non-NULL if the notify callback was queued,
426 * NULL if we are already going to notify someone else (busy)
427 */
428struct GNUNET_CONNECTION_TransmitHandle *
429register_sender (struct GNUNET_SOCKS_Handshake *ih)
430{
431 struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_MINUTES;
432
433 GNUNET_assert (SOCKS5_step_done > ih->step);
434 GNUNET_assert (ih->step >= 0);
435 if (0 == ih->step)
436 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3);
437 unsigned char *b = ih->outstep[ih->step];
438 unsigned char *e = ih->outstep[ih->step + 1];
439 GNUNET_assert (ih->outbuf <= b && b < e && e < &ih->outbuf[1024]);
440 ih->th = GNUNET_CONNECTION_notify_transmit_ready (ih->socks5_connection,
441 e - b,
442 timeout,
443 &transmit_ready,
444 ih);
445 return ih->th;
446}
447
448
449/**
450 * Initialize a SOCKS5 handshake for authentication via username and
451 * password. Tor uses SOCKS username and password authentication to assign
452 * programs unique circuits.
453 *
454 * @param user username for the proxy
455 * @param pass password for the proxy
456 * @return Valid SOCKS5 hanbdshake handle
457 */
458struct GNUNET_SOCKS_Handshake *
459GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
460{
461 struct GNUNET_SOCKS_Handshake *ih =
462 GNUNET_new (struct GNUNET_SOCKS_Handshake);
463 unsigned char *b = ih->outbuf;
464
465 ih->outstep[SOCKS5_step_greet] = b;
466 *(b++) = 5; /* SOCKS5 */
467 unsigned char *n = b++;
468 *n = 1; /* Number of authentication methods */
469 /* We support no authentication even when requesting authentication,
470 * but this appears harmless, given the way that Tor uses authentication.
471 * And some SOCKS5 servers might require this. */
472 *(b++) = SOCKS5_AUTH_NOAUTH;
473 if (NULL != user)
474 {
475 *(b++) = SOCKS5_AUTH_USERPASS;
476 (*n)++;
477 }
478 /* There is no apparent reason to support authentication methods beyond
479 * username and password since afaik Tor does not support them. */
480
481 /* We authenticate with an empty username and password if the server demands
482 * them but we do not have any. */
483 if (user == NULL)
484 user = "";
485 if (pass == NULL)
486 pass = "";
487
488 ih->outstep[SOCKS5_step_auth] = b;
489 *(b++) = 1; /* subnegotiation ver.: 1 */
490 b = SOCK5_proto_string (b, user);
491 b = SOCK5_proto_string (b, pass);
492
493 ih->outstep[SOCKS5_step_cmd] = b;
494
495 ih->inend = ih->instart = ih->inbuf;
496
497 return ih;
498}
499
500
501/**
502 * Initialize a SOCKS5 handshake without authentication, thereby possibly
503 * sharing a Tor circuit with another process.
504 *
505 * @return Valid SOCKS5 hanbdshake handle
506 */
507struct GNUNET_SOCKS_Handshake *
508GNUNET_SOCKS_init_handshake_noauth ()
509{
510 return GNUNET_SOCKS_init_handshake (NULL, NULL);
511}
512
513
514/**
515 * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
516 * and port.
517 *
518 * @param ih SOCKS5 handshake
519 * @param hostname
520 * @param port
521 */
522void
523GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
524 const char *host,
525 uint16_t port)
526{
527 union
528 {
529 struct in_addr in4;
530 struct in6_addr in6;
531 } ia;
532 unsigned char *b = ih->outstep[SOCKS5_step_cmd];
533
534 *(b++) = 5; /* SOCKS5 */
535 *(b++) = 1; /* Establish a TCP/IP stream */
536 *(b++) = 0; /* reserved */
537
538 /* Specify destination */
539 if (1 == inet_pton (AF_INET, host, &ia.in4))
540 {
541 *(b++) = 1; /* IPv4 */
542 GNUNET_memcpy (b, &ia.in4, sizeof(struct in_addr));
543 b += sizeof(struct in_addr); /* 4 */
544 }
545 else if (1 == inet_pton (AF_INET6, host, &ia.in6))
546 {
547 *(b++) = 4; /* IPv6 */
548 GNUNET_memcpy (b, &ia.in6, sizeof(struct in6_addr));
549 b += sizeof(struct in6_addr); /* 16 */
550 }
551 else
552 {
553 *(b++) = 3; /* hostname */
554 b = SOCK5_proto_string (b, host);
555 }
556
557 /* Specify port */
558 *(uint16_t *) b = htons (port);
559 b += 2;
560
561 ih->outstep[SOCKS5_step_done] = b;
562}
563
564
565/**
566 * Run a SOCKS5 handshake on an open but unused TCP connection.
567 *
568 * @param ih SOCKS5 handshake, consumed here.
569 * @param c open unused connection, consumed here.
570 * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
571 */
572struct GNUNET_CONNECTION_Handle *
573GNUNET_SOCKS_run_handshake (struct GNUNET_SOCKS_Handshake *ih,
574 struct GNUNET_CONNECTION_Handle *c)
575{
576 ih->socks5_connection = c;
577 ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c);
578 register_sender (ih);
579
580 return ih->target_connection;
581}
582
583
584/**
585 * Check if a SOCKS proxy is required by a service. Do not use local service
586 * if a SOCKS proxy port is configured as this could deanonymize a user.
587 *
588 * @param service_name name of service to connect to
589 * @param cfg configuration to use
590 * @return GNUNET_YES if so, GNUNET_NO if not
591 */
592int
593GNUNET_SOCKS_check_service (const char *service_name,
594 const struct GNUNET_CONFIGURATION_Handle *cfg)
595{
596 return GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSPORT") ||
597 GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSHOST");
598}
599
600
601/**
602 * Try to connect to a service configured to use a SOCKS5 proxy.
603 *
604 * @param service_name name of service to connect to
605 * @param cfg configuration to use
606 * @return Connection handle that becomes usable when the handshake completes.
607 * NULL if SOCKS not configured or not configured properly
608 */
609struct GNUNET_CONNECTION_Handle *
610GNUNET_SOCKS_do_connect (const char *service_name,
611 const struct GNUNET_CONFIGURATION_Handle *cfg)
612{
613 struct GNUNET_SOCKS_Handshake *ih;
614 struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
615 char *host0;
616 char *host1;
617 char *user;
618 char *pass;
619 unsigned long long port0;
620 unsigned long long port1;
621
622 if (GNUNET_YES != GNUNET_SOCKS_check_service (service_name, cfg))
623 return NULL;
624 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
625 service_name,
626 "SOCKSPORT",
627 &port0))
628 port0 = 9050;
629 /* A typical Tor client should usually try port 9150 for the TBB too, but
630 * GNUnet can probably assume a system Tor installation. */
631 if ((port0 > 65535) || (port0 <= 0))
632 {
633 LOG (GNUNET_ERROR_TYPE_WARNING,
634 _ (
635 "Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
636 port0,
637 service_name);
638 return NULL;
639 }
640 if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
641 service_name,
642 "PORT",
643 &port1)) ||
644 (port1 > 65535) || (port1 <= 0) ||
645 (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
646 service_name,
647 "HOSTNAME",
648 &host1)))
649 {
650 LOG (GNUNET_ERROR_TYPE_WARNING,
651 _ (
652 "Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
653 service_name,
654 port1);
655 return NULL;
656 }
657 /* Appeared to still work after host0 corrupted, so either test case is broken, or
658 this whole routine is not being called. */
659 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
660 service_name,
661 "SOCKSHOST",
662 &host0))
663 host0 = NULL;
664 socks5 = GNUNET_CONNECTION_create_from_connect (cfg,
665 (host0 != NULL) ? host0
666 : "127.0.0.1",
667 port0);
668 GNUNET_free (host0);
669
670 /* Sets to NULL if they do not exist */
671 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
672 service_name,
673 "SOCKSUSER",
674 &user);
675 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
676 service_name,
677 "SOCKSPASS",
678 &pass);
679 ih = GNUNET_SOCKS_init_handshake (user, pass);
680 GNUNET_free (user);
681 GNUNET_free (pass);
682
683 GNUNET_SOCKS_set_handshake_destination (ih, host1, port1);
684 GNUNET_free (host1);
685 return GNUNET_SOCKS_run_handshake (ih, socks5);
686}
687
688
689/* socks.c */
diff --git a/src/util/speedup.c b/src/util/speedup.c
deleted file mode 100644
index 3d9e82319..000000000
--- a/src/util/speedup.c
+++ /dev/null
@@ -1,119 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 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 util/speedup.c
23 * @author Matthias Wachs
24 * @brief functions to speedup peer execution by manipulation system time
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "speedup.h"
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "util-speedup", __VA_ARGS__)
31
32
33static struct GNUNET_TIME_Relative interval;
34
35static struct GNUNET_TIME_Relative delta;
36
37static struct GNUNET_SCHEDULER_Task *speedup_task;
38
39
40static void
41do_speedup (void *cls)
42{
43 static long long current_offset;
44
45 (void) cls;
46 speedup_task = NULL;
47 current_offset += delta.rel_value_us;
48 GNUNET_TIME_set_offset (current_offset);
49 LOG (GNUNET_ERROR_TYPE_DEBUG,
50 "Speeding up execution time by %s\n",
51 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_NO));
52 speedup_task = GNUNET_SCHEDULER_add_delayed (interval,
53 &do_speedup,
54 NULL);
55}
56
57
58/**
59 * Start task that may speed up our system clock artificially
60 *
61 * @param cfg configuration to use
62 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the speedup was not configured
63 */
64int
65GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg)
66{
67 GNUNET_assert (NULL == speedup_task);
68 if (GNUNET_OK !=
69 GNUNET_CONFIGURATION_get_value_time (cfg,
70 "testing",
71 "SPEEDUP_INTERVAL",
72 &interval))
73 return GNUNET_SYSERR;
74 if (GNUNET_OK !=
75 GNUNET_CONFIGURATION_get_value_time (cfg,
76 "testing",
77 "SPEEDUP_DELTA",
78 &delta))
79 return GNUNET_SYSERR;
80
81 if ((0 == interval.rel_value_us) ||
82 (0 == delta.rel_value_us))
83 {
84 LOG (GNUNET_ERROR_TYPE_DEBUG,
85 "Speed up disabled\n");
86 return GNUNET_OK;
87 }
88 LOG (GNUNET_ERROR_TYPE_DEBUG,
89 "Speed up execution by %s\n",
90 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_NO));
91 LOG (GNUNET_ERROR_TYPE_DEBUG,
92 "Speed up executed every %s\n",
93 GNUNET_STRINGS_relative_time_to_string (interval, GNUNET_NO));
94 speedup_task = GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO,
95 &do_speedup,
96 NULL);
97 return GNUNET_OK;
98}
99
100
101/**
102 * Stop tasks that modify clock behavior.
103 */
104void
105GNUNET_SPEEDUP_stop_ ()
106{
107 if (NULL != speedup_task)
108 {
109 GNUNET_SCHEDULER_cancel (speedup_task);
110 speedup_task = NULL;
111 }
112 if ((0 != interval.rel_value_us) &&
113 (0 != delta.rel_value_us))
114 LOG (GNUNET_ERROR_TYPE_DEBUG,
115 "Stopped execution speed up\n");
116}
117
118
119/* end of speedup.c */
diff --git a/src/util/speedup.h b/src/util/speedup.h
deleted file mode 100644
index 505e73bf4..000000000
--- a/src/util/speedup.h
+++ /dev/null
@@ -1,45 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 -- 2013 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 util/speedup.c
23 * @brief Interface for speedup routinues
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#ifndef SPEEDUP_H_
28#define SPEEDUP_H_
29
30/**
31 * Start task that may speed up our system clock artificially
32 *
33 * @param cfg configuration to use
34 * @return GNUNET_OK on success, GNUNET_SYSERR if the speedup was not configured
35 */
36int
37GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg);
38
39/**
40 * Stop tasks that modify clock behavior.
41 */
42void
43GNUNET_SPEEDUP_stop_ (void);
44
45#endif /* SPEEDUP_H_ */
diff --git a/src/util/strings.c b/src/util/strings.c
deleted file mode 100644
index 673915888..000000000
--- a/src/util/strings.c
+++ /dev/null
@@ -1,1935 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2005-2017 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 * @file util/strings.c
22 * @brief string functions
23 * @author Nils Durner
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#if HAVE_ICONV
29#include <iconv.h>
30#endif
31#include "gnunet_crypto_lib.h"
32#include "gnunet_buffer_lib.h"
33#include "gnunet_strings_lib.h"
34#include <unicase.h>
35#include <unistr.h>
36#include <uniconv.h>
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "util-strings", __VA_ARGS__)
39
40#define LOG_STRERROR(kind, syscall) \
41 GNUNET_log_from_strerror (kind, "util-strings", syscall)
42
43
44size_t
45GNUNET_STRINGS_buffer_fill (char *buffer,
46 size_t size,
47 unsigned int count, ...)
48{
49 size_t needed;
50 va_list ap;
51
52 needed = 0;
53 va_start (ap, count);
54 while (count > 0)
55 {
56 const char *s = va_arg (ap, const char *);
57 size_t slen = strlen (s) + 1;
58
59 GNUNET_assert (slen <= size - needed);
60 if (NULL != buffer)
61 GNUNET_memcpy (&buffer[needed],
62 s,
63 slen);
64 needed += slen;
65 count--;
66 }
67 va_end (ap);
68 return needed;
69}
70
71
72char *
73GNUNET_STRINGS_pp2s (const struct GNUNET_PeerIdentity *pids,
74 unsigned int num_pids)
75{
76 char *buf;
77 size_t off;
78 size_t plen = num_pids * 5 + 1;
79
80 GNUNET_assert (num_pids < UINT32_MAX / 5);
81 off = 0;
82 buf = GNUNET_malloc (plen);
83 for (unsigned int i = 0; i < num_pids; i++)
84 {
85 off += GNUNET_snprintf (&buf[off],
86 plen - off,
87 "%s%s",
88 GNUNET_i2s (&pids[i]),
89 (i == num_pids - 1) ? "" : "-");
90 }
91 return buf;
92}
93
94
95unsigned int
96GNUNET_STRINGS_buffer_tokenize (const char *buffer,
97 size_t size,
98 unsigned int count,
99 ...)
100{
101 unsigned int start;
102 unsigned int needed;
103 const char **r;
104 va_list ap;
105
106 needed = 0;
107 va_start (ap, count);
108 while (count > 0)
109 {
110 r = va_arg (ap, const char **);
111
112 start = needed;
113 while ((needed < size) && (buffer[needed] != '\0'))
114 needed++;
115 if (needed == size)
116 {
117 va_end (ap);
118 return 0; /* error */
119 }
120 *r = &buffer[start];
121 needed++; /* skip 0-termination */
122 count--;
123 }
124 va_end (ap);
125 return needed;
126}
127
128
129char *
130GNUNET_STRINGS_byte_size_fancy (unsigned long long size)
131{
132 const char *unit = /* size unit */ "b";
133 char *ret;
134
135 if (size > 5 * 1024)
136 {
137 size = size / 1024;
138 unit = "KiB";
139 if (size > 5 * 1024)
140 {
141 size = size / 1024;
142 unit = "MiB";
143 if (size > 5 * 1024)
144 {
145 size = size / 1024;
146 unit = "GiB";
147 if (size > 5 * 1024)
148 {
149 size = size / 1024;
150 unit = "TiB";
151 }
152 }
153 }
154 }
155 ret = GNUNET_malloc (32);
156 GNUNET_snprintf (ret, 32, "%llu %s", size, unit);
157 return ret;
158}
159
160
161size_t
162GNUNET_strlcpy (char *dst,
163 const char *src,
164 size_t n)
165{
166 size_t slen;
167
168 GNUNET_assert (0 != n);
169 slen = strnlen (src, n - 1);
170 memcpy (dst, src, slen);
171 dst[slen] = '\0';
172 return slen;
173}
174
175
176/**
177 * Unit conversion table entry for 'convert_with_table'.
178 */
179struct ConversionTable
180{
181 /**
182 * Name of the unit (or NULL for end of table).
183 */
184 const char *name;
185
186 /**
187 * Factor to apply for this unit.
188 */
189 unsigned long long value;
190};
191
192
193/**
194 * Convert a string of the form "4 X 5 Y" into a numeric value
195 * by interpreting "X" and "Y" as units and then multiplying
196 * the numbers with the values associated with the respective
197 * unit from the conversion table.
198 *
199 * @param input input string to parse
200 * @param table table with the conversion of unit names to numbers
201 * @param output where to store the result
202 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
203 */
204static int
205convert_with_table (const char *input,
206 const struct ConversionTable *table,
207 unsigned long long *output)
208{
209 unsigned long long ret;
210 char *in;
211 const char *tok;
212 unsigned long long last;
213 unsigned int i;
214 char *sptr;
215
216 ret = 0;
217 last = 0;
218 in = GNUNET_strdup (input);
219 for (tok = strtok_r (in, " ", &sptr);
220 tok != NULL;
221 tok = strtok_r (NULL, " ", &sptr))
222 {
223 do
224 {
225 i = 0;
226 while ((table[i].name != NULL) && (0 != strcasecmp (table[i].name, tok)))
227 i++;
228 if (table[i].name != NULL)
229 {
230 last *= table[i].value;
231 break; /* next tok */
232 }
233 else
234 {
235 char *endptr;
236 ret += last;
237 errno = 0;
238 last = strtoull (tok, &endptr, 10);
239 if ((0 != errno) || (endptr == tok))
240 {
241 GNUNET_free (in);
242 return GNUNET_SYSERR; /* expected number */
243 }
244 if ('\0' == endptr[0])
245 break; /* next tok */
246 else
247 tok = endptr; /* and re-check (handles times like "10s") */
248 }
249 }
250 while (GNUNET_YES);
251 }
252 ret += last;
253 *output = ret;
254 GNUNET_free (in);
255 return GNUNET_OK;
256}
257
258
259int
260GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size,
261 unsigned long long *size)
262{
263 static const struct ConversionTable table[] =
264 { { "B", 1 },
265 { "KiB", 1024 },
266 { "kB", 1000 },
267 { "MiB", 1024 * 1024 },
268 { "MB", 1000 * 1000 },
269 { "GiB", 1024 * 1024 * 1024 },
270 { "GB", 1000 * 1000 * 1000 },
271 { "TiB", 1024LL * 1024LL * 1024LL * 1024LL },
272 { "TB", 1000LL * 1000LL * 1000LL * 1024LL },
273 { "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL },
274 { "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL },
275 { "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL },
276 { "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL },
277 { NULL, 0 } };
278
279 return convert_with_table (fancy_size, table, size);
280}
281
282
283int
284GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time,
285 struct GNUNET_TIME_Relative *rtime)
286{
287 static const struct ConversionTable table[] =
288 { { "us", 1 },
289 { "ms", 1000 },
290 { "s", 1000 * 1000LL },
291 { "second", 1000 * 1000LL },
292 { "seconds", 1000 * 1000LL },
293 { "\"", 1000 * 1000LL },
294 { "m", 60 * 1000 * 1000LL },
295 { "min", 60 * 1000 * 1000LL },
296 { "minute", 60 * 1000 * 1000LL },
297 { "minutes", 60 * 1000 * 1000LL },
298 { "'", 60 * 1000 * 1000LL },
299 { "h", 60 * 60 * 1000 * 1000LL },
300 { "hour", 60 * 60 * 1000 * 1000LL },
301 { "hours", 60 * 60 * 1000 * 1000LL },
302 { "d", 24 * 60 * 60 * 1000LL * 1000LL },
303 { "day", 24 * 60 * 60 * 1000LL * 1000LL },
304 { "days", 24 * 60 * 60 * 1000LL * 1000LL },
305 { "week", 7 * 24 * 60 * 60 * 1000LL * 1000LL },
306 { "weeks", 7 * 24 * 60 * 60 * 1000LL * 1000LL },
307 { "year", 31536000000000LL /* year */ },
308 { "years", 31536000000000LL /* year */ },
309 { "a", 31536000000000LL /* year */ },
310 { NULL, 0 } };
311 int ret;
312 unsigned long long val;
313
314 if (0 == strcasecmp ("forever", fancy_time))
315 {
316 *rtime = GNUNET_TIME_UNIT_FOREVER_REL;
317 return GNUNET_OK;
318 }
319 ret = convert_with_table (fancy_time, table, &val);
320 rtime->rel_value_us = (uint64_t) val;
321 return ret;
322}
323
324
325int
326GNUNET_STRINGS_fancy_time_to_absolute (const char *fancy_time,
327 struct GNUNET_TIME_Absolute *atime)
328{
329 struct tm tv;
330 time_t t;
331 const char *eos;
332
333 if (0 == strcasecmp ("end of time", fancy_time))
334 {
335 *atime = GNUNET_TIME_UNIT_FOREVER_ABS;
336 return GNUNET_OK;
337 }
338 eos = &fancy_time[strlen (fancy_time)];
339 memset (&tv, 0, sizeof(tv));
340 if ((eos != strptime (fancy_time, "%a %b %d %H:%M:%S %Y", &tv)) &&
341 (eos != strptime (fancy_time, "%c", &tv)) &&
342 (eos != strptime (fancy_time, "%Ec", &tv)) &&
343 (eos != strptime (fancy_time, "%Y-%m-%d %H:%M:%S", &tv)) &&
344 (eos != strptime (fancy_time, "%Y-%m-%d %H:%M", &tv)) &&
345 (eos != strptime (fancy_time, "%x", &tv)) &&
346 (eos != strptime (fancy_time, "%Ex", &tv)) &&
347 (eos != strptime (fancy_time, "%Y-%m-%d", &tv)) &&
348 (eos != strptime (fancy_time, "%Y-%m", &tv)) &&
349 (eos != strptime (fancy_time, "%Y", &tv)))
350 return GNUNET_SYSERR;
351 t = mktime (&tv);
352 atime->abs_value_us = (uint64_t) ((uint64_t) t * 1000LL * 1000LL);
353 return GNUNET_OK;
354}
355
356
357char *
358GNUNET_STRINGS_conv (const char *input,
359 size_t len,
360 const char *input_charset,
361 const char *output_charset)
362{
363 char *ret;
364 uint8_t *u8_string;
365 char *encoded_string;
366 size_t u8_string_length;
367 size_t encoded_string_length;
368
369 u8_string = u8_conv_from_encoding (input_charset,
370 iconveh_error,
371 input,
372 len,
373 NULL,
374 NULL,
375 &u8_string_length);
376 if (NULL == u8_string)
377 {
378 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "u8_conv_from_encoding");
379 goto fail;
380 }
381 if (0 == strcmp (output_charset, "UTF-8"))
382 {
383 ret = GNUNET_malloc (u8_string_length + 1);
384 GNUNET_memcpy (ret, u8_string, u8_string_length);
385 ret[u8_string_length] = '\0';
386 free (u8_string);
387 return ret;
388 }
389 encoded_string = u8_conv_to_encoding (output_charset,
390 iconveh_error,
391 u8_string,
392 u8_string_length,
393 NULL,
394 NULL,
395 &encoded_string_length);
396 free (u8_string);
397 if (NULL == encoded_string)
398 {
399 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "u8_conv_to_encoding");
400 goto fail;
401 }
402 ret = GNUNET_malloc (encoded_string_length + 1);
403 GNUNET_memcpy (ret, encoded_string, encoded_string_length);
404 ret[encoded_string_length] = '\0';
405 free (encoded_string);
406 return ret;
407fail:
408 LOG (GNUNET_ERROR_TYPE_WARNING,
409 _ ("Character sets requested were `%s'->`%s'\n"),
410 "UTF-8",
411 output_charset);
412 ret = GNUNET_malloc (len + 1);
413 GNUNET_memcpy (ret, input, len);
414 ret[len] = '\0';
415 return ret;
416}
417
418
419char *
420GNUNET_STRINGS_to_utf8 (const char *input,
421 size_t len,
422 const char *charset)
423{
424 return GNUNET_STRINGS_conv (input,
425 len,
426 charset,
427 "UTF-8");
428}
429
430
431char *
432GNUNET_STRINGS_from_utf8 (const char *input,
433 size_t len,
434 const char *charset)
435{
436 return GNUNET_STRINGS_conv (input,
437 len,
438 "UTF-8",
439 charset);
440}
441
442
443void
444GNUNET_STRINGS_utf8_tolower (const char *input,
445 char *output)
446{
447 uint8_t *tmp_in;
448 size_t len;
449
450 tmp_in = u8_tolower ((uint8_t *) input,
451 strlen ((char *) input),
452 NULL,
453 UNINORM_NFD,
454 NULL,
455 &len);
456 GNUNET_memcpy (output, tmp_in, len);
457 output[len] = '\0';
458 free (tmp_in);
459}
460
461
462void
463GNUNET_STRINGS_utf8_toupper (const char *input,
464 char *output)
465{
466 uint8_t *tmp_in;
467 size_t len;
468
469 tmp_in = u8_toupper ((uint8_t *) input,
470 strlen ((char *) input),
471 NULL,
472 UNINORM_NFD,
473 NULL,
474 &len);
475 GNUNET_memcpy (output, tmp_in, len);
476 output[len] = '\0';
477 free (tmp_in);
478}
479
480
481char *
482GNUNET_STRINGS_filename_expand (const char *fil)
483{
484 char *buffer;
485 size_t len;
486 char *fm;
487 const char *fil_ptr;
488
489 if (fil == NULL)
490 return NULL;
491
492 if (fil[0] == DIR_SEPARATOR)
493 /* absolute path, just copy */
494 return GNUNET_strdup (fil);
495 if (fil[0] == '~')
496 {
497 fm = getenv ("HOME");
498 if (fm == NULL)
499 {
500 LOG (GNUNET_ERROR_TYPE_WARNING,
501 _ ("Failed to expand `$HOME': environment variable `HOME' not set"));
502 return NULL;
503 }
504 fm = GNUNET_strdup (fm);
505 /* do not copy '~' */
506 fil_ptr = fil + 1;
507
508 /* skip over dir separator to be consistent */
509 if (fil_ptr[0] == DIR_SEPARATOR)
510 fil_ptr++;
511 }
512 else
513 {
514 /* relative path */
515 fil_ptr = fil;
516 len = 512;
517 fm = NULL;
518 while (1)
519 {
520 buffer = GNUNET_malloc (len);
521 if (getcwd (buffer, len) != NULL)
522 {
523 fm = buffer;
524 break;
525 }
526 if ((errno == ERANGE) && (len < 1024 * 1024 * 4))
527 {
528 len *= 2;
529 GNUNET_free (buffer);
530 continue;
531 }
532 GNUNET_free (buffer);
533 break;
534 }
535 if (fm == NULL)
536 {
537 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "getcwd");
538 buffer = getenv ("PWD"); /* alternative */
539 if (buffer != NULL)
540 fm = GNUNET_strdup (buffer);
541 }
542 if (fm == NULL)
543 fm = GNUNET_strdup ("./"); /* give up */
544 }
545 GNUNET_asprintf (&buffer,
546 "%s%s%s",
547 fm,
548 (fm[strlen (fm) - 1] == DIR_SEPARATOR) ? ""
549 : DIR_SEPARATOR_STR,
550 fil_ptr);
551 GNUNET_free (fm);
552 return buffer;
553}
554
555
556const char *
557GNUNET_STRINGS_relative_time_to_string (struct GNUNET_TIME_Relative delta,
558 int do_round)
559{
560 static GNUNET_THREAD_LOCAL char buf[128];
561 const char *unit = /* time unit */ "µs";
562 uint64_t dval = delta.rel_value_us;
563
564 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == delta.rel_value_us)
565 return "forever";
566 if (0 == delta.rel_value_us)
567 return "0 ms";
568 if (((GNUNET_YES == do_round) && (dval > 5 * 1000)) || (0 == (dval % 1000)))
569 {
570 dval = dval / 1000;
571 unit = /* time unit */ "ms";
572 if (((GNUNET_YES == do_round) && (dval > 5 * 1000)) || (0 == (dval % 1000)))
573 {
574 dval = dval / 1000;
575 unit = /* time unit */ "s";
576 if (((GNUNET_YES == do_round) && (dval > 5 * 60)) || (0 == (dval % 60)))
577 {
578 dval = dval / 60;
579 unit = /* time unit */ "m";
580 if (((GNUNET_YES == do_round) && (dval > 5 * 60)) || (0 == (dval % 60)))
581 {
582 dval = dval / 60;
583 unit = /* time unit */ "h";
584 if (((GNUNET_YES == do_round) && (dval > 5 * 24)) ||
585 (0 == (dval % 24)))
586 {
587 dval = dval / 24;
588 if (1 == dval)
589 unit = /* time unit */ "day";
590 else
591 unit = /* time unit */ "days";
592 }
593 }
594 }
595 }
596 }
597 GNUNET_snprintf (buf, sizeof(buf), "%llu %s",
598 (unsigned long long) dval, unit);
599 return buf;
600}
601
602
603const char *
604GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t)
605{
606 static GNUNET_THREAD_LOCAL char buf[255];
607 time_t tt;
608 struct tm *tp;
609
610 if (t.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
611 return "end of time";
612 tt = t.abs_value_us / 1000LL / 1000LL;
613 tp = localtime (&tt);
614 /* This is hacky, but i don't know a way to detect libc character encoding.
615 * Just expect utf8 from glibc these days.
616 * As for msvcrt, use the wide variant, which always returns utf16
617 * (otherwise we'd have to detect current codepage or use W32API character
618 * set conversion routines to convert to UTF8).
619 */strftime (buf, sizeof(buf), "%a %b %d %H:%M:%S %Y", tp);
620
621 return buf;
622}
623
624
625const char *
626GNUNET_STRINGS_get_short_name (const char *filename)
627{
628 const char *short_fn = filename;
629 const char *ss;
630
631 while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR)) && (ss[1] != '\0'))
632 short_fn = 1 + ss;
633 return short_fn;
634}
635
636
637/**
638 * Get the decoded value corresponding to a character according to Crockford
639 * Base32 encoding.
640 *
641 * @param a a character
642 * @return corresponding numeric value
643 */
644static unsigned int
645getValue__ (unsigned char a)
646{
647 unsigned int dec;
648
649 switch (a)
650 {
651 case 'O':
652 case 'o':
653 a = '0';
654 break;
655
656 case 'i':
657 case 'I':
658 case 'l':
659 case 'L':
660 a = '1';
661 break;
662
663 /* also consider U to be V */
664 case 'u':
665 case 'U':
666 a = 'V';
667 break;
668
669 default:
670 break;
671 }
672 if ((a >= '0') && (a <= '9'))
673 return a - '0';
674 if ((a >= 'a') && (a <= 'z'))
675 a = toupper (a);
676 /* return (a - 'a' + 10); */
677 dec = 0;
678 if ((a >= 'A') && (a <= 'Z'))
679 {
680 if ('I' < a)
681 dec++;
682 if ('L' < a)
683 dec++;
684 if ('O' < a)
685 dec++;
686 if ('U' < a)
687 dec++;
688 return(a - 'A' + 10 - dec);
689 }
690 return -1;
691}
692
693
694char *
695GNUNET_STRINGS_data_to_string (const void *data,
696 size_t size,
697 char *out,
698 size_t out_size)
699{
700 /**
701 * 32 characters for encoding
702 */
703 static char *encTable__ = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
704 unsigned int wpos;
705 unsigned int rpos;
706 unsigned int bits;
707 unsigned int vbit;
708 const unsigned char *udata;
709
710 GNUNET_assert (size < SIZE_MAX / 8 - 4);
711 udata = data;
712 if (out_size < (size * 8 + 4) / 5)
713 {
714 GNUNET_break (0);
715 return NULL;
716 }
717 vbit = 0;
718 wpos = 0;
719 rpos = 0;
720 bits = 0;
721 while ((rpos < size) || (vbit > 0))
722 {
723 if ((rpos < size) && (vbit < 5))
724 {
725 bits = (bits << 8) | udata[rpos++]; /* eat 8 more bits */
726 vbit += 8;
727 }
728 if (vbit < 5)
729 {
730 bits <<= (5 - vbit); /* zero-padding */
731 GNUNET_assert (vbit == ((size * 8) % 5));
732 vbit = 5;
733 }
734 if (wpos >= out_size)
735 {
736 GNUNET_break (0);
737 return NULL;
738 }
739 out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31];
740 vbit -= 5;
741 }
742 GNUNET_assert (0 == vbit);
743 if (wpos < out_size)
744 out[wpos] = '\0';
745 return &out[wpos];
746}
747
748
749char *
750GNUNET_STRINGS_data_to_string_alloc (const void *buf, size_t size)
751{
752 char *str_buf;
753 size_t len = size * 8;
754 char *end;
755
756 if (len % 5 > 0)
757 len += 5 - len % 5;
758 len /= 5;
759 str_buf = GNUNET_malloc (len + 1);
760 end = GNUNET_STRINGS_data_to_string (buf,
761 size,
762 str_buf,
763 len);
764 if (NULL == end)
765 {
766 GNUNET_free (str_buf);
767 return NULL;
768 }
769 *end = '\0';
770 return str_buf;
771}
772
773
774enum GNUNET_GenericReturnValue
775GNUNET_STRINGS_string_to_data (const char *enc,
776 size_t enclen,
777 void *out,
778 size_t out_size)
779{
780 size_t rpos;
781 size_t wpos;
782 unsigned int bits;
783 unsigned int vbit;
784 int ret;
785 int shift;
786 unsigned char *uout;
787 size_t encoded_len;
788
789 if (0 == enclen)
790 {
791 if (0 == out_size)
792 return GNUNET_OK;
793 return GNUNET_SYSERR;
794 }
795 GNUNET_assert (out_size < SIZE_MAX / 8);
796 encoded_len = out_size * 8;
797 uout = out;
798 wpos = out_size;
799 rpos = enclen;
800 if ((encoded_len % 5) > 0)
801 {
802 vbit = encoded_len % 5; /* padding! */
803 shift = 5 - vbit;
804 bits = (ret = getValue__ (enc[--rpos])) >> shift;
805 }
806 else
807 {
808 vbit = 5;
809 shift = 0;
810 bits = (ret = getValue__ (enc[--rpos]));
811 }
812 if ((encoded_len + shift) / 5 != enclen)
813 return GNUNET_SYSERR;
814 if (-1 == ret)
815 return GNUNET_SYSERR;
816 while (wpos > 0)
817 {
818 if (0 == rpos)
819 {
820 GNUNET_break (0);
821 return GNUNET_SYSERR;
822 }
823 bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits;
824 if (-1 == ret)
825 return GNUNET_SYSERR;
826 vbit += 5;
827 if (vbit >= 8)
828 {
829 uout[--wpos] = (unsigned char) bits;
830 bits >>= 8;
831 vbit -= 8;
832 }
833 }
834 if ((0 != rpos) || (0 != vbit))
835 return GNUNET_SYSERR;
836 return GNUNET_OK;
837}
838
839
840enum GNUNET_GenericReturnValue
841GNUNET_STRINGS_string_to_data_alloc (const char *enc,
842 size_t enclen,
843 void **out,
844 size_t *out_size)
845{
846 size_t size;
847 void *data;
848 int res;
849
850 size = (enclen * 5) / 8;
851 if (size >= GNUNET_MAX_MALLOC_CHECKED)
852 {
853 GNUNET_break_op (0);
854 return GNUNET_SYSERR;
855 }
856 data = GNUNET_malloc (size);
857 res = GNUNET_STRINGS_string_to_data (enc,
858 enclen,
859 data,
860 size);
861 if ( (0 < size) &&
862 (GNUNET_OK != res) )
863 {
864 size--;
865 res = GNUNET_STRINGS_string_to_data (enc,
866 enclen,
867 data,
868 size);
869 }
870 if (GNUNET_OK != res)
871 {
872 GNUNET_break_op (0);
873 GNUNET_free (data);
874 return GNUNET_SYSERR;
875 }
876 *out = data;
877 *out_size = size;
878 return GNUNET_OK;
879}
880
881
882enum GNUNET_GenericReturnValue
883GNUNET_STRINGS_parse_uri (const char *path,
884 char **scheme_part,
885 const char **path_part)
886{
887 size_t len;
888 size_t i;
889 int end;
890 int pp_state = 0;
891 const char *post_scheme_part = NULL;
892
893 len = strlen (path);
894 for (end = 0, i = 0; ! end && i < len; i++)
895 {
896 switch (pp_state)
897 {
898 case 0:
899 if ((path[i] == ':') && (i > 0))
900 {
901 pp_state += 1;
902 continue;
903 }
904 if (! (((path[i] >= 'A') && (path[i] <= 'Z') ) ||
905 ((path[i] >= 'a') && (path[i] <= 'z') ) ||
906 ((path[i] >= '0') && (path[i] <= '9') ) || (path[i] == '+') ||
907 (path[i] == '-') || (path[i] == '.')))
908 end = 1;
909 break;
910
911 case 1:
912 case 2:
913 if (path[i] == '/')
914 {
915 pp_state += 1;
916 continue;
917 }
918 end = 1;
919 break;
920
921 case 3:
922 post_scheme_part = &path[i];
923 end = 1;
924 break;
925
926 default:
927 end = 1;
928 }
929 }
930 if (post_scheme_part == NULL)
931 return GNUNET_NO;
932 if (scheme_part)
933 {
934 *scheme_part = GNUNET_malloc (post_scheme_part - path + 1);
935 GNUNET_memcpy (*scheme_part, path, post_scheme_part - path);
936 (*scheme_part)[post_scheme_part - path] = '\0';
937 }
938 if (path_part)
939 *path_part = post_scheme_part;
940 return GNUNET_YES;
941}
942
943
944enum GNUNET_GenericReturnValue
945GNUNET_STRINGS_path_is_absolute (const char *filename,
946 int can_be_uri,
947 int *r_is_uri,
948 char **r_uri_scheme)
949{
950 const char *post_scheme_path;
951 int is_uri;
952 char *uri;
953 /* consider POSIX paths to be absolute too, even on W32,
954 * as plibc expansion will fix them for us.
955 */
956 if (filename[0] == '/')
957 return GNUNET_YES;
958 if (can_be_uri)
959 {
960 is_uri = GNUNET_STRINGS_parse_uri (filename, &uri, &post_scheme_path);
961 if (r_is_uri)
962 *r_is_uri = is_uri;
963 if (is_uri)
964 {
965 if (r_uri_scheme)
966 *r_uri_scheme = uri;
967 else
968 GNUNET_free (uri);
969
970 return GNUNET_STRINGS_path_is_absolute (post_scheme_path,
971 GNUNET_NO,
972 NULL,
973 NULL);
974 }
975 }
976 else
977 {
978 if (r_is_uri)
979 *r_is_uri = GNUNET_NO;
980 }
981
982 return GNUNET_NO;
983}
984
985
986enum GNUNET_GenericReturnValue
987GNUNET_STRINGS_check_filename (const char *filename,
988 enum GNUNET_STRINGS_FilenameCheck checks)
989{
990 struct stat st;
991
992 if ((NULL == filename) || (filename[0] == '\0'))
993 return GNUNET_SYSERR;
994 if (0 != (checks & GNUNET_STRINGS_CHECK_IS_ABSOLUTE))
995 if (! GNUNET_STRINGS_path_is_absolute (filename, GNUNET_NO, NULL, NULL))
996 return GNUNET_NO;
997 if (0 != (checks
998 & (GNUNET_STRINGS_CHECK_EXISTS | GNUNET_STRINGS_CHECK_IS_DIRECTORY
999 | GNUNET_STRINGS_CHECK_IS_LINK)))
1000 {
1001 if (0 != lstat (filename, &st))
1002 {
1003 if (0 != (checks & GNUNET_STRINGS_CHECK_EXISTS))
1004 return GNUNET_NO;
1005 else
1006 return GNUNET_SYSERR;
1007 }
1008 }
1009 if (0 != (checks & GNUNET_STRINGS_CHECK_IS_DIRECTORY))
1010 if (! S_ISDIR (st.st_mode))
1011 return GNUNET_NO;
1012 if (0 != (checks & GNUNET_STRINGS_CHECK_IS_LINK))
1013 if (! S_ISLNK (st.st_mode))
1014 return GNUNET_NO;
1015 return GNUNET_YES;
1016}
1017
1018
1019enum GNUNET_GenericReturnValue
1020GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr,
1021 uint16_t addrlen,
1022 struct sockaddr_in6 *r_buf)
1023{
1024 char zbuf[addrlen + 1];
1025 int ret;
1026 char *port_colon;
1027 unsigned int port;
1028 char dummy[2];
1029
1030 if (addrlen < 6)
1031 return GNUNET_SYSERR;
1032 GNUNET_memcpy (zbuf, zt_addr, addrlen);
1033 if ('[' != zbuf[0])
1034 {
1035 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1036 _ ("IPv6 address did not start with `['\n"));
1037 return GNUNET_SYSERR;
1038 }
1039 zbuf[addrlen] = '\0';
1040 port_colon = strrchr (zbuf, ':');
1041 if (NULL == port_colon)
1042 {
1043 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1044 _ ("IPv6 address did contain ':' to separate port number\n"));
1045 return GNUNET_SYSERR;
1046 }
1047 if (']' != *(port_colon - 1))
1048 {
1049 GNUNET_log (
1050 GNUNET_ERROR_TYPE_WARNING,
1051 _ ("IPv6 address did contain ']' before ':' to separate port number\n"));
1052 return GNUNET_SYSERR;
1053 }
1054 ret = sscanf (port_colon, ":%u%1s", &port, dummy);
1055 if ((1 != ret) || (port > 65535))
1056 {
1057 GNUNET_log (
1058 GNUNET_ERROR_TYPE_WARNING,
1059 _ ("IPv6 address did contain a valid port number after the last ':'\n"));
1060 return GNUNET_SYSERR;
1061 }
1062 *(port_colon - 1) = '\0';
1063 memset (r_buf, 0, sizeof(struct sockaddr_in6));
1064 ret = inet_pton (AF_INET6, &zbuf[1], &r_buf->sin6_addr);
1065 if (ret <= 0)
1066 {
1067 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1068 _ ("Invalid IPv6 address `%s': %s\n"),
1069 &zbuf[1],
1070 strerror (errno));
1071 return GNUNET_SYSERR;
1072 }
1073 r_buf->sin6_port = htons (port);
1074 r_buf->sin6_family = AF_INET6;
1075#if HAVE_SOCKADDR_IN_SIN_LEN
1076 r_buf->sin6_len = (u_char) sizeof(struct sockaddr_in6);
1077#endif
1078 return GNUNET_OK;
1079}
1080
1081
1082enum GNUNET_GenericReturnValue
1083GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr,
1084 uint16_t addrlen,
1085 struct sockaddr_in *r_buf)
1086{
1087 unsigned int temps[4];
1088 unsigned int port;
1089 unsigned int cnt;
1090 char dummy[2];
1091
1092 if (addrlen < 9)
1093 return GNUNET_SYSERR;
1094 cnt = sscanf (zt_addr,
1095 "%u.%u.%u.%u:%u%1s",
1096 &temps[0],
1097 &temps[1],
1098 &temps[2],
1099 &temps[3],
1100 &port,
1101 dummy);
1102 if (5 != cnt)
1103 return GNUNET_SYSERR;
1104 for (cnt = 0; cnt < 4; cnt++)
1105 if (temps[cnt] > 0xFF)
1106 return GNUNET_SYSERR;
1107 if (port > 65535)
1108 return GNUNET_SYSERR;
1109 r_buf->sin_family = AF_INET;
1110 r_buf->sin_port = htons (port);
1111 r_buf->sin_addr.s_addr =
1112 htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + temps[3]);
1113#if HAVE_SOCKADDR_IN_SIN_LEN
1114 r_buf->sin_len = (u_char) sizeof(struct sockaddr_in);
1115#endif
1116 return GNUNET_OK;
1117}
1118
1119
1120enum GNUNET_GenericReturnValue
1121GNUNET_STRINGS_to_address_ip (const char *addr,
1122 uint16_t addrlen,
1123 struct sockaddr_storage *r_buf)
1124{
1125 if (addr[0] == '[')
1126 return GNUNET_STRINGS_to_address_ipv6 (addr,
1127 addrlen,
1128 (struct sockaddr_in6 *) r_buf);
1129 return GNUNET_STRINGS_to_address_ipv4 (addr,
1130 addrlen,
1131 (struct sockaddr_in *) r_buf);
1132}
1133
1134
1135size_t
1136GNUNET_STRINGS_parse_socket_addr (const char *addr,
1137 uint8_t *af,
1138 struct sockaddr **sa)
1139{
1140 char *cp = GNUNET_strdup (addr);
1141
1142 *af = AF_UNSPEC;
1143 if ('[' == *addr)
1144 {
1145 /* IPv6 */
1146 *sa = GNUNET_malloc (sizeof(struct sockaddr_in6));
1147 if (GNUNET_OK !=
1148 GNUNET_STRINGS_to_address_ipv6 (cp,
1149 strlen (cp),
1150 (struct sockaddr_in6 *) *sa))
1151 {
1152 GNUNET_free (*sa);
1153 *sa = NULL;
1154 GNUNET_free (cp);
1155 return 0;
1156 }
1157 *af = AF_INET6;
1158 GNUNET_free (cp);
1159 return sizeof(struct sockaddr_in6);
1160 }
1161 else
1162 {
1163 /* IPv4 */
1164 *sa = GNUNET_malloc (sizeof(struct sockaddr_in));
1165 if (GNUNET_OK !=
1166 GNUNET_STRINGS_to_address_ipv4 (cp,
1167 strlen (cp),
1168 (struct sockaddr_in *) *sa))
1169 {
1170 GNUNET_free (*sa);
1171 *sa = NULL;
1172 GNUNET_free (cp);
1173 return 0;
1174 }
1175 *af = AF_INET;
1176 GNUNET_free (cp);
1177 return sizeof(struct sockaddr_in);
1178 }
1179}
1180
1181
1182/**
1183 * Makes a copy of argv that consists of a single memory chunk that can be
1184 * freed with a single call to GNUNET_free();
1185 */
1186static char *const *
1187_make_continuous_arg_copy (int argc, char *const *argv)
1188{
1189 size_t argvsize = 0;
1190 char **new_argv;
1191 char *p;
1192
1193 for (int i = 0; i < argc; i++)
1194 argvsize += strlen (argv[i]) + 1 + sizeof(char *);
1195 new_argv = GNUNET_malloc (argvsize + sizeof(char *));
1196 p = (char *) &new_argv[argc + 1];
1197 for (int i = 0; i < argc; i++)
1198 {
1199 new_argv[i] = p;
1200 strcpy (p, argv[i]);
1201 p += strlen (argv[i]) + 1;
1202 }
1203 new_argv[argc] = NULL;
1204 return (char *const *) new_argv;
1205}
1206
1207
1208enum GNUNET_GenericReturnValue
1209GNUNET_STRINGS_get_utf8_args (int argc,
1210 char *const *argv,
1211 int *u8argc,
1212 char *const **u8argv)
1213{
1214 char *const *new_argv =
1215 (char *const *) _make_continuous_arg_copy (argc, argv);
1216 *u8argv = new_argv;
1217 *u8argc = argc;
1218 return GNUNET_OK;
1219}
1220
1221
1222/**
1223 * Parse the given port policy. The format is
1224 * "[!]SPORT[-DPORT]".
1225 *
1226 * @param port_policy string to parse
1227 * @param pp policy to fill in
1228 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
1229 * @a port_policy is malformed
1230 */
1231static enum GNUNET_GenericReturnValue
1232parse_port_policy (const char *port_policy,
1233 struct GNUNET_STRINGS_PortPolicy *pp)
1234{
1235 const char *pos;
1236 int s;
1237 int e;
1238 char eol[2];
1239
1240 pos = port_policy;
1241 if ('!' == *pos)
1242 {
1243 pp->negate_portrange = GNUNET_YES;
1244 pos++;
1245 }
1246 if (2 == sscanf (pos, "%u-%u%1s", &s, &e, eol))
1247 {
1248 if ((0 == s) || (s > 0xFFFF) || (e < s) || (e > 0xFFFF))
1249 {
1250 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Port not in range\n"));
1251 return GNUNET_SYSERR;
1252 }
1253 pp->start_port = (uint16_t) s;
1254 pp->end_port = (uint16_t) e;
1255 return GNUNET_OK;
1256 }
1257 if (1 == sscanf (pos, "%u%1s", &s, eol))
1258 {
1259 if ((0 == s) || (s > 0xFFFF))
1260 {
1261 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Port not in range\n"));
1262 return GNUNET_SYSERR;
1263 }
1264
1265 pp->start_port = (uint16_t) s;
1266 pp->end_port = (uint16_t) s;
1267 return GNUNET_OK;
1268 }
1269 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1270 _ ("Malformed port policy `%s'\n"),
1271 port_policy);
1272 return GNUNET_SYSERR;
1273}
1274
1275
1276struct GNUNET_STRINGS_IPv4NetworkPolicy *
1277GNUNET_STRINGS_parse_ipv4_policy (const char *routeListX)
1278{
1279 unsigned int count;
1280 unsigned int i;
1281 unsigned int j;
1282 unsigned int len;
1283 int cnt;
1284 unsigned int pos;
1285 unsigned int temps[8];
1286 int slash;
1287 struct GNUNET_STRINGS_IPv4NetworkPolicy *result;
1288 int colon;
1289 int end;
1290 char *routeList;
1291 char dummy[2];
1292
1293 if (NULL == routeListX)
1294 return NULL;
1295 len = strlen (routeListX);
1296 if (0 == len)
1297 return NULL;
1298 routeList = GNUNET_strdup (routeListX);
1299 count = 0;
1300 for (i = 0; i < len; i++)
1301 if (routeList[i] == ';')
1302 count++;
1303 result = GNUNET_malloc (sizeof(struct GNUNET_STRINGS_IPv4NetworkPolicy)
1304 * (count + 1));
1305 i = 0;
1306 pos = 0;
1307 while (i < count)
1308 {
1309 for (colon = pos; ':' != routeList[colon]; colon++)
1310 if ((';' == routeList[colon]) || ('\0' == routeList[colon]))
1311 break;
1312 for (end = colon; ';' != routeList[end]; end++)
1313 if ('\0' == routeList[end])
1314 break;
1315 if ('\0' == routeList[end])
1316 break;
1317 routeList[end] = '\0';
1318 if (':' == routeList[colon])
1319 {
1320 routeList[colon] = '\0';
1321 if (GNUNET_OK != parse_port_policy (&routeList[colon + 1], &result[i].pp))
1322 break;
1323 }
1324 cnt = sscanf (&routeList[pos],
1325 "%u.%u.%u.%u/%u.%u.%u.%u%1s",
1326 &temps[0],
1327 &temps[1],
1328 &temps[2],
1329 &temps[3],
1330 &temps[4],
1331 &temps[5],
1332 &temps[6],
1333 &temps[7],
1334 dummy);
1335 if (8 == cnt)
1336 {
1337 for (j = 0; j < 8; j++)
1338 if (temps[j] > 0xFF)
1339 {
1340 LOG (GNUNET_ERROR_TYPE_WARNING,
1341 _ ("Invalid format for IP: `%s'\n"),
1342 &routeList[pos]);
1343 GNUNET_free (result);
1344 GNUNET_free (routeList);
1345 return NULL;
1346 }
1347 result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16)
1348 + (temps[2] << 8) + temps[3]);
1349 result[i].netmask.s_addr = htonl ((temps[4] << 24) + (temps[5] << 16)
1350 + (temps[6] << 8) + temps[7]);
1351 pos = end + 1;
1352 i++;
1353 continue;
1354 }
1355 /* try second notation */
1356 cnt = sscanf (&routeList[pos],
1357 "%u.%u.%u.%u/%u%1s",
1358 &temps[0],
1359 &temps[1],
1360 &temps[2],
1361 &temps[3],
1362 &slash,
1363 dummy);
1364 if (5 == cnt)
1365 {
1366 for (j = 0; j < 4; j++)
1367 if (temps[j] > 0xFF)
1368 {
1369 LOG (GNUNET_ERROR_TYPE_WARNING,
1370 _ ("Invalid format for IP: `%s'\n"),
1371 &routeList[pos]);
1372 GNUNET_free (result);
1373 GNUNET_free (routeList);
1374 return NULL;
1375 }
1376 result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16)
1377 + (temps[2] << 8) + temps[3]);
1378 if ((slash <= 32) && (slash >= 0))
1379 {
1380 result[i].netmask.s_addr = 0;
1381 while (slash > 0)
1382 {
1383 result[i].netmask.s_addr =
1384 (result[i].netmask.s_addr >> 1) + 0x80000000;
1385 slash--;
1386 }
1387 result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
1388 pos = end + 1;
1389 i++;
1390 continue;
1391 }
1392 else
1393 {
1394 LOG (GNUNET_ERROR_TYPE_WARNING,
1395 _ ("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
1396 slash);
1397 GNUNET_free (result);
1398 GNUNET_free (routeList);
1399 return NULL; /* error */
1400 }
1401 }
1402 /* try third notation */
1403 slash = 32;
1404 cnt = sscanf (&routeList[pos],
1405 "%u.%u.%u.%u%1s",
1406 &temps[0],
1407 &temps[1],
1408 &temps[2],
1409 &temps[3],
1410 dummy);
1411 if (4 == cnt)
1412 {
1413 for (j = 0; j < 4; j++)
1414 if (temps[j] > 0xFF)
1415 {
1416 LOG (GNUNET_ERROR_TYPE_WARNING,
1417 _ ("Invalid format for IP: `%s'\n"),
1418 &routeList[pos]);
1419 GNUNET_free (result);
1420 GNUNET_free (routeList);
1421 return NULL;
1422 }
1423 result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16)
1424 + (temps[2] << 8) + temps[3]);
1425 result[i].netmask.s_addr = 0;
1426 while (slash > 0)
1427 {
1428 result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000;
1429 slash--;
1430 }
1431 result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
1432 pos = end + 1;
1433 i++;
1434 continue;
1435 }
1436 LOG (GNUNET_ERROR_TYPE_WARNING,
1437 _ ("Invalid format for IP: `%s'\n"),
1438 &routeList[pos]);
1439 GNUNET_free (result);
1440 GNUNET_free (routeList);
1441 return NULL; /* error */
1442 }
1443 if (pos < strlen (routeList))
1444 {
1445 LOG (GNUNET_ERROR_TYPE_WARNING,
1446 _ ("Invalid format: `%s'\n"),
1447 &routeListX[pos]);
1448 GNUNET_free (result);
1449 GNUNET_free (routeList);
1450 return NULL; /* oops */
1451 }
1452 GNUNET_free (routeList);
1453 return result; /* ok */
1454}
1455
1456
1457struct GNUNET_STRINGS_IPv6NetworkPolicy *
1458GNUNET_STRINGS_parse_ipv6_policy (const char *routeListX)
1459{
1460 unsigned int count;
1461 unsigned int i;
1462 unsigned int len;
1463 unsigned int pos;
1464 int start;
1465 int slash;
1466 int ret;
1467 char *routeList;
1468 struct GNUNET_STRINGS_IPv6NetworkPolicy *result;
1469 unsigned int bits;
1470 unsigned int off;
1471 int save;
1472 int colon;
1473 char dummy[2];
1474
1475 if (NULL == routeListX)
1476 return NULL;
1477 len = strlen (routeListX);
1478 if (0 == len)
1479 return NULL;
1480 routeList = GNUNET_strdup (routeListX);
1481 count = 0;
1482 for (i = 0; i < len; i++)
1483 if (';' == routeList[i])
1484 count++;
1485 if (';' != routeList[len - 1])
1486 {
1487 LOG (GNUNET_ERROR_TYPE_WARNING,
1488 _ ("Invalid network notation (does not end with ';': `%s')\n"),
1489 routeList);
1490 GNUNET_free (routeList);
1491 return NULL;
1492 }
1493
1494 result = GNUNET_malloc (sizeof(struct GNUNET_STRINGS_IPv6NetworkPolicy)
1495 * (count + 1));
1496 i = 0;
1497 pos = 0;
1498 while (i < count)
1499 {
1500 start = pos;
1501 while (';' != routeList[pos])
1502 pos++;
1503 slash = pos;
1504 while ((slash >= start) && (routeList[slash] != '/'))
1505 slash--;
1506
1507 if (slash < start)
1508 {
1509 memset (&result[i].netmask, 0xFF, sizeof(struct in6_addr));
1510 slash = pos;
1511 }
1512 else
1513 {
1514 routeList[pos] = '\0';
1515 for (colon = pos; ':' != routeList[colon]; colon--)
1516 if ('/' == routeList[colon])
1517 break;
1518 if (':' == routeList[colon])
1519 {
1520 routeList[colon] = '\0';
1521 if (GNUNET_OK !=
1522 parse_port_policy (&routeList[colon + 1], &result[i].pp))
1523 {
1524 GNUNET_free (result);
1525 GNUNET_free (routeList);
1526 return NULL;
1527 }
1528 }
1529 ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask);
1530 if (ret <= 0)
1531 {
1532 save = errno;
1533 if ((1 != sscanf (&routeList[slash + 1], "%u%1s", &bits, dummy)) ||
1534 (bits > 128))
1535 {
1536 if (0 == ret)
1537 LOG (GNUNET_ERROR_TYPE_WARNING,
1538 _ ("Wrong format `%s' for netmask\n"),
1539 &routeList[slash + 1]);
1540 else
1541 {
1542 errno = save;
1543 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_pton");
1544 }
1545 GNUNET_free (result);
1546 GNUNET_free (routeList);
1547 return NULL;
1548 }
1549 off = 0;
1550 while (bits > 8)
1551 {
1552 result[i].netmask.s6_addr[off++] = 0xFF;
1553 bits -= 8;
1554 }
1555 while (bits > 0)
1556 {
1557 result[i].netmask.s6_addr[off] =
1558 (result[i].netmask.s6_addr[off] >> 1) + 0x80;
1559 bits--;
1560 }
1561 }
1562 }
1563 routeList[slash] = '\0';
1564 ret = inet_pton (AF_INET6, &routeList[start], &result[i].network);
1565 if (ret <= 0)
1566 {
1567 if (0 == ret)
1568 LOG (GNUNET_ERROR_TYPE_WARNING,
1569 _ ("Wrong format `%s' for network\n"),
1570 &routeList[slash + 1]);
1571 else
1572 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
1573 GNUNET_free (result);
1574 GNUNET_free (routeList);
1575 return NULL;
1576 }
1577 pos++;
1578 i++;
1579 }
1580 GNUNET_free (routeList);
1581 return result;
1582}
1583
1584
1585/** ******************** Base64 encoding ***********/
1586
1587#define FILLCHAR '='
1588static char *cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1589 "abcdefghijklmnopqrstuvwxyz"
1590 "0123456789+/";
1591
1592
1593size_t
1594GNUNET_STRINGS_base64_encode (const void *in,
1595 size_t len,
1596 char **output)
1597{
1598 const char *data = in;
1599 size_t ret;
1600 char *opt;
1601
1602 ret = 0;
1603 GNUNET_assert (len < SIZE_MAX / 4 * 3 );
1604 opt = GNUNET_malloc (2 + (len * 4 / 3) + 8);
1605 for (size_t i = 0; i < len; ++i)
1606 {
1607 char c;
1608
1609 c = (data[i] >> 2) & 0x3f;
1610 opt[ret++] = cvt[(int) c];
1611 c = (data[i] << 4) & 0x3f;
1612 if (++i < len)
1613 c |= (data[i] >> 4) & 0x0f;
1614 opt[ret++] = cvt[(int) c];
1615 if (i < len)
1616 {
1617 c = (data[i] << 2) & 0x3f;
1618 if (++i < len)
1619 c |= (data[i] >> 6) & 0x03;
1620 opt[ret++] = cvt[(int) c];
1621 }
1622 else
1623 {
1624 ++i;
1625 opt[ret++] = FILLCHAR;
1626 }
1627 if (i < len)
1628 {
1629 c = data[i] & 0x3f;
1630 opt[ret++] = cvt[(int) c];
1631 }
1632 else
1633 {
1634 opt[ret++] = FILLCHAR;
1635 }
1636 }
1637 *output = opt;
1638 return ret;
1639}
1640
1641
1642size_t
1643GNUNET_STRINGS_base64url_encode (const void *in,
1644 size_t len,
1645 char **output)
1646{
1647 char *enc;
1648 size_t pos;
1649
1650 GNUNET_STRINGS_base64_encode (in, len, output);
1651 enc = *output;
1652 /* Replace with correct characters for base64url */
1653 pos = 0;
1654 while ('\0' != enc[pos])
1655 {
1656 if ('+' == enc[pos])
1657 enc[pos] = '-';
1658 if ('/' == enc[pos])
1659 enc[pos] = '_';
1660 if ('=' == enc[pos])
1661 {
1662 enc[pos] = '\0';
1663 break;
1664 }
1665 pos++;
1666 }
1667 return strlen (enc);
1668}
1669
1670
1671#define cvtfind(a) \
1672 ((((a) >= 'A') && ((a) <= 'Z')) \
1673 ? (a) - 'A' \
1674 : (((a) >= 'a') && ((a) <= 'z')) \
1675 ? (a) - 'a' + 26 \
1676 : (((a) >= '0') && ((a) <= '9')) \
1677 ? (a) - '0' + 52 \
1678 : ((a) == '+') ? 62 : ((a) == '/') ? 63 : -1)
1679
1680
1681size_t
1682GNUNET_STRINGS_base64_decode (const char *data,
1683 size_t len,
1684 void **out)
1685{
1686 char *output;
1687 size_t ret = 0;
1688
1689#define CHECK_CRLF \
1690 while (data[i] == '\r' || data[i] == '\n') \
1691 { \
1692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, \
1693 "ignoring CR/LF\n"); \
1694 i++; \
1695 if (i >= len) \
1696 goto END; \
1697 }
1698
1699 GNUNET_assert (len / 3 < SIZE_MAX);
1700 output = GNUNET_malloc ((len * 3 / 4) + 8);
1701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1702 "base64_decode decoding len=%d\n",
1703 (int) len);
1704 for (size_t i = 0; i < len; ++i)
1705 {
1706 char c;
1707 char c1;
1708
1709 CHECK_CRLF;
1710 if (FILLCHAR == data[i])
1711 break;
1712 c = (char) cvtfind (data[i]);
1713 ++i;
1714 CHECK_CRLF;
1715 c1 = (char) cvtfind (data[i]);
1716 c = (c << 2) | ((c1 >> 4) & 0x3);
1717 output[ret++] = c;
1718 if (++i < len)
1719 {
1720 CHECK_CRLF;
1721 c = data[i];
1722 if (FILLCHAR == c)
1723 break;
1724 c = (char) cvtfind (c);
1725 c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
1726 output[ret++] = c1;
1727 }
1728 if (++i < len)
1729 {
1730 CHECK_CRLF;
1731 c1 = data[i];
1732 if (FILLCHAR == c1)
1733 break;
1734
1735 c1 = (char) cvtfind (c1);
1736 c = ((c << 6) & 0xc0) | c1;
1737 output[ret++] = c;
1738 }
1739 }
1740END:
1741 *out = output;
1742 return ret;
1743}
1744
1745
1746size_t
1747GNUNET_STRINGS_base64url_decode (const char *data,
1748 size_t len,
1749 void **out)
1750{
1751 char *s;
1752 int padding;
1753 size_t ret;
1754
1755 /* make enough space for padding */
1756 GNUNET_assert (len < SIZE_MAX - 3);
1757 s = GNUNET_malloc (len + 3);
1758 memcpy (s, data, len);
1759
1760 for (int i = 0; i < strlen (s); i++)
1761 {
1762 if (s[i] == '-')
1763 s[i] = '+';
1764 if (s[i] == '_')
1765 s[i] = '/';
1766 }
1767 padding = len % 4;
1768 switch (padding) // Pad with trailing '='s
1769 {
1770 case 0:
1771 break; // No pad chars in this case
1772 case 2:
1773 memcpy (&s[len],
1774 "==",
1775 2);
1776 len += 2;
1777 break; // Two pad chars
1778 case 3:
1779 s[len] = '=';
1780 len++;
1781 break; // One pad char
1782 default:
1783 GNUNET_assert (0);
1784 break;
1785 }
1786 ret = GNUNET_STRINGS_base64_decode (s, len, out);
1787 GNUNET_free (s);
1788 return ret;
1789}
1790
1791
1792size_t
1793GNUNET_STRINGS_urldecode (const char *data,
1794 size_t len,
1795 char **out)
1796{
1797 const char *rpos = data;
1798 *out = GNUNET_malloc (len + 1); /* output should always fit into input */
1799 char *wpos = *out;
1800 size_t resl = 0;
1801
1802 while ('\0' != *rpos)
1803 {
1804 unsigned int num;
1805 switch (*rpos)
1806 {
1807 case '%':
1808 if (1 != sscanf (rpos + 1, "%2x", &num))
1809 break;
1810 *wpos = (char) ((unsigned char) num);
1811 wpos++;
1812 resl++;
1813 rpos += 3;
1814 break;
1815 /* TODO: add bad sequence handling */
1816 /* intentional fall through! */
1817 default:
1818 *wpos = *rpos;
1819 wpos++;
1820 resl++;
1821 rpos++;
1822 }
1823 }
1824 *wpos = '\0'; /* add 0-terminator */
1825 return resl;
1826}
1827
1828
1829size_t
1830GNUNET_STRINGS_urlencode (const char *data,
1831 size_t len,
1832 char **out)
1833{
1834 struct GNUNET_Buffer buf = { 0 };
1835 const uint8_t *i8 = (uint8_t *) data;
1836
1837 while (0 != *i8)
1838 {
1839 if (0 == (0x80 & *i8))
1840 {
1841 /* traditional ASCII */
1842 if (isalnum (*i8) || (*i8 == '-') || (*i8 == '_') || (*i8 == '.') ||
1843 (*i8 == '~') )
1844 GNUNET_buffer_write (&buf, (const char*) i8, 1);
1845 else if (*i8 == ' ')
1846 GNUNET_buffer_write (&buf, "+", 1);
1847 else
1848 GNUNET_buffer_write_fstr (&buf,
1849 "%%%X%X",
1850 *i8 >> 4,
1851 *i8 & 15);
1852 i8++;
1853 continue;
1854 }
1855 if (0x80 + 0x40 == ((0x80 + 0x40 + 0x20) & *i8))
1856 {
1857 /* 2-byte value, percent-encode */
1858 GNUNET_buffer_write_fstr (&buf,
1859 "%%%X%X",
1860 *i8 >> 4,
1861 *i8 & 15);
1862 i8++;
1863 GNUNET_buffer_write_fstr (&buf,
1864 "%%%X%X",
1865 *i8 >> 4,
1866 *i8 & 15);
1867 i8++;
1868 continue;
1869 }
1870 if (0x80 + 0x40 + 0x20 == ((0x80 + 0x40 + 0x20 + 0x10) & *i8))
1871 {
1872 /* 3-byte value, percent-encode */
1873 for (unsigned int i = 0; i<3; i++)
1874 {
1875 GNUNET_buffer_write_fstr (&buf,
1876 "%%%X%X",
1877 *i8 >> 4,
1878 *i8 & 15);
1879 i8++;
1880 }
1881 continue;
1882 }
1883 if (0x80 + 0x40 + 0x20 + 0x10 == ((0x80 + 0x40 + 0x20 + 0x10 + 0x08) & *i8))
1884 {
1885 /* 4-byte value, percent-encode */
1886 for (unsigned int i = 0; i<4; i++)
1887 {
1888 GNUNET_buffer_write_fstr (&buf,
1889 "%%%X%X",
1890 *i8 >> 4,
1891 *i8 & 15);
1892 i8++;
1893 }
1894 continue;
1895 }
1896 if (0x80 + 0x40 + 0x20 + 0x10 + 0x08 == ((0x80 + 0x40 + 0x20 + 0x10 + 0x08
1897 + 0x04) & *i8))
1898 {
1899 /* 5-byte value, percent-encode (outside of UTF-8 modern standard, but so what) */
1900 for (unsigned int i = 0; i<5; i++)
1901 {
1902 GNUNET_buffer_write_fstr (&buf,
1903 "%%%X%X",
1904 *i8 >> 4,
1905 *i8 & 15);
1906 i8++;
1907 }
1908 continue;
1909 }
1910 if (0x80 + 0x40 + 0x20 + 0x10 + 0x08 + 0x04 == ((0x80 + 0x40 + 0x20 + 0x10
1911 + 0x08 + 0x04 + 0x02)
1912 & *i8))
1913 {
1914 /* 6-byte value, percent-encode (outside of UTF-8 modern standard, but so what) */
1915 for (unsigned int i = 0; i<6; i++)
1916 {
1917 GNUNET_buffer_write_fstr (&buf,
1918 "%%%X%X",
1919 *i8 >> 4,
1920 *i8 & 15);
1921 i8++;
1922 }
1923 continue;
1924 }
1925 /* really, really invalid UTF-8: fail */
1926 GNUNET_break (0);
1927 GNUNET_buffer_clear (&buf);
1928 return 0;
1929 }
1930 *out = GNUNET_buffer_reap_str (&buf);
1931 return strlen (*out);
1932}
1933
1934
1935/* end of strings.c */
diff --git a/src/util/test_bio.c b/src/util/test_bio.c
deleted file mode 100644
index f18014719..000000000
--- a/src/util/test_bio.c
+++ /dev/null
@@ -1,476 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 util/test_bio.c
23 * @brief testcase for the buffered IO module
24 * @author Ji Lu
25 */
26
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#define TESTSTRING "testString"
31#define TESTNUMBER64 ((int64_t) 100000L)
32
33
34static int
35test_normal_rw (void)
36{
37 struct GNUNET_BIO_WriteHandle *wh;
38 struct GNUNET_BIO_ReadHandle *rh;
39 void *buffer;
40 size_t buffer_size = 0;
41 char *filename = GNUNET_DISK_mktemp ("gnunet-bio");
42 struct GNUNET_CONTAINER_MetaData *mdW;
43 struct GNUNET_CONTAINER_MetaData *mdR = NULL;
44 char *rString = NULL;
45 int64_t wNum = TESTNUMBER64;
46 int64_t rNum = 0;
47
48 mdW = GNUNET_CONTAINER_meta_data_create ();
49 GNUNET_CONTAINER_meta_data_add_publication_date (mdW);
50
51 struct GNUNET_BIO_WriteSpec ws[] = {
52 GNUNET_BIO_write_spec_string ("test-normal-rw-string", TESTSTRING),
53 GNUNET_BIO_write_spec_meta_data ("test-normal-rw-metadata", mdW),
54 GNUNET_BIO_write_spec_int64 ("test-normal-rw-int64", &wNum),
55 GNUNET_BIO_write_spec_end (),
56 };
57
58 struct GNUNET_BIO_ReadSpec rs[] = {
59 GNUNET_BIO_read_spec_string ("test-normal-rw-string", &rString, 200),
60 GNUNET_BIO_read_spec_meta_data ("test-normal-rw-metadata", &mdR),
61 GNUNET_BIO_read_spec_int64 ("test-normal-rw-int64", &rNum),
62 GNUNET_BIO_read_spec_end (),
63 };
64
65 /* I/O on file */
66 wh = GNUNET_BIO_write_open_file (filename);
67 GNUNET_assert (NULL != wh);
68 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_spec_commit (wh, ws));
69 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
70
71 rh = GNUNET_BIO_read_open_file (filename);
72 GNUNET_assert (NULL != rh);
73 GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_spec_commit (rh, rs));
74 GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
75 GNUNET_assert (0 == strcmp (TESTSTRING, rString));
76 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_meta_data_test_equal (mdR,
77 mdW));
78 GNUNET_assert (wNum == rNum);
79
80 GNUNET_CONTAINER_meta_data_destroy (mdR);
81 GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename));
82 GNUNET_free (filename);
83
84 /* I/O on buffer */
85 wh = GNUNET_BIO_write_open_buffer ();
86 GNUNET_assert (NULL != wh);
87 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_spec_commit (wh, ws));
88 GNUNET_assert (GNUNET_OK ==
89 GNUNET_BIO_get_buffer_contents (wh,
90 NULL,
91 &buffer,
92 &buffer_size));
93 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
94
95 rh = GNUNET_BIO_read_open_buffer (buffer, buffer_size);
96 GNUNET_assert (NULL != rh);
97 GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_spec_commit (rh, rs));
98 GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
99 GNUNET_assert (0 == strcmp (TESTSTRING, rString));
100 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_meta_data_test_equal (mdR,
101 mdW));
102 GNUNET_assert (wNum == rNum);
103
104 GNUNET_free (buffer);
105
106 GNUNET_CONTAINER_meta_data_destroy (mdW);
107 GNUNET_CONTAINER_meta_data_destroy (mdR);
108 return 0;
109}
110
111
112static int
113test_nullstring_rw (void)
114{
115 struct GNUNET_BIO_WriteHandle *wh;
116 struct GNUNET_BIO_ReadHandle *rh;
117 char *filename = GNUNET_DISK_mktemp ("gnunet_bio");
118 char *rString = "not null";
119
120 wh = GNUNET_BIO_write_open_file (filename);
121 GNUNET_assert (NULL != wh);
122 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (wh,
123 "test-nullstring-rw",
124 NULL));
125 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
126
127 rh = GNUNET_BIO_read_open_file (filename);
128 GNUNET_assert (NULL != rh);
129 GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_string (rh,
130 "test-nullstring-rw",
131 &rString, 200));
132 GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
133
134 GNUNET_assert (NULL == rString);
135
136 GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename));
137 GNUNET_free (filename);
138 return 0;
139}
140
141
142static int
143test_emptystring_rw (void)
144{
145 struct GNUNET_BIO_WriteHandle *wh;
146 struct GNUNET_BIO_ReadHandle *rh;
147 char *filename = GNUNET_DISK_mktemp ("gnunet_bio");
148 char *rString = NULL;
149
150 wh = GNUNET_BIO_write_open_file (filename);
151 GNUNET_assert (NULL != wh);
152 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (wh,
153 "test-emptystring-rw",
154 ""));
155 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
156
157 rh = GNUNET_BIO_read_open_file (filename);
158 GNUNET_assert (NULL != rh);
159 GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_string (rh,
160 "test-emptystring-rw",
161 &rString, 200));
162 GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
163
164 GNUNET_free (rString);
165
166 GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename));
167 GNUNET_free (filename);
168 return 0;
169}
170
171
172static int
173test_bigstring_rw (void)
174{
175 struct GNUNET_BIO_WriteHandle *wh;
176 struct GNUNET_BIO_ReadHandle *rh;
177 char *filename = GNUNET_DISK_mktemp ("gnunet_bio");
178 char *rString = NULL;
179
180 wh = GNUNET_BIO_write_open_file (filename);
181 GNUNET_assert (NULL != wh);
182 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (wh,
183 "test-bigstring-rw",
184 TESTSTRING));
185 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
186
187 rh = GNUNET_BIO_read_open_file (filename);
188 GNUNET_assert (NULL != rh);
189 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_string (rh,
190 "test-bigstring-rw",
191 &rString, 1));
192 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL));
193
194 GNUNET_assert (NULL == rString);
195
196 GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename));
197 GNUNET_free (filename);
198 return 0;
199}
200
201
202static int
203test_bigmeta_rw (void)
204{
205 static char meta[1024 * 1024 * 10];
206 struct GNUNET_BIO_WriteHandle *wh;
207 struct GNUNET_BIO_ReadHandle *rh;
208 char *filename = GNUNET_DISK_mktemp ("gnunet_bio");
209 struct GNUNET_CONTAINER_MetaData *mdR = NULL;
210
211 memset (meta, 'b', sizeof (meta));
212 meta[sizeof (meta) - 1] = '\0';
213
214 wh = GNUNET_BIO_write_open_file (filename);
215 GNUNET_assert (NULL != wh);
216 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (wh,
217 "test-bigmeta-rw-int32",
218 sizeof (meta)));
219 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write (wh,
220 "test-bigmeta-rw-bytes",
221 meta,
222 sizeof (meta)));
223 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
224
225 rh = GNUNET_BIO_read_open_file (filename);
226 GNUNET_assert (NULL != rh);
227 GNUNET_assert (GNUNET_SYSERR ==
228 GNUNET_BIO_read_meta_data (rh,
229 "test-bigmeta-rw-metadata",
230 &mdR));
231 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL));
232
233 GNUNET_assert (NULL == mdR);
234
235 GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename));
236 GNUNET_free (filename);
237 return 0;
238}
239
240
241static int
242test_directory_r (void)
243{
244#ifdef LINUX
245 struct GNUNET_BIO_ReadHandle *rh;
246 char rString[200];
247
248 rh = GNUNET_BIO_read_open_file ("/dev");
249 GNUNET_assert (NULL != rh);
250 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read (rh,
251 "test-directory-r",
252 rString,
253 sizeof (rString)));
254 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL));
255#endif
256 return 0;
257}
258
259
260static int
261test_nullfile_rw (void)
262{
263 static char filename[102401];
264 struct GNUNET_BIO_WriteHandle *wh;
265 struct GNUNET_BIO_ReadHandle *rh;
266
267 memset (filename, 'a', sizeof (filename));
268 filename[sizeof (filename) - 1] = '\0';
269
270 GNUNET_log_skip (2, GNUNET_NO);
271 wh = GNUNET_BIO_write_open_file (filename);
272 GNUNET_log_skip (0, GNUNET_YES);
273 GNUNET_assert (NULL == wh);
274
275 GNUNET_log_skip (2, GNUNET_NO);
276 rh = GNUNET_BIO_read_open_file (filename);
277 GNUNET_log_skip (0, GNUNET_YES);
278 GNUNET_assert (NULL == rh);
279
280 return 0;
281}
282
283
284static int
285test_fullfile_rw (void)
286{
287#ifdef LINUX
288 /* /dev/full doesn't exist on every platform */
289 struct GNUNET_BIO_WriteHandle *wh;
290 struct GNUNET_BIO_ReadHandle *rh;
291 char *rString = NULL;
292 char rResult[200];
293 struct GNUNET_CONTAINER_MetaData *mdW;
294 struct GNUNET_CONTAINER_MetaData *mdR = NULL;
295
296 mdW = GNUNET_CONTAINER_meta_data_create ();
297 GNUNET_CONTAINER_meta_data_add_publication_date (mdW);
298
299 struct GNUNET_BIO_WriteSpec ws[] = {
300 GNUNET_BIO_write_spec_object ("test-fullfile-rw-bytes",
301 TESTSTRING,
302 strlen (TESTSTRING)),
303 GNUNET_BIO_write_spec_string ("test-fullfile-rw-string",
304 TESTSTRING),
305 GNUNET_BIO_write_spec_meta_data ("test-fullfile-rw-metadata",
306 mdW),
307 GNUNET_BIO_write_spec_end (),
308 };
309
310 struct GNUNET_BIO_ReadSpec rs[] = {
311 GNUNET_BIO_read_spec_object ("test-fullfile-rw-bytes",
312 rResult,
313 sizeof (rResult)),
314 GNUNET_BIO_read_spec_string ("test-fullfile-rw-string",
315 &rString,
316 200),
317 GNUNET_BIO_read_spec_meta_data ("test-fullfile-rw-metadata",
318 &mdR),
319 GNUNET_BIO_read_spec_end (),
320 };
321
322 wh = GNUNET_BIO_write_open_file ("/dev/full");
323 GNUNET_assert (NULL != wh);
324 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_spec_commit (wh, ws));
325 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_close (wh, NULL));
326
327 rh = GNUNET_BIO_read_open_file ("/dev/null");
328 GNUNET_assert (NULL != rh);
329 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_spec_commit (rh, rs));
330 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL));
331
332 GNUNET_assert (NULL == rString);
333 GNUNET_assert (NULL == mdR);
334#endif
335 return 0;
336}
337
338
339static int
340test_fakestring_rw (void)
341{
342 struct GNUNET_BIO_WriteHandle *wh;
343 struct GNUNET_BIO_ReadHandle *rh;
344 char *filename = GNUNET_DISK_mktemp ("gnunet_bio");
345 char *rString = NULL;
346
347 wh = GNUNET_BIO_write_open_file (filename);
348 GNUNET_assert (NULL != wh);
349 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (wh,
350 "test-fakestring-rw-int32",
351 2));
352 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
353
354 rh = GNUNET_BIO_read_open_file (filename);
355 GNUNET_assert (NULL != rh);
356 GNUNET_assert (GNUNET_SYSERR ==
357 GNUNET_BIO_read_string (rh,
358 "test-fakestring-rw-string",
359 &rString, 200));
360 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL));
361
362 GNUNET_assert (NULL == rString);
363
364 GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename));
365 GNUNET_free (filename);
366 return 0;
367}
368
369
370static int
371test_fakemeta_rw (void)
372{
373 struct GNUNET_BIO_WriteHandle *wh;
374 struct GNUNET_BIO_ReadHandle *rh;
375 char *filename = GNUNET_DISK_mktemp ("gnunet_bio");
376 struct GNUNET_CONTAINER_MetaData *mdR = NULL;
377
378 wh = GNUNET_BIO_write_open_file (filename);
379 GNUNET_assert (NULL != wh);
380 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (wh,
381 "test-fakestring-rw-int32",
382 2));
383 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
384
385 rh = GNUNET_BIO_read_open_file (filename);
386 GNUNET_assert (NULL != rh);
387 GNUNET_assert (GNUNET_SYSERR ==
388 GNUNET_BIO_read_meta_data (rh,
389 "test-fakestring-rw-metadata",
390 &mdR));
391 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL));
392
393 GNUNET_assert (NULL == mdR);
394
395 GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename));
396 GNUNET_free (filename);
397 return 0;
398}
399
400
401static int
402test_fakebigmeta_rw (void)
403{
404 struct GNUNET_BIO_WriteHandle *wh;
405 struct GNUNET_BIO_ReadHandle *rh;
406 char *filename = GNUNET_DISK_mktemp ("gnunet_bio");
407 struct GNUNET_CONTAINER_MetaData *mdR = NULL;
408 int32_t wNum = 1024 * 1024 * 10;
409
410 wh = GNUNET_BIO_write_open_file (filename);
411 GNUNET_assert (NULL != wh);
412 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (wh,
413 "test-fakebigmeta-rw-int32",
414 wNum));
415 GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL));
416
417 rh = GNUNET_BIO_read_open_file (filename);
418 GNUNET_assert (NULL != rh);
419 GNUNET_assert (GNUNET_SYSERR ==
420 GNUNET_BIO_read_meta_data (rh,
421 "test-fakebigmeta-rw-metadata",
422 &mdR));
423 GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL));
424
425 GNUNET_assert (NULL == mdR);
426
427 GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename));
428 GNUNET_free (filename);
429 return 0;
430}
431
432
433static int
434check_string_rw (void)
435{
436 GNUNET_assert (0 == test_nullstring_rw ());
437 GNUNET_assert (0 == test_emptystring_rw ());
438 GNUNET_assert (0 == test_bigstring_rw ());
439 GNUNET_assert (0 == test_fakestring_rw ());
440 return 0;
441}
442
443
444static int
445check_metadata_rw (void)
446{
447 GNUNET_assert (0 == test_fakebigmeta_rw ());
448 GNUNET_assert (0 == test_fakemeta_rw ());
449 GNUNET_assert (0 == test_bigmeta_rw ());
450 return 0;
451}
452
453
454static int
455check_file_rw (void)
456{
457 GNUNET_assert (0 == test_normal_rw ());
458 GNUNET_assert (0 == test_nullfile_rw ());
459 GNUNET_assert (0 == test_fullfile_rw ());
460 GNUNET_assert (0 == test_directory_r ());
461 return 0;
462}
463
464
465int
466main (int argc, char *argv[])
467{
468 GNUNET_log_setup ("test-bio", "WARNING", NULL);
469 GNUNET_assert (0 == check_file_rw ());
470 GNUNET_assert (0 == check_metadata_rw ());
471 GNUNET_assert (0 == check_string_rw ());
472 return 0;
473}
474
475
476/* end of test_bio.c */
diff --git a/src/util/test_child_management.c b/src/util/test_child_management.c
deleted file mode 100644
index 62c143420..000000000
--- a/src/util/test_child_management.c
+++ /dev/null
@@ -1,177 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014-2021 GNUnet e.V.
4
5 GNUNET is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 3, or
8 (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
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public
16 License along with GNUNET; see the file COPYING. If not, see
17 <http://www.gnu.org/licenses/>
18*/
19
20/**
21 * @file lib/test_child_management.c
22 * @brief testcase to test the child management
23 * @author Christian Grothoff
24 * @author Dominik Meister
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29
30static struct GNUNET_ChildWaitHandle *cwh;
31
32static int global_ret;
33
34static struct GNUNET_OS_Process *pid;
35
36
37static void
38child_completed_callback (void *cls,
39 enum GNUNET_OS_ProcessStatusType type,
40 long unsigned int exit_code)
41{
42 cwh = NULL;
43 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
44 "Process extided with code: %lu \n",
45 exit_code);
46 FILE *file;
47 char code[9];
48
49 file = fopen ("child_management_test.txt", "r");
50 if (NULL == file)
51 {
52 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
53 "could not find file: child_management_test.txt in %s:%u\n",
54 __FILE__,
55 __LINE__);
56 global_ret = 1;
57 return;
58 }
59 if (0 == fscanf (file,
60 "%8s",
61 code))
62 {
63 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
64 "could not read file: child_management_test.txt in %s:%u\n",
65 __FILE__,
66 __LINE__);
67 global_ret = 1;
68 return;
69 }
70
71 if (0 != strcmp ("12345678", code))
72 {
73 global_ret = 1;
74 return;
75 }
76 GNUNET_OS_process_destroy (pid);
77 pid = NULL;
78 GNUNET_break (0 == unlink ("child_management_test.txt"));
79 GNUNET_SCHEDULER_shutdown ();
80 global_ret = 0;
81}
82
83
84static void
85do_shutdown (void *cls)
86{
87 if (NULL != cwh)
88 {
89 GNUNET_wait_child_cancel (cwh);
90 cwh = NULL;
91 }
92 if (NULL != pid)
93 {
94 GNUNET_assert (0 ==
95 GNUNET_OS_process_kill (pid,
96 SIGKILL));
97 GNUNET_assert (GNUNET_OK ==
98 GNUNET_OS_process_wait (pid));
99 GNUNET_OS_process_destroy (pid);
100 pid = NULL;
101 }
102}
103
104
105static void
106test_child_management (void *cls)
107{
108 const char *command = "./child_management_test.sh";
109 struct GNUNET_DISK_PipeHandle *p;
110 struct GNUNET_DISK_FileHandle *out;
111
112 (void) cls;
113 p = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
114 if (NULL == p)
115 {
116 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
117 "pipe");
118 global_ret = 2;
119 return;
120 }
121 pid = GNUNET_OS_start_process (0,
122 p,
123 NULL,
124 NULL,
125 command,
126 command,
127 "1234",
128 "5678",
129 NULL);
130 if (NULL == pid)
131 {
132 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
133 "fork");
134 GNUNET_break (GNUNET_OK ==
135 GNUNET_DISK_pipe_close (p));
136 global_ret = 1;
137 return;
138 }
139 GNUNET_break (GNUNET_OK ==
140 GNUNET_DISK_pipe_close_end (p,
141 GNUNET_DISK_PIPE_END_READ));
142 out = GNUNET_DISK_pipe_detach_end (p,
143 GNUNET_DISK_PIPE_END_WRITE);
144 GNUNET_assert (NULL != out);
145 GNUNET_break (GNUNET_OK ==
146 GNUNET_DISK_pipe_close (p));
147
148 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
149 NULL);
150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Alright");
151 cwh = GNUNET_wait_child (pid,
152 &child_completed_callback,
153 cls);
154 GNUNET_break (NULL != cwh);
155 GNUNET_assert (5 ==
156 GNUNET_DISK_file_write (out,
157 "Hello",
158 5));
159 GNUNET_break (GNUNET_OK ==
160 GNUNET_DISK_file_close (out));
161}
162
163
164int
165main (int argc,
166 const char *const argv[])
167{
168 GNUNET_log_setup (argv[0],
169 "DEBUG",
170 NULL);
171 GNUNET_SCHEDULER_run (&test_child_management,
172 NULL);
173 return global_ret;
174}
175
176
177/* end of test_anastasis_child_management.c */
diff --git a/src/util/test_client.c b/src/util/test_client.c
deleted file mode 100644
index ef5765fff..000000000
--- a/src/util/test_client.c
+++ /dev/null
@@ -1,196 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2016 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 * @file util/test_client.c
22 * @brief tests for client.c
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28static int global_ret;
29
30static struct GNUNET_MQ_Handle *client_mq;
31
32#define MY_TYPE 130
33
34
35/**
36 * Callback that just bounces the message back to the sender.
37 */
38static void
39handle_echo (void *cls,
40 const struct GNUNET_MessageHeader *message)
41{
42 struct GNUNET_SERVICE_Client *c = cls;
43 struct GNUNET_MQ_Handle *mq = GNUNET_SERVICE_client_get_mq (c);
44 struct GNUNET_MQ_Envelope *env;
45
46 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
47 "Receiving message from client, bouncing back\n");
48 env = GNUNET_MQ_msg_copy (message);
49 GNUNET_MQ_send (mq,
50 env);
51 GNUNET_SERVICE_client_continue (c);
52}
53
54
55static void
56handle_bounce (void *cls,
57 const struct GNUNET_MessageHeader *got)
58{
59 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
60 "Receiving bounce, checking content\n");
61 GNUNET_assert (NULL != got);
62 global_ret = 2;
63 GNUNET_MQ_destroy (client_mq);
64 client_mq = NULL;
65}
66
67
68/**
69 * Generic error handler, called with the appropriate error code and
70 * the same closure specified at the creation of the message queue.
71 * Not every message queue implementation supports an error handler.
72 *
73 * @param cls closure with the `struct GNUNET_STATISTICS_Handle *`
74 * @param error error code
75 */
76static void
77mq_error_handler (void *cls,
78 enum GNUNET_MQ_Error error)
79{
80 GNUNET_assert (0); /* should never happen */
81}
82
83
84static void
85task (void *cls,
86 const struct GNUNET_CONFIGURATION_Handle *cfg,
87 struct GNUNET_SERVICE_Handle *sh)
88{
89 struct GNUNET_MQ_MessageHandler chandlers[] = {
90 GNUNET_MQ_hd_fixed_size (bounce,
91 MY_TYPE,
92 struct GNUNET_MessageHeader,
93 cls),
94 GNUNET_MQ_handler_end ()
95 };
96 struct GNUNET_MQ_Envelope *env;
97 struct GNUNET_MessageHeader *msg;
98
99 /* test that ill-configured client fails instantly */
100 GNUNET_assert (NULL ==
101 GNUNET_CLIENT_connect (cfg,
102 "invalid-service",
103 NULL,
104 &mq_error_handler,
105 NULL));
106 client_mq = GNUNET_CLIENT_connect (cfg,
107 "test_client",
108 chandlers,
109 &mq_error_handler,
110 NULL);
111 GNUNET_assert (NULL != client_mq);
112 env = GNUNET_MQ_msg (msg,
113 MY_TYPE);
114 GNUNET_MQ_send (client_mq,
115 env);
116}
117
118
119/**
120 * Function called when the client connects to the service.
121 *
122 * @param cls the name of the service
123 * @param c connecting client
124 * @param mq message queue to talk to the client
125 * @return @a c
126 */
127static void *
128connect_cb (void *cls,
129 struct GNUNET_SERVICE_Client *c,
130 struct GNUNET_MQ_Handle *mq)
131{
132 return c;
133}
134
135
136/**
137 * Function called when the client disconnects.
138 *
139 * @param cls our service name
140 * @param c disconnecting client
141 * @param internal_cls must match @a c
142 */
143static void
144disconnect_cb (void *cls,
145 struct GNUNET_SERVICE_Client *c,
146 void *internal_cls)
147{
148 if (2 == global_ret)
149 {
150 GNUNET_SCHEDULER_shutdown ();
151 global_ret = 0;
152 }
153}
154
155
156int
157main (int argc,
158 char *argv[])
159{
160 struct GNUNET_MQ_MessageHandler shandlers[] = {
161 GNUNET_MQ_hd_fixed_size (echo,
162 MY_TYPE,
163 struct GNUNET_MessageHeader,
164 NULL),
165 GNUNET_MQ_handler_end ()
166 };
167 char *test_argv[] = {
168 (char *) "test_client",
169 "-c",
170 "test_client_data.conf",
171 NULL
172 };
173
174 GNUNET_log_setup ("test_client",
175 "WARNING",
176 NULL);
177 if (0 != strstr (argv[0],
178 "unix"))
179 test_argv[2] = "test_client_unix.conf";
180 global_ret = 1;
181 if (0 !=
182 GNUNET_SERVICE_run_ (3,
183 test_argv,
184 "test_client",
185 GNUNET_SERVICE_OPTION_NONE,
186 &task,
187 &connect_cb,
188 &disconnect_cb,
189 NULL,
190 shandlers))
191 global_ret = 3;
192 return global_ret;
193}
194
195
196/* end of test_client.c */
diff --git a/src/util/test_client_data.conf b/src/util/test_client_data.conf
deleted file mode 100644
index fa9a0be03..000000000
--- a/src/util/test_client_data.conf
+++ /dev/null
@@ -1,3 +0,0 @@
1[test_client]
2PORT=14325
3HOSTNAME=localhost
diff --git a/src/util/test_client_unix.conf b/src/util/test_client_unix.conf
deleted file mode 100644
index d3d90627d..000000000
--- a/src/util/test_client_unix.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1[test_client]
2PORT=0
3HOSTNAME=localhost
4UNIXPATH=$GNUNET_RUNTIME_DIR/test-client-unix.sock
5UNIX_MATCH_UID = YES
6UNIX_MATCH_GID = YES
diff --git a/src/util/test_common_allocation.c b/src/util/test_common_allocation.c
deleted file mode 100644
index 50f259257..000000000
--- a/src/util/test_common_allocation.c
+++ /dev/null
@@ -1,177 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2005, 2006, 2017 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 util/test_common_allocation.c
23 * @brief testcase for common_allocation.c
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28
29static int
30check (void)
31{
32#define MAX_TESTVAL 1024
33 char *ptrs[MAX_TESTVAL];
34 unsigned int **a2;
35 char ***a3;
36 char *tmp;
37 int i;
38 int j;
39 int k;
40 unsigned int ui;
41
42 /* GNUNET_malloc/GNUNET_free test */
43 k = 352; /* random start value */
44 for (i = 1; i < MAX_TESTVAL; i++)
45 {
46 ptrs[i] = GNUNET_malloc (i);
47 for (j = 0; j < i; j++)
48 ptrs[i][j] = k++;
49 }
50
51 for (i = MAX_TESTVAL - 1; i >= 1; i--)
52 {
53 for (j = i - 1; j >= 0; j--)
54 if (ptrs[i][j] != (char) --k)
55 return 1;
56 GNUNET_free (ptrs[i]);
57 }
58
59 /* GNUNET_free test */
60 tmp = GNUNET_malloc (4);
61 GNUNET_free (tmp);
62
63 /* GNUNET_strdup tests */
64 ptrs[0] = GNUNET_strdup ("bar");
65 if (0 != strcmp (ptrs[0], "bar"))
66 return 3;
67 /* now realloc */
68 ptrs[0] = GNUNET_realloc (ptrs[0], 12);
69 strcpy (ptrs[0], "Hello World");
70
71 GNUNET_free (ptrs[0]);
72 GNUNET_asprintf (&ptrs[0], "%s %s", "Hello", "World");
73 GNUNET_assert (strlen (ptrs[0]) == 11);
74 GNUNET_free (ptrs[0]);
75
76 /* GNUNET_array_grow tests */
77 ptrs[0] = NULL;
78 ui = 0;
79 GNUNET_array_grow (ptrs[0], ui, 42);
80 if (ui != 42)
81 return 4;
82 GNUNET_array_grow (ptrs[0], ui, 22);
83 if (ui != 22)
84 return 5;
85 for (j = 0; j < 22; j++)
86 ptrs[0][j] = j;
87 GNUNET_array_grow (ptrs[0], ui, 32);
88 for (j = 0; j < 22; j++)
89 if (ptrs[0][j] != j)
90 return 6;
91 for (j = 22; j < 32; j++)
92 if (ptrs[0][j] != 0)
93 return 7;
94 GNUNET_array_grow (ptrs[0], ui, 0);
95 if (i != 0)
96 return 8;
97 if (ptrs[0] != NULL)
98 return 9;
99
100 /* GNUNET_new_array_2d tests */
101 a2 = GNUNET_new_array_2d (17, 22, unsigned int);
102 for (i = 0; i < 17; i++)
103 {
104 for (j = 0; j < 22; j++)
105 {
106 if (0 != a2[i][j])
107 {
108 GNUNET_free (a2);
109 return 10;
110 }
111 a2[i][j] = i * 100 + j;
112 }
113 }
114 GNUNET_free (a2);
115
116 /* GNUNET_new_array_3d tests */
117 a3 = GNUNET_new_array_3d (2, 3, 4, char);
118 for (i = 0; i < 2; i++)
119 {
120 for (j = 0; j < 3; j++)
121 {
122 for (k = 0; k < 4; k++)
123 {
124 if (0 != a3[i][j][k])
125 {
126 GNUNET_free (a3);
127 return 11;
128 }
129 a3[i][j][k] = i * 100 + j * 10 + k;
130 }
131 }
132 }
133 GNUNET_free (a3);
134 return 0;
135}
136
137
138static int
139check2 (void)
140{
141 char *a1 = NULL;
142 unsigned int a1_len = 0;
143 const char *a2 = "test";
144
145 GNUNET_array_append (a1,
146 a1_len,
147 'x');
148 GNUNET_array_concatenate (a1,
149 a1_len,
150 a2,
151 4);
152 GNUNET_assert (0 == strncmp ("xtest",
153 a1,
154 5));
155 GNUNET_assert (5 == a1_len);
156 return 0;
157}
158
159
160int
161main (int argc, char *argv[])
162{
163 int ret;
164
165 GNUNET_log_setup ("test-common-allocation",
166 "WARNING",
167 NULL);
168 ret = check () | check2 ();
169 if (ret != 0)
170 fprintf (stderr,
171 "ERROR %d.\n",
172 ret);
173 return ret;
174}
175
176
177/* end of test_common_allocation.c */
diff --git a/src/util/test_common_endian.c b/src/util/test_common_endian.c
deleted file mode 100644
index 10a85a1bb..000000000
--- a/src/util/test_common_endian.c
+++ /dev/null
@@ -1,43 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_common_endian.c
22 * @brief testcase for common_endian.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27#define CHECK(n) if (n != GNUNET_htonll (GNUNET_ntohll (n))) return 1;
28
29int
30main (int argc, char *argv[])
31{
32 GNUNET_log_setup ("test-common-endian", "WARNING", NULL);
33 CHECK (1);
34 CHECK (0x12345678);
35 CHECK (123456789012345LL);
36 if ((0x1234567890ABCDEFLL != GNUNET_htonll (0xEFCDAB9078563412LL)) &&
37 (42 != htonl (42)) )
38 return 1;
39 return 0;
40}
41
42
43/* end of test_common_endian.c */
diff --git a/src/util/test_common_logging.c b/src/util/test_common_logging.c
deleted file mode 100644
index 7d7656ed8..000000000
--- a/src/util/test_common_logging.c
+++ /dev/null
@@ -1,99 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008 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 util/test_common_logging.c
23 * @brief testcase for the logging module
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29static void
30my_log (void *ctx, enum GNUNET_ErrorType kind, const char *component,
31 const char *date, const char *msg)
32{
33 unsigned int *c = ctx;
34
35 (*c)++;
36}
37
38
39int
40main (int argc, char *argv[])
41{
42 unsigned int failureCount = 0;
43 unsigned int logs = 0;
44
45 if (0 != putenv ("GNUNET_FORCE_LOG="))
46 fprintf (stderr, "Failed to putenv: %s\n", strerror (errno));
47 GNUNET_log_setup ("test-common-logging", "DEBUG", "/dev/null");
48 GNUNET_logger_add (&my_log, &logs);
49 GNUNET_logger_add (&my_log, &logs);
50 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n");
51 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n");
52 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n");
53 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n");
54 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n");
55 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n");
56 GNUNET_logger_remove (&my_log, &logs);
57 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Flusher...\n");
58 /* the last 6 calls should be merged (repated bulk messages!) */
59 GNUNET_logger_remove (&my_log, &logs);
60 if (logs != 4)
61 {
62 fprintf (stdout, "Expected 4 log calls, got %u\n", logs);
63 failureCount++;
64 }
65 GNUNET_break (0 ==
66 strcmp (_ ("ERROR"),
67 GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_ERROR)));
68 GNUNET_break (0 ==
69 strcmp (_ ("WARNING"),
70 GNUNET_error_type_to_string
71 (GNUNET_ERROR_TYPE_WARNING)));
72 GNUNET_break (0 ==
73 strcmp (_ ("INFO"),
74 GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_INFO)));
75 GNUNET_break (0 ==
76 strcmp (_ ("DEBUG"),
77 GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_DEBUG)));
78 GNUNET_log_setup ("test_common_logging", "WARNING", "/dev/null");
79 logs = 0;
80 GNUNET_logger_add (&my_log, &logs);
81 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Checker...\n");
82 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Drop me...\n");
83 GNUNET_logger_remove (&my_log, &logs);
84 if (logs != 1)
85 {
86 fprintf (stdout, "Expected 1 log call, got %u\n", logs);
87 failureCount++;
88 }
89
90 if (failureCount != 0)
91 {
92 fprintf (stdout, "%u TESTS FAILED!\n", failureCount);
93 return -1;
94 }
95 return 0;
96} /* end of main */
97
98
99/* end of test_common_logging.c */
diff --git a/src/util/test_common_logging_dummy.c b/src/util/test_common_logging_dummy.c
deleted file mode 100644
index c6c6411da..000000000
--- a/src/util/test_common_logging_dummy.c
+++ /dev/null
@@ -1,122 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008-2013 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 util/test_common_logging_dummy.c
23 * @brief dummy labrat for the testcase for the logging module (runtime
24 * log level adjustment)
25 * @author LRN
26 */
27#include "platform.h"
28#undef GNUNET_EXTRA_LOGGING
29#define GNUNET_EXTRA_LOGGING GNUNET_YES
30
31#include "gnunet_util_lib.h"
32
33/**
34 * Artificial delay attached to each log call that is not skipped out.
35 * This must be long enough for us to not to mistake skipped log call
36 * on a slow machine for a non-skipped one.
37 */
38#define OUTPUT_DELAY \
39 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS, 1000)
40
41static void
42my_log (void *ctx,
43 enum GNUNET_ErrorType kind,
44 const char *component,
45 const char *date,
46 const char *msg)
47{
48 (void) ctx;
49 (void) kind;
50 (void) component;
51 (void) date;
52 if (strncmp ("test-common-logging-dummy", component, 25) != 0)
53 return;
54 fprintf (stdout, "%s", msg);
55 fflush (stdout);
56}
57
58
59#if ! defined(GNUNET_CULL_LOGGING)
60static int
61expensive_func ()
62{
63 return GNUNET_NETWORK_socket_select (NULL, NULL, NULL, OUTPUT_DELAY);
64}
65
66
67#endif
68
69
70#define pr(kind, lvl) \
71 { \
72 struct GNUNET_TIME_Absolute t1, t2; \
73 t1 = GNUNET_TIME_absolute_get (); \
74 GNUNET_log (kind, "L%s %d\n", lvl, expensive_func ()); \
75 t2 = GNUNET_TIME_absolute_get (); \
76 printf ("1%s %llu\n", \
77 lvl, \
78 (unsigned long long) GNUNET_TIME_absolute_get_difference (t1, t2) \
79 .rel_value_us); \
80 }
81
82#define pr2(kind, lvl) \
83 { \
84 struct GNUNET_TIME_Absolute t1, t2; \
85 t1 = GNUNET_TIME_absolute_get (); \
86 GNUNET_log (kind, "L%s %d\n", lvl, expensive_func ()); \
87 t2 = GNUNET_TIME_absolute_get (); \
88 printf ("2%s %llu\n", \
89 lvl, \
90 (unsigned long long) GNUNET_TIME_absolute_get_difference (t1, t2) \
91 .rel_value_us); \
92 }
93
94
95int
96main (int argc, char *argv[])
97{
98 (void) argc;
99 (void) argv;
100 /* We set up logging with NULL level - will be overridden by
101 * GNUNET_LOG or GNUNET_FORCE_LOG at runtime.
102 */
103 GNUNET_log_setup ("test-common-logging-dummy", NULL, "/dev/null");
104 GNUNET_logger_add (&my_log, NULL);
105 pr (GNUNET_ERROR_TYPE_ERROR, "ERROR");
106 pr (GNUNET_ERROR_TYPE_WARNING, "WARNING");
107 pr (GNUNET_ERROR_TYPE_INFO, "INFO");
108 pr (GNUNET_ERROR_TYPE_DEBUG, "DEBUG");
109
110 /* We set up logging with WARNING level - will onle be overridden by
111 * GNUNET_FORCE_LOG at runtime.
112 */
113 GNUNET_log_setup ("test-common-logging-dummy", "WARNING", "/dev/null");
114 pr2 (GNUNET_ERROR_TYPE_ERROR, "ERROR");
115 pr2 (GNUNET_ERROR_TYPE_WARNING, "WARNING");
116 pr2 (GNUNET_ERROR_TYPE_INFO, "INFO");
117 pr2 (GNUNET_ERROR_TYPE_DEBUG, "DEBUG");
118 return 0;
119} /* end of main */
120
121
122/* end of test_common_logging_dummy.c */
diff --git a/src/util/test_common_logging_runtime_loglevels.c b/src/util/test_common_logging_runtime_loglevels.c
deleted file mode 100644
index 79cf9d53a..000000000
--- a/src/util/test_common_logging_runtime_loglevels.c
+++ /dev/null
@@ -1,456 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 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 util/test_common_logging_runtime_loglevels.c
23 * @brief testcase for the logging module (runtime log level adjustment)
24 * @author LRN
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define VERBOSE GNUNET_NO
30
31/**
32 * How much time the child is allowed to waste on skipped log calls, at most.
33 * Raspberry Pi takes 113 microseconds tops, this is 3x that value.
34 */
35#define MAX_SKIP_DELAY GNUNET_TIME_relative_multiply ( \
36 GNUNET_TIME_UNIT_MICROSECONDS, 400).rel_value_us
37
38/**
39 * How much time non-skipped log call should take, at least.
40 * Keep in sync with the value in the dummy!
41 */
42#define OUTPUT_DELAY GNUNET_TIME_relative_multiply ( \
43 GNUNET_TIME_UNIT_MICROSECONDS, 1000).rel_value_us
44
45static int ok;
46
47static int phase = 0;
48
49static struct GNUNET_OS_Process *proc;
50
51/* Pipe to read from started processes stdout (on read end) */
52static struct GNUNET_DISK_PipeHandle *pipe_stdout;
53
54static struct GNUNET_SCHEDULER_Task *die_task;
55
56static struct GNUNET_SCHEDULER_Task *read_task;
57
58static void
59runone (void);
60
61
62static void
63end_task (void *cls)
64{
65 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending phase %d, ok is %d\n", phase,
66 ok);
67 if (NULL != proc)
68 {
69 if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
70 {
71 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
72 }
73 GNUNET_OS_process_wait (proc);
74 GNUNET_OS_process_destroy (proc);
75 proc = NULL;
76 }
77 if (NULL != read_task)
78 {
79 GNUNET_SCHEDULER_cancel (read_task);
80 read_task = NULL;
81 }
82 GNUNET_DISK_pipe_close (pipe_stdout);
83 if (ok == 1)
84 {
85 if (phase < 9)
86 {
87 phase += 1;
88 runone ();
89 }
90 else
91 ok = 0;
92 }
93 else
94 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failing\n");
95}
96
97
98static char *
99read_output_line (int phase_from1, int phase_to1, int phase_from2,
100 int phase_to2, char c, const char *expect_level,
101 long delay_morethan, long delay_lessthan, int phase,
102 char *p,
103 int *len, long *delay, char level[8])
104{
105 char *r = p;
106 char t[7];
107 int i, j, stop = 0;
108 int level_matches;
109 int delay_is_sane;
110 int delay_is_a_dummy;
111 int delay_outside_of_range;
112
113 j = 0;
114 int stage = 0;
115
116 if (! ((phase >= phase_from1) && (phase <= phase_to1)) &&
117 ! ((phase >= phase_from2) && (phase <= phase_to2)))
118 return p;
119#if 0
120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
121 "Trying to match '%c%s \\d\\r\\n' on %s\n", c, expect_level, p);
122#endif
123 for (i = 0; i < *len && ! stop; i++)
124 {
125 switch (stage)
126 {
127 case 0: /* read first char */
128 if (r[i] != c)
129 {
130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected '%c', but got '%c'\n", c,
131 r[i]);
132 GNUNET_break (0);
133 return NULL;
134 }
135 stage += 1;
136 break;
137
138 case 1: /* read at most 7 char-long error level string, finished by ' ' */
139 if (r[i] == ' ')
140 {
141 level[j] = '\0';
142 stage += 1;
143 j = 0;
144 }
145 else if (i == 8)
146 {
147 GNUNET_break (0);
148 ok = 2;
149 return NULL;
150 }
151 else
152 level[j++] = r[i];
153 break;
154
155 case 2: /* read the delay, finished by '\n' */
156 t[j++] = r[i];
157 if (r[i] == '\n')
158 {
159 t[j - 1] = '\0';
160 *delay = strtol (t, NULL, 10);
161 stop = 1;
162 }
163 break;
164 }
165 }
166 level_matches = (strcmp (expect_level, level) == 0);
167 delay_is_sane = (*delay >= 0) && (*delay <= 1000000);
168 delay_is_a_dummy = (c == 'L');
169 /* Delay must be either less than 'lessthan' (log call is skipped)
170 * or more than 'morethan' (log call is not skipped)
171 */
172 delay_outside_of_range = ((*delay < delay_lessthan) || (*delay >=
173 delay_morethan));
174 if (delay_is_a_dummy)
175 delay_outside_of_range = 1;
176
177 if (! stop)
178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
179 "Wrong log format?\n");
180 if (! level_matches)
181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
182 "Wrong log level\n");
183 if (! delay_is_sane)
184 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
185 "Delay %ld is insane\n",
186 *delay);
187 if (! delay_outside_of_range)
188 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
189 "Delay %ld is not outside of range (%ld ; %ld)\n",
190 *delay,
191 delay_lessthan,
192 delay_morethan);
193 if (! stop || ! level_matches || ! delay_is_sane || ! delay_outside_of_range)
194 return NULL;
195 *len = *len - i;
196 return &r[i];
197}
198
199
200/**
201 * Up to 8 non-skipped GNUNET_log() calls
202 * + extra line with delay for each one
203 */
204#define LOG_MAX_NUM_LINES (8 * 2)
205/**
206 * Actual message is 17 chars at most
207 */
208#define LOG_MAX_LINE_LENGTH (17)
209
210#define LOG_BUFFER_SIZE LOG_MAX_NUM_LINES *LOG_MAX_LINE_LENGTH
211
212static char buf[LOG_BUFFER_SIZE];
213
214static char *buf_ptr;
215
216static int bytes;
217
218
219static void
220read_call (void *cls)
221{
222 const struct GNUNET_DISK_FileHandle *stdout_read_handle = cls;
223 char level[8];
224 long delay;
225 long delays[8];
226 int rd;
227
228 read_task = NULL;
229 rd = GNUNET_DISK_file_read (stdout_read_handle, buf_ptr,
230 sizeof(buf) - bytes);
231 if (rd > 0)
232 {
233 buf_ptr += rd;
234 bytes += rd;
235#if VERBOSE
236 fprintf (stderr, "got %d bytes, reading more\n", rd);
237#endif
238 read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
239 stdout_read_handle,
240 &read_call,
241 (void *) stdout_read_handle);
242 return;
243 }
244
245#if VERBOSE
246 fprintf (stderr, "bytes is %d:%s\n", bytes, buf);
247#endif
248
249 /* +------CHILD OUTPUT--
250 * | SOFT HARD
251 * | E W I D E W I D
252 * | 0E * * *
253 * | 1W * * * *
254 * P 2I * * * * *
255 * H 3D * * * * * *
256 * A
257 * S 4E * *
258 * E 5W * * * *
259 * | 6I * * * * * *
260 * | 7D * * * * * * * *
261 * | 8 * * * *
262 * | 9 * * * *
263 */char *p = buf;
264
265 if ((bytes == LOG_BUFFER_SIZE) ||
266 ! (p =
267 read_output_line (0, 3, 4, 9, 'L', "ERROR", -1,
268 1, phase, p,
269 &bytes, &delay, level)) ||
270 ! (p =
271 read_output_line (0, 3, 4, 9, '1', "ERROR", OUTPUT_DELAY,
272 MAX_SKIP_DELAY, phase, p,
273 &bytes, &delays[0], level)) ||
274 ! (p =
275 read_output_line (1, 3, 5, 9, 'L', "WARNING", -1,
276 1, phase, p,
277 &bytes, &delay, level)) ||
278 ! (p =
279 read_output_line (0, 3, 4, 9, '1', "WARNING", OUTPUT_DELAY,
280 MAX_SKIP_DELAY, phase, p,
281 &bytes, &delays[1], level)) ||
282 ! (p =
283 read_output_line (2, 3, 6, 7, 'L', "INFO", -1,
284 1, phase, p,
285 &bytes, &delay, level)) ||
286 ! (p =
287 read_output_line (0, 3, 4, 9, '1', "INFO", OUTPUT_DELAY,
288 MAX_SKIP_DELAY, phase, p,
289 &bytes, &delays[2], level)) ||
290 ! (p =
291 read_output_line (3, 3, 7, 7, 'L', "DEBUG", -1,
292 1, phase, p,
293 &bytes, &delay, level)) ||
294 ! (p =
295 read_output_line (0, 3, 4, 9, '1', "DEBUG", OUTPUT_DELAY,
296 MAX_SKIP_DELAY, phase, p,
297 &bytes, &delays[3], level)) ||
298 ! (p =
299 read_output_line (0, 3, 4, 9, 'L', "ERROR", -1,
300 1, phase, p,
301 &bytes, &delay, level)) ||
302 ! (p =
303 read_output_line (0, 3, 4, 9, '2', "ERROR", OUTPUT_DELAY,
304 MAX_SKIP_DELAY, phase, p,
305 &bytes, &delays[4], level)) ||
306 ! (p =
307 read_output_line (0, 3, 5, 9, 'L', "WARNING", -1,
308 1, phase, p,
309 &bytes, &delay, level)) ||
310 ! (p =
311 read_output_line (0, 3, 4, 9, '2', "WARNING", OUTPUT_DELAY,
312 MAX_SKIP_DELAY, phase, p,
313 &bytes, &delays[5], level)) ||
314 ! (p =
315 read_output_line (-1, -1, 6, 7, 'L', "INFO", -1,
316 1, phase, p,
317 &bytes, &delay, level)) ||
318 ! (p =
319 read_output_line (0, 3, 4, 9, '2', "INFO", OUTPUT_DELAY,
320 MAX_SKIP_DELAY, phase, p,
321 &bytes, &delays[6], level)) ||
322 ! (p =
323 read_output_line (-1, -1, 7, 7, 'L', "DEBUG", -1,
324 1, phase, p,
325 &bytes, &delay, level)) ||
326 ! (p =
327 read_output_line (0, 3, 4, 9, '2', "DEBUG", OUTPUT_DELAY,
328 MAX_SKIP_DELAY, phase, p,
329 &bytes, &delays[7], level)))
330 {
331 if (bytes == LOG_BUFFER_SIZE)
332 fprintf (stderr, "%s", "Ran out of buffer space!\n");
333 GNUNET_break (0);
334 ok = 2;
335 GNUNET_SCHEDULER_cancel (die_task);
336 GNUNET_SCHEDULER_add_now (&end_task, NULL);
337 return;
338 }
339
340 GNUNET_SCHEDULER_cancel (die_task);
341 GNUNET_SCHEDULER_add_now (&end_task, NULL);
342}
343
344
345static void
346runone ()
347{
348 const struct GNUNET_DISK_FileHandle *stdout_read_handle;
349
350 pipe_stdout = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
351
352 if (pipe_stdout == NULL)
353 {
354 GNUNET_break (0);
355 ok = 2;
356 return;
357 }
358
359 putenv ("GNUNET_LOG=");
360 putenv ("GNUNET_FORCE_LOG=");
361 putenv ("GNUNET_FORCE_LOGFILE=");
362 switch (phase)
363 {
364 case 0:
365 putenv ("GNUNET_LOG=;;;;ERROR");
366 break;
367
368 case 1:
369 putenv ("GNUNET_LOG=;;;;WARNING");
370 break;
371
372 case 2:
373 putenv ("GNUNET_LOG=;;;;INFO");
374 break;
375
376 case 3:
377 putenv ("GNUNET_LOG=;;;;DEBUG");
378 break;
379
380 case 4:
381 putenv ("GNUNET_FORCE_LOG=;;;;ERROR");
382 break;
383
384 case 5:
385 putenv ("GNUNET_FORCE_LOG=;;;;WARNING");
386 break;
387
388 case 6:
389 putenv ("GNUNET_FORCE_LOG=;;;;INFO");
390 break;
391
392 case 7:
393 putenv ("GNUNET_FORCE_LOG=;;;;DEBUG");
394 break;
395
396 case 8:
397 putenv ("GNUNET_LOG=blah;;;;ERROR");
398 break;
399
400 case 9:
401 putenv ("GNUNET_FORCE_LOG=blah;;;;ERROR");
402 break;
403 }
404
405 proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
406 NULL, pipe_stdout, NULL,
407 "./test_common_logging_dummy",
408 "test_common_logging_dummy", NULL);
409 GNUNET_assert (NULL != proc);
410 putenv ("GNUNET_FORCE_LOG=");
411 putenv ("GNUNET_LOG=");
412
413 /* Close the write end of the read pipe */
414 GNUNET_DISK_pipe_close_end (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
415
416 stdout_read_handle =
417 GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_READ);
418
419 die_task =
420 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
421 (GNUNET_TIME_UNIT_SECONDS, 10),
422 &end_task,
423 NULL);
424
425 bytes = 0;
426 buf_ptr = buf;
427 memset (&buf, 0, sizeof(buf));
428
429 read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
430 stdout_read_handle,
431 &read_call,
432 (void *) stdout_read_handle);
433}
434
435
436static void
437task (void *cls)
438{
439 phase = 0;
440 runone ();
441}
442
443
444int
445main (int argc, char *argv[])
446{
447 GNUNET_log_setup ("test-common-logging-runtime-loglevels",
448 "WARNING",
449 NULL);
450 ok = 1;
451 GNUNET_SCHEDULER_run (&task, &ok);
452 return ok;
453}
454
455
456/* end of test_common_logging_runtime_loglevels.c */
diff --git a/src/util/test_configuration.c b/src/util/test_configuration.c
deleted file mode 100644
index 823bf273d..000000000
--- a/src/util/test_configuration.c
+++ /dev/null
@@ -1,580 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2003, 2004, 2005, 2006, 2007 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 * @file util/test_configuration.c
22 * @brief Test that the configuration module works.
23 * @author Christian Grothoff
24 */
25
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29
30/* Test Configuration Diffs Options */
31enum
32{
33 EDIT_NOTHING,
34 EDIT_SECTION,
35 EDIT_ALL,
36 ADD_NEW_SECTION,
37 ADD_NEW_ENTRY,
38 REMOVE_SECTION,
39 REMOVE_ENTRY,
40 COMPARE,
41 PRINT
42};
43
44static struct GNUNET_CONFIGURATION_Handle *cfg;
45static struct GNUNET_CONFIGURATION_Handle *cfg_default;
46
47struct DiffsCBData
48{
49 struct GNUNET_CONFIGURATION_Handle *cfg;
50 struct GNUNET_CONFIGURATION_Handle *cfgDiffs;
51 const char *section;
52 int callBackOption;
53 int status;
54};
55
56
57static void
58initDiffsCBData (struct DiffsCBData *cbData)
59{
60 cbData->section = NULL;
61 cbData->cfg = NULL;
62 cbData->cfgDiffs = NULL;
63 cbData->callBackOption = -1;
64 cbData->status = 0;
65}
66
67
68/**
69 * callback function for modifying
70 * and comparing configuration
71 */
72static void
73diffsCallBack (void *cls,
74 const char *section,
75 const char *option,
76 const char *value)
77{
78 struct DiffsCBData *cbData = cls;
79 int cbOption = cbData->callBackOption;
80
81 if (0 == strcasecmp ("PATHS",
82 section))
83 return;
84 switch (cbOption)
85 {
86 case EDIT_SECTION:
87 if (NULL == cbData->section)
88 cbData->section = section;
89 if (strcmp (cbData->section, section) == 0)
90 {
91 GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, option,
92 "new-value");
93 GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section, option,
94 "new-value");
95 }
96 break;
97 case EDIT_ALL:
98 GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, option,
99 "new-value");
100 GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section, option,
101 "new-value");
102 break;
103 case ADD_NEW_ENTRY:
104 {
105 static int hit = 0;
106
107 if (hit == 0)
108 {
109 hit = 1;
110 GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, "new-key",
111 "new-value");
112 GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section,
113 "new-key", "new-value");
114 }
115 break;
116 }
117 case COMPARE:
118 {
119 int ret;
120 char *diffValue;
121
122 diffValue = NULL;
123 ret =
124 GNUNET_CONFIGURATION_get_value_string (cbData->cfgDiffs,
125 section,
126 option,
127 &diffValue);
128 if (NULL != diffValue)
129 {
130 if ( (ret == GNUNET_SYSERR) ||
131 (strcmp (diffValue, value) != 0) )
132 {
133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
134 "Unexpected value %s in %s/%s\n",
135 diffValue,
136 section,
137 option);
138 cbData->status = 1;
139 }
140 }
141 else
142 {
143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
144 "Unexpected value %s in %s/%s\n",
145 diffValue,
146 section,
147 option);
148 cbData->status = 1;
149 }
150 GNUNET_free (diffValue);
151 break;
152 }
153
154#if 0
155 case PRINT:
156 if (NULL == cbData->section)
157 {
158 cbData->section = section;
159 printf ("\nSection: %s\n", section);
160 }
161 else if (strcmp (cbData->section, section) != 0)
162 {
163 cbData->section = section;
164 printf ("\nSection: %s\n", section);
165 }
166 printf ("%s = %s\n", option, value);
167#endif
168 default:
169 break;
170 }
171}
172
173
174static struct GNUNET_CONFIGURATION_Handle *
175editConfiguration (struct GNUNET_CONFIGURATION_Handle *cfg,
176 int option)
177{
178 struct DiffsCBData diffsCB;
179
180 initDiffsCBData (&diffsCB);
181 diffsCB.cfgDiffs = GNUNET_CONFIGURATION_create ();
182
183 switch (option)
184 {
185 case EDIT_SECTION:
186 case EDIT_ALL:
187 case ADD_NEW_ENTRY:
188 diffsCB.callBackOption = option;
189 diffsCB.cfg = cfg;
190 GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &diffsCB);
191 break;
192
193 case EDIT_NOTHING:
194 /* Do nothing */
195 break;
196
197 case ADD_NEW_SECTION:
198 {
199 int i;
200 char *key;
201
202 for (i = 0; i < 5; i++)
203 {
204 GNUNET_asprintf (&key, "key%d", i);
205 GNUNET_CONFIGURATION_set_value_string (cfg, "new-section", key,
206 "new-value");
207 GNUNET_CONFIGURATION_set_value_string (diffsCB.cfgDiffs, "new-section",
208 key, "new-value");
209 GNUNET_free (key);
210 }
211 break;
212 }
213
214 case REMOVE_SECTION:
215 break;
216
217 case REMOVE_ENTRY:
218 break;
219
220 default:
221 break;
222 }
223
224 return diffsCB.cfgDiffs;
225}
226
227
228/**
229 * Checking configuration diffs
230 */
231static int
232checkDiffs (struct GNUNET_CONFIGURATION_Handle *cfg_default, int option)
233{
234 struct GNUNET_CONFIGURATION_Handle *cfg;
235 struct GNUNET_CONFIGURATION_Handle *cfgDiffs;
236 struct DiffsCBData cbData;
237 int ret;
238 char *diffsFileName;
239
240 initDiffsCBData (&cbData);
241
242 cfg = GNUNET_CONFIGURATION_create ();
243 /* load defaults */
244 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (cfg, NULL));
245
246 /* Modify configuration and save it */
247 cfgDiffs = editConfiguration (cfg, option);
248 diffsFileName = GNUNET_DISK_mktemp ("gnunet-test-configurations-diffs.conf");
249 if (diffsFileName == NULL)
250 {
251 GNUNET_break (0);
252 GNUNET_CONFIGURATION_destroy (cfg);
253 GNUNET_CONFIGURATION_destroy (cfgDiffs);
254 return 1;
255 }
256 GNUNET_CONFIGURATION_write_diffs (cfg_default, cfg, diffsFileName);
257 GNUNET_CONFIGURATION_destroy (cfg);
258
259 /* Compare the dumped configuration with modifications done */
260 cfg = GNUNET_CONFIGURATION_create ();
261 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, diffsFileName));
262 if (0 != remove (diffsFileName))
263 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "remove",
264 diffsFileName);
265 cbData.callBackOption = COMPARE;
266 cbData.cfgDiffs = cfgDiffs;
267 GNUNET_CONFIGURATION_iterate (cfg,
268 &diffsCallBack,
269 &cbData);
270 if (1 == (ret = cbData.status))
271 {
272 fprintf (stderr, "%s",
273 "Incorrect Configuration Diffs: Diffs may contain data not actually edited\n");
274 goto housekeeping;
275 }
276 cbData.cfgDiffs = cfg;
277 GNUNET_CONFIGURATION_iterate (cfgDiffs, diffsCallBack, &cbData);
278 if ((ret = cbData.status) == 1)
279 fprintf (stderr, "%s",
280 "Incorrect Configuration Diffs: Data may be missing in diffs\n");
281
282housekeeping:
283#if 0
284 cbData.section = NULL;
285 cbData.callBackOption = PRINT;
286 printf ("\nExpected Diffs:\n");
287 GNUNET_CONFIGURATION_iterate (cfgDiffs, diffsCallBack, &cbData);
288 cbData.section = NULL;
289 printf ("\nActual Diffs:\n");
290 GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &cbData);
291#endif
292 GNUNET_CONFIGURATION_destroy (cfg);
293 GNUNET_CONFIGURATION_destroy (cfgDiffs);
294 GNUNET_free (diffsFileName);
295 return ret;
296}
297
298
299static int
300testConfig ()
301{
302 char *c;
303 unsigned long long l;
304
305 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "test", "b", &c))
306 return 1;
307 if (0 != strcmp ("b", c))
308 {
309 fprintf (stderr, "Got `%s'\n", c);
310 GNUNET_free (c);
311 return 2;
312 }
313 GNUNET_free (c);
314 if (GNUNET_OK !=
315 GNUNET_CONFIGURATION_get_value_number (cfg, "test", "five", &l))
316 {
317 GNUNET_break (0);
318 return 3;
319 }
320 if (5 != l)
321 {
322 GNUNET_break (0);
323 return 4;
324 }
325 GNUNET_CONFIGURATION_set_value_string (cfg, "more", "c", "YES");
326 if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno (cfg, "more", "c"))
327 {
328 GNUNET_break (0);
329 return 5;
330 }
331 GNUNET_CONFIGURATION_set_value_number (cfg, "NUMBERS", "TEN", 10);
332 if (GNUNET_OK !=
333 GNUNET_CONFIGURATION_get_value_string (cfg, "NUMBERS", "TEN", &c))
334 {
335 GNUNET_break (0);
336 return 6;
337 }
338 if (0 != strcmp (c, "10"))
339 {
340 GNUNET_free (c);
341 GNUNET_break (0);
342 return 7;
343 }
344 GNUNET_free (c);
345
346 if (GNUNET_OK !=
347 GNUNET_CONFIGURATION_get_value_filename (cfg, "last", "test", &c))
348 {
349 GNUNET_break (0);
350 return 8;
351 }
352
353 if (0 != strcmp (c, "/hello/world"))
354 {
355 GNUNET_break (0);
356 GNUNET_free (c);
357 return 9;
358 }
359 GNUNET_free (c);
360
361 if (GNUNET_OK !=
362 GNUNET_CONFIGURATION_get_value_size (cfg, "last", "size", &l))
363 {
364 GNUNET_break (0);
365 return 10;
366 }
367 if (l != 512 * 1024)
368 {
369 GNUNET_break (0);
370 return 11;
371 }
372 return 0;
373}
374
375
376static const char *want[] = {
377 "/Hello",
378 "/File Name",
379 "/World",
380 NULL,
381 NULL,
382};
383
384static int
385check (void *data, const char *fn)
386{
387 int *idx = data;
388
389 if (0 == strcmp (want[*idx], fn))
390 {
391 (*idx)++;
392 return GNUNET_OK;
393 }
394 GNUNET_break (0);
395 return GNUNET_SYSERR;
396}
397
398
399static int
400testConfigFilenames ()
401{
402 int idx;
403
404 idx = 0;
405 if (3 !=
406 GNUNET_CONFIGURATION_iterate_value_filenames (cfg, "FILENAMES", "test",
407 &check, &idx))
408 {
409 GNUNET_break (0);
410 return 8;
411 }
412 if (idx != 3)
413 return 16;
414 if (GNUNET_OK !=
415 GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test",
416 "/File Name"))
417 {
418 GNUNET_break (0);
419 return 24;
420 }
421
422 if (GNUNET_NO !=
423 GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test",
424 "/File Name"))
425 {
426 GNUNET_break (0);
427 return 32;
428 }
429 if (GNUNET_NO !=
430 GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test",
431 "Stuff"))
432 {
433 GNUNET_break (0);
434 return 40;
435 }
436
437 if (GNUNET_NO !=
438 GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test",
439 "/Hello"))
440 {
441 GNUNET_break (0);
442 return 48;
443 }
444 if (GNUNET_NO !=
445 GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test",
446 "/World"))
447 {
448 GNUNET_break (0);
449 return 56;
450 }
451
452 if (GNUNET_YES !=
453 GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test",
454 "/File 1"))
455 {
456 GNUNET_break (0);
457 return 64;
458 }
459
460 if (GNUNET_YES !=
461 GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test",
462 "/File 2"))
463 {
464 GNUNET_break (0);
465 return 72;
466 }
467
468 idx = 0;
469 want[1] = "/World";
470 want[2] = "/File 1";
471 want[3] = "/File 2";
472 if (4 !=
473 GNUNET_CONFIGURATION_iterate_value_filenames (cfg, "FILENAMES", "test",
474 &check, &idx))
475 {
476 GNUNET_break (0);
477 return 80;
478 }
479 if (idx != 4)
480 {
481 GNUNET_break (0);
482 return 88;
483 }
484 return 0;
485}
486
487
488int
489main (int argc, char *argv[])
490{
491 int failureCount = 0;
492 char *c;
493
494 GNUNET_log_setup ("test_configuration", "WARNING", NULL);
495 cfg = GNUNET_CONFIGURATION_create ();
496 GNUNET_assert (cfg != NULL);
497 if (GNUNET_OK !=
498 GNUNET_CONFIGURATION_parse (cfg, "test_configuration_data.conf"))
499 {
500 fprintf (stderr, "%s", "Failed to parse configuration file\n");
501 GNUNET_CONFIGURATION_destroy (cfg);
502 return 1;
503 }
504 failureCount += testConfig ();
505 if (failureCount > 0)
506 goto error;
507
508 failureCount = testConfigFilenames ();
509 if (failureCount > 0)
510 goto error;
511
512 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, "/tmp/gnunet-test.conf"))
513 {
514 fprintf (stderr, "%s", "Failed to write configuration file\n");
515 GNUNET_CONFIGURATION_destroy (cfg);
516 return 1;
517 }
518 GNUNET_CONFIGURATION_destroy (cfg);
519 GNUNET_assert (0 == unlink ("/tmp/gnunet-test.conf"));
520
521 cfg = GNUNET_CONFIGURATION_create ();
522 if (GNUNET_OK !=
523 GNUNET_CONFIGURATION_load (cfg, "test_configuration_data.conf"))
524 {
525 GNUNET_break (0);
526 GNUNET_CONFIGURATION_destroy (cfg);
527 return 1;
528 }
529 if (GNUNET_OK !=
530 GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "WEAKRANDOM", &c))
531 {
532 GNUNET_break (0);
533 GNUNET_CONFIGURATION_destroy (cfg);
534 return 1;
535 }
536 if (0 != strcmp (c, "YES"))
537 {
538 GNUNET_break (0);
539 GNUNET_free (c);
540 GNUNET_CONFIGURATION_destroy (cfg);
541 return 1;
542 }
543
544 GNUNET_free (c);
545 GNUNET_CONFIGURATION_destroy (cfg);
546
547 /* Testing configuration diffs */
548 cfg_default = GNUNET_CONFIGURATION_create ();
549 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg_default, NULL))
550 {
551 GNUNET_break (0);
552 GNUNET_CONFIGURATION_destroy (cfg_default);
553 return 1;
554 }
555
556 /* Nothing changed in the new configuration */
557 failureCount += checkDiffs (cfg_default, EDIT_NOTHING);
558
559 /* Modify all entries of the last section */
560 failureCount += checkDiffs (cfg_default, EDIT_SECTION);
561
562 /* Add a new section */
563 failureCount += checkDiffs (cfg_default, ADD_NEW_SECTION);
564
565 /* Add a new entry to the last section */
566 failureCount += checkDiffs (cfg_default, ADD_NEW_ENTRY);
567
568 /* Modify all entries in the configuration */
569 failureCount += checkDiffs (cfg_default, EDIT_ALL);
570
571 GNUNET_CONFIGURATION_destroy (cfg_default);
572
573error:
574 if (failureCount != 0)
575 {
576 fprintf (stderr, "Test failed: %u\n", failureCount);
577 return 1;
578 }
579 return 0;
580}
diff --git a/src/util/test_configuration_data.conf b/src/util/test_configuration_data.conf
deleted file mode 100644
index 93dfd128a..000000000
--- a/src/util/test_configuration_data.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1[PATHS]
2SUBST=/hello
3
4[GNUNET]
5SUBST=hello
6GNUNET_HOME=$GNUNET_TMP/test-hello-configuration-data/
7
8[test]
9a=a
10b=b
11five=5
12
13[more]
14c=c
15five=42
16
17
18[last]
19test = $SUBST/world
20boom = "1 2 3 testing"
21trailing = YES
22size = 512 KiB
23
24[FILENAMES]
25test = "/Hello /File\ Name /World"
26
27
28[TESTING]
29WEAKRANDOM = YES
30
diff --git a/src/util/test_container_bloomfilter.c b/src/util/test_container_bloomfilter.c
deleted file mode 100644
index 67fbaf38b..000000000
--- a/src/util/test_container_bloomfilter.c
+++ /dev/null
@@ -1,253 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2004, 2009 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 * @file util/test_container_bloomfilter.c
22 * @brief Testcase for the bloomfilter.
23 * @author Christian Grothoff
24 * @author Igor Wronsky
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30#define K 4
31#define SIZE 65536
32#define TESTFILE "/tmp/bloomtest.dat"
33
34/**
35 * Generate a random hashcode.
36 */
37static void
38nextHC (struct GNUNET_HashCode *hc)
39{
40 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, hc);
41}
42
43
44static int
45add_iterator (void *cls, struct GNUNET_HashCode *next)
46{
47 int *ret = cls;
48 struct GNUNET_HashCode pos;
49
50 if (0 == (*ret)--)
51 return GNUNET_NO;
52 nextHC (&pos);
53 *next = pos;
54 return GNUNET_YES;
55}
56
57
58int
59main (int argc, char *argv[])
60{
61 struct GNUNET_CONTAINER_BloomFilter *bf;
62 struct GNUNET_CONTAINER_BloomFilter *bfi;
63 struct GNUNET_HashCode tmp;
64 int i;
65 int ok1;
66 int ok2;
67 int falseok;
68 char buf[SIZE];
69 struct stat sbuf;
70
71 GNUNET_log_setup ("test-container-bloomfilter", "WARNING", NULL);
72 GNUNET_CRYPTO_seed_weak_random (1);
73 if (0 == stat (TESTFILE, &sbuf))
74 if (0 != unlink (TESTFILE))
75 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", TESTFILE);
76 bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K);
77
78 for (i = 0; i < 200; i++)
79 {
80 nextHC (&tmp);
81 GNUNET_CONTAINER_bloomfilter_add (bf, &tmp);
82 }
83 GNUNET_CRYPTO_seed_weak_random (1);
84 ok1 = 0;
85 for (i = 0; i < 200; i++)
86 {
87 nextHC (&tmp);
88 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
89 ok1++;
90 }
91 if (ok1 != 200)
92 {
93 printf ("Got %d elements out of"
94 "200 expected after insertion.\n",
95 ok1);
96 GNUNET_CONTAINER_bloomfilter_free (bf);
97 return -1;
98 }
99 if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_get_raw_data (bf, buf, SIZE))
100 {
101 GNUNET_CONTAINER_bloomfilter_free (bf);
102 return -1;
103 }
104
105 GNUNET_CONTAINER_bloomfilter_free (bf);
106
107 bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K);
108 GNUNET_assert (bf != NULL);
109 bfi = GNUNET_CONTAINER_bloomfilter_init (buf, SIZE, K);
110 GNUNET_assert (bfi != NULL);
111
112 GNUNET_CRYPTO_seed_weak_random (1);
113 ok1 = 0;
114 ok2 = 0;
115 for (i = 0; i < 200; i++)
116 {
117 nextHC (&tmp);
118 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
119 ok1++;
120 if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES)
121 ok2++;
122 }
123 if (ok1 != 200)
124 {
125 printf ("Got %d elements out of 200 "
126 "expected after reloading.\n",
127 ok1);
128 GNUNET_CONTAINER_bloomfilter_free (bf);
129 GNUNET_CONTAINER_bloomfilter_free (bfi);
130 return -1;
131 }
132
133 if (ok2 != 200)
134 {
135 printf ("Got %d elements out of 200 "
136 "expected after initialization.\n",
137 ok2);
138 GNUNET_CONTAINER_bloomfilter_free (bf);
139 GNUNET_CONTAINER_bloomfilter_free (bfi);
140 return -1;
141 }
142
143 GNUNET_CRYPTO_seed_weak_random (1);
144 for (i = 0; i < 100; i++)
145 {
146 nextHC (&tmp);
147 GNUNET_CONTAINER_bloomfilter_remove (bf, &tmp);
148 GNUNET_CONTAINER_bloomfilter_remove (bfi, &tmp);
149 }
150
151 GNUNET_CRYPTO_seed_weak_random (1);
152
153 ok1 = 0;
154 ok2 = 0;
155 for (i = 0; i < 200; i++)
156 {
157 nextHC (&tmp);
158 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
159 ok1++;
160 if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES)
161 ok2++;
162 }
163
164 if (ok1 != 100)
165 {
166 printf ("Expected 100 elements in loaded filter"
167 " after adding 200 and deleting 100, got %d\n",
168 ok1);
169 GNUNET_CONTAINER_bloomfilter_free (bf);
170 GNUNET_CONTAINER_bloomfilter_free (bfi);
171 return -1;
172 }
173 if (ok2 != 200)
174 {
175 printf ("Expected 200 elements in initialized filter"
176 " after adding 200 and deleting 100 "
177 "(which should do nothing for a filter not backed by a file), got %d\n",
178 ok2);
179 GNUNET_CONTAINER_bloomfilter_free (bf);
180 GNUNET_CONTAINER_bloomfilter_free (bfi);
181 return -1;
182 }
183
184 GNUNET_CRYPTO_seed_weak_random (3);
185
186 GNUNET_CONTAINER_bloomfilter_clear (bf);
187 falseok = 0;
188 for (i = 0; i < 1000; i++)
189 {
190 nextHC (&tmp);
191 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
192 falseok++;
193 }
194 if (falseok > 0)
195 {
196 GNUNET_CONTAINER_bloomfilter_free (bf);
197 GNUNET_CONTAINER_bloomfilter_free (bfi);
198 return -1;
199 }
200
201 if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_or (bf, buf, SIZE))
202 {
203 GNUNET_CONTAINER_bloomfilter_free (bf);
204 GNUNET_CONTAINER_bloomfilter_free (bfi);
205 return -1;
206 }
207
208 GNUNET_CRYPTO_seed_weak_random (2);
209 i = 20;
210 GNUNET_CONTAINER_bloomfilter_resize (bfi, &add_iterator, &i, SIZE * 2, K);
211
212 GNUNET_CRYPTO_seed_weak_random (2);
213 i = 20;
214 GNUNET_CONTAINER_bloomfilter_resize (bf, &add_iterator, &i, SIZE * 2, K);
215 GNUNET_CRYPTO_seed_weak_random (2);
216
217 ok1 = 0;
218 ok2 = 0;
219 for (i = 0; i < 20; i++)
220 {
221 nextHC (&tmp);
222 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
223 ok1++;
224 if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES)
225 ok2++;
226 }
227
228 if (ok1 != 20)
229 {
230 printf ("Expected 20 elements in resized file-backed filter"
231 " after adding 20, got %d\n",
232 ok1);
233 GNUNET_CONTAINER_bloomfilter_free (bf);
234 GNUNET_CONTAINER_bloomfilter_free (bfi);
235 return -1;
236 }
237 if (ok2 != 20)
238 {
239 printf ("Expected 20 elements in resized filter"
240 " after adding 20, got %d\n",
241 ok2);
242 GNUNET_CONTAINER_bloomfilter_free (bf);
243 GNUNET_CONTAINER_bloomfilter_free (bfi);
244 return -1;
245 }
246
247
248 GNUNET_CONTAINER_bloomfilter_free (bf);
249 GNUNET_CONTAINER_bloomfilter_free (bfi);
250
251 GNUNET_break (0 == unlink (TESTFILE));
252 return 0;
253}
diff --git a/src/util/test_container_dll.c b/src/util/test_container_dll.c
deleted file mode 100644
index 33671d00b..000000000
--- a/src/util/test_container_dll.c
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2017 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 * @author Christian Grothoff
23 * @file util/test_container_dll.c
24 * @brief Test of DLL operations
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30/**
31 * Element in the DLL.
32 */
33struct Element
34{
35 /**
36 * Required pointer to previous element.
37 */
38 struct Element *prev;
39
40 /**
41 * Required pointer to next element.
42 */
43 struct Element *next;
44
45 /**
46 * Used to sort.
47 */
48 unsigned int value;
49};
50
51
52/**
53 * Compare two elements.
54 *
55 * @param cls closure, NULL
56 * @param e1 an element of to sort
57 * @param e2 another element to sort
58 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
59 */
60static int
61cmp_elem (void *cls,
62 struct Element *e1,
63 struct Element *e2)
64{
65 if (e1->value == e2->value)
66 return 0;
67 return (e1->value < e2->value) ? 1 : -1;
68}
69
70
71int
72main (int argc, char **argv)
73{
74 unsigned int values[] = {
75 4, 5, 8, 6, 9, 3, 7, 2, 1, 0
76 };
77 struct Element *head = NULL;
78 struct Element *tail = NULL;
79 struct Element *e;
80 unsigned int want;
81
82 GNUNET_log_setup ("test-container-dll",
83 "WARNING",
84 NULL);
85 for (unsigned int off = 0;
86 0 != values[off];
87 off++)
88 {
89 e = GNUNET_new (struct Element);
90 e->value = values[off];
91 GNUNET_CONTAINER_DLL_insert_sorted (struct Element,
92 cmp_elem,
93 NULL,
94 head,
95 tail,
96 e);
97 }
98
99 want = 1;
100 while (NULL != (e = head))
101 {
102 GNUNET_assert (e->value == want);
103 GNUNET_CONTAINER_DLL_remove (head,
104 tail,
105 e);
106 GNUNET_free (e);
107 want++;
108 }
109 return 0;
110}
111
112
113/* end of test_container_heap.c */
diff --git a/src/util/test_container_heap.c b/src/util/test_container_heap.c
deleted file mode 100644
index c83c7810f..000000000
--- a/src/util/test_container_heap.c
+++ /dev/null
@@ -1,293 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008 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 * @author Nathan Evans
23 * @file util/test_container_heap.c
24 * @brief Test of heap operations
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30static int
31iterator_callback (void *cls,
32 struct GNUNET_CONTAINER_HeapNode *node,
33 void *element, GNUNET_CONTAINER_HeapCostType cost)
34{
35 return GNUNET_OK;
36}
37
38
39static int
40nstrcmp (const char *a, const char *b)
41{
42 GNUNET_assert (a != NULL);
43 GNUNET_assert (b != NULL);
44 return strcmp (a, b);
45}
46
47
48static int
49check ()
50{
51 struct GNUNET_CONTAINER_Heap *myHeap;
52 struct GNUNET_CONTAINER_HeapNode *n1;
53 struct GNUNET_CONTAINER_HeapNode *n2;
54 struct GNUNET_CONTAINER_HeapNode *n3;
55 struct GNUNET_CONTAINER_HeapNode *n4;
56 struct GNUNET_CONTAINER_HeapNode *n5;
57 struct GNUNET_CONTAINER_HeapNode *n6;
58 struct GNUNET_CONTAINER_HeapNode *n7;
59 struct GNUNET_CONTAINER_HeapNode *n8;
60 const char *r;
61
62 myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
63
64 // GNUNET_CONTAINER_heap_remove_root heap empty, taking if-branch
65 n1 = GNUNET_CONTAINER_heap_remove_root (myHeap);
66 GNUNET_assert (NULL == n1);
67
68 // GNUNET_CONTAINER_heap_peek heap empty, taking if-branch
69 n1 = GNUNET_CONTAINER_heap_peek (myHeap);
70 GNUNET_assert (NULL == n1);
71
72 // GNUNET_CONTAINER_heap_walk_get_next: heap empty, taking if-branch
73 n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap);
74 GNUNET_assert (NULL == n1);
75
76 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "11", 11);
77 GNUNET_assert (NULL != n1);
78
79
80 // GNUNET_CONTAINER_heap_peek not empty, taking if-branch
81 n2 = NULL;
82 n2 = GNUNET_CONTAINER_heap_peek (myHeap);
83 GNUNET_assert (NULL != n2);
84
85 // GNUNET_CONTAINER_heap_walk_get_next: 1 element
86 n1 = NULL;
87 n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap);
88 GNUNET_assert (NULL != n1);
89
90 GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL);
91 GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap));
92 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "78", 78);
93 GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap));
94 GNUNET_assert (0 == strcmp ("78", GNUNET_CONTAINER_heap_remove_node (n2)));
95 GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap));
96 GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL);
97
98 n3 = GNUNET_CONTAINER_heap_insert (myHeap, "15", 5);
99 GNUNET_CONTAINER_heap_update_cost (n3, 15);
100 GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap));
101 GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL);
102
103 n4 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50);
104 GNUNET_CONTAINER_heap_update_cost (n4, 50);
105 GNUNET_assert (3 == GNUNET_CONTAINER_heap_get_size (myHeap));
106 GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL);
107
108 n5 = GNUNET_CONTAINER_heap_insert (myHeap, "100", 100);
109 n6 = GNUNET_CONTAINER_heap_insert (myHeap, "30/200", 30);
110 GNUNET_assert (5 == GNUNET_CONTAINER_heap_get_size (myHeap));
111 GNUNET_CONTAINER_heap_remove_node (n5);
112 r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n1 */
113 GNUNET_assert (NULL != r);
114 GNUNET_assert (0 == strcmp ("11", r));
115 GNUNET_CONTAINER_heap_update_cost (n6, 200);
116 GNUNET_CONTAINER_heap_remove_node (n3);
117 r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n4 */
118 GNUNET_assert (NULL != r);
119 GNUNET_assert (0 == strcmp ("50", r));
120 r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n6 */
121 GNUNET_assert (NULL != r);
122 GNUNET_assert (0 == strcmp ("30/200", r));
123 GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (myHeap));
124
125 GNUNET_CONTAINER_heap_destroy (myHeap);
126
127 // My additions to a complete testcase
128 // Testing a GNUNET_CONTAINER_HEAP_ORDER_MIN
129 // Testing remove_node
130
131 myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
132
133 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
134 GNUNET_CONTAINER_heap_update_cost (n1, 15);
135
136 r = GNUNET_CONTAINER_heap_remove_node (n1);
137 GNUNET_assert (NULL != r);
138 GNUNET_assert (0 == strcmp ("10", r));
139
140 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
141 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
142
143 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
144 r = GNUNET_CONTAINER_heap_remove_node (n2);
145 GNUNET_assert (NULL != r);
146 GNUNET_assert (0 == strcmp ("20", r));
147 r = GNUNET_CONTAINER_heap_remove_node (n1);
148 GNUNET_assert (NULL != r);
149 GNUNET_assert (0 == strcmp ("10", r));
150
151 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
152 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
153 n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10);
154
155 GNUNET_CONTAINER_heap_remove_node (n2);
156 GNUNET_CONTAINER_heap_remove_node (n1);
157 r = GNUNET_CONTAINER_heap_remove_root (myHeap);
158 GNUNET_assert (NULL != r);
159 GNUNET_assert (0 == strcmp ("30", r));
160
161 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
162 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
163 n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10);
164
165 GNUNET_CONTAINER_heap_remove_node (n2);
166 GNUNET_CONTAINER_heap_remove_node (n1);
167 r = GNUNET_CONTAINER_heap_remove_node (n3);
168 GNUNET_assert (NULL != r);
169 GNUNET_assert (0 == strcmp ("30", r));
170
171 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
172 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20);
173 n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30);
174
175 GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2)));
176 GNUNET_assert (0 ==
177 nstrcmp ("10", GNUNET_CONTAINER_heap_remove_root (myHeap)));
178 GNUNET_assert (0 ==
179 nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap)));
180
181 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
182 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20);
183 n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30);
184 n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40);
185 n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50);
186 n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60);
187
188 // Inserting nodes deeper in the tree with lower costs
189 n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10);
190 n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10);
191
192 GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3)));
193
194 // Cleaning up...
195 GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6)));
196 GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5)));
197
198 // Testing heap_walk_get_next
199 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
200 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
201 GNUNET_CONTAINER_heap_walk_get_next (myHeap);;
202 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
203 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
204
205 GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1)));
206 GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2)));
207 GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4)));
208 GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7)));
209 GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8)));
210
211 // End Testing remove_node
212
213 // Testing a GNUNET_CONTAINER_HEAP_ORDER_MAX
214 GNUNET_CONTAINER_heap_destroy (myHeap);
215
216 myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
217
218 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
219 GNUNET_CONTAINER_heap_update_cost (n1, 15);
220
221 GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1)));
222
223 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
224 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
225
226 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
227 GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2)));
228 GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1)));
229
230 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
231 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
232 n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10);
233
234 GNUNET_CONTAINER_heap_remove_node (n2);
235 GNUNET_CONTAINER_heap_remove_node (n1);
236 GNUNET_assert (0 ==
237 nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap)));
238
239 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
240 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
241 n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10);
242
243 GNUNET_CONTAINER_heap_remove_node (n2);
244 GNUNET_CONTAINER_heap_remove_node (n1);
245 GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3)));
246
247 n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
248 n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20);
249 n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30);
250 n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40);
251 n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50);
252 n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60);
253
254 // Inserting nodes deeper in the tree with lower costs
255 n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10);
256 n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10);
257
258 GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3)));
259
260 // Cleaning up...
261 GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6)));
262 GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5)));
263
264 // Testing heap_walk_get_next
265 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
266 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
267 GNUNET_CONTAINER_heap_walk_get_next (myHeap);;
268 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
269 GNUNET_CONTAINER_heap_walk_get_next (myHeap);
270
271 GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1)));
272 GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2)));
273 GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4)));
274 GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7)));
275 GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8)));
276
277 // End Testing remove_node
278
279 GNUNET_CONTAINER_heap_destroy (myHeap);
280
281 return 0;
282}
283
284
285int
286main (int argc, char **argv)
287{
288 GNUNET_log_setup ("test-container-heap", "WARNING", NULL);
289 return check ();
290}
291
292
293/* end of test_container_heap.c */
diff --git a/src/util/test_container_meta_data.c b/src/util/test_container_meta_data.c
deleted file mode 100644
index db413f313..000000000
--- a/src/util/test_container_meta_data.c
+++ /dev/null
@@ -1,375 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2003, 2004, 2006, 2009, 2010 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 util/test_container_meta_data.c
23 * @brief Test for container_meta_data.c
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30#define ABORT(m) { fprintf (stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
31 if (m != NULL) GNUNET_CONTAINER_meta_data_destroy (m); \
32 return 1; }
33
34
35static int
36testMeta (int i)
37{
38 struct GNUNET_CONTAINER_MetaData *m;
39 char val[256];
40 char *sval;
41 int j;
42 unsigned int size;
43
44 m = GNUNET_CONTAINER_meta_data_create ();
45 if (GNUNET_OK !=
46 GNUNET_CONTAINER_meta_data_insert (m, "<test>", EXTRACTOR_METATYPE_TITLE,
47 EXTRACTOR_METAFORMAT_UTF8,
48 "text/plain", "TestTitle",
49 strlen ("TestTitle") + 1))
50 ABORT (m);
51 if (GNUNET_OK !=
52 GNUNET_CONTAINER_meta_data_insert (m, "<test>",
53 EXTRACTOR_METATYPE_AUTHOR_NAME,
54 EXTRACTOR_METAFORMAT_UTF8,
55 "text/plain", "TestTitle",
56 strlen ("TestTitle") + 1))
57 ABORT (m);
58 if (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (m, "<test>",
59 EXTRACTOR_METATYPE_TITLE,
60 EXTRACTOR_METAFORMAT_UTF8,
61 "text/plain",
62 "TestTitle", strlen (
63 "TestTitle") + 1)) /* dup! */
64 ABORT (m);
65 if (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (m, "<test>",
66 EXTRACTOR_METATYPE_AUTHOR_NAME,
67 EXTRACTOR_METAFORMAT_UTF8,
68 "text/plain",
69 "TestTitle", strlen (
70 "TestTitle") + 1)) /* dup! */
71 ABORT (m);
72 if (2 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL))
73 ABORT (m);
74 if (GNUNET_OK !=
75 GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_AUTHOR_NAME,
76 "TestTitle", strlen ("TestTitle") + 1))
77 ABORT (m);
78 if (GNUNET_OK == GNUNET_CONTAINER_meta_data_delete (m,
79 EXTRACTOR_METATYPE_AUTHOR_NAME,
80 "TestTitle", strlen (
81 "TestTitle") + 1)) /* already gone */
82 ABORT (m);
83 if (1 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL))
84 ABORT (m);
85 if (GNUNET_OK !=
86 GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_TITLE,
87 "TestTitle", strlen ("TestTitle") + 1))
88 ABORT (m);
89 if (GNUNET_OK == GNUNET_CONTAINER_meta_data_delete (m,
90 EXTRACTOR_METATYPE_TITLE,
91 "TestTitle", strlen (
92 "TestTitle") + 1)) /* already gone */
93 ABORT (m);
94 if (0 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL))
95 ABORT (m);
96 for (j = 0; j < i; j++)
97 {
98 GNUNET_snprintf (val, sizeof(val), "%s.%d",
99 "A teststring that should compress well.", j);
100 if (GNUNET_OK !=
101 GNUNET_CONTAINER_meta_data_insert (m, "<test>",
102 EXTRACTOR_METATYPE_UNKNOWN,
103 EXTRACTOR_METAFORMAT_UTF8,
104 "text/plain", val, strlen (val) + 1))
105 ABORT (m);
106 }
107 if (i != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL))
108 ABORT (m);
109
110 size = GNUNET_CONTAINER_meta_data_get_serialized_size (m);
111 sval = NULL;
112 if (size !=
113 GNUNET_CONTAINER_meta_data_serialize (m, &sval, size,
114 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL))
115 {
116 GNUNET_free (sval);
117 ABORT (m);
118 }
119 GNUNET_CONTAINER_meta_data_destroy (m);
120 m = GNUNET_CONTAINER_meta_data_deserialize (sval, size);
121 GNUNET_free (sval);
122 if (m == NULL)
123 ABORT (m);
124 for (j = 0; j < i; j++)
125 {
126 GNUNET_snprintf (val,
127 sizeof(val),
128 "%s.%d",
129 "A teststring that should compress well.",
130 j);
131 if (GNUNET_OK !=
132 GNUNET_CONTAINER_meta_data_delete (m,
133 EXTRACTOR_METATYPE_UNKNOWN,
134 val,
135 strlen (val) + 1))
136 {
137 ABORT (m);
138 }
139 }
140 if (0 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL))
141 ABORT (m);
142 GNUNET_CONTAINER_meta_data_destroy (m);
143 return 0;
144}
145
146
147static int
148testMetaMore (int i)
149{
150 struct GNUNET_CONTAINER_MetaData *meta;
151 int q;
152 char txt[128];
153 char *data;
154 unsigned long long size;
155
156 meta = GNUNET_CONTAINER_meta_data_create ();
157 for (q = 0; q <= i; q++)
158 {
159 GNUNET_snprintf (txt, 128, "%u -- %u\n", i, q);
160 GNUNET_CONTAINER_meta_data_insert (meta, "<test>",
161 q
162 % 42 /* EXTRACTOR_metatype_get_max () */,
163 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
164 txt, strlen (txt) + 1);
165 }
166 size = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
167 data = GNUNET_malloc (size * 4);
168 if (size !=
169 GNUNET_CONTAINER_meta_data_serialize (meta, &data, size * 4,
170 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL))
171 {
172 GNUNET_free (data);
173 ABORT (meta);
174 }
175 GNUNET_CONTAINER_meta_data_destroy (meta);
176 GNUNET_free (data);
177 return 0;
178}
179
180
181static int
182testMetaLink ()
183{
184 struct GNUNET_CONTAINER_MetaData *m;
185 char *val;
186 unsigned int size;
187
188 m = GNUNET_CONTAINER_meta_data_create ();
189 if (GNUNET_OK !=
190 GNUNET_CONTAINER_meta_data_insert (m, "<test>",
191 EXTRACTOR_METATYPE_UNKNOWN,
192 EXTRACTOR_METAFORMAT_UTF8,
193 "text/plain", "link",
194 strlen ("link") + 1))
195 ABORT (m);
196 if (GNUNET_OK !=
197 GNUNET_CONTAINER_meta_data_insert (m, "<test>",
198 EXTRACTOR_METATYPE_FILENAME,
199 EXTRACTOR_METAFORMAT_UTF8,
200 "text/plain", "lib-link.m4",
201 strlen ("lib-link.m4") + 1))
202 ABORT (m);
203 val = NULL;
204 size =
205 GNUNET_CONTAINER_meta_data_serialize (m, &val, (size_t) -1,
206 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
207 GNUNET_CONTAINER_meta_data_destroy (m);
208 m = GNUNET_CONTAINER_meta_data_deserialize (val, size);
209 GNUNET_free (val);
210 if (m == NULL)
211 ABORT (m);
212 GNUNET_CONTAINER_meta_data_destroy (m);
213 return 0;
214}
215
216
217static int
218check ()
219{
220 struct GNUNET_CONTAINER_MetaData *meta;
221 struct GNUNET_CONTAINER_MetaData *meta2;
222 int q;
223 int i = 100;
224 char txt[128];
225 char *str;
226 unsigned char *thumb;
227
228 meta = GNUNET_CONTAINER_meta_data_create ();
229 meta2 = GNUNET_CONTAINER_meta_data_create ();
230 for (q = 0; q <= i; q++)
231 {
232 GNUNET_snprintf (txt, 128, "%u -- %u\n", i, q);
233 GNUNET_CONTAINER_meta_data_insert (meta, "<test>",
234 EXTRACTOR_METATYPE_UNKNOWN,
235 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
236 "TestTitle", strlen ("TestTitle") + 1);
237 GNUNET_CONTAINER_meta_data_insert (meta2, "<test>",
238 EXTRACTOR_METATYPE_UNKNOWN,
239 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
240 "TestTitle", strlen ("TestTitle") + 1);
241 }
242
243 // check meta_data_test_equal
244 if (GNUNET_YES != GNUNET_CONTAINER_meta_data_test_equal (meta, meta2))
245 {
246 GNUNET_CONTAINER_meta_data_destroy (meta2);
247 ABORT (meta);
248 }
249
250 // check meta_data_clear
251 GNUNET_CONTAINER_meta_data_clear (meta2);
252 if (0 != GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL))
253 {
254 GNUNET_CONTAINER_meta_data_destroy (meta2);
255 ABORT (meta);
256 }
257 // check equal branch in meta_data_test_equal
258 if (GNUNET_YES != GNUNET_CONTAINER_meta_data_test_equal (meta, meta))
259 {
260 GNUNET_CONTAINER_meta_data_destroy (meta2);
261 ABORT (meta);
262 }
263 // check "count" branch in meta_data_test_equal
264 if (GNUNET_NO != GNUNET_CONTAINER_meta_data_test_equal (meta, meta2))
265 {
266 GNUNET_CONTAINER_meta_data_destroy (meta2);
267 ABORT (meta);
268 }
269
270 // check meta_data_add_publication_date
271 GNUNET_CONTAINER_meta_data_add_publication_date (meta2);
272
273 // check meta_data_merge
274 GNUNET_CONTAINER_meta_data_clear (meta2);
275 GNUNET_CONTAINER_meta_data_merge (meta2, meta);
276 if (100 == GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL))
277 {
278 GNUNET_CONTAINER_meta_data_destroy (meta2);
279 ABORT (meta);
280 }
281
282 // check meta_data_get_by_type
283 GNUNET_CONTAINER_meta_data_clear (meta2);
284 if (NULL !=
285 (str =
286 GNUNET_CONTAINER_meta_data_get_by_type (meta2,
287 EXTRACTOR_METATYPE_UNKNOWN)))
288 {
289 GNUNET_CONTAINER_meta_data_destroy (meta2);
290 GNUNET_free (str);
291 ABORT (meta);
292 }
293
294 str =
295 GNUNET_CONTAINER_meta_data_get_by_type (meta, EXTRACTOR_METATYPE_UNKNOWN);
296 GNUNET_assert (NULL != str);
297 if (str[0] != 'T')
298 {
299 GNUNET_CONTAINER_meta_data_destroy (meta2);
300 GNUNET_free (str);
301 ABORT (meta);
302 }
303 GNUNET_free (str);
304
305 // check branch
306 if (NULL !=
307 (str =
308 GNUNET_CONTAINER_meta_data_get_by_type (meta,
309 EXTRACTOR_METATYPE_PUBLICATION_DATE)))
310 {
311 GNUNET_free (str);
312 GNUNET_CONTAINER_meta_data_destroy (meta2);
313 ABORT (meta);
314 }
315
316 // check meta_data_get_first_by_types
317 str =
318 GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
319 EXTRACTOR_METATYPE_UNKNOWN,
320 -1);
321 GNUNET_assert (NULL != str);
322 if (str[0] != 'T')
323 {
324 GNUNET_CONTAINER_meta_data_destroy (meta2);
325 GNUNET_free (str);
326 ABORT (meta);
327 }
328 GNUNET_free (str);
329
330 // check meta_data_get_thumbnail
331 if (GNUNET_CONTAINER_meta_data_get_thumbnail (meta, &thumb) != 0)
332 {
333 GNUNET_free (thumb);
334 GNUNET_CONTAINER_meta_data_destroy (meta2);
335 ABORT (meta);
336 }
337 GNUNET_CONTAINER_meta_data_destroy (meta2);
338 // check meta_data_duplicate
339 meta2 = GNUNET_CONTAINER_meta_data_duplicate (meta);
340 if (200 == GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL))
341 {
342 GNUNET_CONTAINER_meta_data_destroy (meta2);
343 ABORT (meta);
344 }
345 GNUNET_CONTAINER_meta_data_destroy (meta2);
346 GNUNET_CONTAINER_meta_data_destroy (meta);
347 return 0;
348}
349
350
351int
352main (int argc, char *argv[])
353{
354 int failureCount = 0;
355 int i;
356
357 GNUNET_log_setup ("test-container-meta-data", "WARNING", NULL);
358 for (i = 0; i < 255; i++)
359 failureCount += testMeta (i);
360 for (i = 1; i < 255; i++)
361 failureCount += testMetaMore (i);
362 failureCount += testMetaLink ();
363
364 int ret = check ();
365
366 if (ret == 1)
367 return 1;
368
369 if (failureCount != 0)
370 return 1;
371 return 0;
372}
373
374
375/* end of test_container_meta_data.c */
diff --git a/src/util/test_container_multihashmap.c b/src/util/test_container_multihashmap.c
deleted file mode 100644
index f46b9f56e..000000000
--- a/src/util/test_container_multihashmap.c
+++ /dev/null
@@ -1,139 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008 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 util/test_container_multihashmap.c
23 * @brief Test for container_multihashmap.c
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30#define ABORT() { fprintf (stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
31 if (m != NULL) GNUNET_CONTAINER_multihashmap_destroy (m); \
32 if (NULL != \
33 iter) \
34 GNUNET_CONTAINER_multihashmap_iterator_destroy (iter); \
35 return 1; }
36#define CHECK(c) { if (! (c)) ABORT (); }
37
38static int
39testMap (int i)
40{
41 struct GNUNET_CONTAINER_MultiHashMap *m;
42 struct GNUNET_HashCode k1;
43 struct GNUNET_HashCode k2;
44 struct GNUNET_CONTAINER_MultiHashMapIterator *iter = NULL;
45 struct GNUNET_HashCode key_ret;
46 const char *ret;
47 int j;
48
49 CHECK (NULL != (m = GNUNET_CONTAINER_multihashmap_create (i, GNUNET_NO)));
50 memset (&k1, 0, sizeof(k1));
51 memset (&k2, 1, sizeof(k2));
52 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k1));
53 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k2));
54 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (m, &k1, NULL));
55 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (m, &k2, NULL));
56 CHECK (NULL == GNUNET_CONTAINER_multihashmap_get (m, &k1));
57 CHECK (NULL == GNUNET_CONTAINER_multihashmap_get (m, &k2));
58 CHECK (0 == GNUNET_CONTAINER_multihashmap_remove_all (m, &k1));
59 CHECK (0 == GNUNET_CONTAINER_multihashmap_size (m));
60 CHECK (0 == GNUNET_CONTAINER_multihashmap_iterate (m, NULL, NULL));
61 CHECK (0 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k1, NULL, NULL));
62
63 CHECK (GNUNET_OK ==
64 GNUNET_CONTAINER_multihashmap_put (m, &k1, "v1",
65 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
66 CHECK (1 == GNUNET_CONTAINER_multihashmap_size (m));
67 ret = GNUNET_CONTAINER_multihashmap_get (m, &k1);
68 GNUNET_assert (ret != NULL);
69 CHECK (0 == strcmp ("v1", ret));
70 CHECK (GNUNET_NO ==
71 GNUNET_CONTAINER_multihashmap_put (m, &k1, "v1",
72 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
73 CHECK (1 == GNUNET_CONTAINER_multihashmap_size (m));
74 CHECK (GNUNET_OK ==
75 GNUNET_CONTAINER_multihashmap_put (m, &k1, "v2",
76 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
77 CHECK (GNUNET_OK ==
78 GNUNET_CONTAINER_multihashmap_put (m, &k1, "v3",
79 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
80 CHECK (3 == GNUNET_CONTAINER_multihashmap_size (m));
81 CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (m, &k1, "v3"));
82 CHECK (2 == GNUNET_CONTAINER_multihashmap_size (m));
83 CHECK (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (m, &k1));
84 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k2));
85 CHECK (2 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k1, NULL, NULL));
86 CHECK (0 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k2, NULL, NULL));
87 CHECK (2 == GNUNET_CONTAINER_multihashmap_iterate (m, NULL, NULL));
88 iter = GNUNET_CONTAINER_multihashmap_iterator_create (m);
89 CHECK (GNUNET_YES == GNUNET_CONTAINER_multihashmap_iterator_next (iter,
90 &key_ret,
91 (const
92 void **) &
93 ret));
94 CHECK (0 == memcmp (&key_ret, &k1, sizeof(key_ret)));
95 CHECK (GNUNET_YES == GNUNET_CONTAINER_multihashmap_iterator_next (iter,
96 &key_ret,
97 (const
98 void **) &
99 ret));
100 CHECK (0 == memcmp (&key_ret, &k1, sizeof(key_ret)));
101 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_iterator_next (iter, NULL,
102 NULL));
103 GNUNET_free (iter);
104
105 CHECK (2 == GNUNET_CONTAINER_multihashmap_remove_all (m, &k1));
106 for (j = 0; j < 1024; j++)
107 CHECK (GNUNET_OK ==
108 GNUNET_CONTAINER_multihashmap_put (m, &k1, "v2",
109 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
110 iter = GNUNET_CONTAINER_multihashmap_iterator_create (m);
111 for (j = 0; j < GNUNET_CONTAINER_multihashmap_size (m); j++)
112 CHECK (GNUNET_YES == GNUNET_CONTAINER_multihashmap_iterator_next (iter,
113 NULL,
114 NULL));
115 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_iterator_next (iter, NULL,
116 NULL));
117 GNUNET_CONTAINER_multihashmap_iterator_destroy (iter);
118
119 GNUNET_CONTAINER_multihashmap_destroy (m);
120 return 0;
121}
122
123
124int
125main (int argc, char *argv[])
126{
127 int failureCount = 0;
128 int i;
129
130 GNUNET_log_setup ("test-container-multihashmap", "WARNING", NULL);
131 for (i = 1; i < 255; i++)
132 failureCount += testMap (i);
133 if (failureCount != 0)
134 return 1;
135 return 0;
136}
137
138
139/* end of test_container_multihashmap.c */
diff --git a/src/util/test_container_multihashmap32.c b/src/util/test_container_multihashmap32.c
deleted file mode 100644
index 92aac6eeb..000000000
--- a/src/util/test_container_multihashmap32.c
+++ /dev/null
@@ -1,109 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008 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 util/test_container_multihashmap32.c
23 * @brief Test for container_multihashmap32.c
24 * @author Christian Grothoff
25 * @author Sree Harsha Totakura
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30
31#define ABORT() { fprintf (stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
32 if (m != NULL) GNUNET_CONTAINER_multihashmap32_destroy (m); \
33 return 1; }
34#define CHECK(c) { if (! (c)) ABORT (); }
35
36static int
37testMap (int i)
38{
39 struct GNUNET_CONTAINER_MultiHashMap32 *m;
40 uint32_t k1;
41 uint32_t k2;
42 const char *ret;
43 int j;
44
45 CHECK (NULL != (m = GNUNET_CONTAINER_multihashmap32_create (i)));
46 k1 = 0;
47 k2 = UINT32_MAX;
48 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap32_contains (m, k1));
49 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap32_contains (m, k2));
50 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap32_remove (m, k1, NULL));
51 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap32_remove (m, k2, NULL));
52 CHECK (NULL == GNUNET_CONTAINER_multihashmap32_get (m, k1));
53 CHECK (NULL == GNUNET_CONTAINER_multihashmap32_get (m, k2));
54 CHECK (0 == GNUNET_CONTAINER_multihashmap32_remove_all (m, k1));
55 CHECK (0 == GNUNET_CONTAINER_multihashmap32_size (m));
56 CHECK (0 == GNUNET_CONTAINER_multihashmap32_iterate (m, NULL, NULL));
57 CHECK (0 == GNUNET_CONTAINER_multihashmap32_get_multiple (m, k1, NULL, NULL));
58
59 CHECK (GNUNET_OK ==
60 GNUNET_CONTAINER_multihashmap32_put (m, k1, "v1",
61 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
62 CHECK (1 == GNUNET_CONTAINER_multihashmap32_size (m));
63 ret = GNUNET_CONTAINER_multihashmap32_get (m, k1);
64 GNUNET_assert (ret != NULL);
65 CHECK (0 == strcmp ("v1", ret));
66 CHECK (GNUNET_NO ==
67 GNUNET_CONTAINER_multihashmap32_put (m, k1, "v1",
68 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
69 CHECK (1 == GNUNET_CONTAINER_multihashmap32_size (m));
70 CHECK (GNUNET_OK ==
71 GNUNET_CONTAINER_multihashmap32_put (m, k1, "v2",
72 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
73 CHECK (GNUNET_OK ==
74 GNUNET_CONTAINER_multihashmap32_put (m, k1, "v3",
75 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
76 CHECK (3 == GNUNET_CONTAINER_multihashmap32_size (m));
77 CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap32_remove (m, k1, "v3"));
78 CHECK (2 == GNUNET_CONTAINER_multihashmap32_size (m));
79 CHECK (GNUNET_YES == GNUNET_CONTAINER_multihashmap32_contains (m, k1));
80 CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap32_contains (m, k2));
81 CHECK (2 == GNUNET_CONTAINER_multihashmap32_get_multiple (m, k1, NULL, NULL));
82 CHECK (0 == GNUNET_CONTAINER_multihashmap32_get_multiple (m, k2, NULL, NULL));
83 CHECK (2 == GNUNET_CONTAINER_multihashmap32_iterate (m, NULL, NULL));
84 CHECK (2 == GNUNET_CONTAINER_multihashmap32_remove_all (m, k1));
85 for (j = 0; j < 1024; j++)
86 CHECK (GNUNET_OK ==
87 GNUNET_CONTAINER_multihashmap32_put (m, k1, "v2",
88 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
89 GNUNET_CONTAINER_multihashmap32_destroy (m);
90 return 0;
91}
92
93
94int
95main (int argc, char *argv[])
96{
97 int failureCount = 0;
98 int i;
99
100 GNUNET_log_setup ("test-container-multihashmap", "WARNING", NULL);
101 for (i = 1; i < 255; i++)
102 failureCount += testMap (i);
103 if (failureCount != 0)
104 return 1;
105 return 0;
106}
107
108
109/* end of test_container_multihashmap.c */
diff --git a/src/util/test_container_multipeermap.c b/src/util/test_container_multipeermap.c
deleted file mode 100644
index cb6fc30d2..000000000
--- a/src/util/test_container_multipeermap.c
+++ /dev/null
@@ -1,139 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008, 2013 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 util/test_container_multipeermap.c
23 * @brief Test for container_multipeermap.c
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30#define ABORT() { fprintf (stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
31 if (NULL != m) GNUNET_CONTAINER_multipeermap_destroy (m); \
32 if (NULL != \
33 iter) \
34 GNUNET_CONTAINER_multipeermap_iterator_destroy (iter); \
35 return 1; }
36#define CHECK(c) { if (! (c)) ABORT (); }
37
38static int
39testMap (int i)
40{
41 struct GNUNET_CONTAINER_MultiPeerMap *m;
42 struct GNUNET_PeerIdentity k1;
43 struct GNUNET_PeerIdentity k2;
44 struct GNUNET_CONTAINER_MultiPeerMapIterator *iter = NULL;
45 struct GNUNET_PeerIdentity key_ret;
46 const char *ret;
47 int j;
48
49 CHECK (NULL != (m = GNUNET_CONTAINER_multipeermap_create (i, GNUNET_NO)));
50 memset (&k1, 0, sizeof(k1));
51 memset (&k2, 1, sizeof(k2));
52 CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k1));
53 CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k2));
54 CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_remove (m, &k1, NULL));
55 CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_remove (m, &k2, NULL));
56 CHECK (NULL == GNUNET_CONTAINER_multipeermap_get (m, &k1));
57 CHECK (NULL == GNUNET_CONTAINER_multipeermap_get (m, &k2));
58 CHECK (0 == GNUNET_CONTAINER_multipeermap_remove_all (m, &k1));
59 CHECK (0 == GNUNET_CONTAINER_multipeermap_size (m));
60 CHECK (0 == GNUNET_CONTAINER_multipeermap_iterate (m, NULL, NULL));
61 CHECK (0 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k1, NULL, NULL));
62
63 CHECK (GNUNET_OK ==
64 GNUNET_CONTAINER_multipeermap_put (m, &k1, "v1",
65 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
66 CHECK (1 == GNUNET_CONTAINER_multipeermap_size (m));
67 ret = GNUNET_CONTAINER_multipeermap_get (m, &k1);
68 GNUNET_assert (ret != NULL);
69 CHECK (0 == strcmp ("v1", ret));
70 CHECK (GNUNET_NO ==
71 GNUNET_CONTAINER_multipeermap_put (m, &k1, "v1",
72 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
73 CHECK (1 == GNUNET_CONTAINER_multipeermap_size (m));
74 CHECK (GNUNET_OK ==
75 GNUNET_CONTAINER_multipeermap_put (m, &k1, "v2",
76 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
77 CHECK (GNUNET_OK ==
78 GNUNET_CONTAINER_multipeermap_put (m, &k1, "v3",
79 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
80 CHECK (3 == GNUNET_CONTAINER_multipeermap_size (m));
81 CHECK (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (m, &k1, "v3"));
82 CHECK (2 == GNUNET_CONTAINER_multipeermap_size (m));
83 CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (m, &k1));
84 CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k2));
85 CHECK (2 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k1, NULL, NULL));
86 CHECK (0 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k2, NULL, NULL));
87 CHECK (2 == GNUNET_CONTAINER_multipeermap_iterate (m, NULL, NULL));
88 iter = GNUNET_CONTAINER_multipeermap_iterator_create (m);
89 CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter,
90 &key_ret,
91 (const
92 void **) &
93 ret));
94 CHECK (0 == memcmp (&key_ret, &k1, sizeof(key_ret)));
95 CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter,
96 &key_ret,
97 (const
98 void **) &
99 ret));
100 CHECK (0 == memcmp (&key_ret, &k1, sizeof(key_ret)));
101 CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL,
102 NULL));
103 GNUNET_free (iter);
104
105 CHECK (2 == GNUNET_CONTAINER_multipeermap_remove_all (m, &k1));
106 for (j = 0; j < 1024; j++)
107 CHECK (GNUNET_OK ==
108 GNUNET_CONTAINER_multipeermap_put (m, &k1, "v2",
109 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
110 iter = GNUNET_CONTAINER_multipeermap_iterator_create (m);
111 for (j = 0; j < GNUNET_CONTAINER_multipeermap_size (m); j++)
112 CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter,
113 NULL,
114 NULL));
115 CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL,
116 NULL));
117 GNUNET_CONTAINER_multipeermap_iterator_destroy (iter);
118
119 GNUNET_CONTAINER_multipeermap_destroy (m);
120 return 0;
121}
122
123
124int
125main (int argc, char *argv[])
126{
127 int failureCount = 0;
128 int i;
129
130 GNUNET_log_setup ("test-container-multipeermap", "WARNING", NULL);
131 for (i = 1; i < 255; i++)
132 failureCount += testMap (i);
133 if (failureCount != 0)
134 return 1;
135 return 0;
136}
137
138
139/* end of test_container_multipeermap.c */
diff --git a/src/util/test_crypto_crc.c b/src/util/test_crypto_crc.c
deleted file mode 100644
index 4507deadd..000000000
--- a/src/util/test_crypto_crc.c
+++ /dev/null
@@ -1,220 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2004, 2006 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 For the actual CRC code:
21 Copyright abandoned; this code is in the public domain.
22 Provided to GNUnet by peter@horizon.com
23 */
24
25/**
26 * @file util/test_crypto_crc.c
27 * @brief testcase for crypto_crc.c
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31
32static int expected[] = {
33 -1223996378, 929797997, -1048047323, 1791081351, -425765913, 2138425902,
34 82584863, 1939615314, 1806463044, -1505003452, 1878277636, -997353517,
35 201238705, 1723258694, -1107452366, -344562561, -1102247383, 1973035265,
36 715213337, -1886586005, 2021214515, -1387332962, 593019378, -571088044,
37 1412577760, 412164558, -1626111170, 1556494863, -289796528, -850404775,
38 2066714587, -911838105, -1426027382, 499684507, -835420055, 1817119454,
39 -1221795958, 1516966784, -1038806877, -2115880691, 532627620, 1984437415,
40 -396341583, -1345366324, -590766745, -1801923449, 1752427988, -386896390,
41 453906317, 1552589433, -858925718, 1160445643, -740188079, -486609040,
42 1102529269, -515846212, -1614217202, 1572162207, 943558923, -467330358,
43 -1870764193, 1477005328, -793029208, -888983175, -696956020, 842706021,
44 1642390067, -805889494, 1284862057, 1562545388, 2091626273, 1852404553,
45 -2076508101, 370903003, 1186422975, 1936085227, 769358463, 180401058,
46 2032612572, -105461719, -1119935472, 617249831, 1169304728, 1771205256,
47 -2042554284, 653270859, -918610713, 336081663, -913685370, 1962213744,
48 -505406126, -838622649, -1141518710, 893143582, -1330296611, 122119483,
49 1111564496, 688811976, 1016241049, -1803438473, 359630107, 1034798954,
50 -581359286, 1590946527, -389997034, 2020318460, 1695967527, -464069727,
51 -862641495, -1405012109, -771244841, 738226150, -1035328134, -933945474,
52 1254965774, 1661863830, -884127998, 1800460481, 814702567, -1214068102,
53 -541120421, 1898656429, -236825530, 1505866267, 1252462132, -981007520,
54 1502096471, -2134644056, 483221797, 1276403836, 541133290, -1234093967,
55 350748780, 257941070, 1030457090, 434988890, -1098135432, -1000556640,
56 -577128022, 644806294, -787536281, -1288346343, 998079404, 1259353935,
57 955771631, -958377466, 1746756252, 451579658, 1913409243, -952026299,
58 -1556035958, -830279881, 834744289, -1878491428, 700000962, -1027245802,
59 1393574384, -1260409147, -841420884, 892132797, 1494730226, -1649181766,
60 1651097838, -1041807403, -1916675721, -1324525963, 157405899, -655788033,
61 -1943555237, -79747022, 339721623, -138341083, 1111902411, -435322914,
62 -533294200, -190220608, -1718346014, -1631301894, 1706265243, 745533899,
63 1351941230, 1803009594, -1218191958, 1467751062, 84368433, -711251880,
64 1699423788, -768792716, 846639904, 2103267723, -2095288070, -440571408,
65 -362144485, 2020468971, 352105963, -849211036, -1272592429, 1743440467,
66 2020667861, -1649992312, 172682343, 816705364, -1990206923, 902689869,
67 -298510060, 164207498, 190378213, 242531543, 113383268, 304810777,
68 -1081099373, 819221134, -1100982926, -855941239, 1091308887, -934548124,
69 520508733, -1381763773, -491593287, -2143492665, 700894653, -2049034808,
70 -160942046, -2009323577, 1464245054, 1584746011, -768646852, -993282698,
71 1265838699, -1873820824, 575704373, -986682955, 1270688416, 88587481,
72 -1723991633, -409928242, 866669946, -483811323, -181759253, -963525431,
73 -1686612238, -1663460076, -1128449775, -1368922329, 122318131, 795862385,
74 528576131, -19927090, 1369299478, 1285665642, -738964611, 1328292127,
75 552041252, -1431494354, -1205275362, 42768297, -1329537238, -449177266,
76 943925221, 987016465, -945138414, -270064876, 1650366626, -369252552,
77 582030210, -1229235374, 147901387, -517510506, -1609742888, -1086838308,
78 1391998445, -313975512, -613392078, 855706229, 1475706341, -1112105406,
79 2032001400, 1565777625, 2030937777, 435522421, 1823527907, -691390605,
80 -827253664, 1057171580, -314146639, -630099999, -1347514552, 478716232,
81 -1533658804, -1425371979, 761987780, 1560243817, -1945893959, 1205759225,
82 -959343783, -576742354, -154125407, -1158108776, 1183788580, 1354198127,
83 -1534207721, -823991517, -170534462, -912524170, 1858513573, 467072185,
84 2091040157, -1765027018, -1659401643, -1173890143, -1912754057, -84568053,
85 2010781784, -921970156, 944508352, -922040609, 1055102010, 1018688871,
86 -1186761311, -2012263648, 1311654161, 277659086, 2029602288, 1127061510,
87 1029452642, 285677123, -188521091, -641039012, 653836416, -805916340,
88 -1644860596, 1352872213, 691634876, -1477113308, -748430369, 1030697363,
89 -2007864449, -1196662616, 1313997192, 177342476, -566676450, -1118618118,
90 1697953104, 344671484, -1489783116, -889507873, 1259591310, -716567168,
91 2116447062, 324368527, 1789366816, 1558930442, 1950250221, -785460151,
92 1174714258, -430047304, -859487565, -580633932, 607732845, -1128150220,
93 1544355315, 1460298016, -1771194297, 1215703690, 277231808, -416020628,
94 -418936577, -1724839216, 404731389, 1058730508, -1508366681, 229883053,
95 -572310243, 1883189553, 931286849, 1659300867, -94236383, -241524462,
96 548020458, -302406981, 579986475, 73468197, -984957614, 1554382245,
97 2084807492, -1456802798, -1105192593, 629440327, -16313961, -2102585261,
98 1873675206, 161035128, 1497033351, 1990150811, -499405222, 304019482,
99 41935663, -805987182, -571699268, 1748462913, 2096239823, -116359807,
100 -1871127553, -1074832534, -1558866192, 231353861, 2122854560, -2102323721,
101 -281462361, -343403210, -673268171, 1776058383, 1581561150, 2059580579,
102 768848632, 1347190372, -1701705879, 245282007, -563267886, -592558289,
103 1662399958, 1390406821, -1522485580, -706446863, 2069516289, -301855859,
104 -778346387, -1454093198, 1249083752, -1760506745, 262193320, 630751125,
105 -1495939124, -29980580, -1989626563, 659039376, -329477132, -1003507166,
106 -1322549020, 358606508, -2052572059, 1848014133, 1826958586, -1004948862,
107 -1775370541, 2134177912, -1739214473, 1892700918, 926629675, -1042761322,
108 2020075900, 606370962, -1256609305, 117577265, -586848924, 191368285,
109 1653535275, -1329269701, -375879127, -1089901406, 1206489978, 534223924,
110 -1042752982, -1178316881, -445594741, -1501682065, -1598136839,
111 -467688289, 750784023, 1781080461, 1729380226, 16906088, 862168532,
112 -2037752683, 1455274138, -1491220107, 1058323960, 1711530558, 1355062750,
113 227640096, 396568027, -173579098, -408975801, -993618329, -1470751562,
114 371076647, 209563718, 2015405719, -723460281, -1423934420, -2089643958,
115 353260489, 2084264341, -792676687, 701391030, -1440658244, 1479321011,
116 1907822880, 1232524257, -256712289, 401077577, 621808069, 868263613,
117 1244930119, 2020996902, 117483907, 1341376744, -1936988014, -445200547,
118 -843751811, -435291191, 1041695743, 476132726, -1226874735, -1436046747,
119 -297047422, 1739645396, 1948680937, -718144374, 1141983978, 1673650568,
120 -197244350, 1604464002, 1424069853, -485626505, 1708710014, -849136541,
121 1573778103, 530360999, 1777767203, 1376958336, -1088364352, 1826167753,
122 742735448, -1386211659, -1991323164, -444115655, -443055378, -1586901006,
123 -1741686587, 1925818034, -2118916824, 803890920, -1481793154, 992278937,
124 1302616410, 444517030, 1393144770, -2025632978, 1902300505, -1683582981,
125 800654133, 873850324, -619580878, -2002070410, -2024936385, 1978986634,
126 2012024264, 675768872, 389435615, -867217540, 231209167, -303917385,
127 1445676969, -1385982721, 1310476490, 580273453, -160600202, -1330895874,
128 487110497, 1124384798, 227637416, -1829783306, 1014818058, -1336870683,
129 -1042199518, -468525587, -1186267363, -472843891, 1215617600, -2056648329,
130 -873216891, 156780951, -1883246047, -842549253, -717684332, 760531638,
131 1074787431, 786267513, 814031289, -561255343, -110302255, -1837376592,
132 989669060, -81350614, 546038730, 222899882, 1298746805, 1791615733,
133 1565630269, 1516024174, 421691479, 1860326051, -1973359550, 1854393443,
134 -1401468528, -158562295, 1509929255, -124024738, -462937489, 259890715,
135 -1515121317, -289511197, -913738664, 698079062, -1631229382, -507275144,
136 1897739663, -1118192766, -1687033399, 61405556, -1913606579, -473308896,
137 -259107170, -576944609, -1689355510, 322156799, 545090192, 127425176,
138 -1815211748, -2070235628, -1172529316, 599259550, -910906653, 1797380363,
139 -938649427, 142991392, 504559631, 1208867355, -807699247, -616021271,
140 -254935281, -57151221, -1095534993, 1998380318, 1772459584, 713271407,
141 -1197898266, 808881935, -308133481, -1314455137, 284321772, -743117625,
142 -1622364240, -1667535152, 118713606, 1053615347, -2072876023, -178189072,
143 -828319551, 2047304928, -1311435786, -1970672907, -747972100, 86806159,
144 -436088421, 1464645587, 735840899, 32600466, -190473426, -735703440,
145 482872155, 475662392, -713681085, 1424078728, -150668609, -1137197868,
146 -1682762563, -48035649, 1143959866, -1542015129, 284920371, -1587695586,
147 -625236551, -753893357, -433976266, -1329796037, -1636712478, 1686783454,
148 27839146, 1748631474, -879528256, 2057796026, 773734654, 112269667,
149 -2011541314, 1517797297, -1943171794, 268166111, -1037010413, -1945824504,
150 -1672323792, 306260758, -692968628, -701704965, -462980996, 939188824,
151 553289792, 1790245000, 2093793129, -658085781, -186055037, -2130433650,
152 -1013235433, 1190870089, -2126586963, -1509655742, -1291895256,
153 -1427857845, 309538950, 388316741, 259659733, -1895092434, 110126220,
154 -170175575, -419430224, -696234084, -832170948, -353431720, -797675726,
155 -1644136054, 715163272, -1305904349, -145786463, -99586244, -695450446,
156 -871327102, -725496060, 952863853, -688441983, -1729929460, -103732092,
157 1059054528, 568873585, -982665223, -128672783, 2099418320, 1508239336,
158 -2089480835, -390935727, 664306522, -1607364342, -163246802, -1121295140,
159 -128375779, -615694409, -2079391797, 760542037, 677761593, -750117849,
160 -1060525080, 2128437080, 525250908, 1987657172, 2032530557, -2011247936,
161 1942775263, 1681562788, 688229491, -803856505, 684707948, 1308988965,
162 1455480037, 790659611, 1557968784, -383203149, -361510986, -742575828,
163 558837193, -1214977424, 1253274105, -119513513, -993964385, -33438767,
164 -177452803, 1186928041, -2073533871, 1188528559, 1896514695, 1200128512,
165 1930588755, -1914141443, 1534656032, -1192989829, -1848274656, -220848455,
166 1001806509, 1298797392, 1533031884, -1912322446, 1705583815, 1568094347,
167 -1397640627, 807828512, -1852996497, -1529733505, -1575634185,
168 -1280270160, -1567624159, -1861904922, 1276738579, 1163432999, 626879833,
169 316942006, -1871138342, 1341039701, 1595907877, 1950911580, 1634717748,
170 1071476055, -809354290, -1161553341, -2081621710, -2085557943, 19360224,
171 322135580, -698485151, 1267663094, -233890834, -126361189, -1426257522,
172 1094007921, 500179855, -283548002, -1678987343, 1946999943, 1489410849,
173 2089571262, 1430799093, 1961848046, -99462663, -552833264, 1168700661,
174 -1783882181, 2089196401, 1092839657, 914488673, 80263859, -2140947098,
175 -726384741, -1022448237, 2113887675, 1485770846, -112922517, 1995461466,
176 774613726, 944068011, 1521975359, 289086919, -386920759, -1960513175,
177 358460021, -238698524, -1913640563, -1000324864, 1731755224, -1271586254,
178 -1917469655, 2134162829, -828097534, -1089292503, -1514835999, 1682931514,
179 -482307169, 2110243841, 115744834, -2038340170, 65889188, -539445712,
180 -1713206408, -1842396726, -1659545588, -909558923, 860164922, 1328713040,
181 1044007120, -2103807103, -1073990344, -1312783785, -884980824, -705318011,
182 -1263408788, -2032228692, -1732844111, -1813827156, 1462566279,
183 1179250845, 1732421772, 604429013, -92284336, -1192166516, 304654351,
184 1998552034, -1802461575, -1802704071, -1704833934, -976264396, 1005840702,
185 2108843914, 1363909309, 843040834, -1039625241, 1285007226, 91610001,
186 418426329, 678422358, -945360697, -440008081, -1053091357, 425719777,
187 -1372778676, 591912153, 1229089037, -56663158, 2140251400, 830257037,
188 763914157, 175610373, -2105655963, -1040826150, 1174443038, 339290593,
189 346618443, -180504100, -1363190515, 210620018, 1028894425, 573529714,
190 698460117, 136999397, 1015621712, -1401813739, -297990684, -1820934845,
191 -1299093313, 1299361369, -366522415, 91527707, 1113466178, -956229484,
192 22204763, -1394374195, -1912666711, -1453789804, 1613408399, -169509567,
193 1350520309, 540761213, -2086682848, 1095131491, -812787911, 1860108594,
194 -1121378737, -1667252487, -486084366, 166519760, 1609891237, 728218405,
195 291075010, 646168382, 108462277, -1616661910, 1016600360, 2099958568,
196 27934736, 183821196, 13660496, -805589719, 936068730, -439037934,
197 1414622584, 215845485, -1352304469, -1817427526, -1318710977, -110207199,
198 228524335, 1704746590, 998293651, -1521016702, -641956531, -2089808167,
199 2094404052, -1446381065, -662186492, 1670154584, 9637833, 493925511,
200 660047318, 1197537103, 1696017374, -204994399, -1104145601, -852330465,
201 -1936369658, -829716674, -1255255217, 1264013799, 1642611772, -652520861,
202 777247164, 2028895987, -1424241853, -54367829, -1940161761, -1802831079,
203 -449405299, 838242661, -323055438, 794295411, -136989378, -446686673,
204 -421252799, -16777216,
205};
206
207int
208main (int argc, char *argv[])
209{
210 char buf[1024];
211 int i;
212
213 GNUNET_log_setup ("test-crypto-crc", "WARNING", NULL);
214 for (i = 0; i < 1024; i++)
215 buf[i] = (char) i;
216 for (i = 0; i < 1024; i++)
217 if (expected[i] != GNUNET_CRYPTO_crc32_n (&buf[i], 1024 - i))
218 return 1;
219 return 0;
220}
diff --git a/src/util/test_crypto_ecc_dlog.c b/src/util/test_crypto_ecc_dlog.c
deleted file mode 100644
index 51f290d51..000000000
--- a/src/util/test_crypto_ecc_dlog.c
+++ /dev/null
@@ -1,218 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015 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 util/test_crypto_ecc_dlog.c
23 * @brief testcase for ECC DLOG calculation
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gcrypt.h>
29
30
31/**
32 * Name of the curve we are using. Note that we have hard-coded
33 * structs that use 256 bits, so using a bigger curve will require
34 * changes that break stuff badly. The name of the curve given here
35 * must be agreed by all peers and be supported by libgcrypt.
36 */
37#define CURVE "Ed25519"
38
39/**
40 * Maximum value we test dlog for.
41 */
42#define MAX_FACT 100
43
44/**
45 * Maximum memory to use, sqrt(MAX_FACT) is a good choice.
46 */
47#define MAX_MEM 10
48
49/**
50 * How many values do we test?
51 */
52#define TEST_ITER 100
53
54/**
55 * Range of values to use for MATH tests.
56 */
57#define MATH_MAX 5
58
59
60/**
61 * Do some DLOG operations for testing.
62 *
63 * @param edc context for ECC operations
64 */
65static void
66test_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc)
67{
68 for (unsigned int i = 0; i < TEST_ITER; i++)
69 {
70 struct GNUNET_CRYPTO_EccScalar fact;
71 struct GNUNET_CRYPTO_EccScalar n;
72 struct GNUNET_CRYPTO_EccPoint q;
73 int x;
74
75 fprintf (stderr, ".");
76 x = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
77 MAX_FACT);
78 memset (&n,
79 0,
80 sizeof (n));
81 for (unsigned int j = 0; j < x; j++)
82 sodium_increment (n.v,
83 sizeof (n.v));
84 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
85 2))
86 {
87 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
88 "Trying negative %d\n",
89 -x);
90 crypto_core_ed25519_scalar_negate (fact.v,
91 n.v);
92 x = -x;
93 }
94 else
95 {
96 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
97 "Trying positive %d\n",
98 x);
99 fact = n;
100 }
101 if (0 == x)
102 {
103 /* libsodium does not like to multiply with zero; make sure
104 'q' is a valid point (g) first, then use q = q - q to get
105 the product with zero */
106 sodium_increment (fact.v,
107 sizeof (fact.v));
108 GNUNET_assert (0 ==
109 crypto_scalarmult_ed25519_base_noclamp (q.v,
110 fact.v));
111 GNUNET_assert (
112 0 ==
113 crypto_core_ed25519_sub (q.v,
114 q.v,
115 q.v));
116 }
117 else
118 GNUNET_assert (0 ==
119 crypto_scalarmult_ed25519_base_noclamp (q.v,
120 fact.v));
121 {
122 int iret;
123
124 if (x !=
125 (iret = GNUNET_CRYPTO_ecc_dlog (edc,
126 &q)))
127 {
128 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
129 "DLOG failed for value %d (got: %d)\n",
130 x,
131 iret);
132 GNUNET_assert (0);
133 }
134 }
135 }
136 fprintf (stderr,
137 "\n");
138}
139
140
141/**
142 * Do some arithmetic operations for testing.
143 *
144 * @param edc context for ECC operations
145 */
146static void
147test_math (struct GNUNET_CRYPTO_EccDlogContext *edc)
148{
149 int i;
150 int j;
151 struct GNUNET_CRYPTO_EccPoint ip;
152 struct GNUNET_CRYPTO_EccPoint jp;
153 struct GNUNET_CRYPTO_EccPoint r;
154 struct GNUNET_CRYPTO_EccPoint ir;
155 struct GNUNET_CRYPTO_EccPoint irj;
156 struct GNUNET_CRYPTO_EccPoint r_inv;
157 struct GNUNET_CRYPTO_EccPoint sum;
158
159 for (i = -MATH_MAX; i < MATH_MAX; i++)
160 {
161 GNUNET_CRYPTO_ecc_dexp (i, &ip);
162 for (j = -MATH_MAX; j < MATH_MAX; j++)
163 {
164 fprintf (stderr, ".");
165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
166 "%d + %d\n",
167 i,
168 j);
169 GNUNET_CRYPTO_ecc_dexp (j, &jp);
170 GNUNET_CRYPTO_ecc_rnd (&r,
171 &r_inv);
172 GNUNET_CRYPTO_ecc_add (&ip, &r, &ir);
173 GNUNET_CRYPTO_ecc_add (&ir, &jp, &irj);
174 GNUNET_CRYPTO_ecc_add (&irj, &r_inv, &sum);
175 int res = GNUNET_CRYPTO_ecc_dlog (edc, &sum);
176 if (i + j != res)
177 {
178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
179 "Got %d, expected %d\n",
180 res,
181 i + j);
182 // GNUNET_assert (0);
183 }
184 }
185 }
186 fprintf (stderr, "\n");
187}
188
189
190int
191main (int argc, char *argv[])
192{
193 struct GNUNET_CRYPTO_EccDlogContext *edc;
194
195 if (! gcry_check_version ("1.6.0"))
196 {
197 fprintf (stderr,
198 _
199 (
200 "libgcrypt has not the expected version (version %s is required).\n"),
201 "1.6.0");
202 return 0;
203 }
204 if (getenv ("GNUNET_GCRYPT_DEBUG"))
205 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
206 GNUNET_log_setup ("test-crypto-ecc-dlog",
207 "WARNING",
208 NULL);
209 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_FACT,
210 MAX_MEM);
211 test_dlog (edc);
212 test_math (edc);
213 GNUNET_CRYPTO_ecc_dlog_release (edc);
214 return 0;
215}
216
217
218/* end of test_crypto_ecc_dlog.c */
diff --git a/src/util/test_crypto_ecdh_ecdsa.c b/src/util/test_crypto_ecdh_ecdsa.c
deleted file mode 100644
index 3cc12de9b..000000000
--- a/src/util/test_crypto_ecdh_ecdsa.c
+++ /dev/null
@@ -1,94 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002-2015 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 util/test_crypto_ecdh_ecdsa.c
23 * @brief testcase for ECC DH key exchange with ECDSA private keys.
24 * @author Christian Grothoff
25 * @author Bart Polot
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include <gcrypt.h>
30
31
32static int
33test_ecdh ()
34{
35 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_dsa;
36 struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdh;
37 struct GNUNET_CRYPTO_EcdsaPublicKey id1;
38 struct GNUNET_CRYPTO_EcdhePublicKey id2;
39 struct GNUNET_HashCode dh[2];
40
41 /* Generate keys */
42 GNUNET_CRYPTO_ecdsa_key_create (&priv_dsa);
43 GNUNET_CRYPTO_ecdsa_key_get_public (&priv_dsa,
44 &id1);
45 for (unsigned int j = 0; j < 4; j++)
46 {
47 fprintf (stderr, ",");
48 GNUNET_CRYPTO_ecdhe_key_create (&priv_ecdh);
49 /* Extract public keys */
50 GNUNET_CRYPTO_ecdhe_key_get_public (&priv_ecdh,
51 &id2);
52 /* Do ECDH */
53 GNUNET_assert (GNUNET_OK ==
54 GNUNET_CRYPTO_ecdsa_ecdh (&priv_dsa,
55 &id2,
56 &dh[0]));
57 GNUNET_assert (GNUNET_OK ==
58 GNUNET_CRYPTO_ecdh_ecdsa (&priv_ecdh,
59 &id1,
60 &dh[1]));
61 /* Check that both DH results are equal. */
62 GNUNET_assert (0 ==
63 GNUNET_memcmp (&dh[0],
64 &dh[1]));
65 }
66 return 0;
67}
68
69
70int
71main (int argc, char *argv[])
72{
73 if (! gcry_check_version ("1.6.0"))
74 {
75 fprintf (stderr,
76 "libgcrypt has not the expected version (version %s is required).\n",
77 "1.6.0");
78 return 0;
79 }
80 if (getenv ("GNUNET_GCRYPT_DEBUG"))
81 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
82 GNUNET_log_setup ("test-crypto-ecdh-ecdsa", "WARNING", NULL);
83 for (unsigned int i = 0; i < 4; i++)
84 {
85 fprintf (stderr,
86 ".");
87 if (0 != test_ecdh ())
88 return 1;
89 }
90 return 0;
91}
92
93
94/* end of test_crypto_ecdh_ecdsa.c */
diff --git a/src/util/test_crypto_ecdh_eddsa.c b/src/util/test_crypto_ecdh_eddsa.c
deleted file mode 100644
index 6efd4d2fe..000000000
--- a/src/util/test_crypto_ecdh_eddsa.c
+++ /dev/null
@@ -1,95 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002-2015 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 util/test_crypto_ecdh_eddsa.c
23 * @brief testcase for ECC DH key exchange with EdDSA private keys.
24 * @author Christian Grothoff
25 * @author Bart Polot
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include <gcrypt.h>
30
31
32static int
33test_ecdh ()
34{
35 struct GNUNET_CRYPTO_EddsaPrivateKey priv_dsa;
36 struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdh;
37 struct GNUNET_CRYPTO_EddsaPublicKey id1;
38 struct GNUNET_CRYPTO_EcdhePublicKey id2;
39 struct GNUNET_HashCode dh[2];
40
41 /* Generate keys */
42 GNUNET_CRYPTO_eddsa_key_create (&priv_dsa);
43 GNUNET_CRYPTO_eddsa_key_get_public (&priv_dsa,
44 &id1);
45 for (unsigned int j = 0; j < 4; j++)
46 {
47 fprintf (stderr, ",");
48 GNUNET_CRYPTO_ecdhe_key_create (&priv_ecdh);
49 /* Extract public keys */
50 GNUNET_CRYPTO_ecdhe_key_get_public (&priv_ecdh,
51 &id2);
52 /* Do ECDH */
53 GNUNET_assert (GNUNET_OK ==
54 GNUNET_CRYPTO_eddsa_ecdh (&priv_dsa,
55 &id2,
56 &dh[0]));
57 GNUNET_assert (GNUNET_OK ==
58 GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdh,
59 &id1,
60 &dh[1]));
61 /* Check that both DH results are equal. */
62 GNUNET_assert (0 ==
63 GNUNET_memcmp (&dh[0],
64 &dh[1]));
65 }
66 return 0;
67}
68
69
70int
71main (int argc, char *argv[])
72{
73 if (! gcry_check_version ("1.6.0"))
74 {
75 fprintf (stderr,
76 _ (
77 "libgcrypt has not the expected version (version %s is required).\n"),
78 "1.6.0");
79 return 0;
80 }
81 if (getenv ("GNUNET_GCRYPT_DEBUG"))
82 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
83 GNUNET_log_setup ("test-crypto-ecdh-eddsa", "WARNING", NULL);
84 for (unsigned int i = 0; i < 4; i++)
85 {
86 fprintf (stderr,
87 ".");
88 if (0 != test_ecdh ())
89 return 1;
90 }
91 return 0;
92}
93
94
95/* end of test_crypto_ecdh_eddsa.c */
diff --git a/src/util/test_crypto_ecdhe.c b/src/util/test_crypto_ecdhe.c
deleted file mode 100644
index 1144f1fe5..000000000
--- a/src/util/test_crypto_ecdhe.c
+++ /dev/null
@@ -1,70 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002-2013 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 util/test_crypto_ecdhe.c
23 * @brief testcase for ECC ECDHE public key crypto
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gcrypt.h>
29
30
31int
32main (int argc, char *argv[])
33{
34 struct GNUNET_CRYPTO_EcdhePrivateKey priv1;
35 struct GNUNET_CRYPTO_EcdhePrivateKey priv2;
36 struct GNUNET_CRYPTO_EcdhePublicKey pub1;
37 struct GNUNET_CRYPTO_EcdhePublicKey pub2;
38 struct GNUNET_HashCode ecdh1;
39 struct GNUNET_HashCode ecdh2;
40
41 if (! gcry_check_version ("1.6.0"))
42 {
43 fprintf (stderr,
44 "libgcrypt has not the expected version (version %s is required).\n",
45 "1.6.0");
46 return 0;
47 }
48 if (getenv ("GNUNET_GCRYPT_DEBUG"))
49 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
50 GNUNET_log_setup ("test-crypto-ecdhe", "WARNING", NULL);
51
52 for (unsigned int i = 0; i < 100; i++)
53 {
54 fprintf (stderr,
55 ".");
56 GNUNET_CRYPTO_ecdhe_key_create (&priv1);
57 GNUNET_CRYPTO_ecdhe_key_create (&priv2);
58 GNUNET_CRYPTO_ecdhe_key_get_public (&priv1, &pub1);
59 GNUNET_CRYPTO_ecdhe_key_get_public (&priv2, &pub2);
60 GNUNET_CRYPTO_ecc_ecdh (&priv1, &pub2, &ecdh1);
61 GNUNET_CRYPTO_ecc_ecdh (&priv2, &pub1, &ecdh2);
62 GNUNET_assert (0 ==
63 GNUNET_memcmp (&ecdh1,
64 &ecdh2));
65 }
66 return 0;
67}
68
69
70/* end of test_crypto_ecdhe.c */
diff --git a/src/util/test_crypto_ecdsa.c b/src/util/test_crypto_ecdsa.c
deleted file mode 100644
index 7908590a8..000000000
--- a/src/util/test_crypto_ecdsa.c
+++ /dev/null
@@ -1,281 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002-2013 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 util/test_crypto_ecdsa.c
23 * @brief testcase for ECC ECDSA public key crypto
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_signatures.h"
29#include <gcrypt.h>
30
31#define ITER 25
32
33#define PERF GNUNET_YES
34
35
36static struct GNUNET_CRYPTO_EcdsaPrivateKey key;
37
38
39static int
40testSignVerify (void)
41{
42 struct GNUNET_CRYPTO_EcdsaSignature sig;
43 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
44 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
45 struct GNUNET_TIME_Absolute start;
46 int ok = GNUNET_OK;
47
48 fprintf (stderr, "%s", "W");
49 GNUNET_CRYPTO_ecdsa_key_get_public (&key,
50 &pkey);
51 start = GNUNET_TIME_absolute_get ();
52 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
53 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
54
55 for (unsigned int i = 0; i < ITER; i++)
56 {
57 fprintf (stderr, "%s", ".");
58 fflush (stderr);
59 if (GNUNET_SYSERR ==
60 GNUNET_CRYPTO_ecdsa_sign_ (&key,
61 &purp,
62 &sig))
63 {
64 fprintf (stderr,
65 "GNUNET_CRYPTO_ecdsa_sign returned SYSERR\n");
66 ok = GNUNET_SYSERR;
67 continue;
68 }
69 if (GNUNET_SYSERR ==
70 GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
71 &purp,
72 &sig,
73 &pkey))
74 {
75 fprintf (stderr,
76 "GNUNET_CRYPTO_ecdsa_verify failed!\n");
77 ok = GNUNET_SYSERR;
78 continue;
79 }
80 if (GNUNET_SYSERR !=
81 GNUNET_CRYPTO_ecdsa_verify_ (
82 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
83 &purp,
84 &sig,
85 &pkey))
86 {
87 fprintf (stderr,
88 "GNUNET_CRYPTO_ecdsa_verify failed to fail!\n");
89 ok = GNUNET_SYSERR;
90 continue;
91 }
92 }
93 printf ("%d ECDSA sign/verify operations %s\n",
94 ITER,
95 GNUNET_STRINGS_relative_time_to_string (
96 GNUNET_TIME_absolute_get_duration (start),
97 GNUNET_YES));
98 return ok;
99}
100
101
102static int
103testDeriveSignVerify (void)
104{
105 struct GNUNET_CRYPTO_EcdsaSignature sig;
106 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
107 struct GNUNET_CRYPTO_EcdsaPrivateKey *dpriv;
108 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
109 struct GNUNET_CRYPTO_EcdsaPublicKey dpub;
110 struct GNUNET_CRYPTO_EcdsaPublicKey dpub2;
111
112 dpriv = GNUNET_CRYPTO_ecdsa_private_key_derive (&key,
113 "test-derive",
114 "test-CTX");
115 GNUNET_CRYPTO_ecdsa_key_get_public (&key,
116 &pkey);
117 GNUNET_CRYPTO_ecdsa_public_key_derive (&pkey,
118 "test-derive",
119 "test-CTX",
120 &dpub);
121 GNUNET_CRYPTO_ecdsa_key_get_public (dpriv, &dpub2);
122 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
123 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
124
125 if (0 != GNUNET_memcmp (&dpub.q_y, &dpub2.q_y))
126 {
127 fprintf (stderr, "%s", "key derivation failed\n");
128 GNUNET_free (dpriv);
129 return GNUNET_SYSERR;
130 }
131
132 if (GNUNET_SYSERR ==
133 GNUNET_CRYPTO_ecdsa_sign_ (dpriv,
134 &purp,
135 &sig))
136 {
137 fprintf (stderr, "%s", "GNUNET_CRYPTO_ecdsa_sign returned SYSERR\n");
138 GNUNET_free (dpriv);
139 return GNUNET_SYSERR;
140 }
141 if (GNUNET_SYSERR ==
142 GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
143 &purp,
144 &sig,
145 &dpub))
146 {
147 fprintf (stderr,
148 "GNUNET_CRYPTO_ecdsa_verify failed!\n");
149 GNUNET_free (dpriv);
150 return GNUNET_SYSERR;
151 }
152 if (GNUNET_SYSERR !=
153 GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
154 &purp,
155 &sig,
156 &pkey))
157 {
158 fprintf (stderr,
159 "GNUNET_CRYPTO_ecdsa_verify failed to fail!\n");
160 GNUNET_free (dpriv);
161 return GNUNET_SYSERR;
162 }
163 if (GNUNET_SYSERR !=
164 GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
165 &purp,
166 &sig,
167 &dpub))
168 {
169 fprintf (stderr,
170 "GNUNET_CRYPTO_ecdsa_verify failed to fail!\n");
171 GNUNET_free (dpriv);
172 return GNUNET_SYSERR;
173 }
174 GNUNET_free (dpriv);
175 return GNUNET_OK;
176}
177
178
179#if PERF
180static int
181testSignPerformance (void)
182{
183 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
184 struct GNUNET_CRYPTO_EcdsaSignature sig;
185 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
186 int i;
187 struct GNUNET_TIME_Absolute start;
188 int ok = GNUNET_OK;
189
190 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
191 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
192 fprintf (stderr, "%s", "W");
193 GNUNET_CRYPTO_ecdsa_key_get_public (key, &pkey);
194 start = GNUNET_TIME_absolute_get ();
195 for (i = 0; i < ITER; i++)
196 {
197 fprintf (stderr, "%s", "."); fflush (stderr);
198 if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign_ (key, &purp, &sig))
199 {
200 fprintf (stderr, "%s",
201 "GNUNET_CRYPTO_ecdsa_sign returned SYSERR\n");
202 ok = GNUNET_SYSERR;
203 continue;
204 }
205 }
206 printf ("%d ECC sign operations %s\n", ITER,
207 GNUNET_STRINGS_relative_time_to_string (
208 GNUNET_TIME_absolute_get_duration (start),
209 GNUNET_YES));
210 return ok;
211}
212
213
214#endif
215
216
217static void
218perf_keygen (void)
219{
220 struct GNUNET_TIME_Absolute start;
221 struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
222
223 fprintf (stderr, "%s", "W");
224 start = GNUNET_TIME_absolute_get ();
225 for (unsigned int i = 0; i < 10; i++)
226 {
227 fprintf (stderr, ".");
228 fflush (stderr);
229 GNUNET_CRYPTO_ecdsa_key_create (&pk);
230 }
231 fflush (stderr);
232 printf ("10 ECDSA keys created in %s\n",
233 GNUNET_STRINGS_relative_time_to_string (
234 GNUNET_TIME_absolute_get_duration (start),
235 GNUNET_YES));
236}
237
238
239int
240main (int argc, char *argv[])
241{
242 int failure_count = 0;
243
244 if (! gcry_check_version ("1.6.0"))
245 {
246 fprintf (stderr,
247 "libgcrypt has not the expected version (version %s is required).\n",
248 "1.6.0");
249 return 0;
250 }
251 if (getenv ("GNUNET_GCRYPT_DEBUG"))
252 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
253 GNUNET_log_setup ("test-crypto-ecc", "WARNING", NULL);
254 GNUNET_CRYPTO_ecdsa_key_create (&key);
255 if (GNUNET_OK != testDeriveSignVerify ())
256 {
257 failure_count++;
258 fprintf (stderr,
259 "\n\n%d TESTS FAILED!\n\n", failure_count);
260 return -1;
261 }
262#if PERF
263 if (GNUNET_OK != testSignPerformance ())
264 failure_count++;
265#endif
266 if (GNUNET_OK != testSignVerify ())
267 failure_count++;
268 perf_keygen ();
269
270 if (0 != failure_count)
271 {
272 fprintf (stderr,
273 "\n\n%d TESTS FAILED!\n\n",
274 failure_count);
275 return -1;
276 }
277 return 0;
278}
279
280
281/* end of test_crypto_ecdsa.c */
diff --git a/src/util/test_crypto_eddsa.c b/src/util/test_crypto_eddsa.c
deleted file mode 100644
index 10d6a4e91..000000000
--- a/src/util/test_crypto_eddsa.c
+++ /dev/null
@@ -1,316 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002-2013 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 util/test_crypto_eddsa.c
23 * @brief testcase for ECC public key crypto
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_signatures.h"
29#include <gcrypt.h>
30
31#define ITER 25
32
33#define KEYFILE "/tmp/test-gnunet-crypto-eddsa.key"
34
35#define PERF GNUNET_YES
36
37
38static struct GNUNET_CRYPTO_EddsaPrivateKey key;
39
40
41static int
42testSignVerify (void)
43{
44 struct GNUNET_CRYPTO_EddsaSignature sig;
45 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
46 struct GNUNET_CRYPTO_EddsaPublicKey pkey;
47 struct GNUNET_TIME_Absolute start;
48 int ok = GNUNET_OK;
49
50 fprintf (stderr, "%s", "W");
51 GNUNET_CRYPTO_eddsa_key_get_public (&key,
52 &pkey);
53 start = GNUNET_TIME_absolute_get ();
54 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
55 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
56
57 for (unsigned int i = 0; i < ITER; i++)
58 {
59 fprintf (stderr, "%s", "."); fflush (stderr);
60 if (GNUNET_SYSERR == GNUNET_CRYPTO_eddsa_sign_ (&key,
61 &purp,
62 &sig))
63 {
64 fprintf (stderr,
65 "GNUNET_CRYPTO_eddsa_sign returned SYSERR\n");
66 ok = GNUNET_SYSERR;
67 continue;
68 }
69 if (GNUNET_SYSERR ==
70 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
71 &purp,
72 &sig,
73 &pkey))
74 {
75 fprintf (stderr,
76 "GNUNET_CRYPTO_eddsa_verify failed!\n");
77 ok = GNUNET_SYSERR;
78 continue;
79 }
80 if (GNUNET_SYSERR !=
81 GNUNET_CRYPTO_eddsa_verify_ (
82 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
83 &purp,
84 &sig,
85 &pkey))
86 {
87 fprintf (stderr,
88 "GNUNET_CRYPTO_eddsa_verify failed to fail!\n");
89 ok = GNUNET_SYSERR;
90 continue;
91 }
92 }
93 fprintf (stderr, "\n");
94 printf ("%d EdDSA sign/verify operations %s\n",
95 ITER,
96 GNUNET_STRINGS_relative_time_to_string (
97 GNUNET_TIME_absolute_get_duration (start),
98 GNUNET_YES));
99 return ok;
100}
101
102
103static int
104testDeriveSignVerify (void)
105{
106 struct GNUNET_CRYPTO_EddsaSignature sig;
107 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
108 struct GNUNET_CRYPTO_EddsaPrivateScalar dpriv;
109 struct GNUNET_CRYPTO_EddsaPublicKey pkey;
110 struct GNUNET_CRYPTO_EddsaPublicKey dpub;
111 struct GNUNET_CRYPTO_EddsaPublicKey dpub2;
112
113 GNUNET_CRYPTO_eddsa_private_key_derive (&key,
114 "test-derive",
115 "test-CTX",
116 &dpriv);
117 GNUNET_CRYPTO_eddsa_key_get_public (&key,
118 &pkey);
119 GNUNET_CRYPTO_eddsa_public_key_derive (&pkey,
120 "test-derive",
121 "test-CTX",
122 &dpub);
123 GNUNET_CRYPTO_eddsa_key_get_public_from_scalar (&dpriv, &dpub2);
124 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
125 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
126
127 if (0 != GNUNET_memcmp (&dpub.q_y, &dpub2.q_y))
128 {
129 fprintf (stderr, "%s", "key derivation failed\n");
130 return GNUNET_SYSERR;
131 }
132
133 GNUNET_CRYPTO_eddsa_sign_with_scalar (&dpriv,
134 &purp,
135 &sig);
136 if (GNUNET_SYSERR ==
137 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
138 &purp,
139 &sig,
140 &dpub))
141 {
142 fprintf (stderr,
143 "GNUNET_CRYPTO_eddsa_verify failed!\n");
144 return GNUNET_SYSERR;
145 }
146 if (GNUNET_SYSERR !=
147 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
148 &purp,
149 &sig,
150 &pkey))
151 {
152 fprintf (stderr,
153 "GNUNET_CRYPTO_eddsa_verify failed to fail!\n");
154 return GNUNET_SYSERR;
155 }
156 if (GNUNET_SYSERR !=
157 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
158 &purp,
159 &sig,
160 &dpub))
161 {
162 fprintf (stderr,
163 "GNUNET_CRYPTO_eddsa_verify failed to fail!\n");
164 return GNUNET_SYSERR;
165 }
166 return GNUNET_OK;
167}
168
169
170#if PERF
171static int
172testSignPerformance ()
173{
174 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
175 struct GNUNET_CRYPTO_EddsaSignature sig;
176 struct GNUNET_CRYPTO_EddsaPublicKey pkey;
177 struct GNUNET_TIME_Absolute start;
178 int ok = GNUNET_OK;
179
180 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
181 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
182 fprintf (stderr, "%s", "W");
183 GNUNET_CRYPTO_eddsa_key_get_public (&key,
184 &pkey);
185 start = GNUNET_TIME_absolute_get ();
186 for (unsigned int i = 0; i < ITER; i++)
187 {
188 fprintf (stderr, "%s", ".");
189 fflush (stderr);
190 if (GNUNET_SYSERR ==
191 GNUNET_CRYPTO_eddsa_sign_ (&key,
192 &purp,
193 &sig))
194 {
195 fprintf (stderr, "%s", "GNUNET_CRYPTO_eddsa_sign returned SYSERR\n");
196 ok = GNUNET_SYSERR;
197 continue;
198 }
199 }
200 fprintf (stderr, "\n");
201 printf ("%d EdDSA sign operations %s\n",
202 ITER,
203 GNUNET_STRINGS_relative_time_to_string (
204 GNUNET_TIME_absolute_get_duration (start),
205 GNUNET_YES));
206 return ok;
207}
208
209
210#endif
211
212
213static int
214testCreateFromFile (void)
215{
216 struct GNUNET_CRYPTO_EddsaPublicKey p1;
217 struct GNUNET_CRYPTO_EddsaPublicKey p2;
218
219 GNUNET_assert (0 <=
220 GNUNET_CRYPTO_eddsa_key_from_file (KEYFILE,
221 GNUNET_YES,
222 &key));
223 GNUNET_CRYPTO_eddsa_key_get_public (&key,
224 &p1);
225 GNUNET_assert (GNUNET_NO ==
226 GNUNET_CRYPTO_eddsa_key_from_file (KEYFILE,
227 GNUNET_YES,
228 &key));
229 GNUNET_CRYPTO_eddsa_key_get_public (&key,
230 &p2);
231 GNUNET_assert (0 ==
232 GNUNET_memcmp (&p1,
233 &p2));
234 GNUNET_assert (0 == unlink (KEYFILE));
235 GNUNET_assert (GNUNET_OK ==
236 GNUNET_CRYPTO_eddsa_key_from_file (KEYFILE,
237 GNUNET_NO,
238 &key));
239 GNUNET_CRYPTO_eddsa_key_get_public (&key,
240 &p2);
241 GNUNET_assert (0 !=
242 GNUNET_memcmp (&p1,
243 &p2));
244 return GNUNET_OK;
245}
246
247
248static void
249perf_keygen (void)
250{
251 struct GNUNET_TIME_Absolute start;
252 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
253
254 fprintf (stderr, "%s", "W");
255 start = GNUNET_TIME_absolute_get ();
256 for (unsigned int i = 0; i < 10; i++)
257 {
258 fprintf (stderr, ".");
259 fflush (stderr);
260 GNUNET_CRYPTO_eddsa_key_create (&pk);
261 }
262 fprintf (stderr, "\n");
263 printf ("10 EdDSA keys created in %s\n",
264 GNUNET_STRINGS_relative_time_to_string (
265 GNUNET_TIME_absolute_get_duration (start), GNUNET_YES));
266}
267
268
269int
270main (int argc, char *argv[])
271{
272 int failure_count = 0;
273
274 if (! gcry_check_version ("1.6.0"))
275 {
276 fprintf (stderr,
277 "libgcrypt has not the expected version (version %s is required).\n",
278 "1.6.0");
279 return 0;
280 }
281 if (getenv ("GNUNET_GCRYPT_DEBUG"))
282 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
283 GNUNET_log_setup ("test-crypto-eddsa",
284 "WARNING",
285 NULL);
286 GNUNET_CRYPTO_eddsa_key_create (&key);
287 if (GNUNET_OK != testDeriveSignVerify ())
288 {
289 failure_count++;
290 fprintf (stderr,
291 "\n\n%d TESTS FAILED!\n\n", failure_count);
292 return -1;
293 }
294#if PERF
295 if (GNUNET_OK != testSignPerformance ())
296 failure_count++;
297#endif
298 if (GNUNET_OK != testSignVerify ())
299 failure_count++;
300 if (GNUNET_OK != testCreateFromFile ())
301 failure_count++;
302 GNUNET_assert (0 == unlink (KEYFILE));
303 perf_keygen ();
304
305 if (0 != failure_count)
306 {
307 fprintf (stderr,
308 "\n\n%d TESTS FAILED!\n\n",
309 failure_count);
310 return -1;
311 }
312 return 0;
313}
314
315
316/* end of test_crypto_eddsa.c */
diff --git a/src/util/test_crypto_hash.c b/src/util/test_crypto_hash.c
deleted file mode 100644
index d22e1f5d3..000000000
--- a/src/util/test_crypto_hash.c
+++ /dev/null
@@ -1,168 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002, 2003, 2004, 2006, 2009 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 * @author Christian Grothoff
23 * @file util/test_crypto_hash.c
24 * @brief Test for crypto_hash.c
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29static char block[65536];
30
31#define FILENAME "testblock.dat"
32
33static int
34test (int number)
35{
36 struct GNUNET_HashCode h1;
37 struct GNUNET_HashCode h2;
38 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
39
40 memset (&h1, number, sizeof(struct GNUNET_HashCode));
41 GNUNET_CRYPTO_hash_to_enc (&h1, &enc);
42 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &h2))
43 {
44 printf ("enc2hash failed!\n");
45 return 1;
46 }
47 if (0 != memcmp (&h1, &h2, sizeof(struct GNUNET_HashCode)))
48 return 1;
49 return 0;
50}
51
52
53static int
54testEncoding ()
55{
56 int i;
57
58 for (i = 0; i < 255; i++)
59 if (0 != test (i))
60 return 1;
61 return 0;
62}
63
64
65static int
66testArithmetic ()
67{
68 struct GNUNET_HashCode h1;
69 struct GNUNET_HashCode h2;
70 struct GNUNET_HashCode d;
71 struct GNUNET_HashCode s;
72 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
73 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
74
75 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &h1);
76 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &h2);
77 if (GNUNET_CRYPTO_hash_distance_u32 (&h1, &h2) !=
78 GNUNET_CRYPTO_hash_distance_u32 (&h2, &h1))
79 return 1;
80 GNUNET_CRYPTO_hash_difference (&h1, &h2, &d);
81 GNUNET_CRYPTO_hash_sum (&h1, &d, &s);
82 if (0 != GNUNET_CRYPTO_hash_cmp (&s, &h2))
83 return 1;
84 GNUNET_CRYPTO_hash_xor (&h1, &h2, &d);
85 GNUNET_CRYPTO_hash_xor (&h1, &d, &s);
86 if (0 != GNUNET_CRYPTO_hash_cmp (&s, &h2))
87 return 1;
88 if (0 != GNUNET_CRYPTO_hash_xorcmp (&s, &h2, &h1))
89 return 1;
90 if (-1 != GNUNET_CRYPTO_hash_xorcmp (&h1, &h2, &h1))
91 return 1;
92 if (1 != GNUNET_CRYPTO_hash_xorcmp (&h1, &h2, &h2))
93 return 1;
94 memset (&d, 0x40, sizeof(d));
95 if (0 != GNUNET_CRYPTO_hash_get_bit_rtl (&d, 3))
96 return 1;
97 if (1 != GNUNET_CRYPTO_hash_get_bit_rtl (&d, 6))
98 return 1;
99 memset (&d, 0x02, sizeof(d));
100 if (0 != GNUNET_CRYPTO_hash_get_bit_ltr (&d, 3))
101 return 1;
102 if (1 != GNUNET_CRYPTO_hash_get_bit_ltr (&d, 6))
103 return 1;
104 memset (&d, 0, sizeof(d));
105 GNUNET_CRYPTO_hash_to_aes_key (&d, &skey, &iv);
106 return 0;
107}
108
109
110static void
111finished_task (void *cls, const struct GNUNET_HashCode *res)
112{
113 int *ret = cls;
114 struct GNUNET_HashCode want;
115
116 GNUNET_CRYPTO_hash (block, sizeof(block), &want);
117 if (0 != memcmp (res, &want, sizeof(want)))
118 *ret = 2;
119 else
120 *ret = 0;
121}
122
123
124static void
125file_hasher (void *cls)
126{
127 GNUNET_assert (NULL !=
128 GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
129 FILENAME, 1024, &finished_task, cls));
130}
131
132
133static int
134testFileHash ()
135{
136 int ret;
137 FILE *f;
138
139 memset (block, 42, sizeof(block) / 2);
140 memset (&block[sizeof(block) / 2], 43, sizeof(block) / 2);
141 GNUNET_assert (NULL != (f = fopen (FILENAME, "w+")));
142 GNUNET_break (sizeof(block) == fwrite (block, 1, sizeof(block), f));
143 GNUNET_break (0 == fclose (f));
144 ret = 1;
145 GNUNET_SCHEDULER_run (&file_hasher, &ret);
146 GNUNET_break (0 == unlink (FILENAME));
147 return ret;
148}
149
150
151int
152main (int argc, char *argv[])
153{
154 int failureCount = 0;
155 int i;
156
157 GNUNET_log_setup ("test-crypto-hash", "WARNING", NULL);
158 for (i = 0; i < 10; i++)
159 failureCount += testEncoding ();
160 failureCount += testArithmetic ();
161 failureCount += testFileHash ();
162 if (failureCount != 0)
163 return 1;
164 return 0;
165}
166
167
168/* end of hashingtest.c */
diff --git a/src/util/test_crypto_hash_context.c b/src/util/test_crypto_hash_context.c
deleted file mode 100644
index 8c652595f..000000000
--- a/src/util/test_crypto_hash_context.c
+++ /dev/null
@@ -1,49 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014 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 * @file util/test_crypto_hash_context.c
22 * @brief test case for incremental hashing
23 * @author Florian Dold
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28#define LEN 1234
29
30int
31main ()
32{
33 char data[1234];
34 struct GNUNET_HashCode hc1;
35 struct GNUNET_HashCode hc2;
36 struct GNUNET_HashContext *hctx;
37
38 memset (data, 42, LEN);
39
40 hctx = GNUNET_CRYPTO_hash_context_start ();
41 GNUNET_CRYPTO_hash_context_read (hctx, data, LEN);
42 GNUNET_CRYPTO_hash_context_finish (hctx, &hc1);
43
44 GNUNET_CRYPTO_hash (data, LEN, &hc2);
45
46 if (0 == memcmp (&hc1, &hc2, sizeof(struct GNUNET_HashCode)))
47 return 0;
48 return 1;
49}
diff --git a/src/util/test_crypto_hkdf.c b/src/util/test_crypto_hkdf.c
deleted file mode 100644
index 85be5bb80..000000000
--- a/src/util/test_crypto_hkdf.c
+++ /dev/null
@@ -1,338 +0,0 @@
1/*
2 Copyright (c) 2010 Nils Durner
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23/**
24 * @file src/util/test_crypt_hkdf.c
25 * @brief Testcases for HKDF
26 * @todo: test for out_len < hash_len
27 * @author Nils Durner
28 */
29
30#include <gcrypt.h>
31
32#include "platform.h"
33#include "gnunet_crypto_lib.h"
34
35void
36tc1 ()
37{
38 unsigned char ikm[22] =
39 { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
40 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
41 unsigned char salt[13] =
42 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
43 0x0a, 0x0b, 0x0c };
44 unsigned char info[10] =
45 { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
46 unsigned char okm[42] =
47 { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43,
48 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a,
49 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00,
50 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65 };
51 unsigned char result[44];
52 int l = 42;
53
54 memset (result, 0, sizeof(result));
55 GNUNET_assert (GNUNET_CRYPTO_hkdf
56 (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, salt,
57 sizeof(salt), ikm, sizeof(ikm), info, sizeof(info),
58 NULL) == GNUNET_YES);
59 GNUNET_assert (memcmp (result, okm, l) == 0);
60 GNUNET_assert (memcmp (result + l, "\0", 2) == 0);
61}
62
63
64void
65tc2 ()
66{
67 unsigned char ikm[80] =
68 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
69 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
70 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
71 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
72 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
73 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
74 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
75 unsigned char salt[80] =
76 { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
77 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
78 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81,
79 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
80 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
81 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
82 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf };
83 unsigned char info[80] =
84 { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
85 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
86 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1,
87 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd,
88 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
89 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
90 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
91 unsigned char okm[82] =
92 { 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7,
93 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e,
94 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04,
95 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59,
96 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77,
97 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec,
98 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87 };
99 char result[84];
100 int l = 82;
101
102 memset (result, 0, sizeof(result));
103 GNUNET_assert (GNUNET_CRYPTO_hkdf
104 (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, salt,
105 sizeof(salt), ikm, sizeof(ikm), info, sizeof(info),
106 NULL) == GNUNET_YES);
107 GNUNET_assert (memcmp (result, okm, l) == 0);
108 GNUNET_assert (memcmp (result + l, "\0", 2) == 0);
109}
110
111
112void
113tc3 ()
114{
115 unsigned char ikm[22] =
116 { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
117 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
118 unsigned char okm[42] =
119 { 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f,
120 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1,
121 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20,
122 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8 };
123 unsigned char result[44];
124 int l = 42;
125
126 memset (result, 0, sizeof(result));
127 GNUNET_assert (GNUNET_CRYPTO_hkdf
128 (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, NULL, 0, ikm,
129 sizeof(ikm), NULL, 0, NULL) == GNUNET_YES);
130 GNUNET_assert (memcmp (result, okm, l) == 0);
131 GNUNET_assert (memcmp (result + l, "\0", 2) == 0);
132}
133
134
135void
136tc4 ()
137{
138 unsigned char ikm[11] =
139 { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
140 0x0b };
141 unsigned char salt[13] =
142 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
143 0x0a, 0x0b, 0x0c };
144 unsigned char info[10] =
145 { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
146 unsigned char okm[42] =
147 { 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06,
148 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b,
149 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e,
150 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96 };
151 char result[84];
152 int l = 42;
153
154 memset (result, 0, sizeof(result));
155 GNUNET_assert (GNUNET_CRYPTO_hkdf
156 (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof(salt),
157 ikm, sizeof(ikm), info, sizeof(info), NULL) == GNUNET_YES);
158 GNUNET_assert (memcmp (result, okm, l) == 0);
159 GNUNET_assert (memcmp (result + l, "\0", 2) == 0);
160}
161
162
163void
164tc5 ()
165{
166 unsigned char ikm[80] =
167 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
168 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
169 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
170 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
171 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
172 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
173 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
174 unsigned char salt[80] =
175 { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
176 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
177 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81,
178 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
179 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
180 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
181 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf };
182 unsigned char info[80] =
183 { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
184 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
185 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1,
186 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd,
187 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
188 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
189 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
190 unsigned char okm[82] =
191 { 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1,
192 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d,
193 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3,
194 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2,
195 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c,
196 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f,
197 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 };
198 char result[84];
199 int l = 82;
200
201 memset (result, 0, sizeof(result));
202 GNUNET_assert (GNUNET_CRYPTO_hkdf
203 (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof(salt),
204 ikm, sizeof(ikm), info, sizeof(info), NULL) == GNUNET_YES);
205 GNUNET_assert (memcmp (result, okm, l) == 0);
206 GNUNET_assert (memcmp (result + l, "\0", 2) == 0);
207}
208
209
210void
211tc6 ()
212{
213 unsigned char ikm[22] =
214 { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
215 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
216 unsigned char okm[42] =
217 { 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5,
218 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20,
219 0xa3, 0x06, 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, 0xea, 0x00,
220 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, 0x49, 0x18 };
221 char result[44];
222 int l = 42;
223
224 memset (result, 0, sizeof(result));
225 GNUNET_assert (GNUNET_CRYPTO_hkdf
226 (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, NULL, 0, ikm,
227 sizeof(ikm), NULL, 0, NULL) == GNUNET_YES);
228 GNUNET_assert (memcmp (result, okm, l) == 0);
229 GNUNET_assert (memcmp (result + l, "\0", 2) == 0);
230}
231
232
233void
234tc7 ()
235{
236 unsigned char ikm[80] =
237 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
238 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
239 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
240 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
241 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
242 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
243 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
244 unsigned char salt[80] =
245 { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
246 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
247 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81,
248 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
249 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
250 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
251 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf };
252 unsigned char info1[34] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
253 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
254 0xc0, 0xc1, 0xc2, 0xc3,
255 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
256 0xcc, 0xcd, 0xce, 0xcf,
257 0xd0, 0xd1 };
258 unsigned char info2[46] = { 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
259 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
260 0xe2, 0xe3, 0xe4, 0xe5,
261 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed,
262 0xee, 0xef, 0xf0, 0xf1,
263 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
264 0xfa, 0xfb, 0xfc, 0xfd,
265 0xfe, 0xff };
266 unsigned char okm[82] =
267 { 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1,
268 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d,
269 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3,
270 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2,
271 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c,
272 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f,
273 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 };
274 char result[84];
275 int l = 82;
276
277 memset (result, 0, sizeof(result));
278 GNUNET_assert (GNUNET_CRYPTO_hkdf
279 (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof(salt),
280 ikm, sizeof(ikm), info1, sizeof(info1), info2,
281 sizeof(info2), NULL) == GNUNET_YES);
282 GNUNET_assert (memcmp (result, okm, l) == 0);
283 GNUNET_assert (memcmp (result + l, "\0", 2) == 0);
284}
285
286
287void
288tc8 ()
289{
290 unsigned char ikm[32] =
291 { 0xbf, 0x16, 0x6e, 0x46, 0x3a, 0x6c, 0xf3, 0x93, 0xa7, 0x72,
292 0x11, 0xa1, 0xdc, 0x0b, 0x07, 0xdb, 0x1a, 0x5e, 0xd9, 0xb9, 0x81, 0xbe,
293 0xea, 0xe4, 0x31, 0x5f, 0x24, 0xff, 0xfe, 0x50, 0x8a, 0xde };
294 unsigned char salt[4] = { 0xfc, 0x62, 0x76, 0x35 };
295 unsigned char info[86] =
296 { 0x8c, 0x0d, 0xcf, 0xb3, 0x25, 0x6e, 0x88, 0x0d, 0xc1, 0x0b,
297 0x1d, 0x33, 0x15, 0x3e, 0x52, 0x0b, 0xb0, 0x77, 0xff, 0x7d, 0xc3, 0xc7,
298 0xef, 0xe5, 0x8e, 0x3c, 0xc4, 0x4e, 0x8b, 0x41, 0x46, 0x1f, 0x02, 0x94,
299 0x82, 0x35, 0xc5, 0xa6, 0x5e, 0x91, 0xd8, 0xa2, 0x90, 0xfd, 0x6f, 0xb4,
300 0x07, 0xc9, 0xed, 0x6b, 0x18, 0x90, 0x31, 0xab, 0x0f, 0xb5, 0x6b, 0xec,
301 0x9e, 0x45, 0xa2, 0x83, 0x65, 0x41, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61,
302 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x65, 0x63,
303 0x74, 0x6f, 0x72, 0x00 };
304 unsigned char okm[16] =
305 { 0xd6, 0x90, 0xec, 0x9e, 0x62, 0xdf, 0xb9, 0x41, 0xff, 0x92,
306 0x4f, 0xd2, 0xf6, 0x1d, 0x67, 0xe0 };
307 char result[18];
308 int l = 16;
309
310 memset (result, 0, sizeof(result));
311 GNUNET_assert (GNUNET_CRYPTO_hkdf
312 (result, l, GCRY_MD_SHA512, GCRY_MD_SHA256, salt,
313 sizeof(salt), ikm, sizeof(ikm), info, sizeof(info),
314 NULL) == GNUNET_YES);
315 GNUNET_assert (memcmp (result, okm, l) == 0);
316 GNUNET_assert (memcmp (result + l, "\0", 2) == 0);
317}
318
319
320int
321main ()
322{
323 GNUNET_log_setup ("test-crypto-hkdf", "WARNING", NULL);
324
325 /* Official test vectors */
326 tc1 ();
327 tc2 ();
328 tc3 ();
329 tc4 ();
330 tc5 ();
331 tc6 ();
332
333 /* Additional tests */
334 tc7 ();
335 tc8 ();
336
337 return 0;
338}
diff --git a/src/util/test_crypto_kdf.c b/src/util/test_crypto_kdf.c
deleted file mode 100644
index 7c33e0ba8..000000000
--- a/src/util/test_crypto_kdf.c
+++ /dev/null
@@ -1,71 +0,0 @@
1/*
2 Copyright (c) 2010 Jeffrey Burdges
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23/**
24 * @file src/util/test_crypt_kdf.c
25 * @brief Testcases for KDF mod n
26 * @author Jeffrey Burdges <burdges@gnunet.org>
27 */
28
29#include <gcrypt.h>
30
31#include "platform.h"
32#include "gnunet_crypto_lib.h"
33
34
35int
36main ()
37{
38#define RND_BLK_SIZE 4096
39 unsigned char rnd_blk[RND_BLK_SIZE];
40 int i;
41 gcry_mpi_t r, n;
42
43 GNUNET_log_setup ("test-crypto-kdf", "WARNING", NULL);
44
45 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
46 rnd_blk,
47 RND_BLK_SIZE);
48
49 /* test full domain hash size */
50 for (i = 0; i < 100; i++)
51 {
52 gcry_mpi_scan (&n,
53 GCRYMPI_FMT_USG,
54 rnd_blk, RND_BLK_SIZE,
55 NULL);
56 GNUNET_CRYPTO_kdf_mod_mpi (&r, n,
57 "", 0,
58 "", 0,
59 "");
60 GNUNET_assert (0 > gcry_mpi_cmp (r, n));
61
62 /* Is it worth checking that it's not too small? */
63 /* GNUNET_assert (gcry_mpi_get_nbits(r) > 3*RND_BLK_SIZE/4); */
64 /* This test necessarily randomly fails with probability 2^(3 - RND_BLK_SIZE/4) */
65
66 gcry_mpi_release (n);
67 gcry_mpi_release (r);
68 }
69
70 return 0;
71}
diff --git a/src/util/test_crypto_paillier.c b/src/util/test_crypto_paillier.c
deleted file mode 100644
index 64c9569cb..000000000
--- a/src/util/test_crypto_paillier.c
+++ /dev/null
@@ -1,247 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014 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 util/test_crypto_paillier.c
23 * @brief testcase paillier crypto
24 * @author Christian Fuchs
25 * @author Florian Dold
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include <gcrypt.h>
30
31
32static int
33test_crypto ()
34{
35 gcry_mpi_t plaintext;
36 gcry_mpi_t plaintext_result;
37 struct GNUNET_CRYPTO_PaillierCiphertext ciphertext;
38 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
39 struct GNUNET_CRYPTO_PaillierPrivateKey private_key;
40 int ret = 0;
41
42 GNUNET_CRYPTO_paillier_create (&public_key,
43 &private_key);
44 GNUNET_assert (NULL != (plaintext = gcry_mpi_new (0)));
45 GNUNET_assert (NULL != (plaintext_result = gcry_mpi_new (0)));
46 gcry_mpi_randomize (plaintext,
47 GNUNET_CRYPTO_PAILLIER_BITS / 2,
48 GCRY_WEAK_RANDOM);
49
50 GNUNET_CRYPTO_paillier_encrypt (&public_key,
51 plaintext,
52 0 /* 0 hom ops */,
53 &ciphertext);
54 GNUNET_CRYPTO_paillier_decrypt (&private_key,
55 &public_key,
56 &ciphertext,
57 plaintext_result);
58 if (0 != gcry_mpi_cmp (plaintext,
59 plaintext_result))
60 {
61 fprintf (stderr,
62 "Paillier decryption failed with plaintext of size %u\n",
63 gcry_mpi_get_nbits (plaintext));
64 gcry_log_debugmpi ("\n",
65 plaintext);
66 gcry_log_debugmpi ("\n",
67 plaintext_result);
68 ret = 1;
69 }
70 gcry_mpi_release (plaintext);
71 gcry_mpi_release (plaintext_result);
72 return ret;
73}
74
75
76static int
77test_hom_simple (unsigned int a,
78 unsigned int b)
79{
80 gcry_mpi_t m1;
81 gcry_mpi_t m2;
82 gcry_mpi_t result;
83 gcry_mpi_t hom_result;
84 struct GNUNET_CRYPTO_PaillierCiphertext c1;
85 struct GNUNET_CRYPTO_PaillierCiphertext c2;
86 struct GNUNET_CRYPTO_PaillierCiphertext c_result;
87 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
88 struct GNUNET_CRYPTO_PaillierPrivateKey private_key;
89 int ret = 0;
90
91 GNUNET_CRYPTO_paillier_create (&public_key,
92 &private_key);
93
94 GNUNET_assert (NULL != (m1 = gcry_mpi_new (0)));
95 GNUNET_assert (NULL != (m2 = gcry_mpi_new (0)));
96 GNUNET_assert (NULL != (result = gcry_mpi_new (0)));
97 GNUNET_assert (NULL != (hom_result = gcry_mpi_new (0)));
98 m1 = gcry_mpi_set_ui (m1, a);
99 m2 = gcry_mpi_set_ui (m2, b);
100 gcry_mpi_add (result,
101 m1,
102 m2);
103 GNUNET_CRYPTO_paillier_encrypt (&public_key,
104 m1,
105 2,
106 &c1);
107 GNUNET_CRYPTO_paillier_encrypt (&public_key,
108 m2,
109 2,
110 &c2);
111 GNUNET_CRYPTO_paillier_hom_add (&public_key,
112 &c1,
113 &c2,
114 &c_result);
115 GNUNET_CRYPTO_paillier_decrypt (&private_key,
116 &public_key,
117 &c_result,
118 hom_result);
119 if (0 != gcry_mpi_cmp (result, hom_result))
120 {
121 fprintf (stderr,
122 "GNUNET_CRYPTO_paillier failed simple math!\n");
123 gcry_log_debugmpi ("got ", hom_result);
124 gcry_log_debugmpi ("wanted ", result);
125 ret = 1;
126 }
127 gcry_mpi_release (m1);
128 gcry_mpi_release (m2);
129 gcry_mpi_release (result);
130 gcry_mpi_release (hom_result);
131 return ret;
132}
133
134
135static int
136test_hom ()
137{
138 int ret;
139 gcry_mpi_t m1;
140 gcry_mpi_t m2;
141 gcry_mpi_t result;
142 gcry_mpi_t hom_result;
143 struct GNUNET_CRYPTO_PaillierCiphertext c1;
144 struct GNUNET_CRYPTO_PaillierCiphertext c2;
145 struct GNUNET_CRYPTO_PaillierCiphertext c_result;
146 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
147 struct GNUNET_CRYPTO_PaillierPrivateKey private_key;
148
149 GNUNET_CRYPTO_paillier_create (&public_key,
150 &private_key);
151
152 GNUNET_assert (NULL != (m1 = gcry_mpi_new (0)));
153 GNUNET_assert (NULL != (m2 = gcry_mpi_new (0)));
154 GNUNET_assert (NULL != (result = gcry_mpi_new (0)));
155 GNUNET_assert (NULL != (hom_result = gcry_mpi_new (0)));
156 m1 = gcry_mpi_set_ui (m1, 1);
157 /* m1 = m1 * 2 ^ (GCPB - 3) */
158 gcry_mpi_mul_2exp (m1,
159 m1,
160 GNUNET_CRYPTO_PAILLIER_BITS - 3);
161 m2 = gcry_mpi_set_ui (m2, 15);
162 /* m1 = m1 * 2 ^ (GCPB / 2) */
163 gcry_mpi_mul_2exp (m2,
164 m2,
165 GNUNET_CRYPTO_PAILLIER_BITS / 2);
166 gcry_mpi_add (result,
167 m1,
168 m2);
169
170 if (1 != (ret = GNUNET_CRYPTO_paillier_encrypt (&public_key,
171 m1,
172 2,
173 &c1)))
174 {
175 fprintf (stderr,
176 "GNUNET_CRYPTO_paillier_encrypt 1 failed, should return 1 allowed operation, got %d!\n",
177 ret);
178 ret = 1;
179 goto out;
180 }
181 if (2 != (ret = GNUNET_CRYPTO_paillier_encrypt (&public_key,
182 m2,
183 2,
184 &c2)))
185 {
186 fprintf (stderr,
187 "GNUNET_CRYPTO_paillier_encrypt 2 failed, should return 2 allowed operation, got %d!\n",
188 ret);
189 ret = 1;
190 goto out;
191 }
192
193 if (0 != (ret = GNUNET_CRYPTO_paillier_hom_add (&public_key,
194 &c1,
195 &c2,
196 &c_result)))
197 {
198 fprintf (stderr,
199 "GNUNET_CRYPTO_paillier_hom_add failed, expected 0 remaining operations, got %d!\n",
200 ret);
201 ret = 1;
202 goto out;
203 }
204
205 GNUNET_CRYPTO_paillier_decrypt (&private_key,
206 &public_key,
207 &c_result,
208 hom_result);
209
210 if (0 != gcry_mpi_cmp (result, hom_result))
211 {
212 fprintf (stderr,
213 "GNUNET_CRYPTO_paillier miscalculated with large numbers!\n");
214 gcry_log_debugmpi ("got", hom_result);
215 gcry_log_debugmpi ("wanted", result);
216 ret = 1;
217 }
218out:
219 gcry_mpi_release (m1);
220 gcry_mpi_release (m2);
221 gcry_mpi_release (result);
222 gcry_mpi_release (hom_result);
223 return ret;
224}
225
226
227int
228main (int argc,
229 char *argv[])
230{
231 int ret;
232
233 ret = test_crypto ();
234 if (0 != ret)
235 return ret;
236 ret = test_hom_simple (2, 4);
237 if (0 != ret)
238 return ret;
239 ret = test_hom_simple (13, 17);
240 if (0 != ret)
241 return ret;
242 ret = test_hom ();
243 return ret;
244}
245
246
247/* end of test_crypto_paillier.c */
diff --git a/src/util/test_crypto_random.c b/src/util/test_crypto_random.c
deleted file mode 100644
index b9cbbdf76..000000000
--- a/src/util/test_crypto_random.c
+++ /dev/null
@@ -1,73 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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/**
23 * @file util/test_crypto_random.c
24 * @brief testcase for crypto_random.c
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29static int
30test (enum GNUNET_CRYPTO_Quality mode)
31{
32 int buf[1024];
33 unsigned int *b2;
34 int i;
35 unsigned long long n;
36 struct GNUNET_Uuid tf;
37
38 for (i = 0; i < 1024; i++)
39 GNUNET_break (1024 > (buf[i] = GNUNET_CRYPTO_random_u32 (mode, 1024)));
40 for (i = 0; i < 10; i++)
41 {
42 b2 = GNUNET_CRYPTO_random_permute (mode, 1024);
43 if (0 == memcmp (b2, buf, sizeof(buf)))
44 {
45 fprintf (stderr, "%s", "!");
46 GNUNET_free (b2);
47 continue;
48 }
49 GNUNET_free (b2);
50 break;
51 }
52 if (i == 10)
53 return 1; /* virtually impossible... */
54
55 for (n = 10; n < 1024LL * 1024LL * 1024LL; n *= 10)
56 GNUNET_break (n > GNUNET_CRYPTO_random_u64 (mode, n));
57 GNUNET_CRYPTO_random_timeflake (mode,
58 &tf);
59 return 0;
60}
61
62
63int
64main (int argc, char *argv[])
65{
66 GNUNET_log_setup ("test-crypto-random", "WARNING", NULL);
67 if (0 != test (GNUNET_CRYPTO_QUALITY_WEAK))
68 return 1;
69 if (0 != test (GNUNET_CRYPTO_QUALITY_STRONG))
70 return 1;
71
72 return 0;
73}
diff --git a/src/util/test_crypto_rsa.c b/src/util/test_crypto_rsa.c
deleted file mode 100644
index 2a676c711..000000000
--- a/src/util/test_crypto_rsa.c
+++ /dev/null
@@ -1,148 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014,2015 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 util/test_crypto_rsa.c
23 * @brief testcase for utility functions for RSA cryptography
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 * @author Jeffrey Burdges <burdges@gnunet.org>
26 */
27#include "platform.h"
28#include <gcrypt.h>
29#include "gnunet_util_lib.h"
30
31#define KEY_SIZE 1024
32
33
34int
35main (int argc,
36 char *argv[])
37{
38#define RND_BLK_SIZE 4096
39 unsigned char rnd_blk[RND_BLK_SIZE];
40 struct GNUNET_CRYPTO_RsaPrivateKey *priv;
41 struct GNUNET_CRYPTO_RsaPrivateKey *priv_copy;
42 struct GNUNET_CRYPTO_RsaPublicKey *pub;
43 struct GNUNET_CRYPTO_RsaPublicKey *pub_copy;
44 struct GNUNET_CRYPTO_RsaSignature *sig;
45 struct GNUNET_CRYPTO_RsaSignature *sig_copy;
46 struct GNUNET_CRYPTO_RsaSignature *bsig;
47 struct GNUNET_CRYPTO_RsaBlindingKeySecret bsec;
48 struct GNUNET_HashCode hash;
49 void *blind_buf;
50 size_t bsize;
51
52 GNUNET_log_setup ("test-rsa", "WARNING", NULL);
53 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
54 rnd_blk,
55 RND_BLK_SIZE);
56 GNUNET_CRYPTO_hash (rnd_blk,
57 RND_BLK_SIZE,
58 &hash);
59 priv = GNUNET_CRYPTO_rsa_private_key_create (KEY_SIZE);
60 priv_copy = GNUNET_CRYPTO_rsa_private_key_dup (priv);
61 GNUNET_assert (NULL != priv_copy);
62 GNUNET_assert (0 == GNUNET_CRYPTO_rsa_private_key_cmp (priv, priv_copy));
63 pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
64
65 /* Encoding */
66 size_t size;
67 void *enc;
68 enc = NULL;
69 size = GNUNET_CRYPTO_rsa_private_key_encode (priv, &enc);
70
71 /* Decoding */
72 GNUNET_CRYPTO_rsa_private_key_free (priv);
73 priv = NULL;
74 priv = GNUNET_CRYPTO_rsa_private_key_decode (enc, size);
75 GNUNET_assert (NULL != priv);
76 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
77 enc, size);
78 GNUNET_assert (NULL == GNUNET_CRYPTO_rsa_private_key_decode (enc, size));
79 (void) fprintf (stderr, "The above warning is expected.\n");
80 GNUNET_free (enc);
81
82 /* try ordinary sig first */
83 sig = GNUNET_CRYPTO_rsa_sign_fdh (priv,
84 &hash);
85 sig_copy = GNUNET_CRYPTO_rsa_signature_dup (sig);
86 GNUNET_assert (NULL != sig);
87 GNUNET_assert (0 == GNUNET_CRYPTO_rsa_signature_cmp (sig, sig_copy));
88 pub_copy = GNUNET_CRYPTO_rsa_public_key_dup (pub);
89 GNUNET_assert (NULL != pub_copy);
90 GNUNET_assert (GNUNET_OK ==
91 GNUNET_CRYPTO_rsa_verify (&hash, sig, pub_copy));
92 {
93 void *buf;
94 size_t buf_size;
95 struct GNUNET_CRYPTO_RsaPublicKey *pub2;
96 struct GNUNET_CRYPTO_RsaSignature *sig2;
97
98 buf_size = GNUNET_CRYPTO_rsa_public_key_encode (pub,
99 &buf);
100 pub2 = GNUNET_CRYPTO_rsa_public_key_decode (buf,
101 buf_size);
102 GNUNET_free (buf);
103 buf_size = GNUNET_CRYPTO_rsa_signature_encode (sig,
104 &buf);
105 sig2 = GNUNET_CRYPTO_rsa_signature_decode (buf,
106 buf_size);
107 GNUNET_free (buf);
108 GNUNET_assert (GNUNET_OK ==
109 GNUNET_CRYPTO_rsa_verify (&hash, sig2, pub2));
110 GNUNET_CRYPTO_rsa_public_key_free (pub2);
111 GNUNET_CRYPTO_rsa_signature_free (sig2);
112 }
113 /* corrupt our hash and see if the signature is still valid */
114 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &hash,
115 sizeof(struct GNUNET_HashCode));
116 GNUNET_assert (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (&hash,
117 sig,
118 pub));
119 (void) fprintf (stderr, "The above warning is expected.\n");
120 GNUNET_CRYPTO_rsa_signature_free (sig);
121
122 /* test blind signing */
123 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
124 &bsec,
125 sizeof(bsec));
126 GNUNET_CRYPTO_rsa_blind (&hash,
127 &bsec,
128 pub,
129 &blind_buf, &bsize);
130 GNUNET_assert (0 != bsize);
131 bsig = GNUNET_CRYPTO_rsa_sign_blinded (priv,
132 blind_buf,
133 bsize);
134 GNUNET_free (blind_buf);
135 sig = GNUNET_CRYPTO_rsa_unblind (bsig,
136 &bsec,
137 pub);
138 GNUNET_CRYPTO_rsa_signature_free (bsig);
139 GNUNET_assert (GNUNET_OK ==
140 GNUNET_CRYPTO_rsa_verify (&hash, sig, pub));
141 GNUNET_CRYPTO_rsa_signature_free (sig);
142 GNUNET_CRYPTO_rsa_signature_free (sig_copy);
143 GNUNET_CRYPTO_rsa_private_key_free (priv);
144 GNUNET_CRYPTO_rsa_private_key_free (priv_copy);
145 GNUNET_CRYPTO_rsa_public_key_free (pub);
146 GNUNET_CRYPTO_rsa_public_key_free (pub_copy);
147 return 0;
148}
diff --git a/src/util/test_crypto_symmetric.c b/src/util/test_crypto_symmetric.c
deleted file mode 100644
index 5012c7f5b..000000000
--- a/src/util/test_crypto_symmetric.c
+++ /dev/null
@@ -1,175 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002, 2003, 2004, 2006 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 * @author Christian Grothoff
23 * @file util/test_crypto_symmetric.c
24 * @brief test for AES ciphers
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define TESTSTRING "Hello World!"
30#define INITVALUE "InitializationVectorValueinitializationvectorvalue"
31
32static int
33testSymcipher ()
34{
35 struct GNUNET_CRYPTO_SymmetricSessionKey key;
36 char result[100];
37 int size;
38 char res[100];
39
40 GNUNET_CRYPTO_symmetric_create_session_key (&key);
41 size =
42 GNUNET_CRYPTO_symmetric_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, &key,
43 (const struct
44 GNUNET_CRYPTO_SymmetricInitializationVector
45 *)
46 INITVALUE, result);
47 if (size == -1)
48 {
49 printf ("symciphertest failed: encryptBlock returned %d\n", size);
50 return 1;
51 }
52 size =
53 GNUNET_CRYPTO_symmetric_decrypt (result, size, &key,
54 (const struct
55 GNUNET_CRYPTO_SymmetricInitializationVector
56 *)
57 INITVALUE, res);
58 if (strlen (TESTSTRING) + 1 != size)
59 {
60 printf ("symciphertest failed: decryptBlock returned %d\n", size);
61 return 1;
62 }
63 if (0 != strcmp (res, TESTSTRING))
64 {
65 printf ("symciphertest failed: %s != %s\n", res, TESTSTRING);
66 return 1;
67 }
68 else
69 return 0;
70}
71
72
73static int
74verifyCrypto ()
75{
76 struct GNUNET_CRYPTO_SymmetricSessionKey key;
77 char result[GNUNET_CRYPTO_AES_KEY_LENGTH];
78 char *res;
79 int ret;
80
81 unsigned char plain[] = {
82 29, 128, 192, 253, 74, 171, 38, 187, 84, 219, 76, 76, 209, 118, 33, 249,
83 172, 124, 96, 9, 157, 110, 8, 215, 200, 63, 69, 230, 157, 104, 247, 164
84 };
85 unsigned char raw_key_aes[] = {
86 106, 74, 209, 88, 145, 55, 189, 135, 125, 180, 225, 108, 183, 54, 25,
87 169, 129, 188, 131, 75, 227, 245, 105, 10, 225, 15, 115, 159, 148, 184,
88 34, 191
89 };
90 unsigned char raw_key_twofish[] = {
91 145, 55, 189, 135, 125, 180, 225, 108, 183, 54, 25,
92 169, 129, 188, 131, 75, 227, 245, 105, 10, 225, 15, 115, 159, 148, 184,
93 34, 191, 106, 74, 209, 88
94 };
95 unsigned char encrresult[] = {
96 155, 88, 106, 174, 124, 172, 47, 149, 85, 15, 208, 176, 65, 124, 155,
97 74, 215, 25, 177, 231, 162, 109, 165, 4, 133, 165, 93, 44, 213, 77,
98 206, 204, 1
99 };
100
101 res = NULL;
102 ret = 0;
103
104 GNUNET_memcpy (key.aes_key, raw_key_aes, GNUNET_CRYPTO_AES_KEY_LENGTH);
105 GNUNET_memcpy (key.twofish_key, raw_key_twofish,
106 GNUNET_CRYPTO_AES_KEY_LENGTH);
107 if (GNUNET_CRYPTO_AES_KEY_LENGTH !=
108 GNUNET_CRYPTO_symmetric_encrypt (plain, GNUNET_CRYPTO_AES_KEY_LENGTH,
109 &key,
110 (const struct
111 GNUNET_CRYPTO_SymmetricInitializationVector
112 *)
113 "testtesttesttesttesttesttesttest",
114 result))
115 {
116 printf ("Wrong return value from encrypt block.\n");
117 ret = 1;
118 goto error;
119 }
120
121 if (0 != memcmp (encrresult, result, GNUNET_CRYPTO_AES_KEY_LENGTH))
122 {
123 int i;
124 printf ("Encrypted result wrong.\n");
125 for (i = 0; i < GNUNET_CRYPTO_AES_KEY_LENGTH; i++)
126 printf ("%u, ", (uint8_t) result[i]);
127 ret = 1;
128 goto error;
129 }
130
131 res = GNUNET_malloc (GNUNET_CRYPTO_AES_KEY_LENGTH);
132 if (GNUNET_CRYPTO_AES_KEY_LENGTH !=
133 GNUNET_CRYPTO_symmetric_decrypt (result, GNUNET_CRYPTO_AES_KEY_LENGTH,
134 &key,
135 (const struct
136 GNUNET_CRYPTO_SymmetricInitializationVector
137 *)
138 "testtesttesttesttesttesttesttest", res))
139 {
140 printf ("Wrong return value from decrypt block.\n");
141 ret = 1;
142 goto error;
143 }
144 if (0 != memcmp (res, plain, GNUNET_CRYPTO_AES_KEY_LENGTH))
145 {
146 printf ("Decrypted result does not match input.\n");
147 ret = 1;
148 }
149error:
150 GNUNET_free (res);
151 return ret;
152}
153
154
155int
156main (int argc, char *argv[])
157{
158 int failureCount = 0;
159
160 GNUNET_log_setup ("test-crypto-aes", "WARNING", NULL);
161 GNUNET_assert (strlen (INITVALUE) >
162 sizeof(struct GNUNET_CRYPTO_SymmetricInitializationVector));
163 failureCount += testSymcipher ();
164 failureCount += verifyCrypto ();
165
166 if (failureCount != 0)
167 {
168 printf ("%d TESTS FAILED!\n", failureCount);
169 return -1;
170 }
171 return 0;
172}
173
174
175/* end of test_crypto_aes.c */
diff --git a/src/util/test_crypto_vectors.sh b/src/util/test_crypto_vectors.sh
deleted file mode 100755
index 40700a324..000000000
--- a/src/util/test_crypto_vectors.sh
+++ /dev/null
@@ -1,3 +0,0 @@
1#!/usr/bin/env bash
2
3cat ./crypto-test-vectors.json | ./gnunet-crypto-tvg --verify
diff --git a/src/util/test_disk.c b/src/util/test_disk.c
deleted file mode 100644
index 12bde8107..000000000
--- a/src/util/test_disk.c
+++ /dev/null
@@ -1,290 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 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 util/test_disk.c
23 * @brief testcase for the storage module
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define TESTSTRING "Hello World\0"
30
31
32static int
33testReadWrite (void)
34{
35 char tmp[100 + 1];
36 int ret;
37
38 if (GNUNET_OK !=
39 GNUNET_DISK_fn_write (".testfile", TESTSTRING, strlen (TESTSTRING),
40 GNUNET_DISK_PERM_USER_READ
41 | GNUNET_DISK_PERM_USER_WRITE))
42 return 1;
43 if (GNUNET_OK != GNUNET_DISK_file_test (".testfile"))
44 return 1;
45 ret = GNUNET_DISK_fn_read (".testfile", tmp, sizeof(tmp) - 1);
46 if (ret < 0)
47 {
48 fprintf (stderr, "Error reading file `%s' in testReadWrite\n", ".testfile");
49 return 1;
50 }
51 tmp[ret] = '\0';
52 if (0 != memcmp (tmp, TESTSTRING, strlen (TESTSTRING) + 1))
53 {
54 fprintf (stderr, "Error in testReadWrite: *%s* != *%s* for file %s\n", tmp,
55 TESTSTRING, ".testfile");
56 return 1;
57 }
58 GNUNET_DISK_file_copy (".testfile", ".testfile2");
59 memset (tmp, 0, sizeof(tmp));
60 ret = GNUNET_DISK_fn_read (".testfile2", tmp, sizeof(tmp) - 1);
61 if (ret < 0)
62 {
63 fprintf (stderr, "Error reading file `%s' in testReadWrite\n",
64 ".testfile2");
65 return 1;
66 }
67 tmp[ret] = '\0';
68 if (0 != memcmp (tmp, TESTSTRING, strlen (TESTSTRING) + 1))
69 {
70 fprintf (stderr, "Error in testReadWrite: *%s* != *%s* for file %s\n", tmp,
71 TESTSTRING, ".testfile2");
72 return 1;
73 }
74
75 GNUNET_break (0 == unlink (".testfile"));
76 GNUNET_break (0 == unlink (".testfile2"));
77 if (GNUNET_NO != GNUNET_DISK_file_test (".testfile"))
78 return 1;
79
80 return 0;
81}
82
83
84static int
85testOpenClose ()
86{
87 struct GNUNET_DISK_FileHandle *fh;
88 uint64_t size;
89
90 fh = GNUNET_DISK_file_open (".testfile",
91 GNUNET_DISK_OPEN_READWRITE
92 | GNUNET_DISK_OPEN_CREATE,
93 GNUNET_DISK_PERM_USER_READ
94 | GNUNET_DISK_PERM_USER_WRITE);
95 GNUNET_assert (GNUNET_NO == GNUNET_DISK_handle_invalid (fh));
96 GNUNET_break (5 == GNUNET_DISK_file_write (fh, "Hello", 5));
97 GNUNET_DISK_file_close (fh);
98 GNUNET_break (GNUNET_OK ==
99 GNUNET_DISK_file_size (".testfile", &size, GNUNET_NO,
100 GNUNET_YES));
101 if (size != 5)
102 return 1;
103 GNUNET_break (0 == unlink (".testfile"));
104
105 return 0;
106}
107
108
109static int ok;
110
111
112static int
113scan_callback (void *want, const char *filename)
114{
115 if (NULL != strstr (filename, want))
116 ok++;
117 return GNUNET_OK;
118}
119
120
121static int
122testDirScan ()
123{
124 if (GNUNET_OK !=
125 GNUNET_DISK_directory_create ("test" DIR_SEPARATOR_STR "entry"))
126 {
127 GNUNET_break (0);
128 return 1;
129 }
130 if (GNUNET_OK !=
131 GNUNET_DISK_directory_create ("test" DIR_SEPARATOR_STR "entry_more"))
132 {
133 GNUNET_break (0);
134 return 1;
135 }
136 GNUNET_DISK_directory_scan ("test", &scan_callback,
137 "test" DIR_SEPARATOR_STR "entry");
138 if (GNUNET_OK != GNUNET_DISK_directory_remove ("test"))
139 {
140 GNUNET_break (0);
141 return 1;
142 }
143 if (ok < 2)
144 {
145 GNUNET_break (0);
146 return 1;
147 }
148 return 0;
149}
150
151
152static int
153iter_callback (void *cls,
154 const char *filename)
155{
156 int *i = cls;
157
158 (*i)++;
159 return GNUNET_OK;
160}
161
162
163static int
164testDirIter ()
165{
166 int i;
167
168 i = 0;
169 if (GNUNET_OK != GNUNET_DISK_directory_create ("test/entry"))
170 {
171 GNUNET_break (0);
172 return 1;
173 }
174 if (GNUNET_OK != GNUNET_DISK_directory_create ("test/entry_many"))
175 {
176 GNUNET_break (0);
177 return 1;
178 }
179 if (GNUNET_OK != GNUNET_DISK_directory_create ("test/entry_more"))
180 {
181 GNUNET_break (0);
182 return 1;
183 }
184 GNUNET_DISK_directory_scan ("test",
185 &iter_callback,
186 &i);
187 if (GNUNET_OK != GNUNET_DISK_directory_remove ("test"))
188 {
189 GNUNET_break (0);
190 return 1;
191 }
192 if (i < 3)
193 {
194 GNUNET_break (0);
195 return 1;
196 }
197 return 0;
198}
199
200
201static int
202testCanonicalize ()
203{
204 char *fn = GNUNET_strdup ("ab?><|cd*ef:/g\"");
205
206 GNUNET_DISK_filename_canonicalize (fn);
207 if (0 != strcmp (fn, "ab____cd_ef__g_"))
208 {
209 GNUNET_free (fn);
210 return 1;
211 }
212 GNUNET_free (fn);
213 return 0;
214}
215
216
217static int
218testChangeOwner ()
219{
220 GNUNET_log_skip (1, GNUNET_NO);
221 if (GNUNET_OK == GNUNET_DISK_file_change_owner ("/dev/null", "unknownuser"))
222 return 1;
223 return 0;
224}
225
226
227static int
228testDirMani ()
229{
230 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file ("test/ing"))
231 {
232 GNUNET_break (0);
233 return 1;
234 }
235 if (GNUNET_NO != GNUNET_DISK_file_test ("test"))
236 {
237 GNUNET_break (0);
238 return 1;
239 }
240 if (GNUNET_NO != GNUNET_DISK_file_test ("test/ing"))
241 {
242 GNUNET_break (0);
243 return 1;
244 }
245 if (GNUNET_OK != GNUNET_DISK_directory_remove ("test"))
246 {
247 GNUNET_break (0);
248 return 1;
249 }
250 if (GNUNET_OK != GNUNET_DISK_directory_create ("test"))
251 {
252 GNUNET_break (0);
253 return 1;
254 }
255 if (GNUNET_YES != GNUNET_DISK_directory_test ("test", GNUNET_YES))
256 {
257 GNUNET_break (0);
258 return 1;
259 }
260 if (GNUNET_OK != GNUNET_DISK_directory_remove ("test"))
261 {
262 GNUNET_break (0);
263 return 1;
264 }
265 return 0;
266}
267
268
269int
270main (int argc, char *argv[])
271{
272 unsigned int failureCount = 0;
273
274 GNUNET_log_setup ("test-disk", "WARNING", NULL);
275 failureCount += testReadWrite ();
276 failureCount += testOpenClose ();
277 failureCount += testDirScan ();
278 failureCount += testDirIter ();
279 failureCount += testCanonicalize ();
280 failureCount += testChangeOwner ();
281 failureCount += testDirMani ();
282 if (0 != failureCount)
283 {
284 fprintf (stderr,
285 "\n%u TESTS FAILED!\n",
286 failureCount);
287 return -1;
288 }
289 return 0;
290} /* end of main */
diff --git a/src/util/test_getopt.c b/src/util/test_getopt.c
deleted file mode 100644
index 7252530e2..000000000
--- a/src/util/test_getopt.c
+++ /dev/null
@@ -1,182 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2003, 2004, 2005, 2006, 2009 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 * @file util/test_getopt.c
22 * @brief testcase for util/getopt.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28static int
29testMinimal ()
30{
31 char *const emptyargv[] = { "test", NULL };
32 const struct GNUNET_GETOPT_CommandLineOption emptyoptionlist[] = {
33 GNUNET_GETOPT_OPTION_END
34 };
35
36 if (1 != GNUNET_GETOPT_run ("test", emptyoptionlist, 1, emptyargv))
37 return 1;
38
39 return 0;
40}
41
42
43static int
44testVerbose ()
45{
46 char *const myargv[] = { "test", "-V", "-V", "more", NULL };
47 unsigned int vflags = 0;
48
49 const struct GNUNET_GETOPT_CommandLineOption verboseoptionlist[] =
50 { GNUNET_GETOPT_option_verbose (&vflags), GNUNET_GETOPT_OPTION_END };
51
52 if (3 != GNUNET_GETOPT_run ("test", verboseoptionlist, 4, myargv))
53 {
54 GNUNET_break (0);
55 return 1;
56 }
57 if (vflags != 2)
58 {
59 GNUNET_break (0);
60 return 1;
61 }
62 return 0;
63}
64
65
66static int
67testVersion ()
68{
69 char *const myargv[] = { "test_getopt", "-v", NULL };
70 const struct GNUNET_GETOPT_CommandLineOption versionoptionlist[] =
71 { GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION),
72 GNUNET_GETOPT_OPTION_END };
73
74 if (0 != GNUNET_GETOPT_run ("test_getopt", versionoptionlist, 2, myargv))
75 {
76 GNUNET_break (0);
77 return 1;
78 }
79 return 0;
80}
81
82
83static int
84testAbout ()
85{
86 char *const myargv[] = { "test_getopt", "-h", NULL };
87 const struct GNUNET_GETOPT_CommandLineOption aboutoptionlist[] =
88 { GNUNET_GETOPT_option_help ("Testing"), GNUNET_GETOPT_OPTION_END };
89
90 if (0 != GNUNET_GETOPT_run ("test_getopt", aboutoptionlist, 2, myargv))
91 {
92 GNUNET_break (0);
93 return 1;
94 }
95 return 0;
96}
97
98
99static int
100testLogOpts ()
101{
102 char *const myargv[] =
103 { "test_getopt", "-l", "filename", "-L", "WARNING", NULL };
104 char *level = GNUNET_strdup ("stuff");
105 char *fn = NULL;
106
107 const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] =
108 { GNUNET_GETOPT_option_logfile (&fn),
109 GNUNET_GETOPT_option_loglevel (&level),
110 GNUNET_GETOPT_OPTION_END };
111
112 if (5 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 5, myargv))
113 {
114 GNUNET_break (0);
115 return 1;
116 }
117 GNUNET_assert (NULL != fn);
118 if ((0 != strcmp (level, "WARNING")) || (NULL == strstr (fn, "/filename")))
119 {
120 GNUNET_break (0);
121 GNUNET_free (level);
122 GNUNET_free (fn);
123 return 1;
124 }
125 GNUNET_free (level);
126 GNUNET_free (fn);
127 return 0;
128}
129
130
131static int
132testFlagNum ()
133{
134 char *const myargv[] = { "test_getopt", "-f", "-n", "42", "-N", "42", NULL };
135 int flag = 0;
136 unsigned int num = 0;
137 unsigned long long lnum = 0;
138
139 const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] =
140 { GNUNET_GETOPT_option_flag ('f', "--flag", "helptext", &flag),
141 GNUNET_GETOPT_option_uint ('n', "--num", "ARG", "helptext", &num),
142 GNUNET_GETOPT_option_ulong ('N', "--lnum", "ARG", "helptext", &lnum),
143 GNUNET_GETOPT_OPTION_END };
144
145 if (6 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 6, myargv))
146 {
147 GNUNET_break (0);
148 return 1;
149 }
150 if ((1 != flag) || (42 != num) || (42 != lnum))
151 {
152 GNUNET_break (0);
153 return 1;
154 }
155 return 0;
156}
157
158
159int
160main (int argc, char *argv[])
161{
162 int errCnt = 0;
163
164 GNUNET_log_setup ("test_getopt", "WARNING", NULL);
165 /* suppress output from -h, -v options */
166
167 GNUNET_break (0 == close (1));
168
169 if (0 != testMinimal ())
170 errCnt++;
171 if (0 != testVerbose ())
172 errCnt++;
173 if (0 != testVersion ())
174 errCnt++;
175 if (0 != testAbout ())
176 errCnt++;
177 if (0 != testLogOpts ())
178 errCnt++;
179 if (0 != testFlagNum ())
180 errCnt++;
181 return errCnt;
182}
diff --git a/src/util/test_hexcoder.c b/src/util/test_hexcoder.c
deleted file mode 100644
index 923652a00..000000000
--- a/src/util/test_hexcoder.c
+++ /dev/null
@@ -1,56 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014 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 * @author Christian Grothoff
23 * @file dns/test_hexcoder.c
24 * @brief test for #GNUNET_DNSPARSER_hex_to_bin() and
25 * #GNUNET_DNSPARSER_bin_to_hex()
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dnsparser_lib.h"
30
31#define TESTSTRING "Hello World!"
32
33
34int
35main (int argc,
36 char *argv[])
37{
38 char buf[strlen (TESTSTRING) + 1];
39 char *ret;
40
41 GNUNET_log_setup ("test-hexcoder", "WARNING", NULL);
42 ret = GNUNET_DNSPARSER_bin_to_hex (TESTSTRING,
43 strlen (TESTSTRING) + 1);
44 GNUNET_assert (NULL != ret);
45 GNUNET_assert (sizeof(buf) ==
46 GNUNET_DNSPARSER_hex_to_bin (ret,
47 buf));
48 GNUNET_assert (0 == memcmp (TESTSTRING,
49 buf,
50 sizeof(buf)));
51 GNUNET_free (ret);
52 return 0;
53}
54
55
56/* end of test_hexcoder.c */
diff --git a/src/util/test_mq.c b/src/util/test_mq.c
deleted file mode 100644
index dc34f2da4..000000000
--- a/src/util/test_mq.c
+++ /dev/null
@@ -1,341 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 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 util/test_mq.c
23 * @brief tests for mq
24 * @author Florian Dold
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30#define NUM_TRANSMISSIONS 500
31
32/**
33 * How long does the receiver take per message?
34 */
35#define RECEIVER_THROTTLE GNUNET_TIME_relative_multiply ( \
36 GNUNET_TIME_UNIT_MILLISECONDS, 1)
37
38static unsigned int received_cnt;
39
40
41GNUNET_NETWORK_STRUCT_BEGIN
42
43struct MyMessage
44{
45 struct GNUNET_MessageHeader header;
46 uint32_t x GNUNET_PACKED;
47};
48
49GNUNET_NETWORK_STRUCT_END
50
51static int global_ret;
52
53static struct GNUNET_SCHEDULER_Task *tt;
54
55static struct GNUNET_SCHEDULER_Task *dt;
56
57static struct GNUNET_MQ_Handle *cmq;
58
59
60static void
61do_shutdown (void *cls)
62{
63 (void) cls;
64 if (NULL != tt)
65 {
66 GNUNET_SCHEDULER_cancel (tt);
67 tt = NULL;
68 }
69 if (NULL != cmq)
70 {
71 GNUNET_MQ_destroy (cmq);
72 cmq = NULL;
73 }
74}
75
76
77static void
78do_timeout (void *cls)
79{
80 (void) cls;
81 tt = NULL;
82 GNUNET_SCHEDULER_shutdown ();
83 global_ret = 1;
84}
85
86
87/**
88 * Generic error handler, called with the appropriate
89 * error code and the same closure specified at the creation of
90 * the message queue.
91 * Not every message queue implementation supports an error handler.
92 *
93 * @param cls closure
94 * @param error error code
95 */
96static void
97error_cb (void *cls,
98 enum GNUNET_MQ_Error error)
99{
100 GNUNET_break (0);
101 global_ret = 3;
102 GNUNET_SCHEDULER_shutdown ();
103}
104
105
106static void
107client_continue (void *cls)
108{
109 struct GNUNET_SERVICE_Client *c = cls;
110
111 dt = NULL;
112 GNUNET_SERVICE_client_continue (c);
113}
114
115
116static void
117handle_dummy (void *cls,
118 const struct MyMessage *msg)
119{
120 struct GNUNET_SERVICE_Client *c = cls;
121
122 GNUNET_assert (NULL == dt);
123 /* artificially make receiver slower than sender */
124 dt = GNUNET_SCHEDULER_add_delayed (RECEIVER_THROTTLE,
125 &client_continue,
126 c);
127 if (received_cnt != ntohl (msg->x))
128 {
129 GNUNET_break (0);
130 global_ret = 4;
131 GNUNET_SCHEDULER_shutdown ();
132 }
133 received_cnt++;
134}
135
136
137static void
138handle_dummy2 (void *cls,
139 const struct MyMessage *msg)
140{
141 struct GNUNET_SERVICE_Client *c = cls;
142
143 GNUNET_SERVICE_client_continue (c);
144 if (NUM_TRANSMISSIONS != received_cnt)
145 {
146 GNUNET_break (0);
147 global_ret = 5;
148 }
149 GNUNET_SCHEDULER_shutdown ();
150}
151
152
153/**
154 * Function called whenever MQ has sent a message.
155 */
156static void
157notify_sent_cb (void *cls)
158{
159 static unsigned int seen;
160 unsigned int *cnt = cls;
161
162 if (seen != *cnt)
163 {
164 GNUNET_break (0);
165 global_ret = 6;
166 GNUNET_SCHEDULER_shutdown ();
167 }
168 seen++;
169 GNUNET_free (cnt);
170}
171
172
173/**
174 * Start running the actual test.
175 *
176 * @param cls closure passed to #GNUNET_SERVICE_MAIN
177 * @param cfg configuration to use for this service
178 * @param sh handle to the newly create service
179 */
180static void
181run (void *cls,
182 const struct GNUNET_CONFIGURATION_Handle *cfg,
183 struct GNUNET_SERVICE_Handle *sh)
184{
185 struct GNUNET_MQ_MessageHandler ch[] = {
186 GNUNET_MQ_handler_end ()
187 };
188 struct GNUNET_MQ_Envelope *env;
189 struct MyMessage *m;
190
191 (void) cls;
192 (void) sh;
193 cmq = GNUNET_CLIENT_connect (cfg,
194 "test_client",
195 ch,
196 &error_cb,
197 NULL);
198 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
199 NULL);
200 tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
201 &do_timeout,
202 NULL);
203 for (unsigned int i = 0; i < NUM_TRANSMISSIONS; i++)
204 {
205 unsigned int *cnt;
206
207 cnt = GNUNET_new (unsigned int);
208 *cnt = i;
209 env = GNUNET_MQ_msg (m,
210 GNUNET_MESSAGE_TYPE_DUMMY);
211 GNUNET_MQ_notify_sent (env,
212 &notify_sent_cb,
213 cnt);
214 m->x = htonl (i);
215 GNUNET_MQ_send (cmq,
216 env);
217 }
218 env = GNUNET_MQ_msg (m,
219 GNUNET_MESSAGE_TYPE_DUMMY2);
220 GNUNET_MQ_send (cmq,
221 env);
222}
223
224
225/**
226 * Callback to be called when a client connects to the service.
227 *
228 * @param cls closure for the service
229 * @param c the new client that connected to the service
230 * @param mq the message queue used to send messages to the client
231 * @return the client-specific (`internal') closure
232 */
233static void *
234connect_cb (void *cls,
235 struct GNUNET_SERVICE_Client *c,
236 struct GNUNET_MQ_Handle *mq)
237{
238 (void) cls;
239 (void) mq;
240 return c;
241}
242
243
244/**
245 * Callback to be called when a client disconnected from the service
246 *
247 * @param cls closure for the service
248 * @param c the client that disconnected
249 * @param internal_cls the client-specific (`internal') closure
250 */
251static void
252disconnect_cb (void *cls,
253 struct GNUNET_SERVICE_Client *c,
254 void *internal_cls)
255{
256 (void) cls;
257 (void) c;
258 (void) internal_cls;
259}
260
261
262static void
263test1 ()
264{
265 struct GNUNET_MQ_Envelope *mqm;
266 struct MyMessage *mm;
267
268 mm = NULL;
269 mqm = NULL;
270
271 mqm = GNUNET_MQ_msg (mm,
272 GNUNET_MESSAGE_TYPE_DUMMY);
273 GNUNET_assert (NULL != mqm);
274 GNUNET_assert (NULL != mm);
275 GNUNET_assert (GNUNET_MESSAGE_TYPE_DUMMY == ntohs (mm->header.type));
276 GNUNET_assert (sizeof(struct MyMessage) == ntohs (mm->header.size));
277 GNUNET_MQ_discard (mqm);
278}
279
280
281static void
282test2 ()
283{
284 struct GNUNET_MQ_Envelope *mqm;
285 struct GNUNET_MessageHeader *mh;
286
287 mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_DUMMY);
288 /* how could the above be checked? */
289
290 GNUNET_MQ_discard (mqm);
291
292 mqm = GNUNET_MQ_msg_header_extra (mh,
293 20,
294 GNUNET_MESSAGE_TYPE_DUMMY);
295 GNUNET_assert (GNUNET_MESSAGE_TYPE_DUMMY == ntohs (mh->type));
296 GNUNET_assert (sizeof(struct GNUNET_MessageHeader) + 20 == ntohs (mh->size));
297 GNUNET_MQ_discard (mqm);
298}
299
300
301int
302main (int argc, char **argv)
303{
304 char *test_argv[] = {
305 (char *) "test_client",
306 "-c",
307 "test_client_data.conf",
308 NULL
309 };
310 struct GNUNET_MQ_MessageHandler mh[] = {
311 GNUNET_MQ_hd_fixed_size (dummy,
312 GNUNET_MESSAGE_TYPE_DUMMY,
313 struct MyMessage,
314 NULL),
315 GNUNET_MQ_hd_fixed_size (dummy2,
316 GNUNET_MESSAGE_TYPE_DUMMY2,
317 struct MyMessage,
318 NULL),
319 GNUNET_MQ_handler_end ()
320 };
321
322 (void) argc;
323 (void) argv;
324 GNUNET_log_setup ("test-mq",
325 "INFO",
326 NULL);
327 test1 ();
328 test2 ();
329 if (0 !=
330 GNUNET_SERVICE_run_ (3,
331 test_argv,
332 "test_client",
333 GNUNET_SERVICE_OPTION_NONE,
334 &run,
335 &connect_cb,
336 &disconnect_cb,
337 NULL,
338 mh))
339 return 1;
340 return global_ret;
341}
diff --git a/src/util/test_os_network.c b/src/util/test_os_network.c
deleted file mode 100644
index cca29df0f..000000000
--- a/src/util/test_os_network.c
+++ /dev/null
@@ -1,91 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2003, 2004, 2005, 2006, 2009 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 * @file util/test_os_network.c
22 * @brief testcase for util/os_network.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28/**
29 * Check if the address we got is IPv4 or IPv6 loopback (which should
30 * be present on all systems at all times); if so, set ok to 0
31 * (success).
32 */
33static int
34proc (void *cls,
35 const char *name,
36 int isDefault,
37 const struct sockaddr *addr,
38 const struct sockaddr *broadcast_addr,
39 const struct sockaddr *netmask,
40 socklen_t addrlen)
41{
42 int *ok = cls;
43 char buf[INET6_ADDRSTRLEN];
44 const char *protocol;
45
46 if (NULL == addr)
47 return GNUNET_OK;
48 if (addrlen == sizeof(struct sockaddr_in))
49 protocol = "IPv4";
50 else
51 protocol = "IPv6";
52 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
53 "%s Address `%s'\n",
54 protocol,
55 GNUNET_a2s ((const struct sockaddr *) addr,
56 addrlen));
57 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
58 "Netmask `%s'\n",
59 GNUNET_a2s ((const struct sockaddr *) netmask,
60 addrlen));
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
62 "`%s'\n",
63 GNUNET_a2s ((const struct sockaddr *) broadcast_addr,
64 addrlen));
65 inet_ntop (addr->sa_family,
66 (addr->sa_family ==
67 AF_INET) ? (void *) &((struct sockaddr_in *) addr)->sin_addr
68 : (void *) &((struct sockaddr_in6 *) addr)->sin6_addr, buf,
69 sizeof(buf));
70 if ((0 == strcmp ("::1", buf)) || (0 == strcmp ("127.0.0.1", buf)))
71 *ok = 0;
72 return GNUNET_OK;
73}
74
75
76int
77main (int argc, char *argv[])
78{
79 int ret;
80
81 GNUNET_log_setup ("test-os-network",
82 "WARNING",
83 NULL);
84 ret = 1;
85 GNUNET_OS_network_interfaces_list (&proc,
86 &ret);
87 return ret;
88}
89
90
91/* end of test_os_network.c */
diff --git a/src/util/test_os_start_process.c b/src/util/test_os_start_process.c
deleted file mode 100644
index 435b70e1a..000000000
--- a/src/util/test_os_start_process.c
+++ /dev/null
@@ -1,289 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_os_start_process.c
22 * @brief testcase for os start process code
23 *
24 * This testcase simply calls the os start process code
25 * giving a file descriptor to write stdout to. If the
26 * correct data "HELLO" is read then all is well.
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "disk.h"
31
32
33static const char *test_phrase = "HELLO WORLD";
34
35static int ok;
36
37static struct GNUNET_OS_Process *proc;
38
39/**
40 * Pipe to write to started processes stdin (on write end)
41 */
42static struct GNUNET_DISK_PipeHandle *hello_pipe_stdin;
43
44/**
45 * Pipe to read from started processes stdout (on read end)
46 */
47static struct GNUNET_DISK_PipeHandle *hello_pipe_stdout;
48
49static struct GNUNET_SCHEDULER_Task *die_task;
50
51struct read_context
52{
53 char buf[16];
54 int buf_offset;
55 const struct GNUNET_DISK_FileHandle *stdout_read_handle;
56};
57
58
59static struct read_context rc;
60
61
62static void
63end_task (void *cls)
64{
65 if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
66 {
67 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
68 }
69 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc));
70 GNUNET_OS_process_destroy (proc);
71 proc = NULL;
72 GNUNET_DISK_pipe_close (hello_pipe_stdout);
73 GNUNET_DISK_pipe_close (hello_pipe_stdin);
74}
75
76
77static void
78read_call (void *cls)
79{
80 int bytes;
81
82 bytes = GNUNET_DISK_file_read (rc.stdout_read_handle,
83 &rc.buf[rc.buf_offset],
84 sizeof(rc.buf) - rc.buf_offset);
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "bytes is %d\n",
87 bytes);
88
89 if (bytes < 1)
90 {
91 GNUNET_break (0);
92 ok = 1;
93 GNUNET_SCHEDULER_cancel (die_task);
94 (void) GNUNET_SCHEDULER_add_now (&end_task, NULL);
95 return;
96 }
97
98 ok = strncmp (rc.buf, test_phrase, strlen (test_phrase));
99 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
100 "read %s\n",
101 &rc.buf[rc.buf_offset]);
102 rc.buf_offset += bytes;
103
104 if (0 == ok)
105 {
106 GNUNET_SCHEDULER_cancel (die_task);
107 (void) GNUNET_SCHEDULER_add_now (&end_task, NULL);
108 return;
109 }
110
111 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
112 rc.stdout_read_handle,
113 &read_call,
114 NULL);
115}
116
117
118static void
119run_task (void *cls)
120{
121 const struct GNUNET_DISK_FileHandle *stdout_read_handle;
122 const struct GNUNET_DISK_FileHandle *wh;
123
124 hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
125 hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
126 if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL))
127 {
128 GNUNET_break (0);
129 ok = 1;
130 return;
131 }
132
133 proc =
134 GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR,
135 hello_pipe_stdin, hello_pipe_stdout, NULL,
136 "cat",
137 "cat", "-", NULL);
138 /* Close the write end of the read pipe */
139 GNUNET_DISK_pipe_close_end (hello_pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
140 /* Close the read end of the write pipe */
141 GNUNET_DISK_pipe_close_end (hello_pipe_stdin, GNUNET_DISK_PIPE_END_READ);
142
143 wh = GNUNET_DISK_pipe_handle (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE);
144
145 /* Write the test_phrase to the cat process */
146 if (GNUNET_DISK_file_write (wh, test_phrase, strlen (test_phrase) + 1) !=
147 strlen (test_phrase) + 1)
148 {
149 GNUNET_break (0);
150 ok = 1;
151 return;
152 }
153
154 /* Close the write end to end the cycle! */
155 GNUNET_DISK_pipe_close_end (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE);
156
157 stdout_read_handle =
158 GNUNET_DISK_pipe_handle (hello_pipe_stdout, GNUNET_DISK_PIPE_END_READ);
159
160 die_task =
161 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
162 (GNUNET_TIME_UNIT_MINUTES, 1),
163 &end_task,
164 NULL);
165
166 memset (&rc, 0, sizeof(rc));
167 rc.stdout_read_handle = stdout_read_handle;
168 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
169 stdout_read_handle,
170 &read_call,
171 NULL);
172}
173
174
175/**
176 * Main method, starts scheduler with task1,
177 * checks that "ok" is correct at the end.
178 */
179static int
180check_run ()
181{
182 ok = 1;
183 GNUNET_SCHEDULER_run (&run_task, &ok);
184 return ok;
185}
186
187
188/**
189 * Test killing via pipe.
190 */
191static int
192check_kill ()
193{
194 char *fn;
195
196 hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
197 hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
198 if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL))
199 {
200 return 1;
201 }
202 fn = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
203 proc =
204 GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR
205 | GNUNET_OS_USE_PIPE_CONTROL,
206 hello_pipe_stdin,
207 hello_pipe_stdout,
208 NULL,
209 fn,
210 "gnunet-service-resolver", "-",
211 NULL);
212 if (NULL == proc)
213 {
214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
215 "Failed to launch gnunet-service-resolver. Is your system setup correct?\n");
216 return 77;
217 }
218 sleep (1); /* give process time to start, so we actually use the pipe-kill mechanism! */
219 GNUNET_free (fn);
220 if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
221 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
222 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc));
223 GNUNET_OS_process_destroy (proc);
224 proc = NULL;
225 GNUNET_DISK_pipe_close (hello_pipe_stdout);
226 GNUNET_DISK_pipe_close (hello_pipe_stdin);
227 return 0;
228}
229
230
231/**
232 * Test killing via pipe.
233 */
234static int
235check_instant_kill ()
236{
237 char *fn;
238
239 hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
240 hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
241 if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL))
242 {
243 return 1;
244 }
245 fn = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
246 proc =
247 GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR
248 | GNUNET_OS_USE_PIPE_CONTROL,
249 hello_pipe_stdin, hello_pipe_stdout, NULL,
250 fn,
251 "gnunet-service-resolver", "-", NULL);
252 if (NULL == proc)
253 {
254 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
255 "Failed to launch gnunet-service-resolver. Is your system setup correct?\n");
256 return 77;
257 }
258 if (0 != GNUNET_OS_process_kill (proc,
259 GNUNET_TERM_SIG))
260 {
261 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
262 }
263 GNUNET_free (fn);
264 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc));
265 GNUNET_OS_process_destroy (proc);
266 proc = NULL;
267 GNUNET_DISK_pipe_close (hello_pipe_stdout);
268 GNUNET_DISK_pipe_close (hello_pipe_stdin);
269 return 0;
270}
271
272
273int
274main (int argc, char *argv[])
275{
276 int ret;
277
278 GNUNET_log_setup ("test-os-start-process",
279 "WARNING",
280 NULL);
281 ret = 0;
282 ret |= check_run ();
283 ret |= check_kill ();
284 ret |= check_instant_kill ();
285 return ret;
286}
287
288
289/* end of test_os_start_process.c */
diff --git a/src/util/test_peer.c b/src/util/test_peer.c
deleted file mode 100644
index bb0bc48dc..000000000
--- a/src/util/test_peer.c
+++ /dev/null
@@ -1,139 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_peer.c
22 * @brief testcase for peer.c
23 * @author Safey Mohammed
24 */
25
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gcrypt.h>
29
30#define NUMBER_OF_PEERS 10
31
32/**
33 * A list of Peer ID's to play with
34 */
35static struct GNUNET_PeerIdentity pidArr[NUMBER_OF_PEERS];
36
37
38static void
39generatePeerIdList ()
40{
41 for (unsigned int i = 0; i < NUMBER_OF_PEERS; i++)
42 {
43 gcry_randomize (&pidArr[i],
44 sizeof(struct GNUNET_PeerIdentity),
45 GCRY_STRONG_RANDOM);
46 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
47 "Peer %u: %s\n",
48 i,
49 GNUNET_i2s (&pidArr[i]));
50 }
51}
52
53
54static int
55check ()
56{
57 GNUNET_PEER_Id pid;
58 struct GNUNET_PeerIdentity res;
59 GNUNET_PEER_Id ids[] = { 1, 2, 3 };
60
61 GNUNET_assert (0 == GNUNET_PEER_intern (NULL));
62 /* Insert Peers into PeerEntry table and hashmap */
63 for (unsigned int i = 0; i < NUMBER_OF_PEERS; i++)
64 {
65 pid = GNUNET_PEER_intern (&pidArr[i]);
66 if (pid != (i + 1))
67 {
68 fprintf (stderr, "%s",
69 "Unexpected Peer ID returned by intern function\n");
70 return 1;
71 }
72 }
73
74 /* Referencing the first 3 peers once again */
75 for (unsigned int i = 0; i < 3; i++)
76 {
77 pid = GNUNET_PEER_intern (&pidArr[i]);
78 if (pid != (i + 1))
79 {
80 fprintf (stderr, "%s",
81 "Unexpected Peer ID returned by intern function\n");
82 return 1;
83 }
84 }
85
86 /* Dereferencing the first 3 peers once [decrementing their reference count] */
87 GNUNET_PEER_decrement_rcs (ids, 3);
88
89 /* re-referencing the first 3 peers using the change_rc function */
90 for (unsigned int i = 1; i <= 3; i++)
91 GNUNET_PEER_change_rc (i, 1);
92
93 /* Removing the second Peer from the PeerEntry hash map */
94 GNUNET_PEER_change_rc (2, -2);
95
96 /* convert the pid of the first PeerEntry into that of the third */
97 GNUNET_PEER_resolve (1,
98 &res);
99 GNUNET_assert (0 ==
100 GNUNET_memcmp (&res,
101 &pidArr[0]));
102
103 /*
104 * Attempt to convert pid = 0 (which is reserved)
105 * into a peer identity object, the peer identity memory
106 * is expected to be set to zero
107 */GNUNET_log_skip (1, GNUNET_YES);
108 GNUNET_PEER_resolve (0, &res);
109 GNUNET_assert (GNUNET_YES == GNUNET_is_zero (&res));
110
111 /* Removing peer entries 1 and 3 from table using the list decrement function */
112 /* If count = 0, nothing should be done whatsoever */
113 GNUNET_PEER_decrement_rcs (ids, 0);
114
115 ids[1] = 3;
116 GNUNET_PEER_decrement_rcs (ids, 2);
117 GNUNET_PEER_decrement_rcs (ids, 2);
118
119 return 0;
120}
121
122
123int
124main ()
125{
126 GNUNET_log_setup ("test-peer",
127 "ERROR",
128 NULL);
129 for (unsigned int i = 0; i < 1; i++)
130 {
131 generatePeerIdList ();
132 if (0 != check ())
133 return 1;
134 }
135 return 0;
136}
137
138
139/* end of test_peer.c */
diff --git a/src/util/test_plugin.c b/src/util/test_plugin.c
deleted file mode 100644
index e739d17c9..000000000
--- a/src/util/test_plugin.c
+++ /dev/null
@@ -1,87 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_plugin.c
22 * @brief testcase for plugin.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28static void
29test_cb (void *cls,
30 const char *libname,
31 void *lib_ret)
32{
33 const char *test_cls = cls;
34 char *ret;
35
36 GNUNET_assert (0 == strcmp (test_cls,
37 "test-closure"));
38 GNUNET_assert (0 == strcmp (lib_ret,
39 "Hello"));
40 ret = GNUNET_PLUGIN_unload (libname,
41 "out");
42 GNUNET_assert (NULL != ret);
43 GNUNET_assert (0 == strcmp (ret,
44 "World"));
45 free (ret);
46}
47
48
49int
50main (int argc, char *argv[])
51{
52 void *ret;
53
54 GNUNET_log_setup ("test-plugin",
55 "WARNING",
56 NULL);
57 GNUNET_log_skip (1,
58 GNUNET_NO);
59 ret = GNUNET_PLUGIN_load ("libgnunet_plugin_missing",
60 NULL);
61 GNUNET_log_skip (0, GNUNET_NO);
62 if (NULL != ret)
63 return 1;
64 ret = GNUNET_PLUGIN_load ("libgnunet_plugin_utiltest",
65 "in");
66 if (NULL == ret)
67 return 1;
68 if (0 != strcmp (ret,
69 "Hello"))
70 return 2;
71 ret = GNUNET_PLUGIN_unload ("libgnunet_plugin_utiltest",
72 "out");
73 if (NULL == ret)
74 return 3;
75 if (0 != strcmp (ret,
76 "World"))
77 return 4;
78 free (ret);
79 GNUNET_PLUGIN_load_all ("libgnunet_plugin_utiltes",
80 "in",
81 &test_cb,
82 "test-closure");
83 return 0;
84}
85
86
87/* end of test_plugin.c */
diff --git a/src/util/test_plugin_plug.c b/src/util/test_plugin_plug.c
deleted file mode 100644
index bfaad52e8..000000000
--- a/src/util/test_plugin_plug.c
+++ /dev/null
@@ -1,45 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_plugin_plug.c
22 * @brief plugin for testing
23 */
24#include "platform.h"
25
26
27void *
28libgnunet_plugin_utiltest_init (void *arg)
29{
30 if (0 == strcmp (arg, "in"))
31 return "Hello";
32 return NULL;
33}
34
35
36void *
37libgnunet_plugin_utiltest_done (void *arg)
38{
39 if (0 == strcmp (arg, "out"))
40 return strdup ("World");
41 return NULL;
42}
43
44
45/* end of test_plugin_plug.c */
diff --git a/src/util/test_program.c b/src/util/test_program.c
deleted file mode 100644
index 912a581a5..000000000
--- a/src/util/test_program.c
+++ /dev/null
@@ -1,138 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_program.c
22 * @brief tests for program.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28static int setme1;
29
30static int setme2;
31
32
33/**
34 * Main function that will be run.
35 */
36static void
37runner (void *cls,
38 char *const *args,
39 const char *cfgfile,
40 const struct GNUNET_CONFIGURATION_Handle *cfg)
41{
42 int *ok = cls;
43
44 GNUNET_assert (setme1 == 1);
45 GNUNET_assert (0 == strcmp (args[0], "extra"));
46 GNUNET_assert (args[1] == NULL);
47 GNUNET_assert (NULL != strstr (cfgfile, "/test_program_data.conf"));
48 *ok = 0;
49}
50
51
52int
53main (int argc, char *argv[])
54{
55 int ok = 1;
56 char *const argvx[] = {
57 "test_program",
58 "-c",
59 "test_program_data.conf",
60 "-L",
61 "WARNING",
62 "-n",
63 "extra",
64 NULL
65 };
66 struct GNUNET_GETOPT_CommandLineOption options1[] = {
67 GNUNET_GETOPT_option_flag ('n',
68 "name",
69 "description",
70 &setme1),
71 GNUNET_GETOPT_OPTION_END
72 };
73 struct GNUNET_GETOPT_CommandLineOption options2[] = {
74 GNUNET_GETOPT_option_flag ('n',
75 "name",
76 "description",
77 &setme1),
78 GNUNET_GETOPT_option_flag ('N',
79 "number",
80 "description",
81 &setme2),
82 GNUNET_GETOPT_OPTION_END
83 };
84 struct GNUNET_GETOPT_CommandLineOption options3[] = {
85 GNUNET_GETOPT_option_flag ('N',
86 "number",
87 "description",
88 &setme1),
89 GNUNET_GETOPT_option_flag ('n',
90 "name",
91 "description",
92 &setme2),
93 GNUNET_GETOPT_OPTION_END
94 };
95 struct GNUNET_GETOPT_CommandLineOption options4[] = {
96 GNUNET_GETOPT_option_flag ('n',
97 "name",
98 "description",
99 &setme1),
100 GNUNET_GETOPT_option_flag ('n',
101 "name",
102 "description",
103 &setme2),
104 GNUNET_GETOPT_OPTION_END
105 };
106
107
108 GNUNET_log_setup ("test_program",
109 "WARNING",
110 NULL);
111 GNUNET_assert (GNUNET_OK ==
112 GNUNET_PROGRAM_run (7, argvx,
113 "test_program",
114 "A test",
115 options1,
116 &runner, &ok));
117
118 GNUNET_assert (GNUNET_OK ==
119 GNUNET_PROGRAM_run (7, argvx,
120 "test_program", "A test",
121 options2,
122 &runner, &ok));
123 GNUNET_assert (GNUNET_OK ==
124 GNUNET_PROGRAM_run (7, argvx,
125 "test_program", "A test",
126 options3,
127 &runner, &ok));
128 GNUNET_assert (GNUNET_OK ==
129 GNUNET_PROGRAM_run (7, argvx,
130 "test_program", "A test",
131 options4,
132 &runner, &ok));
133
134 return ok;
135}
136
137
138/* end of test_program.c */
diff --git a/src/util/test_program_data.conf b/src/util/test_program_data.conf
deleted file mode 100644
index fbf745644..000000000
--- a/src/util/test_program_data.conf
+++ /dev/null
@@ -1,2 +0,0 @@
1[resolver]
2HOSTNAME = localhost
diff --git a/src/util/test_regex.c b/src/util/test_regex.c
deleted file mode 100644
index b026ab955..000000000
--- a/src/util/test_regex.c
+++ /dev/null
@@ -1,189 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2013 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 * @file tun/test_regex.c
22 * @brief simple test for regex.c iptoregex functions
23 * @author Maximilian Szengel
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28/**
29 * 'wildcard', matches all possible values (for HEX encoding).
30 */
31#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"
32
33
34static int
35test_iptoregex (const char *ipv4,
36 uint16_t port,
37 const char *expectedv4,
38 const char *ipv6,
39 uint16_t port6,
40 const char *expectedv6)
41{
42 int error = 0;
43
44 struct in_addr a;
45 struct in6_addr b;
46 char rxv4[GNUNET_TUN_IPV4_REGEXLEN];
47 char rxv6[GNUNET_TUN_IPV6_REGEXLEN];
48
49 GNUNET_assert (1 == inet_pton (AF_INET, ipv4, &a));
50 GNUNET_TUN_ipv4toregexsearch (&a, port, rxv4);
51
52 if (0 != strcmp (rxv4, expectedv4))
53 {
54 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
55 "Expected: %s but got: %s\n",
56 expectedv4,
57 rxv4);
58 error++;
59 }
60
61 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6, &b));
62 GNUNET_TUN_ipv6toregexsearch (&b, port6, rxv6);
63 if (0 != strcmp (rxv6, expectedv6))
64 {
65 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
66 "Expected: %s but got: %s\n",
67 expectedv6, rxv6);
68 error++;
69 }
70 return error;
71}
72
73
74static int
75test_policy4toregex (const char *policy,
76 const char *regex)
77{
78 char *r;
79 int ret;
80
81 ret = 0;
82 r = GNUNET_TUN_ipv4policy2regex (policy);
83 if (NULL == r)
84 {
85 GNUNET_break (0);
86 return 1;
87 }
88 if (0 != strcmp (regex, r))
89 {
90 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
91 "Expected: `%s' but got: `%s'\n",
92 regex, r);
93 ret = 2;
94 }
95 GNUNET_free (r);
96 return ret;
97}
98
99
100static int
101test_policy6toregex (const char *policy,
102 const char *regex)
103{
104 char *r;
105 int ret;
106
107 ret = 0;
108 r = GNUNET_TUN_ipv6policy2regex (policy);
109 if (NULL == r)
110 {
111 GNUNET_break (0);
112 return 1;
113 }
114 if (0 != strcmp (regex, r))
115 {
116 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
117 "Expected: `%s' but got: `%s'\n",
118 regex, r);
119 ret = 2;
120 }
121 GNUNET_free (r);
122 return ret;
123}
124
125
126int
127main (int argc, char *argv[])
128{
129 int error;
130 char *r;
131
132 GNUNET_log_setup ("test-regex", "WARNING", NULL);
133 error = 0;
134
135 /* this is just a performance test ... */
136 r = GNUNET_TUN_ipv4policy2regex ("1.2.3.4/16:!25;");
137 GNUNET_break (NULL != r);
138 GNUNET_free (r);
139
140 error +=
141 test_iptoregex ("192.1.2.3", 2086,
142 "4-0826-C0010203",
143 "FFFF::1", 8080,
144 "6-1F90-FFFF0000000000000000000000000001");
145 error +=
146 test_iptoregex ("187.238.255.0", 80,
147 "4-0050-BBEEFF00",
148 "E1E1:73F9:51BE::0", 49,
149 "6-0031-E1E173F951BE00000000000000000000");
150 error +=
151 test_policy4toregex ("192.1.2.0/24:80;",
152 "4-0050-C00102" DOT DOT);
153 error +=
154 test_policy4toregex ("192.1.0.0/16;",
155 "4-" DOT DOT DOT DOT "-C001" DOT DOT DOT DOT);
156 error +=
157 test_policy4toregex ("192.1.0.0/16:80-81;",
158 "4-(0050|0051)-C001" DOT DOT DOT DOT);
159 error +=
160 test_policy4toregex ("192.1.0.0/8:!3-65535;",
161 "4-000(0|1|2)-C0" DOT DOT DOT DOT DOT DOT);
162 error +=
163 test_policy4toregex ("192.1.0.0/8:!25-56;",
164 "4-(0(0(0"DOT
165 "|1(0|1|2|3|4|5|6|7|8)|3(9|A|B|C|D|E|F)|(4|5|6|7|8|9|A|B|C|D|E|F)"DOT
166 ")|(1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"DOT DOT
167 ")|(1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"DOT DOT
168 DOT ")-C0"DOT DOT DOT DOT DOT DOT);
169 error +=
170 test_policy6toregex ("E1E1::1;",
171 "6-"DOT DOT DOT
172 DOT "-E1E10000000000000000000000000001");
173 error +=
174 test_policy6toregex ("E1E1:ABCD::1/120;",
175 "6-"DOT DOT DOT
176 DOT "-E1E1ABCD0000000000000000000000" DOT DOT);
177 error +=
178 test_policy6toregex ("E1E1:ABCD::ABCD/126;",
179 "6-"DOT DOT DOT
180 DOT "-E1E1ABCD00000000000000000000ABC(C|D|E|F)");
181 error +=
182 test_policy6toregex ("E1E1:ABCD::ABCD/127;",
183 "6-"DOT DOT DOT
184 DOT "-E1E1ABCD00000000000000000000ABC(C|D)");
185 error +=
186 test_policy6toregex ("E1E1:ABCD::ABCD/128:80;",
187 "6-0050-E1E1ABCD00000000000000000000ABCD");
188 return error;
189}
diff --git a/src/util/test_resolver_api.c b/src/util/test_resolver_api.c
deleted file mode 100644
index eefb20890..000000000
--- a/src/util/test_resolver_api.c
+++ /dev/null
@@ -1,377 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file resolver/test_resolver_api.c
22 * @brief testcase for resolver_api.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_resolver_service.h"
27#include "resolver.h"
28
29
30static int disable_rootserver_check;
31
32
33/**
34 * Using DNS root servers to check gnunet's resolver service
35 * a.root-servers.net <-> 198.41.0.4 is a fix 1:1 mapping that should not change over years
36 * For more information have a look at IANA's website http://www.root-servers.org/
37 */
38#define ROOTSERVER_NAME "a.root-servers.net"
39#define ROOTSERVER_IP "198.41.0.4"
40
41
42static void
43check_hostname (void *cls,
44 const struct sockaddr *sa,
45 socklen_t salen)
46{
47 int *ok = cls;
48
49 if (0 == salen)
50 {
51 (*ok) &= ~8;
52 return;
53 }
54 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
55 "Got IP address `%s' for our host.\n",
56 GNUNET_a2s (sa, salen));
57}
58
59
60static void
61check_localhost_num (void *cls,
62 const char *hostname)
63{
64 int *ok = cls;
65
66 if (hostname == NULL)
67 return;
68 if (0 == strcmp (hostname, "127.0.0.1"))
69 {
70 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
71 "Received correct hostname `%s'.\n",
72 hostname);
73 (*ok) &= ~4;
74 }
75 else
76 {
77 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
78 "Received invalid hostname `%s'.\n",
79 hostname);
80 GNUNET_break (0);
81 }
82}
83
84
85static void
86check_localhost (void *cls,
87 const char *hostname)
88{
89 int *ok = cls;
90
91 if (NULL == hostname)
92 return;
93 if (0 == strcmp (hostname, "localhost"))
94 {
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96 "Received correct hostname `%s'.\n",
97 hostname);
98 (*ok) &= ~2;
99 }
100 else
101 {
102 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
103 "Received unexpected hostname `%s', expected `localhost' (this could be OK).\n",
104 hostname);
105 }
106}
107
108
109static void
110check_127 (void *cls, const struct sockaddr *sa, socklen_t salen)
111{
112 int *ok = cls;
113 const struct sockaddr_in *sai = (const struct sockaddr_in *) sa;
114
115 if (NULL == sa)
116 return;
117 GNUNET_assert (sizeof(struct sockaddr_in) == salen);
118 if (sai->sin_addr.s_addr == htonl (INADDR_LOOPBACK))
119 {
120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
121 "Received correct address.\n");
122 (*ok) &= ~1;
123 }
124 else
125 {
126 char buf[INET_ADDRSTRLEN];
127
128 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
129 "Received incorrect address `%s'.\n",
130 inet_ntop (AF_INET,
131 &sai->sin_addr,
132 buf,
133 sizeof(buf)));
134 GNUNET_break (0);
135 }
136}
137
138
139static void
140check_rootserver_ip (void *cls, const struct sockaddr *sa, socklen_t salen)
141{
142 int *ok = cls;
143 const struct sockaddr_in *sai = (const struct sockaddr_in *) sa;
144
145 if (NULL == sa)
146 return;
147 GNUNET_assert (sizeof(struct sockaddr_in) == salen);
148
149 if (0 == strcmp (inet_ntoa (sai->sin_addr), ROOTSERVER_IP))
150 {
151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
152 "Received correct rootserver ip address.\n");
153 (*ok) &= ~1;
154 }
155 else
156 {
157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
158 "Received incorrect rootserver ip address.\n");
159 GNUNET_break (0);
160 }
161}
162
163
164static void
165check_rootserver_name (void *cls,
166 const char *hostname)
167{
168 int *ok = cls;
169
170 if (NULL == hostname)
171 return;
172
173 if (0 == strcmp (hostname, ROOTSERVER_NAME))
174 {
175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
176 "Received correct rootserver hostname `%s'.\n",
177 hostname);
178 (*ok) &= ~2;
179 }
180 else
181 {
182 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
183 "Received invalid rootserver hostname `%s', expected `%s'\n",
184 hostname,
185 ROOTSERVER_NAME);
186 GNUNET_break (disable_rootserver_check);
187 }
188}
189
190
191static void
192run (void *cls, char *const *args, const char *cfgfile,
193 const struct GNUNET_CONFIGURATION_Handle *cfg)
194{
195 int *ok = cls;
196 struct sockaddr_in sa;
197 struct GNUNET_TIME_Relative timeout =
198 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30);
199 int count_ips = 0;
200 char *own_fqdn;
201 const char *rootserver_name = ROOTSERVER_NAME;
202 struct hostent *rootserver;
203 struct in_addr rootserver_addr;
204
205 memset (&sa, 0, sizeof(sa));
206 sa.sin_family = AF_INET;
207#if HAVE_SOCKADDR_IN_SIN_LEN
208 sa.sin_len = (u_char) sizeof(sa);
209#endif
210 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
211
212 /*
213 * Looking up our own fqdn
214 */
215 own_fqdn = GNUNET_RESOLVER_local_fqdn_get ();
216 /* can't really check, only thing we can safely
217 compare against is our own identical logic... */
218 GNUNET_free (own_fqdn);
219
220 /*
221 * Testing non-local DNS resolution
222 * DNS rootserver to test: a.root-servers.net - 198.41.0.4
223 */
224
225 rootserver = gethostbyname (rootserver_name);
226 if (NULL == rootserver)
227 {
228 /* Error: resolving ip addresses does not work */
229 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
230 _ ("gethostbyname() could not lookup IP address: %s\n"),
231 hstrerror (h_errno));
232 fprintf (stderr,
233 "%s",
234 "System seems to be off-line, will not run all DNS tests\n");
235 *ok = 0; /* mark test as passing anyway */
236 return;
237 }
238
239 /* Counting returned IP addresses */
240 while (NULL != rootserver->h_addr_list[count_ips])
241 count_ips++;
242 if (count_ips > 1)
243 {
244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
245 "IP received range for root name server, but a root name server has only 1 IP\n");
246 GNUNET_break (0);
247 }
248
249 /* Comparing to resolved address to the address the root name server should have */
250 if (0 !=
251 strcmp (inet_ntoa (*(struct in_addr *) rootserver->h_addr_list[0]),
252 ROOTSERVER_IP))
253 {
254 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
255 "IP received and IP for root name server differ\n");
256 GNUNET_break (0);
257 }
258 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
259 "System's own forward name resolution is working\n");
260 /* Resolve the same using GNUNET */
261 GNUNET_RESOLVER_ip_get (ROOTSERVER_NAME, AF_INET, timeout,
262 &check_rootserver_ip, cls);
263 GNUNET_RESOLVER_ip_get (ROOTSERVER_NAME, AF_INET, timeout,
264 &check_rootserver_ip, cls);
265
266 /*
267 * Success: forward lookups work as expected
268 * Next step: reverse lookups
269 */
270 if (1 != inet_pton (AF_INET,
271 ROOTSERVER_IP,
272 &rootserver_addr))
273 {
274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
275 "Could not transform root name server IP address\n");
276 GNUNET_break (0);
277 }
278
279 rootserver =
280 gethostbyaddr ((const void *) &rootserver_addr,
281 sizeof(rootserver_addr),
282 AF_INET);
283 if (NULL == rootserver)
284 {
285 /* Error: resolving IP addresses does not work */
286 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
287 "gethostbyaddr() could not lookup hostname: %s\n",
288 hstrerror (h_errno));
289 disable_rootserver_check = GNUNET_YES;
290 }
291 else
292 {
293 if (0 != strcmp (rootserver->h_name,
294 ROOTSERVER_NAME))
295 {
296 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
297 "Received hostname and hostname for root name server differ\n");
298 disable_rootserver_check = GNUNET_YES;
299 }
300 }
301
302 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
303 "System's own reverse name resolution is working\n");
304 /* Resolve the same using GNUNET */
305 memset (&sa, 0, sizeof(sa));
306 sa.sin_family = AF_INET;
307#if HAVE_SOCKADDR_IN_SIN_LEN
308 sa.sin_len = (u_char) sizeof(sa);
309#endif
310 inet_aton (ROOTSERVER_IP, &sa.sin_addr);
311
312 GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa,
313 sizeof(struct sockaddr), GNUNET_YES, timeout,
314 &check_rootserver_name, cls);
315
316 memset (&sa, 0, sizeof(sa));
317 sa.sin_family = AF_INET;
318#if HAVE_SOCKADDR_IN_SIN_LEN
319 sa.sin_len = (u_char) sizeof(sa);
320#endif
321 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
322
323 GNUNET_RESOLVER_ip_get ("localhost", AF_INET, timeout, &check_127, cls);
324 GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa,
325 sizeof(struct sockaddr), GNUNET_YES, timeout,
326 &check_localhost, cls);
327
328 GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa,
329 sizeof(struct sockaddr), GNUNET_NO, timeout,
330 &check_localhost_num, cls);
331 GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, timeout, &check_hostname, cls);
332}
333
334
335int
336main (int argc, char *argv[])
337{
338 int ok = 1 + 2 + 4 + 8;
339 char *fn;
340 struct GNUNET_OS_Process *proc;
341 char *const argvx[] = {
342 "test-resolver-api", "-c", "test_resolver_api_data.conf", NULL
343 };
344 struct GNUNET_GETOPT_CommandLineOption options[] =
345 { GNUNET_GETOPT_OPTION_END };
346
347 GNUNET_log_setup ("test-resolver-api",
348 "WARNING",
349 NULL);
350 fn = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
351 proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
352 | GNUNET_OS_USE_PIPE_CONTROL,
353 NULL, NULL, NULL,
354 fn,
355 "gnunet-service-resolver",
356 "-c", "test_resolver_api_data.conf", NULL);
357 GNUNET_assert (NULL != proc);
358 GNUNET_free (fn);
359 GNUNET_assert (GNUNET_OK ==
360 GNUNET_PROGRAM_run ((sizeof(argvx) / sizeof(char *)) - 1,
361 argvx, "test-resolver-api", "nohelp",
362 options, &run, &ok));
363 if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
364 {
365 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
366 ok = 1;
367 }
368 GNUNET_OS_process_wait (proc);
369 GNUNET_OS_process_destroy (proc);
370 proc = NULL;
371 if (0 != ok)
372 fprintf (stderr, "Missed some resolutions: %u\n", ok);
373 return ok;
374}
375
376
377/* end of test_resolver_api.c */
diff --git a/src/util/test_resolver_api_data.conf b/src/util/test_resolver_api_data.conf
deleted file mode 100644
index dd4384b80..000000000
--- a/src/util/test_resolver_api_data.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1[PATHS]
2GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-statistics/
3
4[resolver]
5PORT = 22354
6HOSTNAME = localhost
7
diff --git a/src/util/test_scheduler.c b/src/util/test_scheduler.c
deleted file mode 100644
index 0e2e7f760..000000000
--- a/src/util/test_scheduler.c
+++ /dev/null
@@ -1,293 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_scheduler.c
22 * @brief tests for the scheduler
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28static struct GNUNET_DISK_PipeHandle *p;
29
30static const struct GNUNET_DISK_FileHandle *fds[2];
31
32static struct GNUNET_SCHEDULER_Task *never_run_task;
33
34
35static void
36task2 (void *cls)
37{
38 int *ok = cls;
39
40 /* t3 should be ready (albeit with lower priority) */
41 GNUNET_assert (1 ==
42 GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_COUNT));
43 GNUNET_assert (2 == *ok);
44 (*ok) = 3;
45}
46
47
48static void
49task3 (void *cls)
50{
51 int *ok = cls;
52
53 GNUNET_assert (3 == *ok);
54 (*ok) = 4;
55}
56
57
58static void
59taskWrt (void *cls)
60{
61 static char c;
62 int *ok = cls;
63 const struct GNUNET_SCHEDULER_TaskContext *tc;
64
65 tc = GNUNET_SCHEDULER_get_task_context ();
66 GNUNET_assert (6 == *ok);
67 GNUNET_assert (GNUNET_NETWORK_fdset_handle_isset (tc->write_ready, fds[1]));
68 (*ok) = 7;
69 GNUNET_assert (1 == GNUNET_DISK_file_write (fds[1], &c, 1));
70}
71
72
73static void
74taskNeverRun (void *cls)
75{
76 GNUNET_assert (0);
77}
78
79
80static void
81taskLastRd (void *cls)
82{
83 int *ok = cls;
84
85 GNUNET_assert (8 == *ok);
86 (*ok) = 0;
87}
88
89
90static void
91taskLastSig (void *cls)
92{
93 int *ok = cls;
94
95 GNUNET_SCHEDULER_cancel (never_run_task);
96 GNUNET_assert (9 == *ok);
97 (*ok) = 0;
98}
99
100
101static void
102taskLastShutdown (void *cls)
103{
104 int *ok = cls;
105
106 GNUNET_assert (10 == *ok);
107 (*ok) = 0;
108}
109
110
111static void
112taskRd (void *cls)
113{
114 static char c;
115 int *ok = cls;
116 const struct GNUNET_SCHEDULER_TaskContext *tc;
117
118 tc = GNUNET_SCHEDULER_get_task_context ();
119 GNUNET_assert (7 == *ok);
120 GNUNET_assert (GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, fds[0]));
121 GNUNET_assert (1 == GNUNET_DISK_file_read (fds[0], &c, 1));
122 (*ok) = 8;
123 GNUNET_SCHEDULER_add_shutdown (&taskLastRd,
124 cls);
125 GNUNET_SCHEDULER_shutdown ();
126}
127
128
129static void
130task4 (void *cls)
131{
132 int *ok = cls;
133
134 GNUNET_assert (4 == *ok);
135 (*ok) = 6;
136 p = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
137 GNUNET_assert (NULL != p);
138 fds[0] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_READ);
139 fds[1] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_WRITE);
140 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
141 fds[0],
142 &taskRd,
143 cls);
144 GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
145 fds[1],
146 &taskWrt,
147 cls);
148}
149
150
151static void
152task1 (void *cls)
153{
154 int *ok = cls;
155
156 GNUNET_assert (1 == *ok);
157 (*ok) = 2;
158 GNUNET_SCHEDULER_add_now (&task3, cls);
159 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI,
160 &task2,
161 cls);
162 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
163 &task4,
164 cls);
165}
166
167
168/**
169 * Main method, starts scheduler with task1,
170 * checks that "ok" is correct at the end.
171 */
172static int
173check ()
174{
175 int ok;
176
177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178 "[Check scheduling]\n");
179 ok = 1;
180 GNUNET_SCHEDULER_run (&task1, &ok);
181 return ok;
182}
183
184
185static void
186taskShutdown (void *cls)
187{
188 int *ok = cls;
189
190 GNUNET_assert (1 == *ok);
191 *ok = 10;
192 GNUNET_SCHEDULER_add_shutdown (&taskLastShutdown, cls);
193 GNUNET_SCHEDULER_shutdown ();
194}
195
196
197/**
198 * Main method, starts scheduler with task1,
199 * checks that "ok" is correct at the end.
200 */
201static int
202checkShutdown ()
203{
204 int ok;
205
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207 "[Check shutdown]\n");
208 ok = 1;
209 GNUNET_SCHEDULER_run (&taskShutdown, &ok);
210 return ok;
211}
212
213
214static void
215taskSig (void *cls)
216{
217 int *ok = cls;
218
219 GNUNET_assert (1 == *ok);
220 *ok = 9;
221 GNUNET_SCHEDULER_add_shutdown (&taskLastSig, cls);
222 never_run_task =
223 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
224 GNUNET_TIME_UNIT_SECONDS, 5),
225 &taskNeverRun,
226 NULL);
227 GNUNET_break (0 == kill (getpid (),
228 GNUNET_TERM_SIG));
229}
230
231
232/**
233 * Main method, starts scheduler with task1,
234 * checks that "ok" is correct at the end.
235 */
236static int
237checkSignal (void)
238{
239 int ok;
240
241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242 "[Check signal handling]\n");
243 ok = 1;
244 GNUNET_SCHEDULER_run (&taskSig, &ok);
245 return ok;
246}
247
248
249static void
250taskCancel (void *cls)
251{
252 int *ok = cls;
253
254 GNUNET_assert (1 == *ok);
255 *ok = 0;
256 GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_add_now (&taskNeverRun, NULL));
257}
258
259
260/**
261 * Main method, starts scheduler with task1,
262 * checks that "ok" is correct at the end.
263 */
264static int
265checkCancel ()
266{
267 int ok;
268
269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
270 "[Check task cancellation]\n");
271 ok = 1;
272 GNUNET_SCHEDULER_run (&taskCancel, &ok);
273 return ok;
274}
275
276
277int
278main (int argc, char *argv[])
279{
280 int ret = 0;
281
282 GNUNET_log_setup ("test_scheduler", "WARNING", NULL);
283 ret += check ();
284 ret += checkCancel ();
285 ret += checkSignal ();
286 ret += checkShutdown ();
287 GNUNET_DISK_pipe_close (p);
288
289 return ret;
290}
291
292
293/* end of test_scheduler.c */
diff --git a/src/util/test_scheduler_delay.c b/src/util/test_scheduler_delay.c
deleted file mode 100644
index 003fac196..000000000
--- a/src/util/test_scheduler_delay.c
+++ /dev/null
@@ -1,95 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013 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 * @file util/test_scheduler_delay.c
22 * @brief testcase for delay of scheduler, measures how
23 * precise the timers are. Expect values between 0.2 and 2 ms on
24 * modern machines.
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29static struct GNUNET_TIME_Absolute target;
30
31static int i;
32
33static unsigned long long cumDelta;
34
35#define INCR 47
36
37#define MAXV 5000
38
39
40/**
41 * Signature of the main function of a task.
42 *
43 * @param cls closure
44 */
45static void
46test_task (void *cls)
47{
48 struct GNUNET_TIME_Absolute now;
49
50 now = GNUNET_TIME_absolute_get ();
51 if (now.abs_value_us > target.abs_value_us)
52 cumDelta += (now.abs_value_us - target.abs_value_us);
53 else
54 cumDelta += (target.abs_value_us - now.abs_value_us);
55 target =
56 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply
57 (GNUNET_TIME_UNIT_MICROSECONDS, i));
58 fprintf (stderr, "%s", ".");
59 if (i > MAXV)
60 {
61 fprintf (stderr, "%s", "\n");
62 return;
63 }
64 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
65 (GNUNET_TIME_UNIT_MICROSECONDS, i),
66 &test_task,
67 NULL);
68 i += INCR;
69}
70
71
72int
73main (int argc, char *argv[])
74{
75 GNUNET_log_setup ("test-scheduler-delay",
76 "WARNING",
77 NULL);
78 target = GNUNET_TIME_absolute_get ();
79 GNUNET_SCHEDULER_run (&test_task, NULL);
80 fprintf (stdout,
81 "Sleep precision: %llu microseconds (average delta). ",
82 cumDelta / (MAXV / INCR));
83 if (cumDelta <= 500 * MAXV / INCR)
84 fprintf (stdout, "%s", "Timer precision is excellent.\n");
85 else if (cumDelta <= 5000 * MAXV / INCR) /* 5 ms average deviation */
86 fprintf (stdout, "%s", "Timer precision is good.\n");
87 else if (cumDelta > 25000 * MAXV / INCR)
88 fprintf (stdout, "%s", "Timer precision is awful.\n");
89 else
90 fprintf (stdout, "%s", "Timer precision is acceptable.\n");
91 return 0;
92}
93
94
95/* end of test_scheduler_delay.c */
diff --git a/src/util/test_service.c b/src/util/test_service.c
deleted file mode 100644
index 61afc0cc5..000000000
--- a/src/util/test_service.c
+++ /dev/null
@@ -1,238 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2013, 2016 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 * @file util/test_service.c
22 * @brief tests for service.c
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28/**
29 * Message type we use for testing.
30 */
31#define MY_TYPE 256
32
33#define TIMEOUT GNUNET_TIME_UNIT_SECONDS
34
35static int global_ret = 1;
36
37static struct GNUNET_MQ_Handle *mq;
38
39/**
40 * Timeout task.
41 */
42static struct GNUNET_SCHEDULER_Task *tt;
43
44
45static void
46handle_recv (void *cls,
47 const struct GNUNET_MessageHeader *message)
48{
49 struct GNUNET_SERVICE_Client *client = cls;
50
51 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
52 "Received client message...\n");
53 GNUNET_SERVICE_client_continue (client);
54 global_ret = 2;
55 if (NULL != mq)
56 {
57 GNUNET_MQ_destroy (mq);
58 mq = NULL;
59 }
60}
61
62
63/**
64 * Function called when the client connects to the service.
65 *
66 * @param cls the name of the service
67 * @param c connecting client
68 * @param mq message queue to talk to the client
69 * @return @a c so we have the client handle in the future
70 */
71static void *
72connect_cb (void *cls,
73 struct GNUNET_SERVICE_Client *c,
74 struct GNUNET_MQ_Handle *mq)
75{
76 /* FIXME: in the future, do something with mq
77 to test sending messages to the client! */
78 return c;
79}
80
81
82/**
83 * Function called when the client disconnects.
84 *
85 * @param cls our service name
86 * @param c disconnecting client
87 * @param internal_cls must match @a c
88 */
89static void
90disconnect_cb (void *cls,
91 struct GNUNET_SERVICE_Client *c,
92 void *internal_cls)
93{
94 GNUNET_assert (c == internal_cls);
95 if (2 == global_ret)
96 {
97 GNUNET_SCHEDULER_shutdown ();
98 global_ret = 0;
99 if (NULL != tt)
100 {
101 GNUNET_SCHEDULER_cancel (tt);
102 tt = NULL;
103 }
104 }
105}
106
107
108static void
109timeout_task (void *cls)
110{
111 tt = NULL;
112 if (NULL != mq)
113 {
114 GNUNET_MQ_destroy (mq);
115 mq = NULL;
116 }
117 global_ret = 33;
118 GNUNET_SCHEDULER_shutdown ();
119}
120
121
122/**
123 * Initialization function of the service. Starts
124 * a client to connect to the service.
125 *
126 * @param cls the name of the service (const char *)
127 * @param cfg the configuration we use
128 * @param sh handle to the service
129 */
130static void
131service_init (void *cls,
132 const struct GNUNET_CONFIGURATION_Handle *cfg,
133 struct GNUNET_SERVICE_Handle *sh)
134{
135 const char *service_name = cls;
136 struct GNUNET_MQ_Envelope *env;
137 struct GNUNET_MessageHeader *msg;
138
139 GNUNET_assert (NULL == tt);
140 tt = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
141 &timeout_task,
142 NULL);
143 mq = GNUNET_CLIENT_connect (cfg,
144 service_name,
145 NULL,
146 NULL,
147 NULL);
148 GNUNET_assert (NULL != mq);
149 env = GNUNET_MQ_msg (msg,
150 MY_TYPE);
151 GNUNET_MQ_send (mq,
152 env);
153}
154
155
156/**
157 * Main method, starts the service and initiates
158 * the running of the test.
159 *
160 * @param sname name of the service to run
161 */
162static int
163check (const char *sname)
164{
165 struct GNUNET_MQ_MessageHandler myhandlers[] = {
166 GNUNET_MQ_hd_fixed_size (recv,
167 MY_TYPE,
168 struct GNUNET_MessageHeader,
169 NULL),
170 GNUNET_MQ_handler_end ()
171 };
172 char *const argv[] = {
173 (char *) sname,
174 "-c",
175 "test_service_data.conf",
176 NULL
177 };
178
179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
180 "Starting `%s' service\n",
181 sname);
182 global_ret = 1;
183 GNUNET_assert (0 ==
184 GNUNET_SERVICE_run_ (3,
185 argv,
186 sname,
187 GNUNET_SERVICE_OPTION_NONE,
188 &service_init,
189 &connect_cb,
190 &disconnect_cb,
191 (void *) sname,
192 myhandlers));
193 return global_ret;
194}
195
196
197int
198main (int argc,
199 char *argv[])
200{
201 int ret = 0;
202 struct GNUNET_NETWORK_Handle *s = NULL;
203
204 GNUNET_log_setup ("test-service",
205 "WARNING",
206 NULL);
207 ret += check ("test_service");
208 ret += check ("test_service");
209 s = GNUNET_NETWORK_socket_create (PF_INET6,
210 SOCK_STREAM,
211 0);
212
213 if (NULL == s)
214 {
215 if ((errno == ENOBUFS) ||
216 (errno == ENOMEM) ||
217 (errno == ENFILE) ||
218 (errno == EACCES))
219 {
220 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
221 "socket");
222 return 1;
223 }
224 fprintf (stderr,
225 "IPv6 support seems to not be available (%s), not testing it!\n",
226 strerror (errno));
227 }
228 else
229 {
230 GNUNET_break (GNUNET_OK ==
231 GNUNET_NETWORK_socket_close (s));
232 ret += check ("test_service6");
233 }
234 return ret;
235}
236
237
238/* end of test_service.c */
diff --git a/src/util/test_service_data.conf b/src/util/test_service_data.conf
deleted file mode 100644
index 3263a52c0..000000000
--- a/src/util/test_service_data.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1[test_service]
2PORT=12435
3BINDTO=127.0.0.1
4PIDFILE=$GNUNET_TMP/test-service.pid
5MAXBUF=1024
6DISABLEV6=NO
7ACCEPT_FROM=127.0.0.1;
8REJECT_FROM=1.2.3.0/15;4.5.0.0/8;6.7.8.9/255.255.255.0;
9ACCEPT_FROM6=::1;
10REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40;
11HOSTNAME=localhost
12
13[test_service6]
14PORT=12435
15PIDFILE=$GNUNET_TMP/test-service.pid
16TIMEOUT=30 s
17MAXBUF=1024
18DISABLEV6=NO
19ACCEPT_FROM=127.0.0.1;
20REJECT_FROM=1.2.3.0/15;4.5.0.0/8;6.7.8.9/255.255.255.0;
21ACCEPT_FROM6=::1;
22REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40;
23HOSTNAME=::1
24
25[resolver]
26HOSTNAME=localhost
27
28
diff --git a/src/util/test_socks.c b/src/util/test_socks.c
deleted file mode 100644
index c5a703db4..000000000
--- a/src/util/test_socks.c
+++ /dev/null
@@ -1,257 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015, 2016 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 * @file util/test_socks.c
22 * @brief tests for socks.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28#define PORT 35124
29
30#define MYNAME "test_sockst"
31
32static struct GNUNET_MQ_Handle *mq;
33
34static struct GNUNET_SERVER_Handle *server;
35
36static struct GNUNET_CONFIGURATION_Handle *cfg;
37
38#define MY_TYPE 130
39
40struct CopyContext
41{
42 struct GNUNET_SERVER_Client *client;
43 struct GNUNET_MessageHeader *cpy;
44};
45
46static size_t
47copy_msg (void *cls, size_t size, void *buf)
48{
49 struct CopyContext *ctx = cls;
50 struct GNUNET_MessageHeader *cpy = ctx->cpy;
51
52 GNUNET_assert (sizeof(struct GNUNET_MessageHeader) == ntohs (cpy->size));
53 GNUNET_assert (size >= ntohs (cpy->size));
54 GNUNET_memcpy (buf, cpy, ntohs (cpy->size));
55 GNUNET_SERVER_receive_done (ctx->client, GNUNET_OK);
56 GNUNET_free (cpy);
57 GNUNET_free (ctx);
58 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message bounced back to client\n");
59 return sizeof(struct GNUNET_MessageHeader);
60}
61
62
63/**
64 * Callback that just bounces the message back to the sender.
65 */
66static void
67echo_cb (void *cls, struct GNUNET_SERVER_Client *client,
68 const struct GNUNET_MessageHeader *message)
69{
70 struct CopyContext *cc;
71 struct GNUNET_MessageHeader *cpy;
72
73 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
74 "Receiving message from client, bouncing back\n");
75 GNUNET_assert (sizeof(struct GNUNET_MessageHeader) == ntohs (message->size));
76 cc = GNUNET_new (struct CopyContext);
77 cc->client = client;
78 cpy = GNUNET_malloc (ntohs (message->size));
79 GNUNET_memcpy (cpy, message, ntohs (message->size));
80 cc->cpy = cpy;
81 GNUNET_assert (NULL !=
82 GNUNET_SERVER_notify_transmit_ready (client,
83 ntohs (message->size),
84 GNUNET_TIME_UNIT_SECONDS,
85 &copy_msg, cc));
86}
87
88
89static struct GNUNET_SERVER_MessageHandler handlers[] = {
90 { &echo_cb, NULL, MY_TYPE, sizeof(struct GNUNET_MessageHeader) },
91 { NULL, NULL, 0, 0 }
92};
93
94
95static void
96handle_bounce (void *cls,
97 const struct GNUNET_MessageHeader *got)
98{
99 int *ok = cls;
100
101 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
102 "Receiving bounce, checking content\n");
103 GNUNET_assert (NULL != got);
104 GNUNET_MQ_destroy (mq);
105 mq = NULL;
106 GNUNET_SERVER_destroy (server);
107 server = NULL;
108 *ok = 0;
109}
110
111
112/**
113 * Generic error handler, called with the appropriate error code and
114 * the same closure specified at the creation of the message queue.
115 * Not every message queue implementation supports an error handler.
116 *
117 * @param cls closure with the `struct GNUNET_STATISTICS_Handle *`
118 * @param error error code
119 */
120static void
121mq_error_handler (void *cls,
122 enum GNUNET_MQ_Error error)
123{
124 GNUNET_assert (0); /* should never happen */
125}
126
127
128static void
129task (void *cls)
130{
131 struct sockaddr_in sa;
132 struct sockaddr *sap[2];
133 socklen_t slens[2];
134 struct GNUNET_MQ_Envelope *env;
135 struct GNUNET_MessageHeader *msg;
136 struct GNUNET_MQ_MessageHandler chandlers[] = {
137 GNUNET_MQ_hd_fixed_size (bounce,
138 MY_TYPE,
139 struct GNUNET_MessageHeader,
140 cls),
141 GNUNET_MQ_handler_end ()
142 };
143
144 /* test IPC between client and server */
145 sap[0] = (struct sockaddr *) &sa;
146 slens[0] = sizeof(sa);
147 sap[1] = NULL;
148 slens[1] = 0;
149 memset (&sa, 0, sizeof(sa));
150#if HAVE_SOCKADDR_IN_SIN_LEN
151 sa.sin_len = sizeof(sa);
152#endif
153 sa.sin_family = AF_INET;
154 sa.sin_port = htons (PORT);
155 server =
156 GNUNET_SERVER_create (NULL, NULL, sap, slens,
157 GNUNET_TIME_relative_multiply
158 (GNUNET_TIME_UNIT_MILLISECONDS, 10000), GNUNET_NO);
159 GNUNET_assert (server != NULL);
160 handlers[0].callback_cls = cls;
161 handlers[1].callback_cls = cls;
162 GNUNET_SERVER_add_handlers (server, handlers);
163 mq = GNUNET_CLIENT_connect (cfg,
164 MYNAME,
165 chandlers,
166 &mq_error_handler,
167 NULL);
168 GNUNET_assert (NULL != mq);
169 env = GNUNET_MQ_msg (msg,
170 MY_TYPE);
171 GNUNET_MQ_send (mq,
172 env);
173}
174
175
176int
177main (int argc, char *argv[])
178{
179 int ok;
180 int status;
181 const char *socksport = "1081";
182
183 GNUNET_log_setup ("test_client",
184 "WARNING",
185 NULL);
186
187 pid_t pid = fork ();
188 GNUNET_assert (pid >= 0);
189 if (pid == 0)
190 {
191 execlp ("ssh",
192 "ssh", "-D", socksport,
193 "-o", "BatchMode yes",
194 "-o", "UserKnownHostsFile /tmp/gnunet_test_socks_ssh_garbage",
195 "-o", "StrictHostKeyChecking no",
196 "127.0.0.1", "-N", (char *) NULL);
197 perror (
198 "execlp (\"ssh\",\"ssh\",...,\"-D\",\"1081\",\"127.0.0.1\",\"-N\") ");
199 printf (""
200 "Please ensure you have ssh installed and have sshd installed and running :\n"
201 "\tsudo apt-get install openssh-client openssh-server\n"
202 "If you run Tor as a network proxy then Tor might prevent ssh from connecting\n"
203 "to localhost. Please either run make check from an unproxied user, or else\n"
204 "add these lines to the beginning of your ~/.ssh/config file :"
205 "\tHost 127.0.0.1 localhost\n"
206 "\t CheckHostIP no\n"
207 "\t Protocol 2\n"
208 "\t ProxyCommand nc 127.0.0.1 22\n");
209 kill (getppid (), SIGALRM);
210 return 1;
211 }
212 if (0 != sleep (1))
213 {
214 /* sleep interrupted, likely SIGALRM, failure to
215 launch child, terminate */
216 printf (""
217 "Please ensure you have ssh installed and have sshd installed and running :\n"
218 "\tsudo apt-get install openssh-client openssh-server\n"
219 "If you run Tor as a network proxy then Tor might prevent ssh from connecting\n"
220 "to localhost. Please either run make check from an unproxied user, or else\n"
221 "add these lines to the beginning of your ~/.ssh/config file :"
222 "\tHost 127.0.0.1 localhost\n"
223 "\t CheckHostIP no\n"
224 "\t Protocol 2\n"
225 "\t ProxyCommand nc 127.0.0.1 22\n");
226 return 77;
227 }
228 /* check if child exec()ed but died */
229 if (0 != waitpid (pid, &status, WNOHANG))
230 {
231 printf (""
232 "If you run Tor as a network proxy then Tor might prevent ssh from connecting\n"
233 "to localhost. Please either run make check from an unproxied user, or else\n"
234 "add these lines to the beginning of your ~/.ssh/config file :"
235 "\tHost 127.0.0.1 localhost\n"
236 "\t CheckHostIP no\n"
237 "\t Protocol 2\n"
238 "\t ProxyCommand nc 127.0.0.1 22\n");
239 return 77;
240 }
241
242 cfg = GNUNET_CONFIGURATION_create ();
243 GNUNET_CONFIGURATION_set_value_string (cfg, MYNAME, "SOCKSHOST", "127.0.0.1");
244 GNUNET_CONFIGURATION_set_value_string (cfg, MYNAME, "SOCKSPORT", socksport);
245 GNUNET_CONFIGURATION_set_value_number (cfg, MYNAME, "PORT", PORT);
246 GNUNET_CONFIGURATION_set_value_string (cfg, MYNAME, "HOSTNAME", "127.0.0.1");
247 ok = 1;
248 GNUNET_SCHEDULER_run (&task, &ok);
249 GNUNET_CONFIGURATION_destroy (cfg);
250
251 GNUNET_break (0 == kill (pid, SIGTERM));
252 GNUNET_break (pid == waitpid (pid, &status, 0));
253 return ok;
254}
255
256
257/* end of test_socks.c */
diff --git a/src/util/test_speedup.c b/src/util/test_speedup.c
deleted file mode 100644
index bca6886aa..000000000
--- a/src/util/test_speedup.c
+++ /dev/null
@@ -1,126 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 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 * @file util/test_speedup.c
22 * @brief testcase for speedup.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27/**
28 * Start time of the testcase
29 */
30static struct GNUNET_TIME_Absolute start;
31
32/**
33 * End-time of the testcase (affected by speed-up)
34 */
35static struct GNUNET_TIME_Absolute end;
36
37/**
38 * Number of cycles we have spent in 'run'.
39 */
40static unsigned int cycles;
41
42
43/**
44 * Main task that is scheduled with the speed-up.
45 *
46 * @param cls NULL
47 * @param tc scheduler context, unused
48 */
49static void
50run (void *cls)
51{
52 cycles++;
53 fprintf (stderr, "..%u", cycles);
54 if (cycles <= 5)
55 {
56 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
57 &run,
58 NULL);
59 return;
60 }
61 end = GNUNET_TIME_absolute_get ();
62 fprintf (stderr, "\n");
63 fflush (stdout);
64}
65
66
67/**
68 *
69 */
70static void
71check (void *cls,
72 char *const *args,
73 const char *cfgfile,
74 const struct GNUNET_CONFIGURATION_Handle *cfg)
75{
76 fprintf (stderr, "0");
77 fflush (stdout);
78 GNUNET_SCHEDULER_add_now (&run, NULL);
79}
80
81
82int
83main (int argc, char *argv[])
84{
85 static char *const argvn[] = {
86 "test-speedup",
87 "-c", "test_speedup_data.conf",
88 NULL
89 };
90 static struct GNUNET_GETOPT_CommandLineOption options[] = {
91 GNUNET_GETOPT_OPTION_END
92 };
93 time_t start_real;
94 time_t end_real;
95 struct GNUNET_TIME_Relative delta;
96
97 start_real = time (NULL);
98 start = GNUNET_TIME_absolute_get ();
99 GNUNET_PROGRAM_run ((sizeof(argvn) / sizeof(char *)) - 1, argvn,
100 "test-speedup",
101 "nohelp", options, &check, NULL);
102
103 end_real = time (NULL);
104 delta = GNUNET_TIME_absolute_get_difference (start, end);
105
106 if (delta.rel_value_us > ((end_real - start_real) * 1500LL * 1000LL))
107 {
108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
109 "Execution time in GNUnet time: %s\n",
110 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_YES));
111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
112 "Execution time in system time: %llu ms\n",
113 (unsigned long long) ((end_real - start_real) * 1000LL));
114 return 0;
115 }
116 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
117 "Execution time in GNUnet time: %s\n",
118 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_YES));
119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
120 "Execution time in system time: %llu ms\n",
121 (unsigned long long) ((end_real - start_real) * 1000LL));
122 return 1;
123}
124
125
126/* end of test_speedup.c */
diff --git a/src/util/test_speedup_data.conf b/src/util/test_speedup_data.conf
deleted file mode 100644
index 699cdc933..000000000
--- a/src/util/test_speedup_data.conf
+++ /dev/null
@@ -1,3 +0,0 @@
1[testing]
2SPEEDUP_INTERVAL = 100 ms
3SPEEDUP_DELTA = 100 ms
diff --git a/src/util/test_strings.c b/src/util/test_strings.c
deleted file mode 100644
index d986486d0..000000000
--- a/src/util/test_strings.c
+++ /dev/null
@@ -1,162 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_strings.c
22 * @brief testcase for strings.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28#define WANT(a, b) if (0 != strcmp (a, b)) { fprintf (stderr, \
29 "Got `%s', wanted `%s'\n", \
30 b, a); GNUNET_free (b); \
31 GNUNET_break (0); \
32 return 1; } else { GNUNET_free (b); \
33}
34#define WANTNF(a, b) do { if (0 != strcmp (a, b)) { fprintf (stderr, \
35 "Got `%s', wanted `%s'\n", \
36 b, a); \
37 GNUNET_break (0); return 1; \
38 } } while (0)
39#define WANTB(a, b, l) if (0 != memcmp (a, b, l)) { GNUNET_break (0); return 1; \
40} else { }
41
42#define URLENCODE_TEST_VECTOR_PLAIN "Asbjlaw=ljsdlasjd?人aslkdsa"
43
44#define URLENCODE_TEST_VECTOR_ENCODED \
45 "Asbjlaw\%3Dljsdlasjd\%3F\%E4\%BA\%BAaslkdsa"
46
47int
48main (int argc, char *argv[])
49{
50 char buf[128];
51 char *r;
52 char *b;
53 const char *bc;
54 struct GNUNET_TIME_Absolute at;
55 struct GNUNET_TIME_Absolute atx;
56 struct GNUNET_TIME_Relative rt;
57 struct GNUNET_TIME_Relative rtx;
58 const char *hdir;
59
60 GNUNET_log_setup ("test_strings", "ERROR", NULL);
61 sprintf (buf, "4 %s", _ (/* size unit */ "b"));
62 b = GNUNET_STRINGS_byte_size_fancy (4);
63 WANT (buf, b);
64 sprintf (buf, "10 %s", _ (/* size unit */ "KiB"));
65 b = GNUNET_STRINGS_byte_size_fancy (10240);
66 WANT (buf, b);
67 sprintf (buf, "10 %s", _ (/* size unit */ "TiB"));
68 b = GNUNET_STRINGS_byte_size_fancy (10240LL * 1024LL * 1024LL * 1024LL);
69 WANT (buf, b);
70 sprintf (buf, "4 %s", _ (/* time unit */ "ms"));
71 bc = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply
72 (GNUNET_TIME_UNIT_MILLISECONDS,
73 4), GNUNET_YES);
74 WANTNF (buf, bc);
75 sprintf (buf, "7 %s", _ (/* time unit */ "s"));
76 bc = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply
77 (GNUNET_TIME_UNIT_MILLISECONDS,
78 7 * 1000), GNUNET_YES);
79 WANTNF (buf, bc);
80 sprintf (buf, "7 %s", _ (/* time unit */ "h"));
81 bc = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply
82 (GNUNET_TIME_UNIT_MILLISECONDS,
83 7 * 60 * 60 * 1000),
84 GNUNET_YES);
85 WANTNF (buf, bc);
86
87 hdir = getenv ("HOME");
88
89 GNUNET_snprintf (buf, sizeof(buf), "%s%s", hdir, DIR_SEPARATOR_STR);
90 b = GNUNET_STRINGS_filename_expand ("~");
91 GNUNET_assert (b != NULL);
92 WANT (buf, b);
93 GNUNET_STRINGS_buffer_fill (buf, sizeof(buf), 3, "a", "btx", "c");
94 WANTB ("a\0btx\0c", buf, 8);
95 if (6 != GNUNET_STRINGS_buffer_tokenize (buf, sizeof(buf), 2, &r, &b))
96 return 1;
97 r = GNUNET_strdup (r);
98 WANT ("a", r);
99 b = GNUNET_strdup (b);
100 WANT ("btx", b);
101 if (0 != GNUNET_STRINGS_buffer_tokenize (buf, 2, 2, &r, &b))
102 return 1;
103 at.abs_value_us = 5000000;
104 bc = GNUNET_STRINGS_absolute_time_to_string (at);
105 /* bc should be something like "Wed Dec 31 17:00:05 1969"
106 * where the details of the day and hour depend on the timezone;
107 * however, the "0:05 19" should always be there; hence: */
108 if (NULL == strstr (bc, "0:05 19"))
109 {
110 fprintf (stderr, "Got %s\n", bc);
111 GNUNET_break (0);
112 return 1;
113 }
114 b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "ASCII");
115 WANT ("TEST", b);
116
117 at = GNUNET_TIME_UNIT_FOREVER_ABS;
118 bc = GNUNET_STRINGS_absolute_time_to_string (at);
119 GNUNET_assert (GNUNET_OK ==
120 GNUNET_STRINGS_fancy_time_to_absolute (bc, &atx));
121 GNUNET_assert (atx.abs_value_us == at.abs_value_us);
122
123 at.abs_value_us = 50000000000;
124 bc = GNUNET_STRINGS_absolute_time_to_string (at);
125
126 GNUNET_assert (GNUNET_OK ==
127 GNUNET_STRINGS_fancy_time_to_absolute (bc, &atx));
128
129 if (atx.abs_value_us != at.abs_value_us)
130 {
131 GNUNET_assert (0);
132 }
133
134 GNUNET_log_skip (2, GNUNET_NO);
135 b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "unknown");
136 GNUNET_log_skip (0, GNUNET_YES);
137 WANT ("TEST", b);
138
139 GNUNET_assert (GNUNET_OK ==
140 GNUNET_STRINGS_fancy_time_to_relative ("15m", &rt));
141 GNUNET_assert (GNUNET_OK ==
142 GNUNET_STRINGS_fancy_time_to_relative ("15 m", &rtx));
143 GNUNET_assert (rt.rel_value_us == rtx.rel_value_us);
144
145 GNUNET_assert (0 != GNUNET_STRINGS_urlencode (URLENCODE_TEST_VECTOR_PLAIN,
146 strlen (
147 URLENCODE_TEST_VECTOR_PLAIN),
148 &b));
149 WANT (URLENCODE_TEST_VECTOR_ENCODED, b);
150 GNUNET_free (b);
151 GNUNET_assert (0 !=
152 GNUNET_STRINGS_urldecode (URLENCODE_TEST_VECTOR_ENCODED,
153 strlen (
154 URLENCODE_TEST_VECTOR_ENCODED),
155 &b));
156 WANT (URLENCODE_TEST_VECTOR_PLAIN, b);
157 GNUNET_free (b);
158 return 0;
159}
160
161
162/* end of test_strings.c */
diff --git a/src/util/test_strings_to_data.c b/src/util/test_strings_to_data.c
deleted file mode 100644
index 71861b128..000000000
--- a/src/util/test_strings_to_data.c
+++ /dev/null
@@ -1,65 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file util/test_strings_to_data.c
22 * @brief testcase for strings.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28int
29main (int argc, char *argv[])
30{
31 char buf[1024];
32 char *end;
33 char src[128];
34 char dst[128];
35 unsigned int i;
36 int ret = 0;
37
38 GNUNET_log_setup ("util", "DEBUG", NULL);
39 for (i = 0; i < sizeof(src); i++)
40 {
41 memset (src, i, sizeof(src));
42 memset (dst, i + 1, sizeof(dst));
43
44 end = GNUNET_STRINGS_data_to_string (&src, i, buf, sizeof(buf));
45 GNUNET_assert (NULL != end);
46 end[0] = '\0';
47 if (GNUNET_OK !=
48 GNUNET_STRINGS_string_to_data (buf, strlen (buf), dst, i))
49 {
50 fprintf (stderr, "%u failed decode (%u bytes)\n", i, (unsigned
51 int) strlen (buf));
52 ret = 1;
53 }
54 else if (0 != memcmp (src, dst, i))
55 {
56 fprintf (stderr, "%u wrong decode (%u bytes)\n", i, (unsigned
57 int) strlen (buf));
58 ret = 1;
59 }
60 }
61 return ret;
62}
63
64
65/* end of test_strings_to_data.c */
diff --git a/src/util/test_time.c b/src/util/test_time.c
deleted file mode 100644
index 59917793c..000000000
--- a/src/util/test_time.c
+++ /dev/null
@@ -1,264 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013, 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 * @file util/test_time.c
22 * @brief testcase for time.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28int
29main (int argc, char *argv[])
30{
31 struct GNUNET_TIME_Absolute now;
32 struct GNUNET_TIME_AbsoluteNBO nown;
33 struct GNUNET_TIME_Absolute future;
34 struct GNUNET_TIME_Absolute past;
35 struct GNUNET_TIME_Absolute last;
36 struct GNUNET_TIME_Absolute forever;
37 struct GNUNET_TIME_Absolute zero;
38 struct GNUNET_TIME_Relative rel;
39 struct GNUNET_TIME_Relative relForever;
40 struct GNUNET_TIME_Relative relUnit;
41 struct GNUNET_TIME_RelativeNBO reln;
42 unsigned int i;
43
44 GNUNET_log_setup ("test-time", "WARNING", NULL);
45 forever = GNUNET_TIME_UNIT_FOREVER_ABS;
46 relForever = GNUNET_TIME_UNIT_FOREVER_REL;
47 relUnit = GNUNET_TIME_UNIT_MILLISECONDS;
48 zero.abs_value_us = 0;
49
50 last = now = GNUNET_TIME_absolute_get ();
51 while (now.abs_value_us == last.abs_value_us)
52 now = GNUNET_TIME_absolute_get ();
53 GNUNET_assert (now.abs_value_us > last.abs_value_us);
54
55 /* test overflow checking in multiply */
56 rel = GNUNET_TIME_UNIT_MILLISECONDS;
57 GNUNET_log_skip (1, GNUNET_NO);
58 for (i = 0; i < 55; i++)
59 rel = GNUNET_TIME_relative_multiply (rel, 2);
60 GNUNET_log_skip (0, GNUNET_NO);
61 GNUNET_assert (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us);
62 /*check zero */
63 rel.rel_value_us = (UINT64_MAX) -1024;
64 GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us ==
65 GNUNET_TIME_relative_multiply (rel, 0).rel_value_us);
66
67 /* test infinity-check for relative to absolute */
68 GNUNET_log_skip (1, GNUNET_NO);
69 last = GNUNET_TIME_relative_to_absolute (rel);
70 GNUNET_assert (last.abs_value_us ==
71 GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us);
72 GNUNET_log_skip (0, GNUNET_YES);
73
74 /* check relative to absolute */
75 rel.rel_value_us = 1000000;
76 GNUNET_assert (GNUNET_TIME_absolute_get ().abs_value_us <
77 GNUNET_TIME_relative_to_absolute (rel).abs_value_us);
78 /*check forever */
79 rel.rel_value_us = UINT64_MAX;
80 GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us ==
81 GNUNET_TIME_relative_to_absolute (rel).abs_value_us);
82 /* check overflow for r2a */
83 rel.rel_value_us = (UINT64_MAX) -1024;
84 GNUNET_log_skip (1, GNUNET_NO);
85 last = GNUNET_TIME_relative_to_absolute (rel);
86 GNUNET_log_skip (0, GNUNET_NO);
87 GNUNET_assert (last.abs_value_us ==
88 GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us);
89
90 /* check overflow for relative add */
91 GNUNET_log_skip (1, GNUNET_NO);
92 rel = GNUNET_TIME_relative_add (rel, rel);
93 GNUNET_log_skip (0, GNUNET_NO);
94 GNUNET_assert (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us);
95
96 GNUNET_log_skip (1, GNUNET_NO);
97 rel = GNUNET_TIME_relative_add (relForever, relForever);
98 GNUNET_log_skip (0, GNUNET_NO);
99 GNUNET_assert (rel.rel_value_us == relForever.rel_value_us);
100
101 GNUNET_log_skip (1, GNUNET_NO);
102 rel = GNUNET_TIME_relative_add (relUnit, relUnit);
103 GNUNET_assert (rel.rel_value_us == 2 * relUnit.rel_value_us);
104
105 /* check relation check in get_duration */
106 future.abs_value_us = now.abs_value_us + 1000000;
107 GNUNET_assert (GNUNET_TIME_absolute_get_difference (now,
108 future).rel_value_us ==
109 1000000);
110 GNUNET_assert (GNUNET_TIME_absolute_get_difference (future,
111 now).rel_value_us ==
112 0);
113
114 GNUNET_assert (GNUNET_TIME_absolute_get_difference (zero,
115 forever).rel_value_us
116 == forever.abs_value_us);
117
118 past.abs_value_us = now.abs_value_us - 1000000;
119 rel = GNUNET_TIME_absolute_get_duration (future);
120 GNUNET_assert (rel.rel_value_us == 0);
121 rel = GNUNET_TIME_absolute_get_duration (past);
122 GNUNET_assert (rel.rel_value_us >= 1000000);
123
124 /* check get remaining */
125 rel = GNUNET_TIME_absolute_get_remaining (now);
126 GNUNET_assert (rel.rel_value_us == 0);
127 rel = GNUNET_TIME_absolute_get_remaining (past);
128 GNUNET_assert (rel.rel_value_us == 0);
129 rel = GNUNET_TIME_absolute_get_remaining (future);
130 GNUNET_assert (rel.rel_value_us > 0);
131 GNUNET_assert (rel.rel_value_us <= 1000000);
132 forever = GNUNET_TIME_UNIT_FOREVER_ABS;
133 GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us ==
134 GNUNET_TIME_absolute_get_remaining (forever).rel_value_us);
135
136 /* check endianness */
137 reln = GNUNET_TIME_relative_hton (rel);
138 GNUNET_assert (rel.rel_value_us == GNUNET_TIME_relative_ntoh (
139 reln).rel_value_us);
140 nown = GNUNET_TIME_absolute_hton (now);
141 GNUNET_assert (now.abs_value_us == GNUNET_TIME_absolute_ntoh (
142 nown).abs_value_us);
143
144 /* check absolute addition */
145 future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_SECONDS);
146 GNUNET_assert (future.abs_value_us == now.abs_value_us + 1000 * 1000LL);
147
148 future = GNUNET_TIME_absolute_add (forever, GNUNET_TIME_UNIT_ZERO);
149 GNUNET_assert (future.abs_value_us == forever.abs_value_us);
150
151 rel.rel_value_us = (UINT64_MAX) -1024;
152 now.abs_value_us = rel.rel_value_us;
153 future = GNUNET_TIME_absolute_add (now, rel);
154 GNUNET_assert (future.abs_value_us == forever.abs_value_us);
155
156 /* check zero */
157 future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_ZERO);
158 GNUNET_assert (future.abs_value_us == now.abs_value_us);
159
160 GNUNET_assert (forever.abs_value_us ==
161 GNUNET_TIME_absolute_subtract (forever,
162 GNUNET_TIME_UNIT_MINUTES).
163 abs_value_us);
164 /*check absolute subtract */
165 now.abs_value_us = 50000;
166 rel.rel_value_us = 100000;
167 GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
168 (GNUNET_TIME_absolute_subtract (now, rel)).abs_value_us);
169 rel.rel_value_us = 10000;
170 GNUNET_assert (40000 == (GNUNET_TIME_absolute_subtract (now,
171 rel)).abs_value_us);
172
173 /*check relative divide */
174 GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us ==
175 (GNUNET_TIME_relative_divide (rel, 0)).rel_value_us);
176
177 rel = GNUNET_TIME_UNIT_FOREVER_REL;
178 GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us ==
179 (GNUNET_TIME_relative_divide (rel, 2)).rel_value_us);
180
181 rel = GNUNET_TIME_relative_divide (relUnit, 2);
182 GNUNET_assert (rel.rel_value_us == relUnit.rel_value_us / 2);
183
184
185 /* check Return absolute time of 0ms */
186 zero = GNUNET_TIME_UNIT_ZERO_ABS;
187
188 /* check GNUNET_TIME_calculate_eta */
189 last.abs_value_us = GNUNET_TIME_absolute_get ().abs_value_us - 1024;
190 forever = GNUNET_TIME_UNIT_FOREVER_ABS;
191 forever.abs_value_us = forever.abs_value_us - 1024;
192 GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
193 GNUNET_TIME_calculate_eta (forever, 50000,
194 100000).rel_value_us);
195 /* check zero */
196 GNUNET_log_skip (1, GNUNET_NO);
197 GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us ==
198 (GNUNET_TIME_calculate_eta (last, 60000, 50000)).rel_value_us);
199 GNUNET_log_skip (0, GNUNET_YES);
200 /*check forever */
201 GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us ==
202 (GNUNET_TIME_calculate_eta (last, 0, 50000)).rel_value_us);
203
204 /*check relative subtract */
205 now = GNUNET_TIME_absolute_get ();
206 rel.rel_value_us = now.abs_value_us;
207 relForever.rel_value_us = rel.rel_value_us + 1024;
208 GNUNET_assert (1024 ==
209 GNUNET_TIME_relative_subtract (relForever, rel).rel_value_us);
210 /*check zero */
211 GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us ==
212 GNUNET_TIME_relative_subtract (rel, relForever).rel_value_us);
213 /*check forever */
214 rel.rel_value_us = UINT64_MAX;
215 GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us ==
216 GNUNET_TIME_relative_subtract (rel, relForever).rel_value_us);
217
218 /*check GNUNET_TIME_relative_min */
219 now = GNUNET_TIME_absolute_get ();
220 rel.rel_value_us = now.abs_value_us;
221 relForever.rel_value_us = rel.rel_value_us - 1024;
222 GNUNET_assert (relForever.rel_value_us ==
223 GNUNET_TIME_relative_min (rel, relForever).rel_value_us);
224
225 /*check GNUNET_TIME_relative_max */
226 GNUNET_assert (rel.rel_value_us ==
227 GNUNET_TIME_relative_max (rel, relForever).rel_value_us);
228
229 /*check GNUNET_TIME_absolute_min */
230 now = GNUNET_TIME_absolute_get ();
231 last.abs_value_us = now.abs_value_us - 1024;
232 GNUNET_assert (last.abs_value_us ==
233 GNUNET_TIME_absolute_min (now, last).abs_value_us);
234
235 /*check GNUNET_TIME_absolute_max */
236 GNUNET_assert (now.abs_value_us ==
237 GNUNET_TIME_absolute_max (now, last).abs_value_us);
238 for (unsigned int i = 0; i < 30; i++)
239 {
240 struct GNUNET_CONFIGURATION_Handle *cfg;
241
242 cfg = GNUNET_CONFIGURATION_create ();
243 last = GNUNET_TIME_absolute_get_monotonic (cfg);
244 now = GNUNET_TIME_absolute_get_monotonic (cfg);
245 GNUNET_assert (now.abs_value_us > last.abs_value_us);
246 (void) GNUNET_TIME_absolute_get_monotonic (NULL);
247 GNUNET_CONFIGURATION_set_value_string (cfg,
248 "util",
249 "MONOTONIC_TIME_FILENAME",
250 "monotonic-time.dat");
251 last = GNUNET_TIME_absolute_get_monotonic (cfg);
252 now = GNUNET_TIME_absolute_get_monotonic (cfg);
253 (void) GNUNET_TIME_absolute_get_monotonic (NULL);
254 GNUNET_assert (now.abs_value_us > last.abs_value_us);
255 GNUNET_CONFIGURATION_destroy (cfg);
256 }
257 GNUNET_break (GNUNET_OK ==
258 GNUNET_DISK_directory_remove ("monotonic-time.dat"));
259
260 return 0;
261}
262
263
264/* end of test_time.c */
diff --git a/src/util/test_tun.c b/src/util/test_tun.c
deleted file mode 100644
index ad4a5c19e..000000000
--- a/src/util/test_tun.c
+++ /dev/null
@@ -1,76 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 Christian Grothoff
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 tun/test_tun.c
23 * @brief test for tun.c
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29static int ret;
30
31static void
32test_udp (size_t pll,
33 int pl_fill,
34 uint16_t crc)
35{
36 struct GNUNET_TUN_IPv4Header ip;
37 struct GNUNET_TUN_UdpHeader udp;
38 char payload[pll];
39 struct in_addr src;
40 struct in_addr dst;
41
42 GNUNET_assert (1 == inet_pton (AF_INET, "1.2.3.4", &src));
43 GNUNET_assert (1 == inet_pton (AF_INET, "122.2.3.5", &dst));
44 memset (payload, pl_fill, sizeof(payload));
45 GNUNET_TUN_initialize_ipv4_header (&ip,
46 IPPROTO_UDP,
47 pll + sizeof(udp),
48 &src,
49 &dst);
50 udp.source_port = htons (4242);
51 udp.destination_port = htons (4242);
52 udp.len = htons (pll);
53 GNUNET_TUN_calculate_udp4_checksum (&ip,
54 &udp,
55 payload,
56 pll);
57 if (crc != ntohs (udp.crc))
58 {
59 fprintf (stderr, "Got CRC: %u, wanted: %u\n",
60 ntohs (udp.crc),
61 crc);
62 ret = 1;
63 }
64}
65
66
67int
68main (int argc,
69 char **argv)
70{
71 test_udp (4, 3, 22439);
72 test_udp (4, 1, 23467);
73 test_udp (7, 17, 6516);
74 test_udp (12451, 251, 42771);
75 return ret;
76}
diff --git a/src/util/test_uri.c b/src/util/test_uri.c
deleted file mode 100644
index 7c8156648..000000000
--- a/src/util/test_uri.c
+++ /dev/null
@@ -1,837 +0,0 @@
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include "gnunet_uri_lib.h"
5
6#define KNRM "\x1B[0m"
7#define KBLU "\x1B[34m"
8#define KGRN "\x1B[32m"
9#define KERR "\x1B[5;31;50m"
10
11/* macro to print out the header for a new group of tests */
12#define mu_group(name) printf ("%s • %s%s\n", KBLU, name, KNRM)
13
14/* macro for asserting a statement */
15#define mu_assert(message, test) do { \
16 if (!(test)) { \
17 printf ("\t%s× %s%s\n", KERR, message, KNRM); \
18 return message; \
19 } \
20 printf ("\t%s• %s%s\n", KGRN, message, KNRM); \
21 } while (0)
22
23/* macro for asserting a statement without printing it unless it is a failure */
24#define mu_silent_assert(message, test) do { \
25 if (!(test)) { \
26 printf ("\t\t%s× %s%s\n", KERR, message, KNRM); \
27 return message; \
28 } \
29 } while (0)
30
31/* run a test function and return result */
32#define mu_run_test(test) do { \
33 char *message = test (); tests_run++; \
34 if (message) { return message; } \
35 } while (0)
36
37
38int tests_run;
39
40static int
41strcmp_wrap (const char *str,
42 const char *str2)
43{
44 if (NULL == str && NULL == str2) {
45 return 0;
46 }
47 if (NULL == str) {
48 return 1;
49 }
50 if (NULL == str2) {
51 return -1;
52 }
53
54 return strcmp (str, str2);
55}
56
57#define assert_struct(as_url, \
58 as_scheme, \
59 as_user, \
60 as_pass, \
61 as_host, \
62 as_port, \
63 as_path, \
64 as_query, \
65 as_fragment) \
66 mu_silent_assert ("should set the scheme attribute correctly", \
67 0 == strcmp_wrap (as_url.scheme, as_scheme)); \
68 mu_silent_assert ("should set the username attribute correctly", \
69 0 == strcmp_wrap (as_url.username, as_user)); \
70 mu_silent_assert ("should set the password attribute correctly", \
71 0 == strcmp_wrap (as_url.password, as_pass)); \
72 mu_silent_assert ("should set the host attribute correctly", \
73 0 == strcmp_wrap (as_url.host, as_host)); \
74 mu_silent_assert ("should set the port attribute correctly", \
75 as_port == as_url.port); \
76 mu_silent_assert ("should set the path attribute correctly", \
77 0 == strcmp_wrap (as_url.path, as_path)); \
78 mu_silent_assert ("should set the query attribute correctly", \
79 0 == strcmp_wrap (as_url.query, as_query)); \
80 mu_silent_assert ("should set the fragment attribute correctly", \
81 0 == strcmp_wrap (as_url.fragment, as_fragment));
82
83static char *
84test_parse_http_url_ok (void)
85{
86 int rc;
87 struct GNUNET_Uri url;
88 char *url_string;
89
90 /* Minimal URL */
91 url_string = strdup ("http://example.com");
92 rc = GNUNET_uri_parse (&url,
93 url_string);
94 mu_assert ("minimal HTTP URL", -1 != rc);
95 assert_struct (url,
96 "http",
97 NULL,
98 NULL,
99 "example.com",
100 0,
101 NULL,
102 NULL,
103 NULL);
104 free (url_string);
105
106 /* With path (/) */
107 url_string = strdup ("http://example.com/");
108 rc = GNUNET_uri_parse (&url,
109 url_string);
110 mu_assert ("with path ('/')", -1 != rc);
111 assert_struct (url,
112 "http",
113 NULL,
114 NULL,
115 "example.com",
116 0,
117 "",
118 NULL,
119 NULL);
120 free (url_string);
121
122 /* With path */
123 url_string = strdup ("http://example.com/path");
124 rc = GNUNET_uri_parse (&url,
125 url_string);
126 mu_assert ("with path ('/path')", -1 != rc);
127 assert_struct (url,
128 "http",
129 NULL,
130 NULL,
131 "example.com",
132 0,
133 "path",
134 NULL,
135 NULL);
136 free (url_string);
137
138 /* With port */
139 url_string = strdup ("http://example.com:80");
140 rc = GNUNET_uri_parse (&url,
141 url_string);
142 mu_assert ("with port only",
143 -1 != rc);
144 assert_struct (url,
145 "http",
146 NULL,
147 NULL,
148 "example.com",
149 80,
150 NULL,
151 NULL,
152 NULL);
153 free (url_string);
154
155 /* With query */
156 url_string = strdup ("http://example.com?query=only");
157 rc = GNUNET_uri_parse (&url,
158 url_string);
159 mu_assert ("with query only",
160 -1 != rc);
161 assert_struct (url,
162 "http",
163 NULL,
164 NULL,
165 "example.com",
166 0,
167 NULL,
168 "query=only",
169 NULL);
170 free (url_string);
171
172 /* With fragment */
173 url_string = strdup ("http://example.com#frag=f1");
174 rc = GNUNET_uri_parse (&url,
175 url_string);
176 mu_assert ("with fragment only",
177 -1 != rc);
178 assert_struct (url,
179 "http",
180 NULL,
181 NULL,
182 "example.com",
183 0,
184 NULL,
185 NULL,
186 "frag=f1");
187 free (url_string);
188
189 /* With credentials */
190 url_string = strdup ("http://u:p@example.com");
191 rc = GNUNET_uri_parse (&url,
192 url_string);
193 mu_assert ("with credentials only",
194 -1 != rc);
195 assert_struct (url,
196 "http",
197 "u",
198 "p",
199 "example.com",
200 0,
201 NULL,
202 NULL,
203 NULL);
204 free (url_string);
205
206 /* With port and path */
207 url_string = strdup ("http://example.com:8080/port/and/path");
208 rc = GNUNET_uri_parse (&url,
209 url_string);
210 mu_assert ("with port and path",
211 -1 != rc);
212 assert_struct (url,
213 "http",
214 NULL,
215 NULL,
216 "example.com",
217 8080,
218 "port/and/path",
219 NULL,
220 NULL);
221 free (url_string);
222
223 /* With port and query */
224 url_string = strdup ("http://example.com:8080?query=portANDquery");
225 rc = GNUNET_uri_parse (&url,
226 url_string);
227 mu_assert ("with port and query",
228 -1 != rc);
229 assert_struct (url,
230 "http",
231 NULL,
232 NULL,
233 "example.com",
234 8080,
235 NULL,
236 "query=portANDquery",
237 NULL);
238 free (url_string);
239
240 /* With port and fragment */
241 url_string = strdup ("http://example.com:8080#f1");
242 rc = GNUNET_uri_parse (&url,
243 url_string);
244 mu_assert ("with port and fragment",
245 -1 != rc);
246 assert_struct (url,
247 "http",
248 NULL,
249 NULL,
250 "example.com",
251 8080,
252 NULL,
253 NULL,
254 "f1");
255 free (url_string);
256
257 /* With port and credentials */
258 url_string = strdup ("http://u:p@example.com:8080");
259 rc = GNUNET_uri_parse (&url,
260 url_string);
261 mu_assert ("with port and credentials",
262 -1 != rc);
263 assert_struct (url,
264 "http",
265 "u",
266 "p",
267 "example.com",
268 8080,
269 NULL,
270 NULL,
271 NULL);
272 free (url_string);
273
274 /* With path and query */
275 url_string = strdup ("http://example.com/path/and/query?q=yes");
276 rc = GNUNET_uri_parse (&url,
277 url_string);
278 mu_assert ("with path and query",
279 -1 != rc);
280 assert_struct (url,
281 "http",
282 NULL,
283 NULL,
284 "example.com",
285 0,
286 "path/and/query",
287 "q=yes",
288 NULL);
289 free (url_string);
290
291 /* With path and fragment */
292 url_string = strdup ("http://example.com/path/and#fragment");
293 rc = GNUNET_uri_parse (&url,
294 url_string);
295 mu_assert ("with path and fragment",
296 -1 != rc);
297 assert_struct (url,
298 "http",
299 NULL,
300 NULL,
301 "example.com",
302 0,
303 "path/and",
304 NULL,
305 "fragment");
306 free (url_string);
307
308 /* With query and fragment */
309 url_string = strdup ("http://example.com?q=yes#f1");
310 rc = GNUNET_uri_parse (&url,
311 url_string);
312 mu_assert ("with query and fragment",
313 -1 != rc);
314 assert_struct (url,
315 "http",
316 NULL,
317 NULL,
318 "example.com",
319 0,
320 NULL,
321 "q=yes",
322 "f1");
323 free (url_string);
324
325 /* With query and credentials */
326 url_string = strdup ("http://u:p@example.com?q=yes");
327 rc = GNUNET_uri_parse (&url,
328 url_string);
329 mu_assert ("with query and credentials",
330 -1 != rc);
331 assert_struct (url,
332 "http",
333 "u",
334 "p",
335 "example.com",
336 0,
337 NULL,
338 "q=yes",
339 NULL);
340 free (url_string);
341
342 /* With empty credentials */
343 url_string = strdup ("http://:@example.com");
344 rc = GNUNET_uri_parse (&url,
345 url_string);
346 mu_assert ("with empty credentials",
347 -1 != rc);
348 assert_struct (url,
349 "http",
350 "",
351 "",
352 "example.com",
353 0,
354 NULL,
355 NULL,
356 NULL);
357 free (url_string);
358
359 /* With empty credentials and port */
360 url_string = strdup ("http://:@example.com:89");
361 rc = GNUNET_uri_parse (&url,
362 url_string);
363 mu_assert ("with empty credentials and port",
364 -1 != rc);
365 assert_struct (url,
366 "http",
367 "",
368 "",
369 "example.com",
370 89,
371 NULL,
372 NULL,
373 NULL);
374 free (url_string);
375
376 /* Full URL */
377 url_string = strdup ("https://jack:password@localhost:8989/path/to/test?query=yes&q=jack#fragment1");
378 rc = GNUNET_uri_parse (&url,
379 url_string);
380 mu_assert ("with port, path and query",
381 -1 != rc);
382 assert_struct (url,
383 "https",
384 "jack",
385 "password",
386 "localhost",
387 8989,
388 "path/to/test",
389 "query=yes&q=jack",
390 "fragment1");
391 free (url_string);
392
393 return NULL;
394}
395
396static char *
397test_parse_http_rel_url_ok (void)
398{
399 int rc;
400 struct GNUNET_Uri url;
401 char *url_string;
402
403 /* Minimal relative URL */
404 url_string = strdup ("/");
405 rc = GNUNET_uri_parse (&url,
406 url_string);
407 mu_assert ("minimal relative URL",
408 -1 != rc);
409 assert_struct (url,
410 NULL,
411 NULL,
412 NULL,
413 NULL,
414 0,
415 "",
416 NULL,
417 NULL);
418 free (url_string);
419
420 /* Path only */
421 url_string = strdup ("/hejsan");
422 rc = GNUNET_uri_parse (&url,
423 url_string);
424 mu_assert ("path only",
425 -1 != rc);
426 assert_struct (url,
427 NULL,
428 NULL,
429 NULL,
430 NULL,
431 0,
432 "hejsan",
433 NULL,
434 NULL);
435 free (url_string);
436
437 /* Path and query */
438 url_string = strdup ("/hejsan?q=yes");
439 rc = GNUNET_uri_parse (&url,
440 url_string);
441 mu_assert ("path only",
442 -1 != rc);
443 assert_struct (url,
444 NULL,
445 NULL,
446 NULL,
447 NULL,
448 0,
449 "hejsan",
450 "q=yes",
451 NULL);
452 free (url_string);
453
454 /* Path and fragment */
455 url_string = strdup ("/hejsan#fragment");
456 rc = GNUNET_uri_parse (&url,
457 url_string);
458 mu_assert ("path and fragment",
459 -1 != rc);
460 assert_struct (url,
461 NULL,
462 NULL,
463 NULL,
464 NULL,
465 0,
466 "hejsan",
467 NULL,
468 "fragment");
469 free (url_string);
470
471 /* Path, query and fragment */
472 url_string = strdup ("/?q=yes&q2=no#fragment");
473 rc = GNUNET_uri_parse (&url,
474 url_string);
475 mu_assert ("path, query and fragment",
476 -1 != rc);
477 assert_struct (url,
478 NULL,
479 NULL,
480 NULL,
481 NULL,
482 0,
483 "",
484 "q=yes&q2=no",
485 "fragment");
486 free (url_string);
487
488 return NULL;
489}
490
491static char *
492test_parse_url_fail (void)
493{
494 int rc;
495 struct GNUNET_Uri url;
496 char *url_string;
497
498 /* Empty */
499 url_string = strdup ("");
500 rc = GNUNET_uri_parse (&url,
501 url_string);
502 mu_assert ("empty string should return -1",
503 -1 == rc);
504 free (url_string);
505
506 /* Scheme only */
507 url_string = strdup ("rtsp://");
508 rc = GNUNET_uri_parse (&url,
509 url_string);
510 mu_assert ("scheme only should return -1",
511 -1 == rc);
512 free (url_string);
513
514 /* Hostname only */
515 url_string = strdup ("hostname");
516 rc = GNUNET_uri_parse (&url,
517 url_string);
518 mu_assert ("hostname only should return -1",
519 -1 == rc);
520 free (url_string);
521
522 /* Query only */
523 url_string = strdup ("?query=only");
524 rc = GNUNET_uri_parse (&url,
525 url_string);
526 mu_assert ("query only should return -1",
527 -1 == rc);
528 free (url_string);
529
530 /* Missing scheme */
531 url_string = strdup ("://");
532 rc = GNUNET_uri_parse (&url,
533 url_string);
534 mu_assert ("missing scheme should return -1",
535 -1 == rc);
536 free (url_string);
537
538 /* Missing hostname */
539 url_string = strdup ("rtsp://:8910/path");
540 rc = GNUNET_uri_parse (&url,
541 url_string);
542 mu_assert ("missing hostname should return -1",
543 -1 == rc);
544 free (url_string);
545
546 /* Missing credentials */
547 url_string = strdup ("rtsp://@hostname:8910/path");
548 rc = GNUNET_uri_parse (&url,
549 url_string);
550 mu_assert ("missing credentials should return -1",
551 -1 == rc);
552 free (url_string);
553
554 return NULL;
555}
556
557static char *
558test_split_path_ok (void)
559{
560 int rc;
561 char *path;
562 char *parts[10];
563
564 /* Simple path */
565 path = strdup ("/this/is/a/path");
566 rc = GNUNET_uri_split_path (path,
567 parts,
568 10);
569 mu_assert ("should be able to parse a regular path",
570 4 == rc);
571 mu_silent_assert ("first part should be 'this'",
572 0 == strcmp ("this", parts[0]));
573 mu_silent_assert ("second part should be 'is'",
574 0 == strcmp ("is", parts[1]));
575 mu_silent_assert ("third part should be 'a'",
576 0 == strcmp ("a", parts[2]));
577 mu_silent_assert ("fourth part should be 'path'",
578 0 == strcmp ("path", parts[3]));
579 free (path);
580
581 /* Relative path */
582 path = strdup ("this/is/a/path");
583 rc = GNUNET_uri_split_path (path,
584 parts,
585 10);
586 mu_assert ("should be able to parse a relative path",
587 4 == rc);
588 mu_silent_assert ("first part should be 'this'",
589 0 == strcmp ("this", parts[0]));
590 mu_silent_assert ("second part should be 'is'",
591 0 == strcmp ("is", parts[1]));
592 mu_silent_assert ("third part should be 'a'",
593 0 == strcmp ("a", parts[2]));
594 mu_silent_assert ("fourth part should be 'path'",
595 0 == strcmp ("path", parts[3]));
596 free (path);
597
598 /* Path with empty parts */
599 path = strdup ("//this//is/a/path/");
600 rc = GNUNET_uri_split_path (path,
601 parts,
602 10);
603 mu_assert ("should treat multiple slashes as one",
604 4 == rc);
605 mu_silent_assert ("first part should be 'this'",
606 0 == strcmp("this", parts[0]));
607 mu_silent_assert ("second part should be 'is'",
608 0 == strcmp("is", parts[1]));
609 mu_silent_assert ("third part should be 'a'",
610 0 == strcmp("a", parts[2]));
611 mu_silent_assert ("fourth part should be 'path'",
612 0 == strcmp("path", parts[3]));
613 free (path);
614
615 /* Just one level */
616 path = strdup("/one_level");
617 rc = GNUNET_uri_split_path(path, parts, 10);
618 mu_assert("should be able to parse a path with one level", 1 == rc);
619 mu_silent_assert("first part should be 'this'", 0 == strcmp("one_level", parts[0]));
620 free(path);
621
622 return NULL;
623}
624
625static char *
626test_parse_query_ok (void)
627{
628 int rc;
629 char *q;
630 struct GNUNET_UriParam params[10];
631
632 /* One param query */
633 q = strdup ("q=yes");
634 rc = GNUNET_uri_parse_query (q,
635 '&',
636 params,
637 10);
638 mu_assert ("single parameter with value",
639 1 == rc);
640 mu_silent_assert ("first param key should be 'q'",
641 0 == strcmp ("q", params[0].key));
642 mu_silent_assert ("first param val should be 'yes'",
643 0 == strcmp ("yes", params[0].val));
644 free (q);
645
646 /* One param query without value */
647 q = strdup ("q");
648 rc = GNUNET_uri_parse_query (q,
649 '&',
650 params,
651 10);
652 mu_assert ("single parameter without value",
653 1 == rc);
654 mu_silent_assert ("first param key should be 'q'",
655 0 == strcmp ("q", params[0].key));
656 mu_silent_assert ("first param val should be NULL",
657 NULL == params[0].val);
658 free (q);
659
660 /* Two param query */
661 q = strdup ("query=yes&a1=hello");
662 rc = GNUNET_uri_parse_query (q,
663 '&',
664 params,
665 10);
666 mu_assert ("multiple params with value",
667 2 == rc);
668 mu_silent_assert ("first param key should be 'query'",
669 0 == strcmp ("query", params[0].key));
670 mu_silent_assert ("first param val should be 'yes'",
671 0 == strcmp ("yes", params[0].val));
672 mu_silent_assert ("second param key should be 'a1'",
673 0 == strcmp ("a1", params[1].key));
674 mu_silent_assert ("second param val should be 'hello'",
675 0 == strcmp ("hello", params[1].val));
676 free (q);
677
678 /* Two param query, one without value */
679 q = strdup ("query=yes&forceHttps");
680 rc = GNUNET_uri_parse_query (q,
681 '&',
682 params,
683 10);
684 mu_assert ("multiple params one without value",
685 2 == rc);
686 mu_silent_assert ("first param key should be 'query'",
687 0 == strcmp ("query", params[0].key));
688 mu_silent_assert ("first param val should be 'yes'",
689 0 == strcmp ("yes", params[0].val));
690 mu_silent_assert ("second param key should be 'forceHttps'",
691 0 == strcmp ("forceHttps", params[1].key));
692 mu_silent_assert ("second param val should be NULL",
693 NULL == params[1].val);
694 free (q);
695
696 /* Three param query, all without value */
697 q = strdup ("query&forceHttps&log");
698 rc = GNUNET_uri_parse_query (q,
699 '&',
700 params,
701 10);
702 mu_assert ("multiple params all without value",
703 3 == rc);
704 mu_silent_assert ("first param key should be 'query'",
705 0 == strcmp ("query", params[0].key));
706 mu_silent_assert ("first param val should be NULL",
707 NULL == params[0].val);
708 mu_silent_assert ("second param key should be 'forceHttps'",
709 0 == strcmp ("forceHttps", params[1].key));
710 mu_silent_assert ("second param val should be NULL",
711 NULL == params[1].val);
712 mu_silent_assert ("third param key should be 'log'",
713 0 == strcmp ("log", params[2].key));
714 mu_silent_assert ("third param val should be NULL",
715 NULL == params[2].val);
716 free (q);
717
718 /* Param with empty value */
719 q = strdup ("param=&query=no");
720 rc = GNUNET_uri_parse_query (q,
721 '&',
722 params,
723 10);
724 mu_assert ("param with empty value",
725 2 == rc);
726 mu_silent_assert ("first param key should be 'param'",
727 0 == strcmp ("param", params[0].key));
728 mu_silent_assert ("first param val should be ''",
729 0 == strcmp ("", params[0].val));
730 mu_silent_assert ("second param key should be 'query'",
731 0 == strcmp ("query", params[1].key));
732 mu_silent_assert ("second param val should be 'no'",
733 0 == strcmp ("no", params[1].val));
734 free (q);
735
736 /* Double delimiter */
737 q = strdup ("param=jack&&query=no");
738 rc = GNUNET_uri_parse_query (q,
739 '&',
740 params,
741 10);
742 mu_assert ("double delimiter",
743 3 == rc);
744 mu_silent_assert ("first param key should be 'param'",
745 0 == strcmp ("param", params[0].key));
746 mu_silent_assert ("first param val should be 'jack'",
747 0 == strcmp ("jack", params[0].val));
748 mu_silent_assert ("second param key should be ''",
749 0 == strcmp ("", params[1].key));
750 mu_silent_assert ("second param val should be NULL",
751 NULL == params[1].val);
752 mu_silent_assert ("third param key should be 'query'",
753 0 == strcmp ("query", params[2].key));
754 mu_silent_assert ("third param val should be 'no'",
755 0 == strcmp ("no", params[2].val));
756 free (q);
757
758 /* Delimiter in beginning */
759 q = strdup ("&param=jack&query=no");
760 rc = GNUNET_uri_parse_query (q,
761 '&',
762 params,
763 10);
764 mu_assert ("delimiter in beginning",
765 3 == rc);
766 mu_silent_assert ("first param key should be ''",
767 0 == strcmp ("", params[0].key));
768 mu_silent_assert ("first param val should be NULL",
769 NULL == params[0].val);
770 mu_silent_assert ("second param key should be 'param'",
771 0 == strcmp ("param", params[1].key));
772 mu_silent_assert ("second param val should be 'jack'",
773 0 == strcmp ("jack", params[1].val));
774 mu_silent_assert ("third param key should be 'query'",
775 0 == strcmp ("query", params[2].key));
776 mu_silent_assert ("third param val should be 'no'",
777 0 == strcmp ("no", params[2].val));
778 free (q);
779
780 /* Delimiter at the end */
781 q = strdup ("param=jack&query=no&");
782 rc = GNUNET_uri_parse_query (q,
783 '&',
784 params,
785 10);
786 mu_assert ("delimiter at the end",
787 3 == rc);
788 mu_silent_assert ("first param key should be 'param'",
789 0 == strcmp ("param", params[0].key));
790 mu_silent_assert ("first param val should be 'jack'",
791 0 == strcmp ("jack", params[0].val));
792 mu_silent_assert ("second param key should be 'query'",
793 0 == strcmp ("query", params[1].key));
794 mu_silent_assert ("second param val should be 'no'",
795 0 == strcmp ("no", params[1].val));
796 mu_silent_assert ("third param key should be ''",
797 0 == strcmp ("", params[2].key));
798 mu_silent_assert ("third param val should be NULL",
799 NULL == params[2].val);
800 free (q);
801
802 return NULL;
803}
804
805static char *
806all_tests (void)
807{
808 mu_group ("GNUNET_uri_parse () with an HTTP URL");
809 mu_run_test (test_parse_http_url_ok);
810
811 mu_group ("GNUNET_uri_parse () with an relative URL");
812 mu_run_test (test_parse_http_rel_url_ok);
813
814 mu_group ("GNUNET_uri_parse () with faulty values");
815 mu_run_test (test_parse_url_fail);
816
817 mu_group ("GNUNET_uri_split_path ()");
818 mu_run_test (test_split_path_ok);
819
820 mu_group ("GNUNET_uri_parse_query ()");
821 mu_run_test (test_parse_query_ok);
822
823 return NULL;
824}
825
826int
827main (void)
828{
829 char *result;
830
831 result = all_tests ();
832 if (result != NULL) {
833 exit (EXIT_FAILURE);
834 }
835
836 exit (EXIT_SUCCESS);
837}
diff --git a/src/util/time.c b/src/util/time.c
deleted file mode 100644
index 144e1b401..000000000
--- a/src/util/time.c
+++ /dev/null
@@ -1,789 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013, 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 util/time.c
23 * @author Christian Grothoff
24 * @brief functions for handling time and time arithmetic
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#if __STDC_NO_ATOMICS__
29#define ATOMIC
30#else
31#ifdef HAVE_STDATOMIC_H
32#include <stdatomic.h>
33#define ATOMIC _Atomic
34#else
35#define __STDC_NO_ATOMICS__ 1
36#define ATOMIC
37#endif
38#endif
39
40#define LOG(kind, ...) GNUNET_log_from (kind, "util-time", __VA_ARGS__)
41
42/**
43 * Variable used to simulate clock skew. Used for testing, never in production.
44 */
45static long long timestamp_offset;
46
47void
48GNUNET_TIME_set_offset (long long offset)
49{
50 timestamp_offset = offset;
51}
52
53
54long long
55GNUNET_TIME_get_offset ()
56{
57 return timestamp_offset;
58}
59
60
61int
62GNUNET_TIME_round_abs (struct GNUNET_TIME_Absolute *at)
63{
64 if (at->abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
65 return GNUNET_OK;
66 if (0 == at->abs_value_us % 1000000)
67 return GNUNET_OK;
68 at->abs_value_us -= at->abs_value_us % 1000000;
69 return GNUNET_NO;
70}
71
72
73int
74GNUNET_TIME_round_rel (struct GNUNET_TIME_Relative *rt)
75{
76 if (rt->rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
77 return GNUNET_OK;
78 if (0 == rt->rel_value_us % 1000000)
79 return GNUNET_OK;
80 rt->rel_value_us -= rt->rel_value_us % 1000000;
81 return GNUNET_NO;
82}
83
84
85struct GNUNET_TIME_Absolute
86GNUNET_TIME_absolute_get ()
87{
88 struct GNUNET_TIME_Absolute ret;
89 struct timeval tv;
90
91 gettimeofday (&tv, NULL);
92 ret.abs_value_us = (uint64_t) (((uint64_t) tv.tv_sec * 1000LL * 1000LL)
93 + ((uint64_t) tv.tv_usec))
94 + timestamp_offset;
95 return ret;
96}
97
98
99struct GNUNET_TIME_Relative
100GNUNET_TIME_relative_get_zero_ ()
101{
102 static struct GNUNET_TIME_Relative zero;
103
104 return zero;
105}
106
107
108struct GNUNET_TIME_Absolute
109GNUNET_TIME_absolute_get_zero_ ()
110{
111 static struct GNUNET_TIME_Absolute zero;
112
113 return zero;
114}
115
116
117struct GNUNET_TIME_Relative
118GNUNET_TIME_relative_get_unit_ ()
119{
120 static struct GNUNET_TIME_Relative one = { 1 };
121
122 return one;
123}
124
125
126struct GNUNET_TIME_Relative
127GNUNET_TIME_relative_get_millisecond_ ()
128{
129 static struct GNUNET_TIME_Relative one = { 1000 };
130
131 return one;
132}
133
134
135struct GNUNET_TIME_Relative
136GNUNET_TIME_relative_get_second_ ()
137{
138 static struct GNUNET_TIME_Relative one = { 1000 * 1000LL };
139
140 return one;
141}
142
143
144struct GNUNET_TIME_Relative
145GNUNET_TIME_relative_get_minute_ ()
146{
147 static struct GNUNET_TIME_Relative one = { 60 * 1000 * 1000LL };
148
149 return one;
150}
151
152
153struct GNUNET_TIME_Relative
154GNUNET_TIME_relative_get_hour_ ()
155{
156 static struct GNUNET_TIME_Relative one = { 60 * 60 * 1000 * 1000LL };
157
158 return one;
159}
160
161
162struct GNUNET_TIME_Relative
163GNUNET_TIME_relative_get_forever_ ()
164{
165 static struct GNUNET_TIME_Relative forever = { UINT64_MAX };
166
167 return forever;
168}
169
170
171struct GNUNET_TIME_Absolute
172GNUNET_TIME_absolute_get_forever_ ()
173{
174 static struct GNUNET_TIME_Absolute forever = { UINT64_MAX };
175
176 return forever;
177}
178
179
180struct GNUNET_TIME_Absolute
181GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel)
182{
183 struct GNUNET_TIME_Absolute ret;
184
185 if (rel.rel_value_us == UINT64_MAX)
186 return GNUNET_TIME_UNIT_FOREVER_ABS;
187 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
188
189 if (rel.rel_value_us + now.abs_value_us < rel.rel_value_us)
190 {
191 GNUNET_break (0); /* overflow... */
192 return GNUNET_TIME_UNIT_FOREVER_ABS;
193 }
194 ret.abs_value_us = rel.rel_value_us + now.abs_value_us;
195 return ret;
196}
197
198
199struct GNUNET_TIME_Relative
200GNUNET_TIME_relative_min (struct GNUNET_TIME_Relative t1,
201 struct GNUNET_TIME_Relative t2)
202{
203 return (t1.rel_value_us < t2.rel_value_us) ? t1 : t2;
204}
205
206
207struct GNUNET_TIME_Relative
208GNUNET_TIME_relative_max (struct GNUNET_TIME_Relative t1,
209 struct GNUNET_TIME_Relative t2)
210{
211 return (t1.rel_value_us > t2.rel_value_us) ? t1 : t2;
212}
213
214
215struct GNUNET_TIME_Absolute
216GNUNET_TIME_absolute_min (struct GNUNET_TIME_Absolute t1,
217 struct GNUNET_TIME_Absolute t2)
218{
219 return (t1.abs_value_us < t2.abs_value_us) ? t1 : t2;
220}
221
222
223struct GNUNET_TIME_Absolute
224GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1,
225 struct GNUNET_TIME_Absolute t2)
226{
227 return (t1.abs_value_us > t2.abs_value_us) ? t1 : t2;
228}
229
230
231struct GNUNET_TIME_Relative
232GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future)
233{
234 struct GNUNET_TIME_Relative ret;
235
236 if (future.abs_value_us == UINT64_MAX)
237 return GNUNET_TIME_UNIT_FOREVER_REL;
238 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
239
240 if (now.abs_value_us > future.abs_value_us)
241 return GNUNET_TIME_UNIT_ZERO;
242 ret.rel_value_us = future.abs_value_us - now.abs_value_us;
243 return ret;
244}
245
246
247struct GNUNET_TIME_Relative
248GNUNET_TIME_absolute_get_difference (struct GNUNET_TIME_Absolute start,
249 struct GNUNET_TIME_Absolute end)
250{
251 struct GNUNET_TIME_Relative ret;
252
253 if (end.abs_value_us == UINT64_MAX)
254 return GNUNET_TIME_UNIT_FOREVER_REL;
255 if (end.abs_value_us < start.abs_value_us)
256 return GNUNET_TIME_UNIT_ZERO;
257 ret.rel_value_us = end.abs_value_us - start.abs_value_us;
258 return ret;
259}
260
261
262struct GNUNET_TIME_Relative
263GNUNET_TIME_absolute_get_duration (struct GNUNET_TIME_Absolute whence)
264{
265 struct GNUNET_TIME_Absolute now;
266 struct GNUNET_TIME_Relative ret;
267
268 now = GNUNET_TIME_absolute_get ();
269 if (whence.abs_value_us > now.abs_value_us)
270 return GNUNET_TIME_UNIT_ZERO;
271 ret.rel_value_us = now.abs_value_us - whence.abs_value_us;
272 return ret;
273}
274
275
276struct GNUNET_TIME_Absolute
277GNUNET_TIME_absolute_add (struct GNUNET_TIME_Absolute start,
278 struct GNUNET_TIME_Relative duration)
279{
280 struct GNUNET_TIME_Absolute ret;
281
282 if ((start.abs_value_us == UINT64_MAX) ||
283 (duration.rel_value_us == UINT64_MAX))
284 return GNUNET_TIME_UNIT_FOREVER_ABS;
285 if (start.abs_value_us + duration.rel_value_us < start.abs_value_us)
286 {
287 GNUNET_break (0);
288 return GNUNET_TIME_UNIT_FOREVER_ABS;
289 }
290 ret.abs_value_us = start.abs_value_us + duration.rel_value_us;
291 return ret;
292}
293
294
295struct GNUNET_TIME_Absolute
296GNUNET_TIME_absolute_subtract (struct GNUNET_TIME_Absolute start,
297 struct GNUNET_TIME_Relative duration)
298{
299 struct GNUNET_TIME_Absolute ret;
300
301 if (start.abs_value_us <= duration.rel_value_us)
302 return GNUNET_TIME_UNIT_ZERO_ABS;
303 if (start.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
304 return GNUNET_TIME_UNIT_FOREVER_ABS;
305 ret.abs_value_us = start.abs_value_us - duration.rel_value_us;
306 return ret;
307}
308
309
310struct GNUNET_TIME_Relative
311GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel,
312 unsigned long long factor)
313{
314 struct GNUNET_TIME_Relative ret;
315
316 if (0 == factor)
317 return GNUNET_TIME_UNIT_ZERO;
318 if (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
319 return GNUNET_TIME_UNIT_FOREVER_REL;
320 ret.rel_value_us = rel.rel_value_us * factor;
321 if (ret.rel_value_us / factor != rel.rel_value_us)
322 {
323 GNUNET_break (0);
324 return GNUNET_TIME_UNIT_FOREVER_REL;
325 }
326 return ret;
327}
328
329
330struct GNUNET_TIME_Relative
331relative_multiply_double (struct GNUNET_TIME_Relative rel, double factor)
332{
333 struct GNUNET_TIME_Relative out;
334 double m;
335
336 GNUNET_assert (0 <= factor);
337
338 if (0 == factor)
339 return GNUNET_TIME_UNIT_ZERO;
340 if (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
341 return GNUNET_TIME_UNIT_FOREVER_REL;
342
343 m = ((double) rel.rel_value_us) * factor;
344
345 if (m >= (double) (GNUNET_TIME_UNIT_FOREVER_REL).rel_value_us)
346 {
347 GNUNET_break (0);
348 return GNUNET_TIME_UNIT_FOREVER_REL;
349 }
350
351 out.rel_value_us = (uint64_t) m;
352 return out;
353}
354
355
356struct GNUNET_TIME_Relative
357GNUNET_TIME_relative_saturating_multiply (struct GNUNET_TIME_Relative rel,
358 unsigned long long factor)
359{
360 struct GNUNET_TIME_Relative ret;
361
362 if (0 == factor)
363 return GNUNET_TIME_UNIT_ZERO;
364 if (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
365 return GNUNET_TIME_UNIT_FOREVER_REL;
366 ret.rel_value_us = rel.rel_value_us * factor;
367 if (ret.rel_value_us / factor != rel.rel_value_us)
368 {
369 return GNUNET_TIME_UNIT_FOREVER_REL;
370 }
371 return ret;
372}
373
374
375struct GNUNET_TIME_Relative
376GNUNET_TIME_relative_divide (struct GNUNET_TIME_Relative rel,
377 unsigned long long factor)
378{
379 struct GNUNET_TIME_Relative ret;
380
381 if ((0 == factor) ||
382 (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us))
383 return GNUNET_TIME_UNIT_FOREVER_REL;
384 ret.rel_value_us = rel.rel_value_us / factor;
385 return ret;
386}
387
388
389struct GNUNET_TIME_Relative
390GNUNET_TIME_calculate_eta (struct GNUNET_TIME_Absolute start,
391 uint64_t finished,
392 uint64_t total)
393{
394 struct GNUNET_TIME_Relative due;
395 double exp;
396 struct GNUNET_TIME_Relative ret;
397
398 GNUNET_break (finished <= total);
399 if (finished >= total)
400 return GNUNET_TIME_UNIT_ZERO;
401 if (0 == finished)
402 return GNUNET_TIME_UNIT_FOREVER_REL;
403 due = GNUNET_TIME_absolute_get_duration (start);
404 exp = ((double) due.rel_value_us) * ((double) total) / ((double) finished);
405 ret.rel_value_us = ((uint64_t) exp) - due.rel_value_us;
406 return ret;
407}
408
409
410struct GNUNET_TIME_Relative
411GNUNET_TIME_relative_add (struct GNUNET_TIME_Relative a1,
412 struct GNUNET_TIME_Relative a2)
413{
414 struct GNUNET_TIME_Relative ret;
415
416 if ((a1.rel_value_us == UINT64_MAX) || (a2.rel_value_us == UINT64_MAX))
417 return GNUNET_TIME_UNIT_FOREVER_REL;
418 if (a1.rel_value_us + a2.rel_value_us < a1.rel_value_us)
419 {
420 GNUNET_break (0);
421 return GNUNET_TIME_UNIT_FOREVER_REL;
422 }
423 ret.rel_value_us = a1.rel_value_us + a2.rel_value_us;
424 return ret;
425}
426
427
428struct GNUNET_TIME_Relative
429GNUNET_TIME_relative_subtract (struct GNUNET_TIME_Relative a1,
430 struct GNUNET_TIME_Relative a2)
431{
432 struct GNUNET_TIME_Relative ret;
433
434 if (a2.rel_value_us >= a1.rel_value_us)
435 return GNUNET_TIME_UNIT_ZERO;
436 if (a1.rel_value_us == UINT64_MAX)
437 return GNUNET_TIME_UNIT_FOREVER_REL;
438 ret.rel_value_us = a1.rel_value_us - a2.rel_value_us;
439 return ret;
440}
441
442
443struct GNUNET_TIME_RelativeNBO
444GNUNET_TIME_relative_hton (struct GNUNET_TIME_Relative a)
445{
446 struct GNUNET_TIME_RelativeNBO ret;
447
448 ret.rel_value_us__ = GNUNET_htonll (a.rel_value_us);
449 return ret;
450}
451
452
453struct GNUNET_TIME_Relative
454GNUNET_TIME_relative_ntoh (struct GNUNET_TIME_RelativeNBO a)
455{
456 struct GNUNET_TIME_Relative ret;
457
458 ret.rel_value_us = GNUNET_ntohll (a.rel_value_us__);
459 return ret;
460}
461
462
463struct GNUNET_TIME_AbsoluteNBO
464GNUNET_TIME_absolute_hton (struct GNUNET_TIME_Absolute a)
465{
466 struct GNUNET_TIME_AbsoluteNBO ret;
467
468 ret.abs_value_us__ = GNUNET_htonll (a.abs_value_us);
469 return ret;
470}
471
472
473bool
474GNUNET_TIME_absolute_is_never (struct GNUNET_TIME_Absolute abs)
475{
476 return GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == abs.abs_value_us;
477}
478
479
480bool
481GNUNET_TIME_relative_is_forever (struct GNUNET_TIME_Relative rel)
482{
483 return GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rel.rel_value_us;
484}
485
486
487bool
488GNUNET_TIME_relative_is_zero (struct GNUNET_TIME_Relative rel)
489{
490 return 0 == rel.rel_value_us;
491}
492
493
494bool
495GNUNET_TIME_absolute_is_past (struct GNUNET_TIME_Absolute abs)
496{
497 struct GNUNET_TIME_Absolute now;
498
499 now = GNUNET_TIME_absolute_get ();
500 return abs.abs_value_us < now.abs_value_us;
501}
502
503
504bool
505GNUNET_TIME_absolute_is_future (struct GNUNET_TIME_Absolute abs)
506{
507 struct GNUNET_TIME_Absolute now;
508
509 now = GNUNET_TIME_absolute_get ();
510 return abs.abs_value_us > now.abs_value_us;
511}
512
513
514struct GNUNET_TIME_Absolute
515GNUNET_TIME_absolute_from_ms (uint64_t ms_after_epoch)
516{
517 struct GNUNET_TIME_Absolute ret;
518
519 ret.abs_value_us = GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us
520 * ms_after_epoch;
521 if (ret.abs_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us !=
522 ms_after_epoch)
523 ret = GNUNET_TIME_UNIT_FOREVER_ABS;
524 return ret;
525}
526
527
528struct GNUNET_TIME_Absolute
529GNUNET_TIME_absolute_from_s (uint64_t s_after_epoch)
530{
531 struct GNUNET_TIME_Absolute ret;
532
533 ret.abs_value_us = GNUNET_TIME_UNIT_SECONDS.rel_value_us * s_after_epoch;
534 if (ret.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us !=
535 s_after_epoch)
536 ret = GNUNET_TIME_UNIT_FOREVER_ABS;
537 return ret;
538}
539
540
541struct GNUNET_TIME_Absolute
542GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a)
543{
544 struct GNUNET_TIME_Absolute ret;
545
546 ret.abs_value_us = GNUNET_ntohll (a.abs_value_us__);
547 return ret;
548}
549
550
551unsigned int
552GNUNET_TIME_get_current_year ()
553{
554 time_t tp;
555 struct tm *t;
556
557 tp = time (NULL);
558 t = gmtime (&tp);
559 if (t == NULL)
560 return 0;
561 return t->tm_year + 1900;
562}
563
564
565unsigned int
566GNUNET_TIME_time_to_year (struct GNUNET_TIME_Absolute at)
567{
568 struct tm *t;
569 time_t tp;
570
571 tp = at.abs_value_us / 1000LL / 1000LL; /* microseconds to seconds */
572 t = gmtime (&tp);
573 if (t == NULL)
574 return 0;
575 return t->tm_year + 1900;
576}
577
578
579#ifndef HAVE_TIMEGM
580/**
581 * As suggested in the timegm() man page.
582 */
583static time_t
584my_timegm (struct tm *tm)
585{
586 time_t ret;
587 char *tz;
588
589 tz = getenv ("TZ");
590 setenv ("TZ", "", 1);
591 tzset ();
592 ret = mktime (tm);
593 if (tz)
594 setenv ("TZ", tz, 1);
595 else
596 unsetenv ("TZ");
597 tzset ();
598 return ret;
599}
600
601
602#endif
603
604
605struct GNUNET_TIME_Absolute
606GNUNET_TIME_year_to_time (unsigned int year)
607{
608 struct GNUNET_TIME_Absolute ret;
609 time_t tp;
610 struct tm t;
611
612 memset (&t, 0, sizeof(t));
613 if (year < 1900)
614 {
615 GNUNET_break (0);
616 return GNUNET_TIME_absolute_get (); /* now */
617 }
618 t.tm_year = year - 1900;
619 t.tm_mday = 1;
620 t.tm_mon = 0;
621 t.tm_wday = 1;
622 t.tm_yday = 1;
623#ifndef HAVE_TIMEGM
624 tp = my_timegm (&t);
625#else
626 tp = timegm (&t);
627#endif
628 GNUNET_break (tp != (time_t) -1);
629 ret.abs_value_us = tp * 1000LL * 1000LL; /* seconds to microseconds */
630 return ret;
631}
632
633
634struct GNUNET_TIME_Relative
635GNUNET_TIME_randomized_backoff (struct GNUNET_TIME_Relative rt,
636 struct GNUNET_TIME_Relative threshold)
637{
638 double r = (rand () % 500) / 1000.0;
639 struct GNUNET_TIME_Relative t;
640
641 t = relative_multiply_double (
642 GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, rt),
643 2 + r);
644 return GNUNET_TIME_relative_min (threshold, t);
645}
646
647
648struct GNUNET_TIME_Relative
649GNUNET_TIME_randomize (struct GNUNET_TIME_Relative r)
650{
651 double d = ((rand () % 1001) + 500) / 1000.0;
652
653 return relative_multiply_double (r, d);
654}
655
656
657struct GNUNET_TIME_Absolute
658GNUNET_TIME_absolute_get_monotonic (
659 const struct GNUNET_CONFIGURATION_Handle *cfg)
660{
661 static const struct GNUNET_CONFIGURATION_Handle *last_cfg;
662 static struct GNUNET_TIME_Absolute last_time;
663 static struct GNUNET_DISK_MapHandle *map_handle;
664 static ATOMIC volatile uint64_t *map;
665 struct GNUNET_TIME_Absolute now;
666
667 now = GNUNET_TIME_absolute_get ();
668 if (last_cfg != cfg)
669 {
670 char *filename;
671
672 if (NULL != map_handle)
673 {
674 GNUNET_DISK_file_unmap (map_handle);
675 map_handle = NULL;
676 }
677 map = NULL;
678
679 last_cfg = cfg;
680 if ((NULL != cfg) &&
681 (GNUNET_OK ==
682 GNUNET_CONFIGURATION_get_value_filename (cfg,
683 "util",
684 "MONOTONIC_TIME_FILENAME",
685 &filename)))
686 {
687 struct GNUNET_DISK_FileHandle *fh;
688
689 fh = GNUNET_DISK_file_open (filename,
690 GNUNET_DISK_OPEN_READWRITE
691 | GNUNET_DISK_OPEN_CREATE,
692 GNUNET_DISK_PERM_USER_WRITE
693 | GNUNET_DISK_PERM_GROUP_WRITE
694 | GNUNET_DISK_PERM_USER_READ
695 | GNUNET_DISK_PERM_GROUP_READ);
696 if (NULL == fh)
697 {
698 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
699 _ ("Failed to map `%s', cannot assure monotonic time!\n"),
700 filename);
701 }
702 else
703 {
704 off_t size;
705
706 size = 0;
707 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &size));
708 if (size < (off_t) sizeof(*map))
709 {
710 struct GNUNET_TIME_AbsoluteNBO o;
711
712 o = GNUNET_TIME_absolute_hton (now);
713 if (sizeof(o) != GNUNET_DISK_file_write (fh, &o, sizeof(o)))
714 size = 0;
715 else
716 size = sizeof(o);
717 }
718 if (size == sizeof(*map))
719 {
720 map = GNUNET_DISK_file_map (fh,
721 &map_handle,
722 GNUNET_DISK_MAP_TYPE_READWRITE,
723 sizeof(*map));
724 if (NULL == map)
725 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
726 _ (
727 "Failed to map `%s', cannot assure monotonic time!\n"),
728 filename);
729 }
730 else
731 {
732 GNUNET_log (
733 GNUNET_ERROR_TYPE_WARNING,
734 _ (
735 "Failed to setup monotonic time file `%s', cannot assure monotonic time!\n"),
736 filename);
737 }
738 }
739 GNUNET_DISK_file_close (fh);
740 GNUNET_free (filename);
741 }
742 }
743 if (NULL != map)
744 {
745 struct GNUNET_TIME_AbsoluteNBO mt;
746
747#if __STDC_NO_ATOMICS__
748#if __GNUC__
749 mt.abs_value_us__ = __sync_fetch_and_or (map, 0);
750#else
751 mt.abs_value_us__ = *map; /* godspeed, pray this is atomic */
752#endif
753#else
754 mt.abs_value_us__ = atomic_load (map);
755#endif
756 last_time =
757 GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_ntoh (mt), last_time);
758 }
759 if (now.abs_value_us <= last_time.abs_value_us)
760 now.abs_value_us = last_time.abs_value_us + 1;
761 last_time = now;
762 if (NULL != map)
763 {
764 uint64_t val = GNUNET_TIME_absolute_hton (now).abs_value_us__;
765#if __STDC_NO_ATOMICS__
766#if __GNUC__
767 (void) __sync_lock_test_and_set (map, val);
768#else
769 *map = val; /* godspeed, pray this is atomic */
770#endif
771#else
772 atomic_store (map, val);
773#endif
774 }
775 return now;
776}
777
778
779/**
780 * Destructor
781 */
782void __attribute__ ((destructor))
783GNUNET_util_time_fini ()
784{
785 (void) GNUNET_TIME_absolute_get_monotonic (NULL);
786}
787
788
789/* end of time.c */
diff --git a/src/util/tun.c b/src/util/tun.c
deleted file mode 100644
index d2b675c71..000000000
--- a/src/util/tun.c
+++ /dev/null
@@ -1,319 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 Christian Grothoff
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 tun/tun.c
23 * @brief standard IP calculations for TUN interaction
24 * @author Philipp Toelke
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30/**
31 * IP TTL we use for packets that we assemble (8 bit unsigned integer)
32 */
33#define FRESH_TTL 64
34
35
36/**
37 * Initialize an IPv4 header.
38 *
39 * @param ip header to initialize
40 * @param protocol protocol to use (e.g. IPPROTO_UDP)
41 * @param payload_length number of bytes of payload that follow (excluding IPv4 header)
42 * @param src source IP address to use
43 * @param dst destination IP address to use
44 */
45void
46GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip,
47 uint8_t protocol,
48 uint16_t payload_length,
49 const struct in_addr *src,
50 const struct in_addr *dst)
51{
52 GNUNET_assert (20 == sizeof(struct GNUNET_TUN_IPv4Header));
53 GNUNET_assert (payload_length <=
54 UINT16_MAX - sizeof(struct GNUNET_TUN_IPv4Header));
55 memset (ip, 0, sizeof(struct GNUNET_TUN_IPv4Header));
56 ip->header_length = sizeof(struct GNUNET_TUN_IPv4Header) / 4;
57 ip->version = 4;
58 ip->total_length =
59 htons (sizeof(struct GNUNET_TUN_IPv4Header) + payload_length);
60 ip->identification =
61 (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 65536);
62 ip->ttl = FRESH_TTL;
63 ip->protocol = protocol;
64 ip->source_address = *src;
65 ip->destination_address = *dst;
66 ip->checksum =
67 GNUNET_CRYPTO_crc16_n (ip, sizeof(struct GNUNET_TUN_IPv4Header));
68}
69
70
71/**
72 * Initialize an IPv6 header.
73 *
74 * @param ip header to initialize
75 * @param protocol protocol to use (e.g. IPPROTO_UDP), technically "next_header" for IPv6
76 * @param payload_length number of bytes of payload that follow (excluding IPv6 header)
77 * @param src source IP address to use
78 * @param dst destination IP address to use
79 */
80void
81GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
82 uint8_t protocol,
83 uint16_t payload_length,
84 const struct in6_addr *src,
85 const struct in6_addr *dst)
86{
87 GNUNET_assert (40 == sizeof(struct GNUNET_TUN_IPv6Header));
88 GNUNET_assert (payload_length <=
89 UINT16_MAX - sizeof(struct GNUNET_TUN_IPv6Header));
90 memset (ip, 0, sizeof(struct GNUNET_TUN_IPv6Header));
91 ip->version = 6;
92 ip->next_header = protocol;
93 ip->payload_length = htons ((uint16_t) payload_length);
94 ip->hop_limit = FRESH_TTL;
95 ip->destination_address = *dst;
96 ip->source_address = *src;
97}
98
99
100/**
101 * Calculate IPv4 TCP checksum.
102 *
103 * @param ip ipv4 header fully initialized
104 * @param tcp TCP header (initialized except for CRC)
105 * @param payload the TCP payload
106 * @param payload_length number of bytes of TCP payload
107 */
108void
109GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
110 struct GNUNET_TUN_TcpHeader *tcp,
111 const void *payload,
112 uint16_t payload_length)
113{
114 uint32_t sum;
115 uint16_t tmp;
116
117 GNUNET_assert (20 == sizeof(struct GNUNET_TUN_TcpHeader));
118 GNUNET_assert (payload_length + sizeof(struct GNUNET_TUN_IPv4Header)
119 + sizeof(struct GNUNET_TUN_TcpHeader) ==
120 ntohs (ip->total_length));
121 GNUNET_assert (IPPROTO_TCP == ip->protocol);
122
123 tcp->crc = 0;
124 sum = GNUNET_CRYPTO_crc16_step (0,
125 &ip->source_address,
126 sizeof(struct in_addr) * 2);
127 tmp = htons (IPPROTO_TCP);
128 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof(uint16_t));
129 tmp = htons (payload_length + sizeof(struct GNUNET_TUN_TcpHeader));
130 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof(uint16_t));
131 sum =
132 GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof(struct GNUNET_TUN_TcpHeader));
133 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
134 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
135}
136
137
138/**
139 * Calculate IPv6 TCP checksum.
140 *
141 * @param ip ipv6 header fully initialized
142 * @param tcp header (initialized except for CRC)
143 * @param payload the TCP payload
144 * @param payload_length number of bytes of TCP payload
145 */
146void
147GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
148 struct GNUNET_TUN_TcpHeader *tcp,
149 const void *payload,
150 uint16_t payload_length)
151{
152 uint32_t sum;
153 uint32_t tmp;
154
155 GNUNET_assert (20 == sizeof(struct GNUNET_TUN_TcpHeader));
156 GNUNET_assert (payload_length + sizeof(struct GNUNET_TUN_TcpHeader) ==
157 ntohs (ip->payload_length));
158 GNUNET_assert (IPPROTO_TCP == ip->next_header);
159 tcp->crc = 0;
160 sum = GNUNET_CRYPTO_crc16_step (0,
161 &ip->source_address,
162 2 * sizeof(struct in6_addr));
163 tmp = htonl (sizeof(struct GNUNET_TUN_TcpHeader) + payload_length);
164 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof(uint32_t));
165 tmp = htonl (IPPROTO_TCP);
166 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof(uint32_t));
167 sum =
168 GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof(struct GNUNET_TUN_TcpHeader));
169 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
170 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
171}
172
173
174/**
175 * Calculate IPv4 UDP checksum.
176 *
177 * @param ip ipv4 header fully initialized
178 * @param udp UDP header (initialized except for CRC)
179 * @param payload the UDP payload
180 * @param payload_length number of bytes of UDP payload
181 */
182void
183GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
184 struct GNUNET_TUN_UdpHeader *udp,
185 const void *payload,
186 uint16_t payload_length)
187{
188 uint32_t sum;
189 uint16_t tmp;
190
191 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
192 GNUNET_assert (payload_length + sizeof(struct GNUNET_TUN_IPv4Header)
193 + sizeof(struct GNUNET_TUN_UdpHeader) ==
194 ntohs (ip->total_length));
195 GNUNET_assert (IPPROTO_UDP == ip->protocol);
196
197 udp->crc =
198 0; /* technically optional, but we calculate it anyway, just to be sure */
199 sum = GNUNET_CRYPTO_crc16_step (0,
200 &ip->source_address,
201 sizeof(struct in_addr) * 2);
202 tmp = htons (IPPROTO_UDP);
203 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof(uint16_t));
204 tmp = htons (sizeof(struct GNUNET_TUN_UdpHeader) + payload_length);
205 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof(uint16_t));
206 sum =
207 GNUNET_CRYPTO_crc16_step (sum, udp, sizeof(struct GNUNET_TUN_UdpHeader));
208 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
209 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
210}
211
212
213/**
214 * Calculate IPv6 UDP checksum.
215 *
216 * @param ip ipv6 header fully initialized
217 * @param udp UDP header (initialized except for CRC)
218 * @param payload the UDP payload
219 * @param payload_length number of bytes of UDP payload
220 */
221void
222GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
223 struct GNUNET_TUN_UdpHeader *udp,
224 const void *payload,
225 uint16_t payload_length)
226{
227 uint32_t sum;
228 uint32_t tmp;
229
230 GNUNET_assert (payload_length + sizeof(struct GNUNET_TUN_UdpHeader) ==
231 ntohs (ip->payload_length));
232 GNUNET_assert (payload_length + sizeof(struct GNUNET_TUN_UdpHeader) ==
233 ntohs (udp->len));
234 GNUNET_assert (IPPROTO_UDP == ip->next_header);
235
236 udp->crc = 0;
237 sum = GNUNET_CRYPTO_crc16_step (0,
238 &ip->source_address,
239 sizeof(struct in6_addr) * 2);
240 tmp = htons (sizeof(struct GNUNET_TUN_UdpHeader)
241 + payload_length); /* aka udp->len */
242 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof(uint32_t));
243 tmp = htons (ip->next_header);
244 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof(uint32_t));
245 sum =
246 GNUNET_CRYPTO_crc16_step (sum, udp, sizeof(struct GNUNET_TUN_UdpHeader));
247 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
248 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
249}
250
251
252/**
253 * Calculate ICMP checksum.
254 *
255 * @param icmp IMCP header (initialized except for CRC)
256 * @param payload the ICMP payload
257 * @param payload_length number of bytes of ICMP payload
258 */
259void
260GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp,
261 const void *payload,
262 uint16_t payload_length)
263{
264 uint32_t sum;
265
266 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_IcmpHeader));
267 icmp->crc = 0;
268 sum =
269 GNUNET_CRYPTO_crc16_step (0, icmp, sizeof(struct GNUNET_TUN_IcmpHeader));
270 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
271 icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
272}
273
274
275/**
276 * Check if two sockaddrs are equal.
277 *
278 * @param sa one address
279 * @param sb another address
280 * @param include_port also check ports
281 * @return #GNUNET_YES if they are equal
282 */
283int
284GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa,
285 const struct sockaddr *sb,
286 int include_port)
287{
288 if (sa->sa_family != sb->sa_family)
289 return GNUNET_NO;
290
291 switch (sa->sa_family)
292 {
293 case AF_INET: {
294 const struct sockaddr_in *sa4 = (const struct sockaddr_in *) sa;
295 const struct sockaddr_in *sb4 = (const struct sockaddr_in *) sb;
296 if ((include_port) && (sa4->sin_port != sb4->sin_port))
297 return GNUNET_NO;
298 return(sa4->sin_addr.s_addr == sb4->sin_addr.s_addr);
299 }
300
301 case AF_INET6: {
302 const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa;
303 const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb;
304
305 if ((include_port) && (sa6->sin6_port != sb6->sin6_port))
306 return GNUNET_NO;
307 return(
308 0 == memcmp (&sa6->sin6_addr, &sb6->sin6_addr, sizeof(struct
309 in6_addr)));
310 }
311
312 default:
313 GNUNET_break (0);
314 return GNUNET_SYSERR;
315 }
316}
317
318
319/* end of tun.c */
diff --git a/src/util/uri.c b/src/util/uri.c
deleted file mode 100644
index fa383110d..000000000
--- a/src/util/uri.c
+++ /dev/null
@@ -1,344 +0,0 @@
1/**
2 * Copyright (C) 2016,2017 Jack Engqvist Johansson
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include "gnunet_uri_lib.h"
26
27
28/**
29 * Parse a non null terminated string into an integer.
30 *
31 * str: the string containing the number.
32 * len: Number of characters to parse.
33 */
34static inline int
35natoi (const char *str,
36 size_t len)
37{
38 int i, r = 0;
39 for (i = 0; i < len; i++) {
40 r *= 10;
41 r += str[i] - '0';
42 }
43
44 return r;
45}
46
47
48/**
49 * Check if a URL is relative (no scheme and hostname).
50 *
51 * url: the string containing the URL to check.
52 *
53 * Returns 1 if relative, otherwise 0.
54 */
55static inline int
56is_relative (const char *url)
57{
58 return (*url == '/') ? 1 : 0;
59}
60
61
62/**
63 * Parse the scheme of a URL by inserting a null terminator after the scheme.
64 *
65 * str: the string containing the URL to parse. Will be modified.
66 *
67 * Returns a pointer to the hostname on success, otherwise NULL.
68 */
69static inline char *
70parse_scheme (char *str)
71{
72 char *s;
73
74 /* If not found or first in string, return error */
75 s = strchr (str, ':');
76 if (s == NULL || s == str) {
77 return NULL;
78 }
79
80 /* If not followed by two slashes, return error */
81 if (s[1] == '\0' || s[1] != '/' || s[2] == '\0' || s[2] != '/') {
82 return NULL;
83 }
84
85 *s = '\0'; // Replace ':' with NULL
86
87 return s + 3;
88}
89
90
91/**
92 * Find a character in a string, replace it with '\0' and return the next
93 * character in the string.
94 *
95 * str: the string to search in.
96 * find: the character to search for.
97 *
98 * Returns a pointer to the character after the one to search for. If not
99 * found, NULL is returned.
100 */
101static inline char *
102find_and_terminate (char *str,
103 char find)
104{
105 str = strchr(str, find);
106 if (NULL == str) {
107 return NULL;
108 }
109
110 *str = '\0';
111 return str + 1;
112}
113
114
115/* Yes, the following functions could be implemented as preprocessor macros
116 instead of inline functions, but I think that this approach will be more
117 clean in this case. */
118static inline char *
119find_fragment (char *str)
120{
121 return find_and_terminate (str, '#');
122}
123
124
125static inline char *
126find_query (char *str)
127{
128 return find_and_terminate (str, '?');
129}
130
131
132static inline char *
133find_path (char *str)
134{
135 return find_and_terminate (str, '/');
136}
137
138
139/**
140 * Parse a URL to a struct.
141 *
142 * The URL string should be in one of the following formats:
143 *
144 * Absolute URL:
145 * scheme ":" [ "//" ] [ username ":" password "@" ] host [ ":" port ] [ "/" ] [ path ] [ "?" query ] [ "#" fragment ]
146 *
147 * Relative URL:
148 * path [ "?" query ] [ "#" fragment ]
149 *
150 * The following parts will be parsed to the corresponding struct member.
151 *
152 * *url: a pointer to the struct where to store the parsed values.
153 * *url_str: a pointer to the url to be parsed (null terminated). The string
154 * will be modified.
155 *
156 * Returns 0 on success, otherwise -1.
157 */
158int
159GNUNET_uri_parse (struct GNUNET_Uri *url,
160 char *u)
161{
162 if (NULL == url || NULL == u) {
163 return -1;
164 }
165
166 memset(url, 0, sizeof (struct GNUNET_Uri));
167
168 /* (Fragment) */
169 url->fragment = find_fragment (u);
170
171 /* (Query) */
172 url->query = find_query (u);
173
174 /* Relative URL? Parse scheme and hostname */
175 if (!is_relative (u)) {
176 /* Scheme */
177 url->scheme = u;
178 u = parse_scheme (u);
179 if (u == NULL) {
180 return -1;
181 }
182
183 /* Host */
184 if ('\0' == *u) {
185 return -1;
186 }
187 url->host = u;
188
189 /* (Path) */
190 url->path = find_path (u);
191
192 /* (Credentials) */
193 u = strchr (url->host, '@');
194 if (NULL != u) {
195 /* Missing credentials? */
196 if (u == url->host) {
197 return -1;
198 }
199
200 url->username = url->host;
201 url->host = u + 1;
202 *u = '\0';
203
204 u = strchr (url->username, ':');
205 if (NULL == u) {
206 return -1;
207 }
208
209 url->password = u + 1;
210 *u = '\0';
211 }
212
213 /* Missing hostname? */
214 if ('\0' == *url->host) {
215 return -1;
216 }
217
218 /* (Port) */
219 u = strchr (url->host, ':');
220 if (NULL != u && (NULL == url->path || u < url->path)) {
221 *(u++) = '\0';
222 if ('\0' == *u) {
223 return -1;
224 }
225
226 if (url->path) {
227 url->port = natoi (u, url->path - u - 1);
228 } else {
229 url->port = atoi (u);
230 }
231 }
232
233 /* Missing hostname? */
234 if ('\0' == *url->host) {
235 return -1;
236 }
237 } else {
238 /* (Path) */
239 url->path = find_path (u);
240 }
241
242 return 0;
243}
244
245
246/**
247 * Split a path into several strings.
248 *
249 * No data is copied, the slashed are used as null terminators and then
250 * pointers to each path part will be stored in **parts. Double slashes will be
251 * treated as one.
252 *
253 * *path: the path to split. The string will be modified.
254 * **parts: a pointer to an array of (char *) where to store the result.
255 * max_parts: max number of parts to parse.
256 *
257 * Returns the number of parsed items. -1 on error.
258 */
259int
260GNUNET_uri_split_path (char *path,
261 char **parts,
262 int max_parts)
263{
264 int i = 0;
265
266 if (NULL == path || '\0' == *path) {
267 return -1;
268 }
269
270 do {
271 /* Forward to after slashes */
272 while (*path == '/') path++;
273
274 if ('\0' == *path) {
275 break;
276 }
277
278 parts[i++] = path;
279
280 path = strchr (path, '/');
281 if (NULL == path) {
282 break;
283 }
284
285 *(path++) = '\0';
286 } while (i < max_parts);
287
288 return i;
289}
290
291
292/**
293 * Parse a query string into a key/value struct.
294 *
295 * The query string should be a null terminated string of parameters separated by
296 * a delimiter. Each parameter are checked for the equal sign character. If it
297 * appears in the parameter, it will be used as a null terminator and the part
298 * that comes after it will be the value of the parameter.
299 *
300 * No data are copied, the equal sign and delimiters are used as null
301 * terminators and then pointers to each parameter key and value will be stored
302 * in the yuarel_param struct.
303 *
304 * *query: the query string to parse. The string will be modified.
305 * delimiter: the character that separates the key/value pairs from each other.
306 * *params: an array of (struct yuarel_param) where to store the result.
307 * max_values: max number of parameters to parse.
308 *
309 * Returns the number of parsed items. -1 on error.
310 */
311int
312GNUNET_uri_parse_query (char *query,
313 char delimiter,
314 struct GNUNET_UriParam *params,
315 int max_params)
316{
317 int i = 0;
318
319 if (NULL == query || '\0' == *query) {
320 return -1;
321 }
322
323 params[i++].key = query;
324 while (i < max_params && NULL != (query = strchr (query, delimiter))) {
325 *query = '\0';
326 params[i].key = ++query;
327 params[i].val = NULL;
328
329 /* Go back and split previous param */
330 if (i > 0) {
331 if ((params[i - 1].val = strchr (params[i - 1].key, '=')) != NULL) {
332 *(params[i - 1].val)++ = '\0';
333 }
334 }
335 i++;
336 }
337
338 /* Go back and split last param */
339 if ((params[i - 1].val = strchr (params[i - 1].key, '=')) != NULL) {
340 *(params[i - 1].val)++ = '\0';
341 }
342
343 return i;
344}
diff --git a/src/util/util.conf b/src/util/util.conf
deleted file mode 100644
index 4f0860a49..000000000
--- a/src/util/util.conf
+++ /dev/null
@@ -1,79 +0,0 @@
1[PATHS]
2# The PATHS section is special, as filenames including $-expression are
3# expanded using the values from PATHS or the system environment (PATHS
4# is checked first). GNUnet also supports expanding $-expressions using
5# defaults with the syntax "${VAR:-default}". Here, "default" can again
6# be a $-expression.
7#
8# We usually want $HOME for $GNUNET_HOME, but we allow testcases to
9# easily override this by setting $GNUNET_TEST_HOME.
10#
11GNUNET_HOME = ${GNUNET_TEST_HOME:-${HOME:-${USERPROFILE}}}
12
13# see XDG Base Directory Specification at
14# http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
15# for how these should be used.
16
17# Persistent data storage
18GNUNET_DATA_HOME = ${XDG_DATA_HOME:-$GNUNET_HOME/.local/share}/gnunet/
19
20# Configuration files
21GNUNET_CONFIG_HOME = ${XDG_CONFIG_HOME:-$GNUNET_HOME/.config}/gnunet/
22
23# Cached data, no big deal if lost
24GNUNET_CACHE_HOME = ${XDG_CACHE_HOME:-$GNUNET_HOME/.cache}/gnunet/
25
26# Runtime data (i.e UNIX domain sockets, locks, always lost on system boot)
27# This is the variable for system-wide services; use GNUNET_USER_RUNTIME_DIR
28# for per-user services (where RUN_PER_USER=YES is set)
29# Note that the 'gnunet'/system user must have $TMPDIR/$TMP set to
30# exactly the same values as 'normal' users, otherwise this will fail.
31# If $TMPDIR or $TMP are set to different directories for different
32# users, this option should be changed to point to the same directory
33# for all users (i.e. by simply using "/tmp/gnunet-system-runtime/").
34GNUNET_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-system-runtime/
35
36# Runtime data for per-user services
37GNUNET_USER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-${USERHOME:-${USER:-user}}-runtime/
38
39# Directory to use for temporary files.
40GNUNET_TMP = ${TMPDIR:-${TMP:-/tmp}}/gnunet/
41
42
43# Override for GNUNET_HOME used by test cases.
44# GNUNET_TEST_HOME = /tmp/foo/bar
45
46# DEFAULTCONFIG = /etc/gnunet.conf
47# If 'DEFAULTCONFIG' is not defined, the current
48# configuration file is assumed to be the default,
49# which is what we want by default...
50
51# Location of binaries requiring setuid or setgid flags, e.g. gnunet-helper-vpn.
52# By default it is assumed to be in the libexec directory, but on some systems
53# like NixOS setuid / setgid is only possible through a wrapper in a specific
54# location.
55# SUID_BINARY_PATH =
56
57
58[PEER]
59# Where do we store our private key?
60PRIVATE_KEY = $GNUNET_DATA_HOME/private_key.ecc
61
62# What kind of system are we on? Choices are
63# INFRASTRUCTURE (always-on, grid, data center)
64# DESKTOP (sometimes-on, grid, office)
65# NOTEBOOK (sometimes-on, mobile, often limited network,
66# if on-battery than large battery)
67# MOBILE (sometimes-on, mobile, always limited network,
68# always battery limited)
69# UNKNOWN (not configured/specified/known)
70SYSTEM_TYPE = UNKNOWN
71
72[TESTING]
73SPEEDUP_INTERVAL = 0 ms
74SPEEDUP_DELTA = 0 ms
75# This following option is applicable to LINUX. Enabling this option causes all
76# UNIX domain sockets to be opened as abstract sockets. Note that the
77# filesystem level restrictions no longer apply for abstract sockets. An
78# end-user should not modify this option.
79USE_ABSTRACT_SOCKETS = NO
diff --git a/src/util/util.supp b/src/util/util.supp
deleted file mode 100644
index f04775cac..000000000
--- a/src/util/util.supp
+++ /dev/null
@@ -1,11 +0,0 @@
1{
2 cache-libexecdir-value
3 Memcheck:Leak
4 fun:malloc
5 fun:GNUNET_xmalloc_unchecked_
6 fun:GNUNET_xmalloc_
7 fun:GNUNET_asprintf
8 fun:GNUNET_OS_installation_get_path
9 fun:GNUNET_OS_get_libexec_binary_path
10 ...
11} \ No newline at end of file