aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/.gitignore87
-rw-r--r--src/util/Makefile.am687
-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.c1121
-rw-r--r--src/util/common_allocation.c520
-rw-r--r--src/util/common_endian.c104
-rw-r--r--src/util/common_logging.c1591
-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.c816
-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_cs.c343
-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.c460
-rw-r--r--src/util/crypto_ecc_setup.c313
-rw-r--r--src/util/crypto_edx25519.c354
-rw-r--r--src/util/crypto_hash.c413
-rw-r--r--src/util/crypto_hash_file.c243
-rw-r--r--src/util/crypto_hkdf.c368
-rw-r--r--src/util/crypto_kdf.c144
-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.c425
-rw-r--r--src/util/crypto_rsa.c1262
-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.c732
-rw-r--r--src/util/getopt.c1014
-rw-r--r--src/util/getopt_helpers.c1016
-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.c1542
-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.c325
-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.c1032
-rw-r--r--src/util/mst.c425
-rw-r--r--src/util/nc.c227
-rw-r--r--src/util/network.c1334
-rw-r--r--src/util/op.c334
-rw-r--r--src/util/os_installation.c833
-rw-r--r--src/util/os_network.c443
-rw-r--r--src/util/os_priority.c1190
-rw-r--r--src/util/peer.c253
-rw-r--r--src/util/perf_crypto_asymmetric.c132
-rw-r--r--src/util/perf_crypto_cs.c183
-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.c212
-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.c2567
-rw-r--r--src/util/service.c2448
-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.c1956
-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.c301
-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_cs.c609
-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.c318
-rw-r--r--src/util/test_crypto_edx25519.c326
-rw-r--r--src/util/test_crypto_hash.c217
-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.c168
-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.c990
-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
163 files changed, 0 insertions, 69436 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore
deleted file mode 100644
index 0e3449fed..000000000
--- a/src/util/.gitignore
+++ /dev/null
@@ -1,87 +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_edx25519
40test_crypto_hash
41test_crypto_hash_context
42test_crypto_hkdf
43test_crypto_kdf
44test_crypto_paillier
45test_crypto_random
46test_crypto_rsa
47test_crypto_cs
48test_crypto_symmetric
49test_disk
50test_getopt
51test_mq
52test_os_network
53test_os_start_process
54test_peer
55test_plugin
56test_program
57test_resolver_api.nc
58test_scheduler
59test_scheduler_delay
60test_server.nc
61test_server_disconnect.nc
62test_server_mst_interrupt.nc
63test_server_with_client.nc
64test_server_with_client_unix
65test_service
66test_speedup
67test_strings
68test_strings_to_data
69test_time
70test_socks.nc
71perf_crypto_asymmetric
72perf_crypto_hash
73perf_crypto_symmetric
74perf_crypto_rsa
75perf_crypto_cs
76perf_crypto_ecc_dlog
77perf_crypto_paillier
78test_hexcoder
79test_regex
80test_tun
81test_uri
82gnunet-timeout
83python27_location
84perf_malloc
85perf_mq
86perf_scheduler
87gnunet-base32
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
deleted file mode 100644
index 9cb7da15b..000000000
--- a/src/util/Makefile.am
+++ /dev/null
@@ -1,687 +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_cs.c \
65 crypto_ecc.c \
66 crypto_ecc_gnsrecord.c \
67 $(DLOG) \
68 crypto_ecc_setup.c \
69 crypto_edx25519.c \
70 crypto_hash.c \
71 crypto_hash_file.c \
72 crypto_hkdf.c \
73 crypto_kdf.c \
74 crypto_mpi.c \
75 crypto_paillier.c \
76 crypto_pow.c \
77 crypto_random.c \
78 crypto_rsa.c \
79 disk.c \
80 disk.h \
81 dnsparser.c \
82 dnsstub.c \
83 getopt.c \
84 getopt_helpers.c \
85 helper.c \
86 load.c \
87 mst.c \
88 mq.c \
89 nc.c \
90 network.c \
91 op.c \
92 os_installation.c \
93 os_network.c \
94 os_priority.c \
95 peer.c \
96 plugin.c \
97 program.c \
98 regex.c \
99 resolver_api.c resolver.h \
100 scheduler.c \
101 service.c \
102 signal.c \
103 strings.c \
104 time.c \
105 tun.c \
106 uri.c \
107 speedup.c speedup.h \
108 proc_compat.c
109
110if HAVE_LIBATOMIC
111if DARWIN
112 LIBATOMIC=
113else
114 LIBATOMIC= -latomic
115endif
116else
117 LIBATOMIC=
118endif
119
120if HAVE_LIBIDN
121 LIBIDN= -lidn
122else
123 LIBIDN=
124endif
125
126if HAVE_LIBIDN2
127 LIBIDN2= -lidn2
128else
129 LIBIDN2=
130endif
131
132libgnunetutil_la_LIBADD = \
133 $(GCLIBADD) $(WINLIB) \
134 $(LIBATOMIC) \
135 $(LIBGCRYPT_LIBS) \
136 $(LTLIBICONV) \
137 $(LTLIBINTL) \
138 -lltdl \
139 $(LIBIDN) $(LIBIDN2) \
140 $(Z_LIBS) \
141 -lunistring \
142 -lsodium \
143 $(XLIB) \
144 $(PTHREAD)
145
146libgnunetutil_la_LDFLAGS = \
147 $(GN_LIB_LDFLAGS) \
148 -version-info 15:0:0
149
150GNUNET_ECC = gnunet-ecc
151GNUNET_SCRYPT = gnunet-scrypt
152
153lib_LTLIBRARIES = libgnunetutil.la
154
155libexec_PROGRAMS = \
156 gnunet-service-resolver \
157 gnunet-timeout
158
159bin_PROGRAMS = \
160 gnunet-base32 \
161 gnunet-config \
162 gnunet-crypto-tvg \
163 gnunet-resolver \
164 $(GNUNET_ECC) \
165 $(GNUNET_SCRYPT) \
166 gnunet-uri
167if HAVE_ZBAR
168bin_PROGRAMS += gnunet-qr
169endif
170
171noinst_PROGRAMS = \
172 gnunet-config-diff \
173 test_common_logging_dummy
174
175
176if ENABLE_TEST_RUN
177AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
178TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
179endif
180
181gnunet_timeout_SOURCES = \
182 gnunet-timeout.c
183
184gnunet_service_resolver_SOURCES = \
185 gnunet-service-resolver.c
186gnunet_service_resolver_LDADD = \
187 libgnunetutil.la \
188 $(GN_LIBINTL)
189if HAVE_GETADDRINFO_A
190gnunet_service_resolver_LDADD += -lanl
191endif
192
193
194gnunet_resolver_SOURCES = \
195 gnunet-resolver.c
196gnunet_resolver_LDADD = \
197 libgnunetutil.la \
198 $(GN_LIBINTL)
199
200gnunet_crypto_tvg_SOURCES = \
201 gnunet-crypto-tvg.c
202gnunet_crypto_tvg_LDADD = \
203 libgnunetutil.la \
204 $(GN_LIBINTL) -lgcrypt -ljansson
205
206gnunet_ecc_SOURCES = \
207 gnunet-ecc.c
208gnunet_ecc_LDADD = \
209 libgnunetutil.la \
210 $(GN_LIBINTL) -lgcrypt
211
212gnunet_base32_SOURCES = \
213 gnunet-base32.c
214gnunet_base32_LDADD = \
215 libgnunetutil.la \
216 $(GN_LIBINTL)
217
218gnunet_scrypt_SOURCES = \
219 gnunet-scrypt.c
220gnunet_scrypt_LDADD = \
221 libgnunetutil.la \
222 $(GN_LIBINTL) -lgcrypt
223
224
225gnunet_config_SOURCES = \
226 gnunet-config.c
227gnunet_config_LDADD = \
228 libgnunetutil.la \
229 $(GN_LIBINTL)
230
231gnunet_uri_SOURCES = \
232 gnunet-uri.c
233gnunet_uri_LDADD = \
234 libgnunetutil.la \
235 $(GN_LIBINTL)
236
237
238gnunet_qr_SOURCES = \
239 gnunet-qr.c
240gnunet_qr_LDADD = \
241 libgnunetutil.la \
242 $(GN_LIBINTL)
243gnunet_qr_LDFLAGS= -lzbar
244if HAVE_PNG
245gnunet_qr_LDFLAGS += -lpng
246endif
247
248plugin_LTLIBRARIES = \
249 libgnunet_plugin_utiltest.la
250
251libgnunet_plugin_utiltest_la_SOURCES = \
252 test_plugin_plug.c
253libgnunet_plugin_utiltest_la_LDFLAGS = \
254 $(GN_PLUGIN_LDFLAGS)
255
256if HAVE_BENCHMARKS
257 BENCHMARKS = \
258 perf_crypto_cs \
259 perf_crypto_hash \
260 perf_crypto_rsa \
261 perf_crypto_paillier \
262 perf_crypto_symmetric \
263 perf_crypto_asymmetric \
264 perf_malloc \
265 perf_mq \
266 perf_scheduler \
267 perf_crypto_ecc_dlog
268endif
269
270if HAVE_SSH_KEY
271# SSH_USING_TESTS = test_socks.nc
272endif
273
274check_SCRIPTS = \
275 test_crypto_vectors.sh
276
277check_PROGRAMS = \
278 test_bio \
279 test_child_management \
280 test_client.nc \
281 $(TEST_CLIENT_UNIX_NC) \
282 test_common_allocation \
283 test_common_endian \
284 test_common_logging \
285 test_configuration \
286 test_container_bloomfilter \
287 test_container_dll \
288 test_container_meta_data \
289 test_container_multihashmap \
290 test_container_multihashmap32 \
291 test_container_multipeermap \
292 test_container_heap \
293 test_crypto_symmetric \
294 test_crypto_crc \
295 test_crypto_cs \
296 test_crypto_ecdsa \
297 test_crypto_eddsa \
298 test_crypto_ecdhe \
299 test_crypto_ecdh_eddsa \
300 test_crypto_ecdh_ecdsa \
301 test_crypto_edx25519 \
302 $(DLOG_TEST) \
303 test_crypto_hash \
304 test_crypto_hash_context \
305 test_crypto_hkdf \
306 test_crypto_kdf \
307 test_crypto_paillier \
308 test_crypto_random \
309 test_crypto_rsa \
310 test_disk \
311 test_getopt \
312 test_hexcoder \
313 test_mq \
314 test_os_network \
315 test_peer \
316 test_plugin \
317 test_program \
318 test_regex \
319 test_resolver_api.nc \
320 test_scheduler \
321 test_scheduler_delay \
322 test_service \
323 test_strings \
324 test_strings_to_data \
325 test_speedup \
326 test_time \
327 test_tun \
328 test_uri \
329 $(BENCHMARKS) \
330 test_os_start_process \
331 test_common_logging_runtime_loglevels
332
333
334test_child_management_SOURCES = \
335 test_child_management.c
336test_child_management_LDADD = \
337 libgnunetutil.la \
338 $(XLIB)
339
340
341
342# Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart
343# sequential execution order for them
344TEST_EXTENSIONS = .nc
345test_test_client_unix.log: test_client.log
346
347test_bio_SOURCES = \
348 test_bio.c
349test_bio_LDADD = \
350 libgnunetutil.la
351
352test_hexcoder_SOURCES = \
353 test_hexcoder.c
354test_hexcoder_LDADD = \
355 libgnunetutil.la
356
357test_tun_SOURCES = \
358 test_tun.c
359test_tun_LDADD = \
360 libgnunetutil.la
361
362test_regex_SOURCES = \
363 test_regex.c
364test_regex_LDADD = \
365 libgnunetutil.la
366
367test_os_start_process_SOURCES = \
368 test_os_start_process.c
369test_os_start_process_LDADD = \
370 libgnunetutil.la
371
372test_client_nc_SOURCES = \
373 test_client.c
374test_client_nc_LDADD = \
375 libgnunetutil.la
376
377test_client_unix_nc_SOURCES = \
378 test_client.c
379test_client_unix_nc_LDADD = \
380 libgnunetutil.la
381
382#test_socks_nc_SOURCES = \
383# test_socks.c
384#test_socks_nc_LDADD = \
385# libgnunetutil.la
386
387test_common_allocation_SOURCES = \
388 test_common_allocation.c
389test_common_allocation_LDADD = \
390 libgnunetutil.la
391
392test_common_endian_SOURCES = \
393 test_common_endian.c
394test_common_endian_LDADD = \
395 libgnunetutil.la
396
397test_common_logging_SOURCES = \
398 test_common_logging.c
399test_common_logging_LDADD = \
400 libgnunetutil.la
401
402test_common_logging_runtime_loglevels_SOURCES = \
403 test_common_logging_runtime_loglevels.c
404test_common_logging_runtime_loglevels_LDADD = \
405 libgnunetutil.la
406
407test_configuration_SOURCES = \
408 test_configuration.c
409test_configuration_LDADD = \
410 libgnunetutil.la
411
412test_container_bloomfilter_SOURCES = \
413 test_container_bloomfilter.c
414test_container_bloomfilter_LDADD = \
415 libgnunetutil.la
416
417test_container_dll_SOURCES = \
418 test_container_dll.c
419test_container_dll_LDADD = \
420 libgnunetutil.la
421
422test_container_meta_data_SOURCES = \
423 test_container_meta_data.c
424test_container_meta_data_LDADD = \
425 libgnunetutil.la
426
427test_container_multihashmap_SOURCES = \
428 test_container_multihashmap.c
429test_container_multihashmap_LDADD = \
430 libgnunetutil.la
431
432test_container_multihashmap32_SOURCES = \
433 test_container_multihashmap32.c
434test_container_multihashmap32_LDADD = \
435 libgnunetutil.la
436
437test_container_multipeermap_SOURCES = \
438 test_container_multipeermap.c
439test_container_multipeermap_LDADD = \
440 libgnunetutil.la
441
442test_container_heap_SOURCES = \
443 test_container_heap.c
444test_container_heap_LDADD = \
445 libgnunetutil.la
446
447test_crypto_symmetric_SOURCES = \
448 test_crypto_symmetric.c
449test_crypto_symmetric_LDADD = \
450 libgnunetutil.la
451
452test_crypto_crc_SOURCES = \
453 test_crypto_crc.c
454test_crypto_crc_LDADD = \
455 libgnunetutil.la
456
457test_crypto_cs_SOURCES = \
458 test_crypto_cs.c
459test_crypto_cs_LDADD = \
460 libgnunetutil.la \
461 -lsodium
462
463test_crypto_ecdsa_SOURCES = \
464 test_crypto_ecdsa.c
465test_crypto_ecdsa_LDADD = \
466 libgnunetutil.la \
467 $(LIBGCRYPT_LIBS)
468
469test_crypto_eddsa_SOURCES = \
470 test_crypto_eddsa.c
471test_crypto_eddsa_LDADD = \
472 libgnunetutil.la \
473 $(LIBGCRYPT_LIBS)
474
475test_crypto_edx25519_SOURCES = \
476 test_crypto_edx25519.c
477test_crypto_edx25519_LDADD = \
478 libgnunetutil.la \
479 $(LIBGCRYPT_LIBS)
480
481test_crypto_ecc_dlog_SOURCES = \
482 test_crypto_ecc_dlog.c
483test_crypto_ecc_dlog_LDADD = \
484 -lsodium \
485 libgnunetutil.la \
486 $(LIBGCRYPT_LIBS)
487
488test_crypto_ecdhe_SOURCES = \
489 test_crypto_ecdhe.c
490test_crypto_ecdhe_LDADD = \
491 libgnunetutil.la \
492 $(LIBGCRYPT_LIBS)
493
494test_crypto_ecdh_eddsa_SOURCES = \
495 test_crypto_ecdh_eddsa.c
496test_crypto_ecdh_eddsa_LDADD = \
497 libgnunetutil.la \
498 $(LIBGCRYPT_LIBS)
499
500test_crypto_ecdh_ecdsa_SOURCES = \
501 test_crypto_ecdh_ecdsa.c
502test_crypto_ecdh_ecdsa_LDADD = \
503 libgnunetutil.la \
504 $(LIBGCRYPT_LIBS)
505
506
507test_crypto_hash_SOURCES = \
508 test_crypto_hash.c
509test_crypto_hash_LDADD = \
510 libgnunetutil.la
511
512test_crypto_hash_context_SOURCES = \
513 test_crypto_hash_context.c
514test_crypto_hash_context_LDADD = \
515 libgnunetutil.la
516
517test_crypto_hkdf_SOURCES = \
518 test_crypto_hkdf.c
519test_crypto_hkdf_LDADD = \
520 libgnunetutil.la
521
522test_crypto_kdf_SOURCES = \
523 test_crypto_kdf.c
524test_crypto_kdf_LDADD = \
525 libgnunetutil.la -lgcrypt
526
527test_crypto_paillier_SOURCES = \
528 test_crypto_paillier.c
529test_crypto_paillier_LDADD = \
530 $(LIBGCRYPT_LIBS) \
531 libgnunetutil.la
532
533test_crypto_random_SOURCES = \
534 test_crypto_random.c
535test_crypto_random_LDADD = \
536 libgnunetutil.la
537
538test_crypto_rsa_SOURCES = \
539 test_crypto_rsa.c
540test_crypto_rsa_LDADD = \
541 libgnunetutil.la -lgcrypt
542
543test_disk_SOURCES = \
544 test_disk.c
545test_disk_LDADD = \
546 libgnunetutil.la
547
548test_getopt_SOURCES = \
549 test_getopt.c
550test_getopt_LDADD = \
551 libgnunetutil.la
552
553test_mq_SOURCES = \
554 test_mq.c
555test_mq_LDADD = \
556 libgnunetutil.la
557
558test_os_network_SOURCES = \
559 test_os_network.c
560test_os_network_LDADD = \
561 libgnunetutil.la
562
563test_peer_SOURCES = \
564 test_peer.c
565test_peer_LDADD = \
566 libgnunetutil.la -lgcrypt
567
568test_plugin_SOURCES = \
569 test_plugin.c
570test_plugin_LDADD = \
571 libgnunetutil.la
572
573test_program_SOURCES = \
574 test_program.c
575test_program_LDADD = \
576 libgnunetutil.la
577
578test_resolver_api_nc_SOURCES = \
579 test_resolver_api.c
580test_resolver_api_nc_LDADD = \
581 libgnunetutil.la
582
583test_scheduler_SOURCES = \
584 test_scheduler.c
585test_scheduler_LDADD = \
586 libgnunetutil.la
587
588test_scheduler_delay_SOURCES = \
589 test_scheduler_delay.c
590test_scheduler_delay_LDADD = \
591 libgnunetutil.la
592
593test_service_SOURCES = \
594 test_service.c
595test_service_LDADD = \
596 libgnunetutil.la
597
598test_strings_SOURCES = \
599 test_strings.c
600test_strings_LDADD = \
601 libgnunetutil.la
602
603test_strings_to_data_SOURCES = \
604 test_strings_to_data.c
605test_strings_to_data_LDADD = \
606 libgnunetutil.la
607
608
609test_time_SOURCES = \
610 test_time.c
611test_time_LDADD = \
612 libgnunetutil.la
613
614test_speedup_SOURCES = \
615 test_speedup.c
616test_speedup_LDADD = \
617 libgnunetutil.la
618
619test_uri_SOURCES = \
620 test_uri.c
621test_uri_LDADD = \
622 libgnunetutil.la
623
624perf_crypto_cs_SOURCES = \
625 perf_crypto_cs.c
626perf_crypto_cs_LDADD = \
627 libgnunetutil.la
628
629perf_crypto_hash_SOURCES = \
630 perf_crypto_hash.c
631perf_crypto_hash_LDADD = \
632 libgnunetutil.la
633
634perf_crypto_ecc_dlog_SOURCES = \
635 perf_crypto_ecc_dlog.c
636perf_crypto_ecc_dlog_LDADD = \
637 libgnunetutil.la \
638 -lsodium
639
640perf_crypto_rsa_SOURCES = \
641 perf_crypto_rsa.c
642perf_crypto_rsa_LDADD = \
643 libgnunetutil.la
644
645perf_crypto_symmetric_SOURCES = \
646 perf_crypto_symmetric.c
647perf_crypto_symmetric_LDADD = \
648 libgnunetutil.la
649
650perf_crypto_asymmetric_SOURCES = \
651 perf_crypto_asymmetric.c
652perf_crypto_asymmetric_LDADD = \
653 libgnunetutil.la
654
655perf_crypto_paillier_SOURCES = \
656 perf_crypto_paillier.c
657perf_crypto_paillier_LDADD = \
658 libgnunetutil.la \
659 -lgcrypt
660
661perf_malloc_SOURCES = \
662 perf_malloc.c
663perf_malloc_LDADD = \
664 libgnunetutil.la
665
666perf_mq_SOURCES = \
667 perf_mq.c
668perf_mq_LDADD = \
669 libgnunetutil.la
670
671perf_scheduler_SOURCES = \
672 perf_scheduler.c
673perf_scheduler_LDADD = \
674 libgnunetutil.la
675
676
677EXTRA_DIST = \
678 test_client_data.conf \
679 test_client_unix.conf \
680 test_configuration_data.conf \
681 test_program_data.conf \
682 test_resolver_api_data.conf \
683 test_service_data.conf \
684 test_speedup_data.conf \
685 child_management_test.sh \
686 test_crypto_vectors.sh \
687 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 9950c9e2f..000000000
--- a/src/util/client.c
+++ /dev/null
@@ -1,1121 +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 and size %u trying to send with socket %p (MQ: %p\n",
265 ntohs (cstate->msg->type),
266 ntohs (cstate->msg->size),
267 cstate->sock,
268 cstate->mq);
269
270 RETRY:
271 ret = GNUNET_NETWORK_socket_send (cstate->sock,
272 &pos[cstate->msg_off],
273 len - cstate->msg_off);
274 if ( (-1 == ret) &&
275 ( (EAGAIN == errno) ||
276 (EINTR == errno) ) )
277 {
278 /* ignore */
279 ret = 0;
280 }
281 if (-1 == ret)
282 {
283 LOG (GNUNET_ERROR_TYPE_WARNING,
284 "Error during sending message of type %u: %s\n",
285 ntohs (cstate->msg->type),
286 strerror (errno));
287 if (EINTR == errno)
288 {
289 LOG (GNUNET_ERROR_TYPE_DEBUG,
290 "Retrying message of type %u\n",
291 ntohs (cstate->msg->type));
292 goto RETRY;
293 }
294 GNUNET_MQ_inject_error (cstate->mq,
295 GNUNET_MQ_ERROR_WRITE);
296 return;
297 }
298 notify_in_flight = (0 == cstate->msg_off);
299 cstate->msg_off += ret;
300 if (cstate->msg_off < len)
301 {
302 LOG (GNUNET_ERROR_TYPE_DEBUG,
303 "rescheduling message of type %u\n",
304 ntohs (cstate->msg->type));
305 cstate->send_task
306 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
307 cstate->sock,
308 &transmit_ready,
309 cstate);
310 if (notify_in_flight)
311 GNUNET_MQ_impl_send_in_flight (cstate->mq);
312 return;
313 }
314 LOG (GNUNET_ERROR_TYPE_DEBUG,
315 "sending message of type %u and size %u successful\n",
316 ntohs (cstate->msg->type),
317 ntohs (cstate->msg->size));
318 cstate->msg = NULL;
319 GNUNET_MQ_impl_send_continue (cstate->mq);
320}
321
322
323/**
324 * We have received a full message, pass to the MQ dispatcher.
325 * Called by the tokenizer via #receive_ready().
326 *
327 * @param cls the `struct ClientState`
328 * @param msg message we received.
329 * @return #GNUNET_OK on success,
330 * #GNUNET_NO to stop further processing due to disconnect (no error)
331 * #GNUNET_SYSERR to stop further processing due to error
332 */
333static int
334recv_message (void *cls,
335 const struct GNUNET_MessageHeader *msg)
336{
337 struct ClientState *cstate = cls;
338
339 if (GNUNET_YES == cstate->in_destroy)
340 return GNUNET_NO;
341 LOG (GNUNET_ERROR_TYPE_DEBUG,
342 "Received message of type %u and size %u from %s\n",
343 ntohs (msg->type),
344 ntohs (msg->size),
345 cstate->service_name);
346 GNUNET_MQ_inject_message (cstate->mq,
347 msg);
348 if (GNUNET_YES == cstate->in_destroy)
349 return GNUNET_NO;
350 return GNUNET_OK;
351}
352
353
354/**
355 * Cancel all remaining connect attempts
356 *
357 * @param cstate handle of the client state to process
358 */
359static void
360cancel_aps (struct ClientState *cstate)
361{
362 struct AddressProbe *pos;
363
364 while (NULL != (pos = cstate->ap_head))
365 {
366 GNUNET_break (GNUNET_OK ==
367 GNUNET_NETWORK_socket_close (pos->sock));
368 GNUNET_SCHEDULER_cancel (pos->task);
369 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
370 cstate->ap_tail,
371 pos);
372 GNUNET_free (pos);
373 }
374}
375
376
377/**
378 * Implement the destruction of a message queue. Implementations must
379 * not free @a mq, but should take care of @a impl_state.
380 *
381 * @param mq the message queue to destroy
382 * @param impl_state our `struct ClientState`
383 */
384static void
385connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
386 void *impl_state)
387{
388 struct ClientState *cstate = impl_state;
389
390 (void) mq;
391 if (NULL != cstate->dns_active)
392 {
393 GNUNET_RESOLVER_request_cancel (cstate->dns_active);
394 cstate->dns_active = NULL;
395 }
396 if (NULL != cstate->send_task)
397 {
398 GNUNET_SCHEDULER_cancel (cstate->send_task);
399 cstate->send_task = NULL;
400 }
401 if (NULL != cstate->retry_task)
402 {
403 GNUNET_SCHEDULER_cancel (cstate->retry_task);
404 cstate->retry_task = NULL;
405 }
406 if (GNUNET_SYSERR == cstate->in_destroy)
407 {
408 /* defer destruction */
409 cstate->in_destroy = GNUNET_YES;
410 cstate->mq = NULL;
411 return;
412 }
413 if (NULL != cstate->recv_task)
414 {
415 GNUNET_SCHEDULER_cancel (cstate->recv_task);
416 cstate->recv_task = NULL;
417 }
418 if (NULL != cstate->sock)
419 {
420 LOG (GNUNET_ERROR_TYPE_DEBUG,
421 "destroying socket: %p\n",
422 cstate->sock);
423 GNUNET_NETWORK_socket_close (cstate->sock);
424 }
425 cancel_aps (cstate);
426 GNUNET_free (cstate->service_name);
427 GNUNET_free (cstate->hostname);
428 GNUNET_MST_destroy (cstate->mst);
429 GNUNET_free (cstate);
430}
431
432
433/**
434 * This function is called once we have data ready to read.
435 *
436 * @param cls `struct ClientState` with connection to read from
437 */
438static void
439receive_ready (void *cls)
440{
441 struct ClientState *cstate = cls;
442 int ret;
443
444 cstate->recv_task = NULL;
445 cstate->in_destroy = GNUNET_SYSERR;
446 ret = GNUNET_MST_read (cstate->mst,
447 cstate->sock,
448 GNUNET_NO,
449 GNUNET_NO);
450 if (GNUNET_SYSERR == ret)
451 {
452 if (NULL != cstate->mq)
453 GNUNET_MQ_inject_error (cstate->mq,
454 GNUNET_MQ_ERROR_READ);
455 if (GNUNET_YES == cstate->in_destroy)
456 connection_client_destroy_impl (cstate->mq,
457 cstate);
458 return;
459 }
460 if (GNUNET_YES == cstate->in_destroy)
461 {
462 connection_client_destroy_impl (cstate->mq,
463 cstate);
464 return;
465 }
466 cstate->in_destroy = GNUNET_NO;
467 cstate->recv_task
468 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
469 cstate->sock,
470 &receive_ready,
471 cstate);
472}
473
474
475/**
476 * We've succeeded in establishing a connection.
477 *
478 * @param cstate the connection we tried to establish
479 */
480static void
481connect_success_continuation (struct ClientState *cstate)
482{
483 GNUNET_assert (NULL == cstate->recv_task);
484 cstate->recv_task
485 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
486 cstate->sock,
487 &receive_ready,
488 cstate);
489 if (NULL != cstate->msg)
490 {
491 GNUNET_assert (NULL == cstate->send_task);
492 cstate->send_task
493 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
494 cstate->sock,
495 &transmit_ready,
496 cstate);
497 }
498}
499
500
501/**
502 * Try connecting to the server using UNIX domain sockets.
503 *
504 * @param service_name name of service to connect to
505 * @param cfg configuration to use
506 * @return NULL on error, socket connected to UNIX otherwise
507 */
508static struct GNUNET_NETWORK_Handle *
509try_unixpath (const char *service_name,
510 const struct GNUNET_CONFIGURATION_Handle *cfg)
511{
512#if AF_UNIX
513 struct GNUNET_NETWORK_Handle *sock;
514 char *unixpath;
515 struct sockaddr_un s_un;
516
517 unixpath = NULL;
518 if ((GNUNET_OK ==
519 GNUNET_CONFIGURATION_get_value_filename (cfg,
520 service_name,
521 "UNIXPATH",
522 &unixpath)) &&
523 (0 < strlen (unixpath)))
524 {
525 /* We have a non-NULL unixpath, need to validate it */
526 if (strlen (unixpath) >= sizeof(s_un.sun_path))
527 {
528 LOG (GNUNET_ERROR_TYPE_WARNING,
529 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
530 unixpath,
531 (unsigned long long) sizeof(s_un.sun_path));
532 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
533 LOG (GNUNET_ERROR_TYPE_INFO,
534 _ ("Using `%s' instead\n"),
535 unixpath);
536 if (NULL == unixpath)
537 return NULL;
538 }
539 memset (&s_un,
540 0,
541 sizeof(s_un));
542 s_un.sun_family = AF_UNIX;
543 GNUNET_strlcpy (s_un.sun_path,
544 unixpath,
545 sizeof(s_un.sun_path));
546#if HAVE_SOCKADDR_UN_SUN_LEN
547 s_un.sun_len = (u_char) sizeof(struct sockaddr_un);
548#endif
549 sock = GNUNET_NETWORK_socket_create (AF_UNIX,
550 SOCK_STREAM,
551 0);
552 if ((NULL != sock) &&
553 ((GNUNET_OK ==
554 GNUNET_NETWORK_socket_connect (sock,
555 (struct sockaddr *) &s_un,
556 sizeof(s_un))) ||
557 (EINPROGRESS == errno)))
558 {
559 LOG (GNUNET_ERROR_TYPE_DEBUG,
560 "Successfully connected to unixpath `%s'!\n",
561 unixpath);
562 GNUNET_free (unixpath);
563 return sock;
564 }
565 if (NULL != sock)
566 GNUNET_NETWORK_socket_close (sock);
567 }
568 GNUNET_free (unixpath);
569#endif
570 return NULL;
571}
572
573
574/**
575 * Scheduler let us know that we're either ready to write on the
576 * socket OR connect timed out. Do the right thing.
577 *
578 * @param cls the `struct AddressProbe *` with the address that we are probing
579 */
580static void
581connect_probe_continuation (void *cls)
582{
583 struct AddressProbe *ap = cls;
584 struct ClientState *cstate = ap->cstate;
585 const struct GNUNET_SCHEDULER_TaskContext *tc;
586 int error;
587 socklen_t len;
588
589 ap->task = NULL;
590 GNUNET_assert (NULL != ap->sock);
591 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
592 cstate->ap_tail,
593 ap);
594 len = sizeof(error);
595 error = 0;
596 tc = GNUNET_SCHEDULER_get_task_context ();
597 if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
598 (GNUNET_OK !=
599 GNUNET_NETWORK_socket_getsockopt (ap->sock,
600 SOL_SOCKET,
601 SO_ERROR,
602 &error,
603 &len)) ||
604 (0 != error))
605 {
606 GNUNET_break (GNUNET_OK ==
607 GNUNET_NETWORK_socket_close (ap->sock));
608 GNUNET_free (ap);
609 if ((NULL == cstate->ap_head) &&
610 // (NULL == cstate->proxy_handshake) &&
611 (NULL == cstate->dns_active))
612 connect_fail_continuation (cstate);
613 return;
614 }
615 LOG (GNUNET_ERROR_TYPE_DEBUG,
616 "Connection to `%s' succeeded!\n",
617 cstate->service_name);
618 /* trigger jobs that waited for the connection */
619 GNUNET_assert (NULL == cstate->sock);
620 cstate->sock = ap->sock;
621 GNUNET_free (ap);
622 cancel_aps (cstate);
623 connect_success_continuation (cstate);
624}
625
626
627/**
628 * Try to establish a connection given the specified address.
629 * This function is called by the resolver once we have a DNS reply.
630 *
631 * @param cls our `struct ClientState *`
632 * @param addr address to try, NULL for "last call"
633 * @param addrlen length of @a addr
634 */
635static void
636try_connect_using_address (void *cls,
637 const struct sockaddr *addr,
638 socklen_t addrlen)
639{
640 struct ClientState *cstate = cls;
641 struct AddressProbe *ap;
642
643 if (NULL == addr)
644 {
645 cstate->dns_active = NULL;
646 if ((NULL == cstate->ap_head) &&
647 // (NULL == cstate->proxy_handshake) &&
648 (NULL == cstate->sock))
649 connect_fail_continuation (cstate);
650 return;
651 }
652 if (NULL != cstate->sock)
653 return; /* already connected */
654 /* try to connect */
655 LOG (GNUNET_ERROR_TYPE_DEBUG,
656 "Trying to connect using address `%s:%u'\n",
657 GNUNET_a2s (addr,
658 addrlen),
659 (unsigned int) cstate->port);
660 ap = GNUNET_malloc (sizeof(struct AddressProbe) + addrlen);
661 ap->addr = (const struct sockaddr *) &ap[1];
662 GNUNET_memcpy (&ap[1],
663 addr,
664 addrlen);
665 ap->addrlen = addrlen;
666 ap->cstate = cstate;
667
668 switch (ap->addr->sa_family)
669 {
670 case AF_INET:
671 ((struct sockaddr_in *) ap->addr)->sin_port = htons (cstate->port);
672 break;
673
674 case AF_INET6:
675 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (cstate->port);
676 break;
677
678 default:
679 GNUNET_break (0);
680 GNUNET_free (ap);
681 return; /* not supported by us */
682 }
683 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
684 SOCK_STREAM,
685 0);
686 if (NULL == ap->sock)
687 {
688 GNUNET_free (ap);
689 return; /* not supported by OS */
690 }
691 if ((GNUNET_OK !=
692 GNUNET_NETWORK_socket_connect (ap->sock,
693 ap->addr,
694 ap->addrlen)) &&
695 (EINPROGRESS != errno))
696 {
697 /* maybe refused / unsupported address, try next */
698 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
699 "connect");
700 GNUNET_break (GNUNET_OK ==
701 GNUNET_NETWORK_socket_close (ap->sock));
702 GNUNET_free (ap);
703 return;
704 }
705 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
706 cstate->ap_tail,
707 ap);
708 ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
709 ap->sock,
710 &connect_probe_continuation,
711 ap);
712}
713
714
715/**
716 * Test whether the configuration has proper values for connection
717 * (UNIXPATH || (PORT && HOSTNAME)).
718 *
719 * @param service_name name of service to connect to
720 * @param cfg configuration to use
721 * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
722 */
723static int
724test_service_configuration (const char *service_name,
725 const struct GNUNET_CONFIGURATION_Handle *cfg)
726{
727 int ret = GNUNET_SYSERR;
728 char *hostname = NULL;
729 unsigned long long port;
730
731#if AF_UNIX
732 char *unixpath = NULL;
733
734 if ((GNUNET_OK ==
735 GNUNET_CONFIGURATION_get_value_filename (cfg,
736 service_name,
737 "UNIXPATH",
738 &unixpath)) &&
739 (0 < strlen (unixpath)))
740 ret = GNUNET_OK;
741 else if ((GNUNET_OK ==
742 GNUNET_CONFIGURATION_have_value (cfg,
743 service_name,
744 "UNIXPATH")))
745 {
746 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
747 service_name,
748 "UNIXPATH",
749 _ ("not a valid filename"));
750 GNUNET_free (unixpath);
751 return GNUNET_SYSERR; /* UNIXPATH specified but invalid! */
752 }
753 GNUNET_free (unixpath);
754#endif
755
756 if ((GNUNET_YES ==
757 GNUNET_CONFIGURATION_have_value (cfg,
758 service_name,
759 "PORT")) &&
760 (GNUNET_OK ==
761 GNUNET_CONFIGURATION_get_value_number (cfg,
762 service_name,
763 "PORT",
764 &port)) &&
765 (port <= 65535) &&
766 (0 != port) &&
767 (GNUNET_OK ==
768 GNUNET_CONFIGURATION_get_value_string (cfg,
769 service_name,
770 "HOSTNAME",
771 &hostname)) &&
772 (0 != strlen (hostname)))
773 ret = GNUNET_OK;
774 GNUNET_free (hostname);
775 return ret;
776}
777
778
779/**
780 * Try to connect to the service.
781 *
782 * @param cls the `struct ClientState` to try to connect to the service
783 */
784static void
785start_connect (void *cls)
786{
787 struct ClientState *cstate = cls;
788
789 cstate->retry_task = NULL;
790#if 0
791 /* Never use a local source if a proxy is configured */
792 if (GNUNET_YES ==
793 GNUNET_SOCKS_check_service (cstate->service_name,
794 cstate->cfg))
795 {
796 socks_connect (cstate);
797 return;
798 }
799#endif
800
801 if ((0 == (cstate->attempts++ % 2)) ||
802 (0 == cstate->port) ||
803 (NULL == cstate->hostname))
804 {
805 /* on even rounds, try UNIX first, or always
806 if we do not have a DNS name and TCP port. */
807 cstate->sock = try_unixpath (cstate->service_name,
808 cstate->cfg);
809 if (NULL != cstate->sock)
810 {
811 connect_success_continuation (cstate);
812 return;
813 }
814 }
815 if ((NULL == cstate->hostname) ||
816 (0 == cstate->port))
817 {
818 /* All options failed. Boo! */
819 connect_fail_continuation (cstate);
820 return;
821 }
822 cstate->dns_active
823 = GNUNET_RESOLVER_ip_get (cstate->hostname,
824 AF_UNSPEC,
825 CONNECT_RETRY_TIMEOUT,
826 &try_connect_using_address,
827 cstate);
828}
829
830
831/**
832 * Implements the transmission functionality of a message queue.
833 *
834 * @param mq the message queue
835 * @param msg the message to send
836 * @param impl_state our `struct ClientState`
837 */
838static void
839connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
840 const struct GNUNET_MessageHeader *msg,
841 void *impl_state)
842{
843 struct ClientState *cstate = impl_state;
844
845 (void) mq;
846 /* only one message at a time allowed */
847 GNUNET_assert (NULL == cstate->msg);
848 GNUNET_assert (NULL == cstate->send_task);
849 cstate->msg = msg;
850 cstate->msg_off = 0;
851 if (NULL == cstate->sock)
852 {
853 LOG (GNUNET_ERROR_TYPE_DEBUG,
854 "message of type %u waiting for socket\n",
855 ntohs (msg->type));
856 return; /* still waiting for connection */
857 }
858 cstate->send_task
859 = GNUNET_SCHEDULER_add_now (&transmit_ready,
860 cstate);
861}
862
863
864/**
865 * Cancel the currently sent message.
866 *
867 * @param mq message queue
868 * @param impl_state our `struct ClientState`
869 */
870static void
871connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
872 void *impl_state)
873{
874 struct ClientState *cstate = impl_state;
875
876 (void) mq;
877 GNUNET_assert (NULL != cstate->msg);
878 GNUNET_assert (0 == cstate->msg_off);
879 cstate->msg = NULL;
880 if (NULL != cstate->send_task)
881 {
882 GNUNET_SCHEDULER_cancel (cstate->send_task);
883 cstate->send_task = NULL;
884 }
885}
886
887
888/**
889 * Test if the port or UNIXPATH of the given @a service_name
890 * is in use and thus (most likely) the respective service is up.
891 *
892 * @param cfg our configuration
893 * @param service_name name of the service to connect to
894 * @return #GNUNET_YES if the service is (likely) up,
895 * #GNUNET_NO if the service is (definitively) down,
896 * #GNUNET_SYSERR if the configuration does not give us
897 * the necessary information about the service, or if
898 * we could not check (e.g. socket() failed)
899 */
900int
901GNUNET_CLIENT_test (const struct GNUNET_CONFIGURATION_Handle *cfg,
902 const char *service_name)
903{
904 char *hostname = NULL;
905 unsigned long long port;
906 int ret;
907
908#if AF_UNIX
909 {
910 char *unixpath = NULL;
911
912 if (GNUNET_OK ==
913 GNUNET_CONFIGURATION_get_value_filename (cfg,
914 service_name,
915 "UNIXPATH",
916 &unixpath))
917 {
918 if (0 == strlen (unixpath))
919 {
920 GNUNET_free (unixpath);
921 return GNUNET_SYSERR; /* empty string not OK */
922 }
923 if (0 == access (unixpath,
924 F_OK))
925 {
926 GNUNET_free (unixpath);
927 return GNUNET_OK; /* file exists, we assume service is running */
928 }
929 GNUNET_free (unixpath);
930 }
931 else if (GNUNET_OK ==
932 GNUNET_CONFIGURATION_have_value (cfg,
933 service_name,
934 "UNIXPATH"))
935 {
936 /* UNIXPATH specified but not a valid path! */
937 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
938 service_name,
939 "UNIXPATH",
940 _ ("not a valid filename"));
941 return GNUNET_SYSERR;
942 }
943 }
944#endif
945
946 if ( (GNUNET_OK !=
947 GNUNET_CONFIGURATION_get_value_number (cfg,
948 service_name,
949 "PORT",
950 &port)) ||
951 (port > 65535) ||
952 (0 == port) )
953 {
954 return GNUNET_SYSERR;
955 }
956 if (GNUNET_OK ==
957 GNUNET_CONFIGURATION_get_value_string (cfg,
958 service_name,
959 "HOSTNAME",
960 &hostname))
961 {
962 /* We always assume remotes are up */
963 ret = GNUNET_YES;
964 }
965 else
966 {
967 /* We look for evidence the service is up */
968 ret = GNUNET_NO;
969 }
970 if ( (NULL == hostname) ||
971 (0 == strcasecmp (hostname,
972 "localhost")) ||
973 (0 == strcasecmp (hostname,
974 "ip6-localnet")) )
975 {
976 /* service runs on loopback */
977 struct sockaddr_in v4;
978 struct sockaddr_in6 v6;
979 int sock;
980
981 memset (&v4, 0, sizeof (v4));
982 memset (&v6, 0, sizeof (v6));
983 v4.sin_family = AF_INET;
984 v4.sin_port = htons ((uint16_t) port);
985#if HAVE_SOCKADDR_IN_SUN_LEN
986 v4.sin_len = (u_char) sizeof(struct sockaddr_in);
987#endif
988 inet_pton (AF_INET,
989 "127.0.0.1",
990 &v4.sin_addr);
991 ret = GNUNET_NO;
992 sock = socket (AF_INET,
993 SOCK_STREAM,
994 0);
995 if (-1 != sock)
996 {
997 if (0 != bind (sock,
998 (struct sockaddr *) &v4,
999 sizeof (v4)))
1000 {
1001 /* bind failed, so someone is listening! */
1002 ret = GNUNET_YES;
1003 }
1004 (void) close (sock);
1005 }
1006 else
1007 {
1008 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1009 "socket");
1010 if (GNUNET_NO == ret)
1011 ret = GNUNET_SYSERR;
1012 }
1013 v6.sin6_family = AF_INET6;
1014 v6.sin6_port = htons ((uint16_t) port);
1015#if HAVE_SOCKADDR_IN_SUN_LEN
1016 v6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
1017#endif
1018 inet_pton (AF_INET6,
1019 "::1",
1020 &v6.sin6_addr);
1021 sock = socket (AF_INET6,
1022 SOCK_STREAM,
1023 0);
1024 if (-1 != sock)
1025 {
1026 if (0 != bind (sock,
1027 (struct sockaddr *) &v6,
1028 sizeof (v6)))
1029 {
1030 /* bind failed, so someone is listening! */
1031 ret = GNUNET_YES;
1032 }
1033 (void) close (sock);
1034 }
1035 else
1036 {
1037 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1038 "socket");
1039 /* not changing 'ret' intentionally here, as
1040 v4 succeeding and v6 failing just means we
1041 should use v4 */
1042 }
1043 }
1044 else
1045 {
1046 /* service running remotely */
1047 ret = GNUNET_OK;
1048 }
1049 GNUNET_free (hostname);
1050 return ret;
1051}
1052
1053
1054/**
1055 * Create a message queue to connect to a GNUnet service.
1056 * If handlers are specified, receive messages from the connection.
1057 *
1058 * @param cfg our configuration
1059 * @param service_name name of the service to connect to
1060 * @param handlers handlers for receiving messages, can be NULL
1061 * @param error_handler error handler
1062 * @param error_handler_cls closure for the @a error_handler
1063 * @return the message queue, NULL on error
1064 */
1065struct GNUNET_MQ_Handle *
1066GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1067 const char *service_name,
1068 const struct GNUNET_MQ_MessageHandler *handlers,
1069 GNUNET_MQ_ErrorHandler error_handler,
1070 void *error_handler_cls)
1071{
1072 struct ClientState *cstate;
1073
1074 if (GNUNET_OK !=
1075 test_service_configuration (service_name,
1076 cfg))
1077 return NULL;
1078 cstate = GNUNET_new (struct ClientState);
1079 cstate->service_name = GNUNET_strdup (service_name);
1080 cstate->cfg = cfg;
1081 cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
1082 cstate);
1083 cstate->mst = GNUNET_MST_create (&recv_message,
1084 cstate);
1085 if (GNUNET_YES ==
1086 GNUNET_CONFIGURATION_have_value (cfg,
1087 service_name,
1088 "PORT"))
1089 {
1090 if (! ((GNUNET_OK !=
1091 GNUNET_CONFIGURATION_get_value_number (cfg,
1092 service_name,
1093 "PORT",
1094 &cstate->port)) ||
1095 (cstate->port > 65535) ||
1096 (GNUNET_OK !=
1097 GNUNET_CONFIGURATION_get_value_string (cfg,
1098 service_name,
1099 "HOSTNAME",
1100 &cstate->hostname))) &&
1101 (0 == strlen (cstate->hostname)))
1102 {
1103 GNUNET_free (cstate->hostname);
1104 cstate->hostname = NULL;
1105 LOG (GNUNET_ERROR_TYPE_WARNING,
1106 _ ("Need a non-empty hostname for service `%s'.\n"),
1107 service_name);
1108 }
1109 }
1110 cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
1111 &connection_client_destroy_impl,
1112 &connection_client_cancel_impl,
1113 cstate,
1114 handlers,
1115 error_handler,
1116 error_handler_cls);
1117 return cstate->mq;
1118}
1119
1120
1121/* 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 b07f3fc0b..000000000
--- a/src/util/common_logging.c
+++ /dev/null
@@ -1,1591 +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
324const char *
325GNUNET_b2s (const void *buf,
326 size_t buf_size)
327{
328 static GNUNET_THREAD_LOCAL char ret[9];
329 struct GNUNET_HashCode hc;
330 char *tmp;
331
332 GNUNET_CRYPTO_hash (buf,
333 buf_size,
334 &hc);
335 tmp = GNUNET_STRINGS_data_to_string_alloc (&hc,
336 sizeof (hc));
337 memcpy (ret,
338 tmp,
339 8);
340 GNUNET_free (tmp);
341 ret[8] = '\0';
342 return ret;
343}
344
345
346/**
347 * Setup the log file.
348 *
349 * @param tm timestamp for which we should setup logging
350 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
351 */
352static int
353setup_log_file (const struct tm *tm)
354{
355 static char last_fn[PATH_MAX + 1];
356 char fn[PATH_MAX + 1];
357 int altlog_fd;
358 int dup_return;
359 FILE *altlog;
360 char *leftsquare;
361
362 if (NULL == log_file_name)
363 return GNUNET_SYSERR;
364 if (0 == strftime (fn, sizeof(fn), log_file_name, tm))
365 return GNUNET_SYSERR;
366 leftsquare = strrchr (fn, '[');
367 if ((NULL != leftsquare) && (']' == leftsquare[1]))
368 {
369 char *logfile_copy = GNUNET_strdup (fn);
370
371 logfile_copy[leftsquare - fn] = '\0';
372 logfile_copy[leftsquare - fn + 1] = '\0';
373 snprintf (fn,
374 PATH_MAX,
375 "%s%d%s",
376 logfile_copy,
377 getpid (),
378 &logfile_copy[leftsquare - fn + 2]);
379 GNUNET_free (logfile_copy);
380 }
381 if (0 == strcmp (fn, last_fn))
382 return GNUNET_OK; /* no change */
383 log_rotate (last_fn);
384 strcpy (last_fn, fn);
385 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (fn))
386 {
387 fprintf (stderr,
388 "Failed to create directory for `%s': %s\n",
389 fn,
390 strerror (errno));
391 return GNUNET_SYSERR;
392 }
393 altlog_fd = open (fn,
394 O_APPEND | O_WRONLY | O_CREAT,
395 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
396
397 if (-1 != altlog_fd)
398 {
399 if (NULL != GNUNET_stderr)
400 fclose (GNUNET_stderr);
401 dup_return = dup2 (altlog_fd, 2);
402 (void) close (altlog_fd);
403 if (-1 != dup_return)
404 {
405 altlog = fdopen (2, "ab");
406 if (NULL == altlog)
407 {
408 (void) close (2);
409 altlog_fd = -1;
410 }
411 }
412 else
413 {
414 altlog_fd = -1;
415 }
416 }
417 if (-1 == altlog_fd)
418 {
419 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
420 return GNUNET_SYSERR;
421 }
422 GNUNET_stderr = altlog;
423 return GNUNET_OK;
424}
425
426
427/**
428 * Utility function - adds a parsed definition to logdefs array.
429 *
430 * @param component see struct LogDef, can't be NULL
431 * @param file see struct LogDef, can't be NULL
432 * @param function see struct LogDef, can't be NULL
433 * @param from_line see struct LogDef
434 * @param to_line see struct LogDef
435 * @param level see struct LogDef, must be >= 0
436 * @param force see struct LogDef
437 * @return 0 on success, regex-specific error otherwise
438 */
439static int
440add_definition (const char *component,
441 const char *file,
442 const char *function,
443 int from_line,
444 int to_line,
445 int level,
446 int force)
447{
448 struct LogDef n;
449 int r;
450
451 if (logdefs_size == logdefs_len)
452 resize_logdefs ();
453 memset (&n, 0, sizeof(n));
454 if (0 == strlen (component))
455 component = (char *) ".*";
456 r = regcomp (&n.component_regex, (const char *) component, REG_NOSUB);
457 if (0 != r)
458 {
459 return r;
460 }
461 if (0 == strlen (file))
462 file = (char *) ".*";
463 r = regcomp (&n.file_regex, (const char *) file, REG_NOSUB);
464 if (0 != r)
465 {
466 regfree (&n.component_regex);
467 return r;
468 }
469 if ((NULL == function) || (0 == strlen (function)))
470 function = (char *) ".*";
471 r = regcomp (&n.function_regex, (const char *) function, REG_NOSUB);
472 if (0 != r)
473 {
474 regfree (&n.component_regex);
475 regfree (&n.file_regex);
476 return r;
477 }
478 n.from_line = from_line;
479 n.to_line = to_line;
480 n.level = level;
481 n.force = force;
482 logdefs[logdefs_len++] = n;
483 return 0;
484}
485
486
487/**
488 * Decides whether a particular logging call should or should not be allowed
489 * to be made. Used internally by GNUNET_log*()
490 *
491 * @param caller_level loglevel the caller wants to use
492 * @param comp component name the caller uses (NULL means that global
493 * component name is used)
494 * @param file file name containing the logging call, usually __FILE__
495 * @param function function which tries to make a logging call,
496 * usually __FUNCTION__
497 * @param line line at which the call is made, usually __LINE__
498 * @return 0 to disallow the call, 1 to allow it
499 */
500int
501GNUNET_get_log_call_status (int caller_level,
502 const char *comp,
503 const char *file,
504 const char *function,
505 int line)
506{
507 struct LogDef *ld;
508 int i;
509 int force_only;
510
511 if (NULL == comp)
512 /* Use default component */
513 comp = component_nopid;
514
515 /* We have no definitions to override globally configured log level,
516 * so just use it right away.
517 */
518 if ((min_level >= 0) && (GNUNET_NO == gnunet_force_log_present))
519 return caller_level <= min_level;
520
521 /* Only look for forced definitions? */
522 force_only = min_level >= 0;
523 for (i = 0; i < logdefs_len; i++)
524 {
525 ld = &logdefs[i];
526 if (((! force_only) || ld->force) &&
527 ((line >= ld->from_line) && (line <= ld->to_line) ) &&
528 (0 == regexec (&ld->component_regex, comp, 0, NULL, 0)) &&
529 (0 == regexec (&ld->file_regex, file, 0, NULL, 0)) &&
530 (0 == regexec (&ld->function_regex, function, 0, NULL, 0)))
531 {
532 /* We're finished */
533 return caller_level <= ld->level;
534 }
535 }
536 /* No matches - use global level, if defined */
537 if (min_level >= 0)
538 return caller_level <= min_level;
539 /* All programs/services previously defaulted to WARNING.
540 * Now *we* default to WARNING, and THEY default to NULL.
541 * Or rather we default to MESSAGE, since things aren't always bad.
542 */
543 return caller_level <= GNUNET_ERROR_TYPE_MESSAGE;
544}
545
546
547/**
548 * Utility function - parses a definition
549 *
550 * Definition format:
551 * component;file;function;from_line-to_line;level[/component...]
552 * All entries are mandatory, but may be empty.
553 * Empty entries for component, file and function are treated as
554 * "matches anything".
555 * Empty line entry is treated as "from 0 to INT_MAX"
556 * Line entry with only one line is treated as "this line only"
557 * Entry for level MUST NOT be empty.
558 * Entries for component, file and function that consist of a
559 * single character "*" are treated (at the moment) the same way
560 * empty entries are treated (wildcard matching is not implemented (yet?)).
561 * file entry is matched to the end of __FILE__. That is, it might be
562 * a base name, or a base name with leading directory names (some compilers
563 * define __FILE__ to absolute file path).
564 *
565 * @param constname name of the environment variable from which to get the
566 * string to be parsed
567 * @param force 1 if definitions found in constname are to be forced
568 * @return number of added definitions
569 */
570static int
571parse_definitions (const char *constname, int force)
572{
573 char *def;
574 const char *tmp;
575 char *comp = NULL;
576 char *file = NULL;
577 char *function = NULL;
578 char *p;
579 char *start;
580 char *t;
581 short state;
582 int level;
583 int from_line, to_line;
584 int counter = 0;
585 int keep_looking = 1;
586
587 tmp = getenv (constname);
588 if (NULL == tmp)
589 return 0;
590 def = GNUNET_strdup (tmp);
591 from_line = 0;
592 to_line = INT_MAX;
593 for (p = def, state = 0, start = def; keep_looking; p++)
594 {
595 switch (p[0])
596 {
597 case ';': /* found a field separator */
598 p[0] = '\0';
599 switch (state)
600 {
601 case 0: /* within a component name */
602 comp = start;
603 break;
604
605 case 1: /* within a file name */
606 file = start;
607 break;
608
609 case 2: /* within a function name */
610 /* after a file name there must be a function name */
611 function = start;
612 break;
613
614 case 3: /* within a from-to line range */
615 if (strlen (start) > 0)
616 {
617 errno = 0;
618 from_line = strtol (start, &t, 10);
619 if ((0 != errno) || (from_line < 0))
620 {
621 GNUNET_free (def);
622 return counter;
623 }
624 if ((t < p) && ('-' == t[0]))
625 {
626 errno = 0;
627 start = t + 1;
628 to_line = strtol (start, &t, 10);
629 if ((0 != errno) || (to_line < 0) || (t != p))
630 {
631 GNUNET_free (def);
632 return counter;
633 }
634 }
635 else /* one number means "match this line only" */
636 to_line = from_line;
637 }
638 else /* default to 0-max */
639 {
640 from_line = 0;
641 to_line = INT_MAX;
642 }
643 break;
644
645 default:
646 fprintf (
647 stderr,
648 _ ("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"),
649 p);
650 break;
651 }
652 start = p + 1;
653 state++;
654 break;
655
656 case '\0': /* found EOL */
657 keep_looking = 0;
658
659 /* fall through to '/' */
660 case '/': /* found a definition separator */
661 switch (state)
662 {
663 case 4: /* within a log level */
664 p[0] = '\0';
665 state = 0;
666 level = get_type ((const char *) start);
667 if ((GNUNET_ERROR_TYPE_INVALID == level) ||
668 (GNUNET_ERROR_TYPE_UNSPECIFIED == level) ||
669 (0 != add_definition (comp,
670 file,
671 function,
672 from_line,
673 to_line,
674 level,
675 force)))
676 {
677 GNUNET_free (def);
678 return counter;
679 }
680 counter++;
681 start = p + 1;
682 break;
683
684 default:
685 fprintf (
686 stderr,
687 _ ("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"),
688 p);
689 break;
690 }
691
692 default:
693 break;
694 }
695 }
696 GNUNET_free (def);
697 return counter;
698}
699
700
701/**
702 * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG.
703 */
704static void
705parse_all_definitions ()
706{
707 if (GNUNET_NO == gnunet_force_log_parsed)
708 gnunet_force_log_present =
709 parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO;
710 gnunet_force_log_parsed = GNUNET_YES;
711
712 if (GNUNET_NO == gnunet_log_parsed)
713 parse_definitions ("GNUNET_LOG", 0);
714 gnunet_log_parsed = GNUNET_YES;
715}
716
717
718#endif
719
720
721/**
722 * Setup logging.
723 *
724 * @param comp default component to use
725 * @param loglevel what types of messages should be logged
726 * @param logfile which file to write log messages to (can be NULL)
727 * @return #GNUNET_OK on success
728 */
729int
730GNUNET_log_setup (const char *comp,
731 const char *loglevel,
732 const char *logfile)
733{
734 const char *env_logfile;
735
736 min_level = get_type (loglevel);
737#if ! defined(GNUNET_CULL_LOGGING)
738 parse_all_definitions ();
739#endif
740 GNUNET_free (component);
741 GNUNET_asprintf (&component, "%s-%d", comp, getpid ());
742 GNUNET_free (component_nopid);
743 component_nopid = GNUNET_strdup (comp);
744
745 env_logfile = getenv ("GNUNET_FORCE_LOGFILE");
746 if ((NULL != env_logfile) && (strlen (env_logfile) > 0))
747 logfile = env_logfile;
748 if (NULL == logfile)
749 return GNUNET_OK;
750 GNUNET_free (log_file_name);
751 log_file_name = GNUNET_STRINGS_filename_expand (logfile);
752 if (NULL == log_file_name)
753 return GNUNET_SYSERR;
754#if defined(GNUNET_CULL_LOGGING)
755 /* log file option not allowed for wallet logic */
756 GNUNET_assert (NULL == logfile);
757 return GNUNET_OK;
758#else
759 {
760 time_t t;
761 const struct tm *tm;
762
763 t = time (NULL);
764 tm = gmtime (&t);
765 return setup_log_file (tm);
766 }
767#endif
768}
769
770
771/**
772 * Add a custom logger. Note that installing any custom logger
773 * will disable the standard logger. When multiple custom loggers
774 * are installed, all will be called. The standard logger will
775 * only be used if no custom loggers are present.
776 *
777 * @param logger log function
778 * @param logger_cls closure for @a logger
779 */
780void
781GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls)
782{
783 struct CustomLogger *entry;
784
785 entry = GNUNET_new (struct CustomLogger);
786 entry->logger = logger;
787 entry->logger_cls = logger_cls;
788 entry->next = loggers;
789 loggers = entry;
790}
791
792
793/**
794 * Remove a custom logger.
795 *
796 * @param logger log function
797 * @param logger_cls closure for @a logger
798 */
799void
800GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls)
801{
802 struct CustomLogger *pos;
803 struct CustomLogger *prev;
804
805 prev = NULL;
806 pos = loggers;
807 while ((NULL != pos) &&
808 ((pos->logger != logger) || (pos->logger_cls != logger_cls)))
809 {
810 prev = pos;
811 pos = pos->next;
812 }
813 GNUNET_assert (NULL != pos);
814 if (NULL == prev)
815 loggers = pos->next;
816 else
817 prev->next = pos->next;
818 GNUNET_free (pos);
819}
820
821
822/**
823 * Actually output the log message.
824 *
825 * @param kind how severe was the issue
826 * @param comp component responsible
827 * @param datestr current date/time
828 * @param msg the actual message
829 */
830static void
831output_message (enum GNUNET_ErrorType kind,
832 const char *comp,
833 const char *datestr,
834 const char *msg)
835{
836 struct CustomLogger *pos;
837
838 /* only use the standard logger if no custom loggers are present */
839 if ((NULL != GNUNET_stderr) && (NULL == loggers))
840 {
841 if (kind == GNUNET_ERROR_TYPE_MESSAGE)
842 {
843 /* The idea here is to produce "normal" output messages
844 * for end users while still having the power of the
845 * logging engine for developer needs. So ideally this
846 * is what it should look like when CLI tools are used
847 * interactively, yet the same message shouldn't look
848 * this way if the output is going to logfiles or robots
849 * instead.
850 */fprintf (GNUNET_stderr, "* %s", msg);
851 }
852 else if (GNUNET_YES == current_async_scope.have_scope)
853 {
854 static GNUNET_THREAD_LOCAL char id_buf[27];
855 char *end;
856
857 /* We're logging, so skip_log must be currently 0. */
858 skip_log = 100;
859 end = GNUNET_STRINGS_data_to_string (&current_async_scope.scope_id,
860 sizeof(struct GNUNET_AsyncScopeId),
861 id_buf,
862 sizeof(id_buf) - 1);
863 GNUNET_assert (NULL != end);
864 *end = '\0';
865 skip_log = 0;
866 fprintf (GNUNET_stderr,
867 "%s %s(%s) %s %s",
868 datestr,
869 comp,
870 id_buf,
871 GNUNET_error_type_to_string (kind),
872 msg);
873 }
874 else
875 {
876 fprintf (GNUNET_stderr,
877 "%s %s %s %s",
878 datestr,
879 comp,
880 GNUNET_error_type_to_string (kind),
881 msg);
882 }
883 fflush (GNUNET_stderr);
884 }
885 pos = loggers;
886 while (NULL != pos)
887 {
888 pos->logger (pos->logger_cls, kind, comp, datestr, msg);
889 pos = pos->next;
890 }
891}
892
893
894/**
895 * Flush an existing bulk report to the output.
896 *
897 * @param datestr our current timestamp
898 */
899static void
900flush_bulk (const char *datestr)
901{
902 char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256];
903 int rev;
904 char *last;
905 const char *ft;
906
907 if ((0 == last_bulk_time.abs_value_us) || (0 == last_bulk_repeat))
908 return;
909 rev = 0;
910 last = memchr (last_bulk, '\0', BULK_TRACK_SIZE);
911 if (last == NULL)
912 last = &last_bulk[BULK_TRACK_SIZE - 1];
913 else if (last != last_bulk)
914 last--;
915 if (last[0] == '\n')
916 {
917 rev = 1;
918 last[0] = '\0';
919 }
920 ft =
921 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (
922 last_bulk_time),
923 GNUNET_YES);
924 snprintf (msg,
925 sizeof(msg),
926 _ ("Message `%.*s' repeated %u times in the last %s\n"),
927 BULK_TRACK_SIZE,
928 last_bulk,
929 last_bulk_repeat,
930 ft);
931 if (rev == 1)
932 last[0] = '\n';
933 output_message (last_bulk_kind, last_bulk_comp, datestr, msg);
934 last_bulk_time = GNUNET_TIME_absolute_get ();
935 last_bulk_repeat = 0;
936}
937
938
939/**
940 * Ignore the next n calls to the log function.
941 *
942 * @param n number of log calls to ignore (could be negative)
943 * @param check_reset #GNUNET_YES to assert that the log skip counter is currently zero
944 */
945void
946GNUNET_log_skip (int n, int check_reset)
947{
948 int ok;
949
950 if (0 == n)
951 {
952 ok = (0 == skip_log);
953 skip_log = 0;
954 if (check_reset)
955 GNUNET_break (ok);
956 }
957 else
958 {
959 skip_log += n;
960 }
961}
962
963
964/**
965 * Get the number of log calls that are going to be skipped
966 *
967 * @return number of log calls to be ignored
968 */
969int
970GNUNET_get_log_skip ()
971{
972 return skip_log;
973}
974
975
976/**
977 * Output a log message using the default mechanism.
978 *
979 * @param kind how severe was the issue
980 * @param comp component responsible
981 * @param message the actual message
982 * @param va arguments to the format string "message"
983 */
984static void
985mylog (enum GNUNET_ErrorType kind,
986 const char *comp,
987 const char *message,
988 va_list va)
989{
990 char date[DATE_STR_SIZE];
991 char date2[DATE_STR_SIZE];
992 struct tm *tmptr;
993 size_t size;
994 va_list vacp;
995
996 va_copy (vacp, va);
997 size = vsnprintf (NULL, 0, message, vacp) + 1;
998 GNUNET_assert (0 != size);
999 va_end (vacp);
1000 memset (date, 0, DATE_STR_SIZE);
1001 {
1002 char buf[size];
1003 long long offset;
1004
1005 struct timeval timeofday;
1006
1007 gettimeofday (&timeofday, NULL);
1008 offset = GNUNET_TIME_get_offset ();
1009 if (offset > 0)
1010 {
1011 timeofday.tv_sec += offset / 1000LL;
1012 timeofday.tv_usec += (offset % 1000LL) * 1000LL;
1013 if (timeofday.tv_usec > 1000000LL)
1014 {
1015 timeofday.tv_usec -= 1000000LL;
1016 timeofday.tv_sec++;
1017 }
1018 }
1019 else
1020 {
1021 timeofday.tv_sec += offset / 1000LL;
1022 if (timeofday.tv_usec > -(offset % 1000LL) * 1000LL)
1023 {
1024 timeofday.tv_usec += (offset % 1000LL) * 1000LL;
1025 }
1026 else
1027 {
1028 timeofday.tv_usec += 1000000LL + (offset % 1000LL) * 1000LL;
1029 timeofday.tv_sec--;
1030 }
1031 }
1032 tmptr = localtime (&timeofday.tv_sec);
1033 if (NULL == tmptr)
1034 {
1035 strcpy (date, "localtime error");
1036 }
1037 else
1038 {
1039 /* RFC 3339 timestamp, with snprintf placeholder for microseconds */
1040 if (0 == strftime (date2, DATE_STR_SIZE, "%Y-%m-%dT%H:%M:%S.%%06u%z",
1041 tmptr))
1042 abort ();
1043 /* Fill in microseconds */
1044 if (0 > snprintf (date, sizeof(date), date2, timeofday.tv_usec))
1045 abort ();
1046 }
1047
1048 vsnprintf (buf, size, message, va);
1049#if ! defined(GNUNET_CULL_LOGGING)
1050 if (NULL != tmptr)
1051 (void) setup_log_file (tmptr);
1052#endif
1053 if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
1054 (0 != last_bulk_time.abs_value_us) &&
1055 (0 == strncmp (buf, last_bulk, sizeof(last_bulk))))
1056 {
1057 last_bulk_repeat++;
1058 if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value_us >
1059 BULK_DELAY_THRESHOLD) ||
1060 (last_bulk_repeat > BULK_REPEAT_THRESHOLD))
1061 flush_bulk (date);
1062 return;
1063 }
1064 flush_bulk (date);
1065 GNUNET_strlcpy (last_bulk, buf, sizeof(last_bulk));
1066 last_bulk_repeat = 0;
1067 last_bulk_kind = kind;
1068 last_bulk_time = GNUNET_TIME_absolute_get ();
1069 GNUNET_strlcpy (last_bulk_comp, comp, sizeof(last_bulk_comp));
1070 output_message (kind, comp, date, buf);
1071 }
1072}
1073
1074
1075/**
1076 * Main log function.
1077 *
1078 * @param kind how serious is the error?
1079 * @param message what is the message (format string)
1080 * @param ... arguments for format string
1081 */
1082void
1083GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...)
1084{
1085 va_list va;
1086
1087 va_start (va, message);
1088 mylog (kind, component, message, va);
1089 va_end (va);
1090}
1091
1092
1093/**
1094 * Log function that specifies an alternative component.
1095 * This function should be used by plugins.
1096 *
1097 * @param kind how serious is the error?
1098 * @param comp component responsible for generating the message
1099 * @param message what is the message (format string)
1100 * @param ... arguments for format string
1101 */
1102void
1103GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind,
1104 const char *comp,
1105 const char *message,
1106 ...)
1107{
1108 va_list va;
1109 char comp_w_pid[128];
1110
1111 if (comp == NULL)
1112 comp = component_nopid;
1113
1114 va_start (va, message);
1115 GNUNET_snprintf (comp_w_pid, sizeof(comp_w_pid), "%s-%d", comp, getpid ());
1116 mylog (kind, comp_w_pid, message, va);
1117 va_end (va);
1118}
1119
1120
1121/**
1122 * Convert error type to string.
1123 *
1124 * @param kind type to convert
1125 * @return string corresponding to the type
1126 */
1127const char *
1128GNUNET_error_type_to_string (enum GNUNET_ErrorType kind)
1129{
1130 if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0)
1131 return _ ("ERROR");
1132 if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0)
1133 return _ ("WARNING");
1134 if ((kind & GNUNET_ERROR_TYPE_MESSAGE) > 0)
1135 return _ ("MESSAGE");
1136 if ((kind & GNUNET_ERROR_TYPE_INFO) > 0)
1137 return _ ("INFO");
1138 if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0)
1139 return _ ("DEBUG");
1140 if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0)
1141 return _ ("NONE");
1142 return _ ("INVALID");
1143}
1144
1145
1146/**
1147 * Convert a hash to a string (for printing debug messages).
1148 *
1149 * @param hc the hash code
1150 * @return string form; will be overwritten by next call to GNUNET_h2s.
1151 */
1152const char *
1153GNUNET_h2s (const struct GNUNET_HashCode *hc)
1154{
1155 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1156
1157 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1158 ret.encoding[8] = '\0';
1159 return (const char *) ret.encoding;
1160}
1161
1162
1163/**
1164 * Convert a hash to a string (for printing debug messages).
1165 * This is one of the very few calls in the entire API that is
1166 * NOT reentrant! Identical to #GNUNET_h2s(), except that another
1167 * buffer is used so both #GNUNET_h2s() and #GNUNET_h2s2() can be
1168 * used within the same log statement.
1169 *
1170 * @param hc the hash code
1171 * @return string form; will be overwritten by next call to GNUNET_h2s.
1172 */
1173const char *
1174GNUNET_h2s2 (const struct GNUNET_HashCode *hc)
1175{
1176 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1177
1178 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1179 ret.encoding[8] = '\0';
1180 return (const char *) ret.encoding;
1181}
1182
1183
1184/**
1185 * @ingroup logging
1186 * Convert a public key value to a string (for printing debug messages).
1187 * This is one of the very few calls in the entire API that is
1188 * NOT reentrant!
1189 *
1190 * @param hc the hash code
1191 * @return string
1192 */
1193const char *
1194GNUNET_p2s (const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1195{
1196 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1197 struct GNUNET_HashCode hc;
1198
1199 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1200 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1201 ret.encoding[6] = '\0';
1202 return (const char *) ret.encoding;
1203}
1204
1205
1206/**
1207 * @ingroup logging
1208 * Convert a public key value to a string (for printing debug messages).
1209 * This is one of the very few calls in the entire API that is
1210 * NOT reentrant!
1211 *
1212 * @param hc the hash code
1213 * @return string
1214 */
1215const char *
1216GNUNET_p2s2 (const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1217{
1218 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1219 struct GNUNET_HashCode hc;
1220
1221 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1222 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1223 ret.encoding[6] = '\0';
1224 return (const char *) ret.encoding;
1225}
1226
1227
1228/**
1229 * @ingroup logging
1230 * Convert a public key value to a string (for printing debug messages).
1231 * This is one of the very few calls in the entire API that is
1232 * NOT reentrant!
1233 *
1234 * @param hc the hash code
1235 * @return string
1236 */
1237const char *
1238GNUNET_e2s (const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1239{
1240 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1241 struct GNUNET_HashCode hc;
1242
1243 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1244 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1245 ret.encoding[6] = '\0';
1246 return (const char *) ret.encoding;
1247}
1248
1249
1250/**
1251 * @ingroup logging
1252 * Convert a public key value to a string (for printing debug messages).
1253 * This is one of the very few calls in the entire API that is
1254 * NOT reentrant!
1255 *
1256 * @param hc the hash code
1257 * @return string
1258 */
1259const char *
1260GNUNET_e2s2 (const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1261{
1262 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1263 struct GNUNET_HashCode hc;
1264
1265 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1266 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1267 ret.encoding[6] = '\0';
1268 return (const char *) ret.encoding;
1269}
1270
1271
1272/**
1273 * @ingroup logging
1274 * Convert a short hash value to a string (for printing debug messages).
1275 * This is one of the very few calls in the entire API that is
1276 * NOT reentrant!
1277 *
1278 * @param shc the hash code
1279 * @return string
1280 */
1281const char *
1282GNUNET_sh2s (const struct GNUNET_ShortHashCode *shc)
1283{
1284 static GNUNET_THREAD_LOCAL char buf[64];
1285
1286 GNUNET_STRINGS_data_to_string (shc, sizeof(*shc), buf, sizeof(buf));
1287 buf[6] = '\0';
1288 return (const char *) buf;
1289}
1290
1291
1292/**
1293 * @ingroup logging
1294 * Convert a UUID to a string (for printing debug messages).
1295 * This is one of the very few calls in the entire API that is
1296 * NOT reentrant!
1297 *
1298 * @param uuid the UUID
1299 * @return string
1300 */
1301const char *
1302GNUNET_uuid2s (const struct GNUNET_Uuid *uuid)
1303{
1304 static GNUNET_THREAD_LOCAL char buf[32];
1305
1306 GNUNET_STRINGS_data_to_string (uuid, sizeof(*uuid), buf, sizeof(buf));
1307 buf[6] = '\0';
1308 return (const char *) buf;
1309}
1310
1311
1312/**
1313 * Convert a hash to a string (for printing debug messages).
1314 * This is one of the very few calls in the entire API that is
1315 * NOT reentrant!
1316 *
1317 * @param hc the hash code
1318 * @return string form; will be overwritten by next call to GNUNET_h2s_full.
1319 */
1320const char *
1321GNUNET_h2s_full (const struct GNUNET_HashCode *hc)
1322{
1323 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1324
1325 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1326 ret.encoding[sizeof(ret) - 1] = '\0';
1327 return (const char *) ret.encoding;
1328}
1329
1330
1331/**
1332 * Convert a peer identity to a string (for printing debug messages).
1333 *
1334 * @param pid the peer identity
1335 * @return string form of the pid; will be overwritten by next
1336 * call to #GNUNET_i2s.
1337 */
1338const char *
1339GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
1340{
1341 static GNUNET_THREAD_LOCAL char buf[5];
1342 char *ret;
1343
1344 if (NULL == pid)
1345 return "NULL";
1346 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1347 GNUNET_strlcpy (buf, ret, sizeof(buf));
1348 GNUNET_free (ret);
1349 return buf;
1350}
1351
1352
1353/**
1354 * Convert a peer identity to a string (for printing debug messages).
1355 * Identical to #GNUNET_i2s(), except that another
1356 * buffer is used so both #GNUNET_i2s() and #GNUNET_i2s2() can be
1357 * used within the same log statement.
1358 *
1359 * @param pid the peer identity
1360 * @return string form of the pid; will be overwritten by next
1361 * call to #GNUNET_i2s.
1362 */
1363const char *
1364GNUNET_i2s2 (const struct GNUNET_PeerIdentity *pid)
1365{
1366 static GNUNET_THREAD_LOCAL char buf[5];
1367 char *ret;
1368
1369 if (NULL == pid)
1370 return "NULL";
1371 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1372 GNUNET_strlcpy (buf, ret, sizeof(buf));
1373 GNUNET_free (ret);
1374 return buf;
1375}
1376
1377
1378/**
1379 * Convert a peer identity to a string (for printing debug messages).
1380 *
1381 * @param pid the peer identity
1382 * @return string form of the pid; will be overwritten by next
1383 * call to #GNUNET_i2s_full.
1384 */
1385const char *
1386GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid)
1387{
1388 static GNUNET_THREAD_LOCAL char buf[256];
1389 char *ret;
1390
1391 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1392 strcpy (buf, ret);
1393 GNUNET_free (ret);
1394 return buf;
1395}
1396
1397
1398/**
1399 * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string
1400 * (for printing debug messages). This is one of the very few calls
1401 * in the entire API that is NOT reentrant!
1402 *
1403 * @param addr the address
1404 * @param addrlen the length of the address in @a addr
1405 * @return nicely formatted string for the address
1406 * will be overwritten by next call to #GNUNET_a2s.
1407 */
1408const char *
1409GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
1410{
1411#define LEN \
1412 GNUNET_MAX ((INET6_ADDRSTRLEN + 8), \
1413 (1 + sizeof(struct sockaddr_un) - sizeof(sa_family_t)))
1414 static GNUNET_THREAD_LOCAL char buf[LEN];
1415#undef LEN
1416 static GNUNET_THREAD_LOCAL char b2[6];
1417 const struct sockaddr_in *v4;
1418 const struct sockaddr_un *un;
1419 const struct sockaddr_in6 *v6;
1420 unsigned int off;
1421
1422 if (addr == NULL)
1423 return _ ("unknown address");
1424 switch (addr->sa_family)
1425 {
1426 case AF_INET:
1427 if (addrlen != sizeof(struct sockaddr_in))
1428 return "<invalid v4 address>";
1429 v4 = (const struct sockaddr_in *) addr;
1430 inet_ntop (AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN);
1431 if (0 == ntohs (v4->sin_port))
1432 return buf;
1433 strcat (buf, ":");
1434 GNUNET_snprintf (b2, sizeof(b2), "%u", ntohs (v4->sin_port));
1435 strcat (buf, b2);
1436 return buf;
1437
1438 case AF_INET6:
1439 if (addrlen != sizeof(struct sockaddr_in6))
1440 return "<invalid v6 address>";
1441 v6 = (const struct sockaddr_in6 *) addr;
1442 buf[0] = '[';
1443 inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN);
1444 if (0 == ntohs (v6->sin6_port))
1445 return &buf[1];
1446 strcat (buf, "]:");
1447 GNUNET_snprintf (b2, sizeof(b2), "%u", ntohs (v6->sin6_port));
1448 strcat (buf, b2);
1449 return buf;
1450
1451 case AF_UNIX:
1452 if (addrlen <= sizeof(sa_family_t))
1453 return "<unbound UNIX client>";
1454 un = (const struct sockaddr_un *) addr;
1455 off = 0;
1456 if ('\0' == un->sun_path[0])
1457 off++;
1458 memset (buf, 0, sizeof(buf));
1459 GNUNET_snprintf (buf,
1460 sizeof(buf),
1461 "%s%.*s",
1462 (1 == off) ? "@" : "",
1463 (int) (addrlen - sizeof(sa_family_t) - off),
1464 &un->sun_path[off]);
1465 return buf;
1466
1467 default:
1468 return _ ("invalid address");
1469 }
1470}
1471
1472
1473/**
1474 * Log error message about missing configuration option.
1475 *
1476 * @param kind log level
1477 * @param section section with missing option
1478 * @param option name of missing option
1479 */
1480void
1481GNUNET_log_config_missing (enum GNUNET_ErrorType kind,
1482 const char *section,
1483 const char *option)
1484{
1485 GNUNET_log (kind,
1486 _ (
1487 "Configuration fails to specify option `%s' in section `%s'!\n"),
1488 option,
1489 section);
1490}
1491
1492
1493/**
1494 * Log error message about invalid configuration option value.
1495 *
1496 * @param kind log level
1497 * @param section section with invalid option
1498 * @param option name of invalid option
1499 * @param required what is required that is invalid about the option
1500 */
1501void
1502GNUNET_log_config_invalid (enum GNUNET_ErrorType kind,
1503 const char *section,
1504 const char *option,
1505 const char *required)
1506{
1507 GNUNET_log (
1508 kind,
1509 _ (
1510 "Configuration specifies invalid value for option `%s' in section `%s': %s\n"),
1511 option,
1512 section,
1513 required);
1514}
1515
1516
1517/**
1518 * Set the async scope for the current thread.
1519 *
1520 * @param aid the async scope identifier
1521 * @param old_scope[out] location to save the old scope
1522 */
1523void
1524GNUNET_async_scope_enter (const struct GNUNET_AsyncScopeId *aid,
1525 struct GNUNET_AsyncScopeSave *old_scope)
1526{
1527 *old_scope = current_async_scope;
1528 current_async_scope.have_scope = GNUNET_YES;
1529 current_async_scope.scope_id = *aid;
1530}
1531
1532
1533/**
1534 * Clear the current thread's async scope.
1535 *
1536 * @param old_scope scope to restore
1537 */
1538void
1539GNUNET_async_scope_restore (struct GNUNET_AsyncScopeSave *old_scope)
1540{
1541 current_async_scope = *old_scope;
1542}
1543
1544
1545/**
1546 * Generate a fresh async scope identifier.
1547 *
1548 * @param[out] aid_ret pointer to where the result is stored
1549 */
1550void
1551GNUNET_async_scope_fresh (struct GNUNET_AsyncScopeId *aid_ret)
1552{
1553 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1554 aid_ret,
1555 sizeof(struct GNUNET_AsyncScopeId));
1556}
1557
1558
1559/**
1560 * Get the current async scope.
1561 *
1562 * @param[out] scope_ret pointer to where the result is stored
1563 */
1564void
1565GNUNET_async_scope_get (struct GNUNET_AsyncScopeSave *scope_ret)
1566{
1567 *scope_ret = current_async_scope;
1568}
1569
1570
1571/**
1572 * Initializer
1573 */
1574void __attribute__ ((constructor))
1575GNUNET_util_cl_init ()
1576{
1577 GNUNET_stderr = stderr;
1578}
1579
1580
1581/**
1582 * Destructor
1583 */
1584void __attribute__ ((destructor))
1585GNUNET_util_cl_fini ()
1586{
1587
1588}
1589
1590
1591/* 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 9f6c3c0cc..000000000
--- a/src/util/container_bloomfilter.c
+++ /dev/null
@@ -1,816 +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
86size_t
87GNUNET_CONTAINER_bloomfilter_get_element_addresses (
88 const struct GNUNET_CONTAINER_BloomFilter *bf)
89{
90 if (bf == NULL)
91 return 0;
92 return bf->addressesPerElement;
93}
94
95
96size_t
97GNUNET_CONTAINER_bloomfilter_get_size (
98 const struct GNUNET_CONTAINER_BloomFilter *bf)
99{
100 if (bf == NULL)
101 return 0;
102 return bf->bitArraySize;
103}
104
105
106struct GNUNET_CONTAINER_BloomFilter *
107GNUNET_CONTAINER_bloomfilter_copy (
108 const struct GNUNET_CONTAINER_BloomFilter *bf)
109{
110 return GNUNET_CONTAINER_bloomfilter_init (bf->bitArray,
111 bf->bitArraySize,
112 bf->addressesPerElement);
113}
114
115
116/**
117 * Sets a bit active in the bitArray. Increment bit-specific
118 * usage counter on disk only if below 4bit max (==15).
119 *
120 * @param bitArray memory area to set the bit in
121 * @param bitIdx which bit to set
122 */
123static void
124setBit (char *bitArray,
125 unsigned int bitIdx)
126{
127 size_t arraySlot;
128 unsigned int targetBit;
129
130 arraySlot = bitIdx / 8;
131 targetBit = (1L << (bitIdx % 8));
132 bitArray[arraySlot] |= targetBit;
133}
134
135
136/**
137 * Clears a bit from bitArray. Bit is cleared from the array
138 * only if the respective usage counter on the disk hits/is zero.
139 *
140 * @param bitArray memory area to set the bit in
141 * @param bitIdx which bit to unset
142 */
143static void
144clearBit (char *bitArray, unsigned int bitIdx)
145{
146 size_t slot;
147 unsigned int targetBit;
148
149 slot = bitIdx / 8;
150 targetBit = (1L << (bitIdx % 8));
151 bitArray[slot] = bitArray[slot] & (~targetBit);
152}
153
154
155/**
156 * Checks if a bit is active in the bitArray
157 *
158 * @param bitArray memory area to set the bit in
159 * @param bitIdx which bit to test
160 * @return true if the bit is set, false if not.
161 */
162static bool
163testBit (char *bitArray,
164 unsigned int bitIdx)
165{
166 size_t slot;
167 unsigned int targetBit;
168
169 slot = bitIdx / 8;
170 targetBit = (1L << (bitIdx % 8));
171 if (bitArray[slot] & targetBit)
172 return true;
173 return false;
174}
175
176
177/**
178 * Sets a bit active in the bitArray and increments
179 * bit-specific usage counter on disk (but only if
180 * the counter was below 4 bit max (==15)).
181 *
182 * @param bitArray memory area to set the bit in
183 * @param bitIdx which bit to test
184 * @param fh A file to keep the 4 bit address usage counters in
185 */
186static void
187incrementBit (char *bitArray,
188 unsigned int bitIdx,
189 const struct GNUNET_DISK_FileHandle *fh)
190{
191 off_t fileSlot;
192 unsigned char value;
193 unsigned int high;
194 unsigned int low;
195 unsigned int targetLoc;
196
197 setBit (bitArray,
198 bitIdx);
199 if (GNUNET_DISK_handle_invalid (fh))
200 return;
201 /* Update the counter file on disk */
202 fileSlot = bitIdx / 2;
203 targetLoc = bitIdx % 2;
204
205 GNUNET_assert (fileSlot ==
206 GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET));
207 if (1 != GNUNET_DISK_file_read (fh, &value, 1))
208 value = 0;
209 low = value & 0xF;
210 high = (value & (~0xF)) >> 4;
211
212 if (targetLoc == 0)
213 {
214 if (low < 0xF)
215 low++;
216 }
217 else
218 {
219 if (high < 0xF)
220 high++;
221 }
222 value = ((high << 4) | low);
223 GNUNET_assert (fileSlot ==
224 GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET));
225 GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1));
226}
227
228
229/**
230 * Clears a bit from bitArray if the respective usage
231 * counter on the disk hits/is zero.
232 *
233 * @param bitArray memory area to set the bit in
234 * @param bitIdx which bit to test
235 * @param fh A file to keep the 4bit address usage counters in
236 */
237static void
238decrementBit (char *bitArray,
239 unsigned int bitIdx,
240 const struct GNUNET_DISK_FileHandle *fh)
241{
242 off_t fileslot;
243 unsigned char value;
244 unsigned int high;
245 unsigned int low;
246 unsigned int targetLoc;
247
248 if (GNUNET_DISK_handle_invalid (fh))
249 return; /* cannot decrement! */
250 /* Each char slot in the counter file holds two 4 bit counters */
251 fileslot = bitIdx / 2;
252 targetLoc = bitIdx % 2;
253 if (GNUNET_SYSERR ==
254 GNUNET_DISK_file_seek (fh, fileslot, GNUNET_DISK_SEEK_SET))
255 {
256 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "seek");
257 return;
258 }
259 if (1 != GNUNET_DISK_file_read (fh, &value, 1))
260 value = 0;
261 low = value & 0xF;
262 high = (value & 0xF0) >> 4;
263
264 /* decrement, but once we have reached the max, never go back! */
265 if (targetLoc == 0)
266 {
267 if ((low > 0) && (low < 0xF))
268 low--;
269 if (low == 0)
270 {
271 clearBit (bitArray, bitIdx);
272 }
273 }
274 else
275 {
276 if ((high > 0) && (high < 0xF))
277 high--;
278 if (high == 0)
279 {
280 clearBit (bitArray, bitIdx);
281 }
282 }
283 value = ((high << 4) | low);
284 if (GNUNET_SYSERR ==
285 GNUNET_DISK_file_seek (fh, fileslot, GNUNET_DISK_SEEK_SET))
286 {
287 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "seek");
288 return;
289 }
290 GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1));
291}
292
293
294#define BUFFSIZE 65536
295
296/**
297 * Creates a file filled with zeroes
298 *
299 * @param fh the file handle
300 * @param size the size of the file
301 * @return #GNUNET_OK if created ok, #GNUNET_SYSERR otherwise
302 */
303static enum GNUNET_GenericReturnValue
304make_empty_file (const struct GNUNET_DISK_FileHandle *fh,
305 size_t size)
306{
307 char buffer[BUFFSIZE];
308 size_t bytesleft = size;
309 int res = 0;
310
311 if (GNUNET_DISK_handle_invalid (fh))
312 return GNUNET_SYSERR;
313 memset (buffer, 0, sizeof(buffer));
314 GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_SET);
315 while (bytesleft > 0)
316 {
317 if (bytesleft > sizeof(buffer))
318 {
319 res = GNUNET_DISK_file_write (fh, buffer, sizeof(buffer));
320 if (res >= 0)
321 bytesleft -= res;
322 }
323 else
324 {
325 res = GNUNET_DISK_file_write (fh, buffer, bytesleft);
326 if (res >= 0)
327 bytesleft -= res;
328 }
329 if (GNUNET_SYSERR == res)
330 return GNUNET_SYSERR;
331 }
332 return GNUNET_OK;
333}
334
335
336/* ************** GNUNET_CONTAINER_BloomFilter iterator ********* */
337
338/**
339 * Iterator (callback) method to be called by the
340 * bloomfilter iterator on each bit that is to be
341 * set or tested for the key.
342 *
343 * @param cls closure
344 * @param bf the filter to manipulate
345 * @param bit the current bit
346 * @return #GNUNET_YES to continue, #GNUNET_NO to stop early
347 */
348typedef enum GNUNET_GenericReturnValue
349(*BitIterator)(void *cls,
350 const struct GNUNET_CONTAINER_BloomFilter *bf,
351 unsigned int bit);
352
353
354/**
355 * Call an iterator for each bit that the bloomfilter
356 * must test or set for this element.
357 *
358 * @param bf the filter
359 * @param callback the method to call
360 * @param arg extra argument to callback
361 * @param key the key for which we iterate over the BF bits
362 */
363static void
364iterateBits (const struct GNUNET_CONTAINER_BloomFilter *bf,
365 BitIterator callback,
366 void *arg,
367 const struct GNUNET_HashCode *key)
368{
369 struct GNUNET_HashCode tmp = *key;
370 int bitCount;
371 unsigned int slot = 0;
372
373 bitCount = bf->addressesPerElement;
374 GNUNET_assert (bf->bitArraySize > 0);
375 GNUNET_assert (bf->bitArraySize * 8LL > bf->bitArraySize);
376 while (bitCount > 0)
377 {
378 while ( (0 != bitCount) &&
379 (slot < (sizeof(struct GNUNET_HashCode) / sizeof(uint32_t))) )
380 {
381 if (GNUNET_YES !=
382 callback (arg,
383 bf,
384 ntohl ((((uint32_t *) &tmp)[slot]))
385 % ((bf->bitArraySize * 8LL))))
386 return;
387 slot++;
388 bitCount--;
389 }
390 if (0 == bitCount)
391 break;
392 GNUNET_CRYPTO_hash (&tmp,
393 sizeof(tmp),
394 &tmp);
395 slot = 0;
396 }
397}
398
399
400/**
401 * Callback: increment bit
402 *
403 * @param cls pointer to writeable form of bf
404 * @param bf the filter to manipulate
405 * @param bit the bit to increment
406 * @return #GNUNET_YES
407 */
408static enum GNUNET_GenericReturnValue
409incrementBitCallback (void *cls,
410 const struct GNUNET_CONTAINER_BloomFilter *bf,
411 unsigned int bit)
412{
413 struct GNUNET_CONTAINER_BloomFilter *b = cls;
414
415 incrementBit (b->bitArray,
416 bit,
417 bf->fh);
418 return GNUNET_YES;
419}
420
421
422/**
423 * Callback: decrement bit
424 *
425 * @param cls pointer to writeable form of bf
426 * @param bf the filter to manipulate
427 * @param bit the bit to decrement
428 * @return #GNUNET_YES
429 */
430static enum GNUNET_GenericReturnValue
431decrementBitCallback (void *cls,
432 const struct GNUNET_CONTAINER_BloomFilter *bf,
433 unsigned int bit)
434{
435 struct GNUNET_CONTAINER_BloomFilter *b = cls;
436
437 decrementBit (b->bitArray,
438 bit,
439 bf->fh);
440 return GNUNET_YES;
441}
442
443
444/**
445 * Callback: test if all bits are set
446 *
447 * @param cls pointer set to false if bit is not set
448 * @param bf the filter
449 * @param bit the bit to test
450 * @return #GNUNET_YES if the bit is set, #GNUNET_NO if not
451 */
452static enum GNUNET_GenericReturnValue
453testBitCallback (void *cls,
454 const struct GNUNET_CONTAINER_BloomFilter *bf,
455 unsigned int bit)
456{
457 bool *arg = cls;
458
459 if (! testBit (bf->bitArray, bit))
460 {
461 *arg = false;
462 return GNUNET_NO;
463 }
464 return GNUNET_YES;
465}
466
467
468/* *********************** INTERFACE **************** */
469
470/**
471 * Load a bloom-filter from a file.
472 *
473 * @param filename the name of the file (or the prefix)
474 * @param size the size of the bloom-filter (number of
475 * bytes of storage space to use); will be rounded up
476 * to next power of 2
477 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per
478 * element (number of bits set per element in the set)
479 * @return the bloomfilter
480 */
481struct GNUNET_CONTAINER_BloomFilter *
482GNUNET_CONTAINER_bloomfilter_load (const char *filename,
483 size_t size,
484 unsigned int k)
485{
486 struct GNUNET_CONTAINER_BloomFilter *bf;
487 char *rbuff;
488 off_t pos;
489 int i;
490 size_t ui;
491 off_t fsize;
492 int must_read;
493
494 GNUNET_assert (NULL != filename);
495 if ((k == 0) || (size == 0))
496 return NULL;
497 if (size < BUFFSIZE)
498 size = BUFFSIZE;
499 ui = 1;
500 while ((ui < size) && (ui * 2 > ui))
501 ui *= 2;
502 size = ui; /* make sure it's a power of 2 */
503
504 bf = GNUNET_new (struct GNUNET_CONTAINER_BloomFilter);
505 /* Try to open a bloomfilter file */
506 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
507 bf->fh = GNUNET_DISK_file_open (filename,
508 GNUNET_DISK_OPEN_READWRITE,
509 GNUNET_DISK_PERM_USER_READ
510 | GNUNET_DISK_PERM_USER_WRITE);
511 if (NULL != bf->fh)
512 {
513 /* file existed, try to read it! */
514 must_read = GNUNET_YES;
515 if (GNUNET_OK !=
516 GNUNET_DISK_file_handle_size (bf->fh,
517 &fsize))
518 {
519 GNUNET_DISK_file_close (bf->fh);
520 GNUNET_free (bf);
521 return NULL;
522 }
523 if (0 == fsize)
524 {
525 /* found existing empty file, just overwrite */
526 if (GNUNET_OK !=
527 make_empty_file (bf->fh,
528 size * 4LL))
529 {
530 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
531 "write");
532 GNUNET_DISK_file_close (bf->fh);
533 GNUNET_free (bf);
534 return NULL;
535 }
536 }
537 else if (fsize != ((off_t) size) * 4LL)
538 {
539 GNUNET_log (
540 GNUNET_ERROR_TYPE_ERROR,
541 _ (
542 "Size of file on disk is incorrect for this Bloom filter (want %llu, have %llu)\n"),
543 (unsigned long long) (size * 4LL),
544 (unsigned long long) fsize);
545 GNUNET_DISK_file_close (bf->fh);
546 GNUNET_free (bf);
547 return NULL;
548 }
549 }
550 else
551 {
552 /* file did not exist, don't read, just create */
553 must_read = GNUNET_NO;
554 bf->fh = GNUNET_DISK_file_open (filename,
555 GNUNET_DISK_OPEN_CREATE
556 | GNUNET_DISK_OPEN_READWRITE,
557 GNUNET_DISK_PERM_USER_READ
558 | GNUNET_DISK_PERM_USER_WRITE);
559 if (NULL == bf->fh)
560 {
561 GNUNET_free (bf);
562 return NULL;
563 }
564 if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL))
565 {
566 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
567 GNUNET_DISK_file_close (bf->fh);
568 GNUNET_free (bf);
569 return NULL;
570 }
571 }
572 bf->filename = GNUNET_strdup (filename);
573 /* Alloc block */
574 bf->bitArray = GNUNET_malloc_large (size);
575 if (NULL == bf->bitArray)
576 {
577 if (NULL != bf->fh)
578 GNUNET_DISK_file_close (bf->fh);
579 GNUNET_free (bf->filename);
580 GNUNET_free (bf);
581 return NULL;
582 }
583 bf->bitArraySize = size;
584 bf->addressesPerElement = k;
585 if (GNUNET_YES != must_read)
586 return bf; /* already done! */
587 /* Read from the file what bits we can */
588 rbuff = GNUNET_malloc (BUFFSIZE);
589 pos = 0;
590 while (pos < ((off_t) size) * 8LL)
591 {
592 int res;
593
594 res = GNUNET_DISK_file_read (bf->fh, rbuff, BUFFSIZE);
595 if (res == -1)
596 {
597 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", bf->filename);
598 GNUNET_free (rbuff);
599 GNUNET_free (bf->filename);
600 GNUNET_DISK_file_close (bf->fh);
601 GNUNET_free (bf);
602 return NULL;
603 }
604 if (res == 0)
605 break; /* is ok! we just did not use that many bits yet */
606 for (i = 0; i < res; i++)
607 {
608 if ((rbuff[i] & 0x0F) != 0)
609 setBit (bf->bitArray, pos + i * 2);
610 if ((rbuff[i] & 0xF0) != 0)
611 setBit (bf->bitArray, pos + i * 2 + 1);
612 }
613 if (res < BUFFSIZE)
614 break;
615 pos += BUFFSIZE * 2; /* 2 bits per byte in the buffer */
616 }
617 GNUNET_free (rbuff);
618 return bf;
619}
620
621
622struct GNUNET_CONTAINER_BloomFilter *
623GNUNET_CONTAINER_bloomfilter_init (const char *data,
624 size_t size,
625 unsigned int k)
626{
627 struct GNUNET_CONTAINER_BloomFilter *bf;
628
629 if ((0 == k) || (0 == size))
630 return NULL;
631 bf = GNUNET_new (struct GNUNET_CONTAINER_BloomFilter);
632 bf->filename = NULL;
633 bf->fh = NULL;
634 bf->bitArray = GNUNET_malloc_large (size);
635 if (NULL == bf->bitArray)
636 {
637 GNUNET_free (bf);
638 return NULL;
639 }
640 bf->bitArraySize = size;
641 bf->addressesPerElement = k;
642 if (NULL != data)
643 GNUNET_memcpy (bf->bitArray, data, size);
644 return bf;
645}
646
647
648enum GNUNET_GenericReturnValue
649GNUNET_CONTAINER_bloomfilter_get_raw_data (
650 const struct GNUNET_CONTAINER_BloomFilter *bf,
651 char *data,
652 size_t size)
653{
654 if (NULL == bf)
655 return GNUNET_SYSERR;
656 if (bf->bitArraySize != size)
657 return GNUNET_SYSERR;
658 GNUNET_memcpy (data, bf->bitArray, size);
659 return GNUNET_OK;
660}
661
662
663void
664GNUNET_CONTAINER_bloomfilter_free (struct GNUNET_CONTAINER_BloomFilter *bf)
665{
666 if (NULL == bf)
667 return;
668 if (bf->fh != NULL)
669 GNUNET_DISK_file_close (bf->fh);
670 GNUNET_free (bf->filename);
671 GNUNET_free (bf->bitArray);
672 GNUNET_free (bf);
673}
674
675
676void
677GNUNET_CONTAINER_bloomfilter_clear (struct GNUNET_CONTAINER_BloomFilter *bf)
678{
679 if (NULL == bf)
680 return;
681
682 memset (bf->bitArray, 0, bf->bitArraySize);
683 if (bf->filename != NULL)
684 make_empty_file (bf->fh, bf->bitArraySize * 4LL);
685}
686
687
688bool
689GNUNET_CONTAINER_bloomfilter_test (
690 const struct GNUNET_CONTAINER_BloomFilter *bf,
691 const struct GNUNET_HashCode *e)
692{
693 bool res;
694
695 if (NULL == bf)
696 return true;
697 res = true;
698 iterateBits (bf,
699 &testBitCallback,
700 &res,
701 e);
702 return res;
703}
704
705
706void
707GNUNET_CONTAINER_bloomfilter_add (struct GNUNET_CONTAINER_BloomFilter *bf,
708 const struct GNUNET_HashCode *e)
709{
710 if (NULL == bf)
711 return;
712 iterateBits (bf,
713 &incrementBitCallback,
714 bf,
715 e);
716}
717
718
719enum GNUNET_GenericReturnValue
720GNUNET_CONTAINER_bloomfilter_or (struct GNUNET_CONTAINER_BloomFilter *bf,
721 const char *data,
722 size_t size)
723{
724 unsigned int i;
725 unsigned int n;
726 unsigned long long *fc;
727 const unsigned long long *dc;
728
729 if (NULL == bf)
730 return GNUNET_YES;
731 if (bf->bitArraySize != size)
732 return GNUNET_SYSERR;
733 fc = (unsigned long long *) bf->bitArray;
734 dc = (const unsigned long long *) data;
735 n = size / sizeof(unsigned long long);
736
737 for (i = 0; i < n; i++)
738 fc[i] |= dc[i];
739 for (i = n * sizeof(unsigned long long); i < size; i++)
740 bf->bitArray[i] |= data[i];
741 return GNUNET_OK;
742}
743
744
745enum GNUNET_GenericReturnValue
746GNUNET_CONTAINER_bloomfilter_or2 (
747 struct GNUNET_CONTAINER_BloomFilter *bf,
748 const struct GNUNET_CONTAINER_BloomFilter *to_or)
749{
750 unsigned int i;
751 unsigned int n;
752 unsigned long long *fc;
753 const unsigned long long *dc;
754 size_t size;
755
756 if (NULL == bf)
757 return GNUNET_OK;
758 if (bf->bitArraySize != to_or->bitArraySize)
759 {
760 GNUNET_break (0);
761 return GNUNET_SYSERR;
762 }
763 size = bf->bitArraySize;
764 fc = (unsigned long long *) bf->bitArray;
765 dc = (const unsigned long long *) to_or->bitArray;
766 n = size / sizeof(unsigned long long);
767
768 for (i = 0; i < n; i++)
769 fc[i] |= dc[i];
770 for (i = n * sizeof(unsigned long long); i < size; i++)
771 bf->bitArray[i] |= to_or->bitArray[i];
772 return GNUNET_OK;
773}
774
775
776void
777GNUNET_CONTAINER_bloomfilter_remove (struct GNUNET_CONTAINER_BloomFilter *bf,
778 const struct GNUNET_HashCode *e)
779{
780 if (NULL == bf)
781 return;
782 if (NULL == bf->filename)
783 return;
784 iterateBits (bf,
785 &decrementBitCallback,
786 bf,
787 e);
788}
789
790
791void
792GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf,
793 GNUNET_CONTAINER_HashCodeIterator iterator,
794 void *iterator_cls,
795 size_t size,
796 unsigned int k)
797{
798 struct GNUNET_HashCode hc;
799 unsigned int i;
800
801 GNUNET_free (bf->bitArray);
802 i = 1;
803 while (i < size)
804 i *= 2;
805 size = i; /* make sure it's a power of 2 */
806 bf->addressesPerElement = k;
807 bf->bitArraySize = size;
808 bf->bitArray = GNUNET_malloc (size);
809 if (NULL != bf->filename)
810 make_empty_file (bf->fh, bf->bitArraySize * 4LL);
811 while (GNUNET_YES == iterator (iterator_cls, &hc))
812 GNUNET_CONTAINER_bloomfilter_add (bf, &hc);
813}
814
815
816/* 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_cs.c b/src/util/crypto_cs.c
deleted file mode 100644
index 4c6648229..000000000
--- a/src/util/crypto_cs.c
+++ /dev/null
@@ -1,343 +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_cs.c
23 * @brief Clause Blind Schnorr signatures using Curve25519
24 * @author Lucien Heuzeveldt <lucienclaude.heuzeveldt@students.bfh.ch>
25 * @author Gian Demarmels <gian@demarmels.org>
26 */
27#include "platform.h"
28#include "gnunet_crypto_lib.h"
29#include <sodium.h>
30#include <gcrypt.h>
31
32/**
33 * IMPLEMENTATION NOTICE:
34 *
35 * This is an implementation of the Clause Blind Schnorr Signature Scheme using Curve25519.
36 * Further details about the Clause Blind Schnorr Signature Scheme can be found here:
37 * https://eprint.iacr.org/2019/877.pdf
38 *
39 * We use libsodium wherever possible.
40 */
41
42
43void
44GNUNET_CRYPTO_cs_private_key_generate (struct GNUNET_CRYPTO_CsPrivateKey *priv)
45{
46 crypto_core_ed25519_scalar_random (priv->scalar.d);
47}
48
49
50void
51GNUNET_CRYPTO_cs_private_key_get_public (
52 const struct GNUNET_CRYPTO_CsPrivateKey *priv,
53 struct GNUNET_CRYPTO_CsPublicKey *pub)
54{
55 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (pub->point.y,
56 priv->scalar.d));
57}
58
59
60/**
61 * Maps 32 random bytes to a scalar. This is necessary because libsodium
62 * expects scalar to be in the prime order subgroup.
63 *
64 * @param[in,out] scalar containing 32 byte char array, is modified to be in prime order subgroup
65 */
66static void
67map_to_scalar_subgroup (struct GNUNET_CRYPTO_Cs25519Scalar *scalar)
68{
69 /* perform clamping as described in RFC7748 */
70 scalar->d[0] &= 248;
71 scalar->d[31] &= 127;
72 scalar->d[31] |= 64;
73}
74
75
76void
77GNUNET_CRYPTO_cs_r_derive (const struct GNUNET_CRYPTO_CsNonce *nonce,
78 const char *seed,
79 const struct GNUNET_CRYPTO_CsPrivateKey *lts,
80 struct GNUNET_CRYPTO_CsRSecret r[2])
81{
82 GNUNET_assert (
83 GNUNET_YES ==
84 GNUNET_CRYPTO_kdf (
85 r, sizeof (struct GNUNET_CRYPTO_CsRSecret) * 2,
86 seed, strlen (seed),
87 lts, sizeof (*lts),
88 nonce, sizeof (*nonce),
89 NULL, 0));
90 map_to_scalar_subgroup (&r[0].scalar);
91 map_to_scalar_subgroup (&r[1].scalar);
92}
93
94
95void
96GNUNET_CRYPTO_cs_r_get_public (const struct GNUNET_CRYPTO_CsRSecret *r_priv,
97 struct GNUNET_CRYPTO_CsRPublic *r_pub)
98{
99 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (r_pub->point.y,
100 r_priv->scalar.d));
101}
102
103
104void
105GNUNET_CRYPTO_cs_blinding_secrets_derive (
106 const struct GNUNET_CRYPTO_CsNonce *blind_seed,
107 struct GNUNET_CRYPTO_CsBlindingSecret bs[2])
108{
109 GNUNET_assert (
110 GNUNET_YES ==
111 GNUNET_CRYPTO_hkdf (bs,
112 sizeof (struct GNUNET_CRYPTO_CsBlindingSecret) * 2,
113 GCRY_MD_SHA512,
114 GCRY_MD_SHA256,
115 "alphabeta",
116 strlen ("alphabeta"),
117 blind_seed,
118 sizeof(*blind_seed),
119 NULL,
120 0));
121 map_to_scalar_subgroup (&bs[0].alpha);
122 map_to_scalar_subgroup (&bs[0].beta);
123 map_to_scalar_subgroup (&bs[1].alpha);
124 map_to_scalar_subgroup (&bs[1].beta);
125}
126
127
128/*
129order of subgroup required for scalars by libsodium
1302^252 + 27742317777372353535851937790883648493
131copied from https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c
132and converted to big endian
133*/
134static const unsigned char L_BIG_ENDIAN[32] = {
135 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7,
137 0x9c, 0xd6, 0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed
138};
139
140
141/**
142 * Computes a Hash of (R', m) mapped to a Curve25519 scalar
143 *
144 * @param hash initial hash of the message to be signed
145 * @param pub denomination public key (used as salt)
146 * @param[out] c C containing scalar
147 */
148static void
149cs_full_domain_hash (const struct GNUNET_CRYPTO_CsRPublic *r_dash,
150 const void *msg,
151 size_t msg_len,
152 const struct GNUNET_CRYPTO_CsPublicKey *pub,
153 struct GNUNET_CRYPTO_CsC *c)
154{
155 // SHA-512 hash of R' and message
156 size_t r_m_concat_len = sizeof(struct GNUNET_CRYPTO_CsRPublic) + msg_len;
157 char r_m_concat[r_m_concat_len];
158 memcpy (r_m_concat, r_dash, sizeof(struct GNUNET_CRYPTO_CsRPublic));
159 memcpy (r_m_concat + sizeof(struct GNUNET_CRYPTO_CsRPublic), msg, msg_len);
160 struct GNUNET_HashCode prehash;
161
162 GNUNET_CRYPTO_hash (r_m_concat,
163 r_m_concat_len,
164 &prehash);
165
166 // modulus converted to MPI representation
167 gcry_mpi_t l_mpi;
168 GNUNET_CRYPTO_mpi_scan_unsigned (&l_mpi,
169 L_BIG_ENDIAN,
170 sizeof(L_BIG_ENDIAN));
171
172 // calculate full domain hash
173 gcry_mpi_t c_mpi;
174 GNUNET_CRYPTO_kdf_mod_mpi (&c_mpi,
175 l_mpi,
176 pub,
177 sizeof(struct GNUNET_CRYPTO_CsPublicKey),
178 &prehash,
179 sizeof(struct GNUNET_HashCode),
180 "Curve25519FDH");
181 gcry_mpi_release (l_mpi);
182
183 // convert c from mpi
184 unsigned char c_big_endian[256 / 8];
185 GNUNET_CRYPTO_mpi_print_unsigned (c_big_endian,
186 sizeof(c_big_endian),
187 c_mpi);
188 gcry_mpi_release (c_mpi);
189 for (size_t i = 0; i<32; i++)
190 c->scalar.d[i] = c_big_endian[31 - i];
191}
192
193
194/**
195 * calculate R'
196 *
197 * @param bs blinding secret
198 * @param r_pub R
199 * @param pub public key
200 * @param[out] blinded_r_pub R'
201 */
202static void
203calc_r_dash (const struct GNUNET_CRYPTO_CsBlindingSecret *bs,
204 const struct GNUNET_CRYPTO_CsRPublic *r_pub,
205 const struct GNUNET_CRYPTO_CsPublicKey *pub,
206 struct GNUNET_CRYPTO_CsRPublic *blinded_r_pub)
207{
208 // R'i = Ri + alpha i*G + beta i*pub
209 struct GNUNET_CRYPTO_Cs25519Point alpha_mul_base;
210 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (
211 alpha_mul_base.y,
212 bs->alpha.d));
213 struct GNUNET_CRYPTO_Cs25519Point beta_mul_pub;
214 GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (beta_mul_pub.y,
215 bs->beta.d,
216 pub->point.y));
217 struct GNUNET_CRYPTO_Cs25519Point alpha_mul_base_plus_beta_mul_pub;
218 GNUNET_assert (0 == crypto_core_ed25519_add (
219 alpha_mul_base_plus_beta_mul_pub.y,
220 alpha_mul_base.y,
221 beta_mul_pub.y));
222 GNUNET_assert (0 == crypto_core_ed25519_add (blinded_r_pub->point.y,
223 r_pub->point.y,
224 alpha_mul_base_plus_beta_mul_pub.
225 y));
226}
227
228
229void
230GNUNET_CRYPTO_cs_calc_blinded_c (
231 const struct GNUNET_CRYPTO_CsBlindingSecret bs[2],
232 const struct GNUNET_CRYPTO_CsRPublic r_pub[2],
233 const struct GNUNET_CRYPTO_CsPublicKey *pub,
234 const void *msg,
235 size_t msg_len,
236 struct GNUNET_CRYPTO_CsC blinded_c[2],
237 struct GNUNET_CRYPTO_CsRPublic blinded_r_pub[2])
238{
239 // for i 0/1: R'i = Ri + alpha i*G + beta i*pub
240 calc_r_dash (&bs[0], &r_pub[0], pub, &blinded_r_pub[0]);
241 calc_r_dash (&bs[1], &r_pub[1], pub, &blinded_r_pub[1]);
242
243 // for i 0/1: c'i = H(R'i, msg)
244 struct GNUNET_CRYPTO_CsC c_dash_0;
245 struct GNUNET_CRYPTO_CsC c_dash_1;
246 cs_full_domain_hash (&blinded_r_pub[0], msg, msg_len, pub, &c_dash_0);
247 cs_full_domain_hash (&blinded_r_pub[1], msg, msg_len, pub, &c_dash_1);
248
249 // for i 0/1: ci = c'i + beta i mod p
250 crypto_core_ed25519_scalar_add (blinded_c[0].scalar.d,
251 c_dash_0.scalar.d,
252 bs[0].beta.d);
253 crypto_core_ed25519_scalar_add (blinded_c[1].scalar.d,
254 c_dash_1.scalar.d,
255 bs[1].beta.d);
256}
257
258
259unsigned int
260GNUNET_CRYPTO_cs_sign_derive (
261 const struct GNUNET_CRYPTO_CsPrivateKey *priv,
262 const struct GNUNET_CRYPTO_CsRSecret r[2],
263 const struct GNUNET_CRYPTO_CsC c[2],
264 const struct GNUNET_CRYPTO_CsNonce *nonce,
265 struct GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar)
266{
267 uint32_t hkdf_out;
268
269 // derive clause session identifier b (random bit)
270 GNUNET_assert (GNUNET_YES ==
271 GNUNET_CRYPTO_hkdf (&hkdf_out,
272 sizeof (hkdf_out),
273 GCRY_MD_SHA512,
274 GCRY_MD_SHA256,
275 "b",
276 strlen ("b"),
277 priv,
278 sizeof (*priv),
279 nonce,
280 sizeof (*nonce),
281 NULL,
282 0));
283 unsigned int b = hkdf_out % 2;
284
285 // s = r_b + c_b priv
286 struct GNUNET_CRYPTO_Cs25519Scalar c_b_mul_priv;
287 crypto_core_ed25519_scalar_mul (c_b_mul_priv.d,
288 c[b].scalar.d,
289 priv->scalar.d);
290 crypto_core_ed25519_scalar_add (blinded_signature_scalar->scalar.d,
291 r[b].scalar.d,
292 c_b_mul_priv.d);
293
294 return b;
295}
296
297
298void
299GNUNET_CRYPTO_cs_unblind (
300 const struct GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar,
301 const struct GNUNET_CRYPTO_CsBlindingSecret *bs,
302 struct GNUNET_CRYPTO_CsS *signature_scalar)
303{
304 crypto_core_ed25519_scalar_add (signature_scalar->scalar.d,
305 blinded_signature_scalar->scalar.d,
306 bs->alpha.d);
307}
308
309
310enum GNUNET_GenericReturnValue
311GNUNET_CRYPTO_cs_verify (const struct GNUNET_CRYPTO_CsSignature *sig,
312 const struct GNUNET_CRYPTO_CsPublicKey *pub,
313 const void *msg,
314 size_t msg_len)
315{
316 // calculate c' = H(R, m)
317 struct GNUNET_CRYPTO_CsC c_dash;
318
319 cs_full_domain_hash (&sig->r_point,
320 msg,
321 msg_len,
322 pub,
323 &c_dash);
324
325 // s'G ?= R' + c' pub
326 struct GNUNET_CRYPTO_Cs25519Point sig_scal_mul_base;
327 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (
328 sig_scal_mul_base.y,
329 sig->s_scalar.scalar.d));
330 struct GNUNET_CRYPTO_Cs25519Point c_dash_mul_pub;
331 GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (c_dash_mul_pub.y,
332 c_dash.scalar.d,
333 pub->point.y));
334 struct GNUNET_CRYPTO_Cs25519Point R_add_c_dash_mul_pub;
335 GNUNET_assert (0 == crypto_core_ed25519_add (R_add_c_dash_mul_pub.y,
336 sig->r_point.point.y,
337 c_dash_mul_pub.y));
338
339 return 0 == GNUNET_memcmp (&sig_scal_mul_base,
340 &R_add_c_dash_mul_pub)
341 ? GNUNET_OK
342 : GNUNET_SYSERR;
343}
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 0ee0570c0..000000000
--- a/src/util/crypto_ecc_gnsrecord.c
+++ /dev/null
@@ -1,460 +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
71enum GNUNET_GenericReturnValue
72GNUNET_CRYPTO_eddsa_sign_derived (
73 const struct GNUNET_CRYPTO_EddsaPrivateKey *pkey,
74 const char *label,
75 const char *context,
76 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
77 struct GNUNET_CRYPTO_EddsaSignature *sig)
78{
79 struct GNUNET_CRYPTO_EddsaPrivateScalar priv;
80 crypto_hash_sha512_state hs;
81 unsigned char sk[64];
82 unsigned char r[64];
83 unsigned char hram[64];
84 unsigned char R[32];
85 unsigned char zk[32];
86 unsigned char tmp[32];
87
88 /**
89 * Derive the private key
90 */
91 GNUNET_CRYPTO_eddsa_private_key_derive (pkey,
92 label,
93 context,
94 &priv);
95
96 crypto_hash_sha512_init (&hs);
97
98 /**
99 * Instead of expanding the private here, we already
100 * have the secret scalar as input. Use it.
101 * Note that sk is not plain SHA512 (d).
102 * sk[0..31] contains the derived private scalar
103 * sk[0..31] = h * SHA512 (d)[0..31]
104 * sk[32..63] = SHA512 (d)[32..63]
105 */
106 memcpy (sk, priv.s, 64);
107
108 /**
109 * Calculate the derived zone key zk' from the
110 * derived private scalar.
111 */
112 crypto_scalarmult_ed25519_base_noclamp (zk,
113 sk);
114
115 /**
116 * Calculate r:
117 * r = SHA512 (sk[32..63] | M)
118 * where M is our message (purpose).
119 * Note that sk[32..63] is the other half of the
120 * expansion from the original, non-derived private key
121 * "d".
122 */
123 crypto_hash_sha512_update (&hs, sk + 32, 32);
124 crypto_hash_sha512_update (&hs, (uint8_t*) purpose, ntohl (purpose->size));
125 crypto_hash_sha512_final (&hs, r);
126
127 /**
128 * Temporarily put zk into S
129 */
130 memcpy (sig->s, zk, 32);
131
132 /**
133 * Reduce the scalar value r
134 */
135 unsigned char r_mod[64];
136 crypto_core_ed25519_scalar_reduce (r_mod, r);
137
138 /**
139 * Calculate R := r * G of the signature
140 */
141 crypto_scalarmult_ed25519_base_noclamp (R, r_mod);
142 memcpy (sig->r, R, sizeof (R));
143
144 /**
145 * Calculate
146 * hram := SHA512 (R | zk' | M)
147 */
148 crypto_hash_sha512_init (&hs);
149 crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64);
150 crypto_hash_sha512_update (&hs, (uint8_t*) purpose,
151 ntohl (purpose->size));
152 crypto_hash_sha512_final (&hs, hram);
153
154 /**
155 * Reduce the resulting scalar value
156 */
157 unsigned char hram_mod[64];
158 crypto_core_ed25519_scalar_reduce (hram_mod, hram);
159
160 /**
161 * Calculate
162 * S := r + hram * s mod L
163 */
164 crypto_core_ed25519_scalar_mul (tmp, hram_mod, sk);
165 crypto_core_ed25519_scalar_add (sig->s, tmp, r_mod);
166
167 sodium_memzero (sk, sizeof (sk));
168 sodium_memzero (r, sizeof (r));
169 sodium_memzero (r_mod, sizeof (r_mod));
170 return GNUNET_OK;
171}
172
173enum GNUNET_GenericReturnValue
174GNUNET_CRYPTO_ecdsa_sign_derived (
175 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
176 const char *label,
177 const char *context,
178 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
179 struct GNUNET_CRYPTO_EcdsaSignature *sig)
180{
181 struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
182 enum GNUNET_GenericReturnValue res;
183 key = GNUNET_CRYPTO_ecdsa_private_key_derive (priv,
184 label,
185 context);
186 res = GNUNET_CRYPTO_ecdsa_sign_ (key,
187 purpose,
188 sig);
189 GNUNET_free (key);
190 return res;
191}
192
193struct GNUNET_CRYPTO_EcdsaPrivateKey *
194GNUNET_CRYPTO_ecdsa_private_key_derive (
195 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
196 const char *label,
197 const char *context)
198{
199 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
200 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
201 struct GNUNET_HashCode hc;
202 uint8_t dc[32];
203 gcry_mpi_t h;
204 gcry_mpi_t x;
205 gcry_mpi_t d;
206 gcry_mpi_t n;
207 gcry_ctx_t ctx;
208
209 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
210
211 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
212 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
213
214 derive_h (&pub, sizeof (pub), label, context, &hc);
215 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
216
217 /* Convert to big endian for libgcrypt */
218 for (size_t i = 0; i < 32; i++)
219 dc[i] = priv->d[31 - i];
220 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));
221 d = gcry_mpi_new (256);
222 gcry_mpi_mulm (d, h, x, n);
223 gcry_mpi_release (h);
224 gcry_mpi_release (x);
225 gcry_mpi_release (n);
226 gcry_ctx_release (ctx);
227 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
228 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
229 /* Convert to big endian for libgcrypt */
230 for (size_t i = 0; i < 32; i++)
231 ret->d[i] = dc[31 - i];
232 sodium_memzero (dc, sizeof(dc));
233 gcry_mpi_release (d);
234 return ret;
235}
236
237
238void
239GNUNET_CRYPTO_ecdsa_public_key_derive (
240 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
241 const char *label,
242 const char *context,
243 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
244{
245 struct GNUNET_HashCode hc;
246 gcry_ctx_t ctx;
247 gcry_mpi_t q_y;
248 gcry_mpi_t h;
249 gcry_mpi_t n;
250 gcry_mpi_t h_mod_n;
251 gcry_mpi_point_t q;
252 gcry_mpi_point_t v;
253
254 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
255
256 /* obtain point 'q' from original public key. The provided 'q' is
257 compressed thus we first store it in the context and then get it
258 back as a (decompresssed) point. */
259 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
260 GNUNET_assert (NULL != q_y);
261 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
262 gcry_mpi_release (q_y);
263 q = gcry_mpi_ec_get_point ("q", ctx, 0);
264 GNUNET_assert (q);
265
266 /* calculate h_mod_n = h % n */
267 derive_h (pub, sizeof (*pub), label, context, &hc);
268 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
269 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
270 h_mod_n = gcry_mpi_new (256);
271 gcry_mpi_mod (h_mod_n, h, n);
272 /* calculate v = h_mod_n * q */
273 v = gcry_mpi_point_new (0);
274 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
275 gcry_mpi_release (h_mod_n);
276 gcry_mpi_release (h);
277 gcry_mpi_release (n);
278 gcry_mpi_point_release (q);
279
280 /* convert point 'v' to public key that we return */
281 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
282 gcry_mpi_point_release (v);
283 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
284 GNUNET_assert (q_y);
285 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
286 gcry_mpi_release (q_y);
287 gcry_ctx_release (ctx);
288}
289
290
291void
292GNUNET_CRYPTO_eddsa_private_key_derive (
293 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
294 const char *label,
295 const char *context,
296 struct GNUNET_CRYPTO_EddsaPrivateScalar *result)
297{
298 struct GNUNET_CRYPTO_EddsaPublicKey pub;
299 struct GNUNET_HashCode hc;
300 uint8_t dc[32];
301 unsigned char sk[64];
302 gcry_mpi_t h;
303 gcry_mpi_t h_mod_n;
304 gcry_mpi_t x;
305 gcry_mpi_t d;
306 gcry_mpi_t n;
307 gcry_mpi_t a1;
308 gcry_mpi_t a2;
309 gcry_ctx_t ctx;
310
311 /**
312 * Libsodium does not offer an API with arbitrary arithmetic.
313 * Hence we have to use libgcrypt here.
314 */
315 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
316
317 /**
318 * Get our modulo
319 */
320 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
321 GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub);
322
323 /**
324 * This is the standard private key expansion in Ed25519.
325 * The first 32 octets are used as a little-endian private
326 * scalar.
327 * We derive this scalar using our "h".
328 */
329 crypto_hash_sha512 (sk, priv->d, 32);
330 sk[0] &= 248;
331 sk[31] &= 127;
332 sk[31] |= 64;
333
334 /**
335 * Get h mod n
336 */
337 derive_h (&pub, sizeof (pub), label, context, &hc);
338 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
339 h_mod_n = gcry_mpi_new (256);
340 gcry_mpi_mod (h_mod_n, h, n);
341 /* Convert scalar to big endian for libgcrypt */
342 for (size_t i = 0; i < 32; i++)
343 dc[i] = sk[31 - i];
344
345 /**
346 * dc now contains the private scalar "a".
347 * We carefully remove the clamping and derive a'.
348 * Calculate:
349 * a1 := a / 8
350 * a2 := h * a1 mod n
351 * a' := a2 * 8 mod n
352 */
353 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc)); // a
354 a1 = gcry_mpi_new (256);
355 gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8);
356 gcry_mpi_div (a1, NULL, x, eight, 0); // a1 := a / 8
357 a2 = gcry_mpi_new (256);
358 gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n
359 d = gcry_mpi_new (256);
360 gcry_mpi_mul (d, a2, eight); // a' := a2 * 8
361 gcry_mpi_release (h);
362 gcry_mpi_release (x);
363 gcry_mpi_release (n);
364 gcry_mpi_release (a1);
365 gcry_mpi_release (a2);
366 gcry_ctx_release (ctx);
367 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
368 /**
369 * We hash the derived "h" parameter with the
370 * other half of the expanded private key. This ensures
371 * that for signature generation, the "R" is derived from
372 * the same derivation path as "h" and is not reused.
373 */
374 crypto_hash_sha256_state hs;
375 crypto_hash_sha256_init (&hs);
376 crypto_hash_sha256_update (&hs, sk + 32, 32);
377 crypto_hash_sha256_update (&hs, (unsigned char*) &hc, sizeof (hc));
378 crypto_hash_sha256_final (&hs, result->s + 32);
379 //memcpy (result->s, sk, sizeof (sk));
380 /* Convert to little endian for libsodium */
381 for (size_t i = 0; i < 32; i++)
382 result->s[i] = dc[31 - i];
383
384 sodium_memzero (dc, sizeof(dc));
385 gcry_mpi_release (d);
386}
387
388
389void
390GNUNET_CRYPTO_eddsa_public_key_derive (
391 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
392 const char *label,
393 const char *context,
394 struct GNUNET_CRYPTO_EddsaPublicKey *result)
395{
396 struct GNUNET_HashCode hc;
397 gcry_ctx_t ctx;
398 gcry_mpi_t q_y;
399 gcry_mpi_t h;
400 gcry_mpi_t n;
401 gcry_mpi_t h_mod_n;
402 gcry_mpi_point_t q;
403 gcry_mpi_point_t v;
404
405 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
406
407 /* obtain point 'q' from original public key. The provided 'q' is
408 compressed thus we first store it in the context and then get it
409 back as a (decompresssed) point. */
410 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
411 GNUNET_assert (NULL != q_y);
412 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
413 gcry_mpi_release (q_y);
414 q = gcry_mpi_ec_get_point ("q", ctx, 0);
415 GNUNET_assert (q);
416
417 /* calculate h_mod_n = h % n */
418 derive_h (pub, sizeof (*pub), label, context, &hc);
419 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
420
421 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
422 h_mod_n = gcry_mpi_new (256);
423 gcry_mpi_mod (h_mod_n, h, n);
424
425 /* calculate v = h_mod_n * q */
426 v = gcry_mpi_point_new (0);
427 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
428 gcry_mpi_release (h_mod_n);
429 gcry_mpi_release (h);
430 gcry_mpi_release (n);
431 gcry_mpi_point_release (q);
432
433 /* convert point 'v' to public key that we return */
434 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
435 gcry_mpi_point_release (v);
436 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
437 GNUNET_assert (q_y);
438 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
439 gcry_mpi_release (q_y);
440 gcry_ctx_release (ctx);
441
442}
443
444
445void
446GNUNET_CRYPTO_eddsa_key_get_public_from_scalar (
447 const struct GNUNET_CRYPTO_EddsaPrivateScalar *priv,
448 struct GNUNET_CRYPTO_EddsaPublicKey *pkey)
449{
450 unsigned char sk[32];
451
452 memcpy (sk, priv->s, 32);
453
454 /**
455 * Calculate the derived zone key zk' from the
456 * derived private scalar.
457 */
458 crypto_scalarmult_ed25519_base_noclamp (pkey->q_y,
459 sk);
460}
diff --git a/src/util/crypto_ecc_setup.c b/src/util/crypto_ecc_setup.c
deleted file mode 100644
index 21ce48eef..000000000
--- a/src/util/crypto_ecc_setup.c
+++ /dev/null
@@ -1,313 +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,
138 * - #GNUNET_NO if @a do_create was set but we found an existing file,
139 * - #GNUNET_SYSERR on failure _or_ if the file didn't exist and @a
140 * do_create was not set
141 */
142enum GNUNET_GenericReturnValue
143GNUNET_CRYPTO_eddsa_key_from_file (const char *filename,
144 int do_create,
145 struct GNUNET_CRYPTO_EddsaPrivateKey *pkey)
146{
147 enum GNUNET_GenericReturnValue ret;
148
149 if (GNUNET_OK ==
150 read_from_file (filename,
151 pkey,
152 sizeof (*pkey)))
153 {
154 /* file existed, report that we didn't create it... */
155 return (do_create) ? GNUNET_NO : GNUNET_OK;
156 }
157 else if (! do_create)
158 {
159 return GNUNET_SYSERR;
160 }
161
162 GNUNET_CRYPTO_eddsa_key_create (pkey);
163 ret = GNUNET_DISK_fn_write (filename,
164 pkey,
165 sizeof (*pkey),
166 GNUNET_DISK_PERM_USER_READ);
167 if ( (GNUNET_OK == ret) ||
168 (GNUNET_SYSERR == ret) )
169 return ret;
170 /* maybe another process succeeded in the meantime, try reading one more time */
171 if (GNUNET_OK ==
172 read_from_file (filename,
173 pkey,
174 sizeof (*pkey)))
175 {
176 /* file existed, report that *we* didn't create it... */
177 return (do_create) ? GNUNET_NO : GNUNET_OK;
178 }
179 /* give up */
180 return GNUNET_SYSERR;
181}
182
183
184/**
185 * @ingroup crypto
186 * @brief Create a new private key by reading it from a file.
187 *
188 * If the files does not exist and @a do_create is set, creates a new key and
189 * write it to the file.
190 *
191 * If the contents of the file are invalid, an error is returned.
192 *
193 * @param filename name of file to use to store the key
194 * @param do_create should a file be created?
195 * @param[out] pkey set to the private key from @a filename on success
196 * @return #GNUNET_OK on success, #GNUNET_NO if @a do_create was set but
197 * we found an existing file, #GNUNET_SYSERR on failure
198 */
199enum GNUNET_GenericReturnValue
200GNUNET_CRYPTO_ecdsa_key_from_file (const char *filename,
201 int do_create,
202 struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey)
203{
204 if (GNUNET_OK ==
205 read_from_file (filename,
206 pkey,
207 sizeof (*pkey)))
208 {
209 /* file existed, report that we didn't create it... */
210 return (do_create) ? GNUNET_NO : GNUNET_OK;
211 }
212 GNUNET_CRYPTO_ecdsa_key_create (pkey);
213 if (GNUNET_OK ==
214 GNUNET_DISK_fn_write (filename,
215 pkey,
216 sizeof (*pkey),
217 GNUNET_DISK_PERM_USER_READ))
218 return GNUNET_OK;
219 /* maybe another process succeeded in the meantime, try reading one more time */
220 if (GNUNET_OK ==
221 read_from_file (filename,
222 pkey,
223 sizeof (*pkey)))
224 {
225 /* file existed, report that *we* didn't create it... */
226 return (do_create) ? GNUNET_NO : GNUNET_OK;
227 }
228 /* give up */
229 return GNUNET_SYSERR;
230}
231
232
233/**
234 * Create a new private key by reading our peer's key from
235 * the file specified in the configuration.
236 *
237 * @param cfg the configuration to use
238 * @return new private key, NULL on error (for example,
239 * permission denied)
240 */
241struct GNUNET_CRYPTO_EddsaPrivateKey *
242GNUNET_CRYPTO_eddsa_key_create_from_configuration (
243 const struct GNUNET_CONFIGURATION_Handle *cfg)
244{
245 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
246 char *fn;
247
248 if (GNUNET_OK !=
249 GNUNET_CONFIGURATION_get_value_filename (cfg,
250 "PEER",
251 "PRIVATE_KEY",
252 &fn))
253 return NULL;
254 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
255 GNUNET_CRYPTO_eddsa_key_from_file (fn,
256 GNUNET_YES,
257 priv);
258 GNUNET_free (fn);
259 return priv;
260}
261
262
263/**
264 * Retrieve the identity of the host's peer.
265 *
266 * @param cfg configuration to use
267 * @param dst pointer to where to write the peer identity
268 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
269 * could not be retrieved
270 */
271enum GNUNET_GenericReturnValue
272GNUNET_CRYPTO_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
273 struct GNUNET_PeerIdentity *dst)
274{
275 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
276
277 if (NULL == (priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg)))
278 {
279 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
280 _ ("Could not load peer's private key\n"));
281 return GNUNET_SYSERR;
282 }
283 GNUNET_CRYPTO_eddsa_key_get_public (priv,
284 &dst->public_key);
285 GNUNET_free (priv);
286 return GNUNET_OK;
287}
288
289
290/**
291 * Setup a key file for a peer given the name of the
292 * configuration file (!). This function is used so that
293 * at a later point code can be certain that reading a
294 * key is fast (for example in time-dependent testcases).
295 *
296 * @param cfg_name name of the configuration file to use
297 */
298void
299GNUNET_CRYPTO_eddsa_setup_key (const char *cfg_name)
300{
301 struct GNUNET_CONFIGURATION_Handle *cfg;
302 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
303
304 cfg = GNUNET_CONFIGURATION_create ();
305 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
306 priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
307 if (NULL != priv)
308 GNUNET_free (priv);
309 GNUNET_CONFIGURATION_destroy (cfg);
310}
311
312
313/* end of crypto_ecc_setup.c */
diff --git a/src/util/crypto_edx25519.c b/src/util/crypto_edx25519.c
deleted file mode 100644
index 775b64190..000000000
--- a/src/util/crypto_edx25519.c
+++ /dev/null
@@ -1,354 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 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_edx25519.c
23 * @brief An variant of EdDSA which allows for iterative derivation of key pairs.
24 * @author Özgür Kesim
25 * @author Christian Grothoff
26 * @author Florian Dold
27 * @author Martin Schanzenbach
28 */
29#include "platform.h"
30#include <gcrypt.h>
31#include <sodium.h>
32#include "gnunet_crypto_lib.h"
33#include "gnunet_strings_lib.h"
34
35#define CURVE "Ed25519"
36
37void
38GNUNET_CRYPTO_edx25519_key_clear (struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
39{
40 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_Edx25519PrivateKey));
41}
42
43
44void
45GNUNET_CRYPTO_edx25519_key_create_from_seed (
46 const void *seed,
47 size_t seedsize,
48 struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
49{
50
51 GNUNET_static_assert (sizeof(*pk) == sizeof(struct GNUNET_HashCode));
52 GNUNET_CRYPTO_hash (seed,
53 seedsize,
54 (struct GNUNET_HashCode *) pk);
55
56 /* Clamp the first half of the key. The second half is used in the signature
57 * process. */
58 pk->a[0] &= 248;
59 pk->a[31] &= 127;
60 pk->a[31] |= 64;
61}
62
63
64void
65GNUNET_CRYPTO_edx25519_key_create (
66 struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
67{
68 char seed[256 / 8];
69 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
70 seed,
71 sizeof (seed));
72 GNUNET_CRYPTO_edx25519_key_create_from_seed (seed,
73 sizeof(seed),
74 pk);
75}
76
77
78void
79GNUNET_CRYPTO_edx25519_key_get_public (
80 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
81 struct GNUNET_CRYPTO_Edx25519PublicKey *pub)
82{
83 crypto_scalarmult_ed25519_base_noclamp (pub->q_y,
84 priv->a);
85}
86
87
88/**
89 * This function operates the basically same way as the signature function for
90 * EdDSA. But instead of expanding a private seed (which is usually the case
91 * for crypto APIs) and using the resulting scalars, it takes the scalars
92 * directly from Edx25519PrivateKey. We require this functionality in order to
93 * use derived private keys for signatures.
94 *
95 * The resulting signature is a standard EdDSA signature
96 * which can be verified using the usual APIs.
97 *
98 * @param priv the private key (containing two scalars .a and .b)
99 * @param purp the signature purpose
100 * @param sig the resulting signature
101 */
102enum GNUNET_GenericReturnValue
103GNUNET_CRYPTO_edx25519_sign_ (
104 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
105 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
106 struct GNUNET_CRYPTO_Edx25519Signature *sig)
107{
108
109 crypto_hash_sha512_state hs;
110 unsigned char r[64];
111 unsigned char hram[64];
112 unsigned char P[32];
113 unsigned char r_mod[64];
114 unsigned char R[32];
115 unsigned char tmp[32];
116
117 crypto_hash_sha512_init (&hs);
118
119 /**
120 * Calculate the public key P from the private scalar in the key.
121 */
122 crypto_scalarmult_ed25519_base_noclamp (P,
123 priv->a);
124
125 /**
126 * Calculate r:
127 * r = SHA512 (b ∥ M)
128 * where M is our message (purpose).
129 */
130 crypto_hash_sha512_update (&hs,
131 priv->b,
132 sizeof(priv->b));
133 crypto_hash_sha512_update (&hs,
134 (uint8_t*) purpose,
135 ntohl (purpose->size));
136 crypto_hash_sha512_final (&hs,
137 r);
138
139 /**
140 * Temporarily put P into S
141 */
142 memcpy (sig->s, P, 32);
143
144 /**
145 * Reduce the scalar value r
146 */
147 crypto_core_ed25519_scalar_reduce (r_mod, r);
148
149 /**
150 * Calculate R := r * G of the signature
151 */
152 crypto_scalarmult_ed25519_base_noclamp (R, r_mod);
153 memcpy (sig->r, R, sizeof (R));
154
155 /**
156 * Calculate
157 * hram := SHA512 (R ∥ P ∥ M)
158 */
159 crypto_hash_sha512_init (&hs);
160 crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64);
161 crypto_hash_sha512_update (&hs, (uint8_t*) purpose,
162 ntohl (purpose->size));
163 crypto_hash_sha512_final (&hs, hram);
164
165 /**
166 * Reduce the resulting scalar value
167 */
168 unsigned char hram_mod[64];
169 crypto_core_ed25519_scalar_reduce (hram_mod, hram);
170
171 /**
172 * Calculate
173 * S := r + hram * s mod L
174 */
175 crypto_core_ed25519_scalar_mul (tmp, hram_mod, priv->a);
176 crypto_core_ed25519_scalar_add (sig->s, tmp, r_mod);
177
178 sodium_memzero (r, sizeof (r));
179 sodium_memzero (r_mod, sizeof (r_mod));
180
181 return GNUNET_OK;
182}
183
184
185enum GNUNET_GenericReturnValue
186GNUNET_CRYPTO_edx25519_verify_ (
187 uint32_t purpose,
188 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
189 const struct GNUNET_CRYPTO_Edx25519Signature *sig,
190 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub)
191{
192 const unsigned char *m = (const void *) validate;
193 size_t mlen = ntohl (validate->size);
194 const unsigned char *s = (const void *) sig;
195
196 int res;
197
198 if (purpose != ntohl (validate->purpose))
199 return GNUNET_SYSERR; /* purpose mismatch */
200
201 res = crypto_sign_verify_detached (s, m, mlen, pub->q_y);
202 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
203}
204
205
206/**
207 * Derive the 'h' value for key derivation, where
208 * 'h = H(P ∥ seed) mod n' and 'n' is the size of the cyclic subroup.
209 *
210 * @param pub public key for deriviation
211 * @param seed seed for key the deriviation
212 * @param seedsize the size of the seed
213 * @param[out] phc if not NULL, the output of H() will be written into
214 * return h_mod_n (allocated by this function)
215 */
216static void
217derive_h (
218 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub,
219 const void *seed,
220 size_t seedsize,
221 struct GNUNET_HashCode *phc)
222{
223 static const char *const salt = "edx2559-derivation";
224
225 GNUNET_CRYPTO_kdf (/* output*/
226 phc, sizeof(*phc),
227 /* salt */
228 seed, seedsize,
229 /* ikm */
230 pub, sizeof(*pub),
231 /* ctx chunks*/
232 salt, strlen (salt),
233 NULL, 0);
234
235}
236
237
238void
239GNUNET_CRYPTO_edx25519_private_key_derive (
240 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
241 const void *seed,
242 size_t seedsize,
243 struct GNUNET_CRYPTO_Edx25519PrivateKey *result)
244{
245 struct GNUNET_CRYPTO_Edx25519PublicKey pub;
246 struct GNUNET_HashCode hc;
247 uint8_t a[32];
248 uint8_t eight[32] = { 8 };
249 uint8_t eight_inv[32];
250 uint8_t h[64] = { 0 };
251
252 GNUNET_CRYPTO_edx25519_key_get_public (priv, &pub);
253
254 /* Get h mod n */
255 derive_h (&pub,
256 seed,
257 seedsize,
258 &hc);
259
260 memcpy (h, &hc, 64);
261 crypto_core_ed25519_scalar_reduce (h,
262 h);
263#ifdef CHECK_RARE_CASES
264 /**
265 * Note that the following cases would be problematic:
266 * 1.) h == 0 mod n
267 * 2.) h == 1 mod n
268 * 3.) [h] * P == E
269 * We assume that the probalities for these cases to occur are neglegible.
270 */
271 {
272 char zero[32] = { 0 };
273 char one[32] = { 1 };
274
275 GNUNET_assert (0 != memcmp (zero, h, 32));
276 GNUNET_assert (0 != memcmp (one, h, 32));
277 }
278#endif
279
280 /**
281 * dc now contains the private scalar "a".
282 * We carefully remove the clamping and derive a'.
283 * Calculate:
284 * a1 := a / 8
285 * a2 := h * a1 mod n
286 * a' := a2 * 8 mod n
287 */
288
289 GNUNET_assert (0 == crypto_core_ed25519_scalar_invert (eight_inv,
290 eight));
291
292 crypto_core_ed25519_scalar_mul (a, priv->a, eight_inv);
293 crypto_core_ed25519_scalar_mul (a, a, h);
294 crypto_core_ed25519_scalar_mul (a, a, eight);
295
296#ifdef CHECK_RARE_CASES
297 /* The likelihood for a' == 0 or a' == 1 is neglegible */
298 {
299 char zero[32] = { 0 };
300 char one[32] = { 1 };
301
302 GNUNET_assert (0 != memcmp (zero, a, 32));
303 GNUNET_assert (0 != memcmp (one, a, 32));
304 }
305#endif
306
307 /* We hash the derived "h" parameter with the other half of the expanded
308 * private key (that is: priv->b). This ensures that for signature
309 * generation, the "R" is derived from the same derivation path as "h" and is
310 * not reused. */
311 {
312 struct GNUNET_HashCode hcb;
313 struct GNUNET_HashContext *hctx;
314
315 hctx = GNUNET_CRYPTO_hash_context_start ();
316 GNUNET_CRYPTO_hash_context_read (hctx, priv->b, sizeof(priv->b));
317 GNUNET_CRYPTO_hash_context_read (hctx, (unsigned char*) &hc, sizeof (hc));
318 GNUNET_CRYPTO_hash_context_finish (hctx, &hcb);
319
320 /* Truncate result, effectively doing SHA512/256 */
321 for (size_t i = 0; i < 32; i++)
322 result->b[i] = ((unsigned char *) &hcb)[i];
323 }
324
325 for (size_t i = 0; i < 32; i++)
326 result->a[i] = a[i];
327
328 sodium_memzero (a, sizeof(a));
329}
330
331
332void
333GNUNET_CRYPTO_edx25519_public_key_derive (
334 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub,
335 const void *seed,
336 size_t seedsize,
337 struct GNUNET_CRYPTO_Edx25519PublicKey *result)
338{
339 struct GNUNET_HashCode hc;
340 uint8_t h[64] = { 0 };
341
342 derive_h (pub,
343 seed,
344 seedsize,
345 &hc);
346 memcpy (h,
347 &hc,
348 64);
349 crypto_core_ed25519_scalar_reduce (h,
350 h);
351 GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (result->q_y,
352 h,
353 pub->q_y));
354}
diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c
deleted file mode 100644
index f516f5474..000000000
--- a/src/util/crypto_hash.c
+++ /dev/null
@@ -1,413 +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 if (GNUNET_OK != GNUNET_STRINGS_utf8_toupper (enc, up_ptr))
80 return GNUNET_SYSERR;
81
82 return GNUNET_STRINGS_string_to_data (upper_enc, enclen,
83 (unsigned char *) result,
84 sizeof(struct GNUNET_HashCode));
85}
86
87
88unsigned int
89GNUNET_CRYPTO_hash_distance_u32 (const struct GNUNET_HashCode *a,
90 const struct GNUNET_HashCode *b)
91{
92 unsigned int x1 = (a->bits[1] - b->bits[1]) >> 16;
93 unsigned int x2 = (b->bits[1] - a->bits[1]) >> 16;
94
95 return(x1 * x2);
96}
97
98
99void
100GNUNET_CRYPTO_hash_create_random (enum GNUNET_CRYPTO_Quality mode,
101 struct GNUNET_HashCode *result)
102{
103 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(uint32_t)) - 1;
104 i >= 0;
105 i--)
106 result->bits[i] = GNUNET_CRYPTO_random_u32 (mode, UINT32_MAX);
107}
108
109
110void
111GNUNET_CRYPTO_hash_difference (const struct GNUNET_HashCode *a,
112 const struct GNUNET_HashCode *b,
113 struct GNUNET_HashCode *result)
114{
115 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(unsigned int)) - 1;
116 i >= 0;
117 i--)
118 result->bits[i] = b->bits[i] - a->bits[i];
119}
120
121
122void
123GNUNET_CRYPTO_hash_sum (const struct GNUNET_HashCode *a,
124 const struct GNUNET_HashCode *delta, struct
125 GNUNET_HashCode *result)
126{
127 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(unsigned int)) - 1;
128 i >= 0;
129 i--)
130 result->bits[i] = delta->bits[i] + a->bits[i];
131}
132
133
134void
135GNUNET_CRYPTO_hash_xor (const struct GNUNET_HashCode *a,
136 const struct GNUNET_HashCode *b,
137 struct GNUNET_HashCode *result)
138{
139 const unsigned long long *lla = (const unsigned long long *) a;
140 const unsigned long long *llb = (const unsigned long long *) b;
141 unsigned long long *llr = (unsigned long long *) result;
142
143 GNUNET_static_assert (8 == sizeof (unsigned long long));
144 GNUNET_static_assert (0 == sizeof (*a) % sizeof (unsigned long long));
145 for (int i = sizeof (*result) / sizeof (*llr) - 1; i>=0; i--)
146 llr[i] = lla[i] ^ llb[i];
147}
148
149
150void
151GNUNET_CRYPTO_hash_to_aes_key (
152 const struct GNUNET_HashCode *hc,
153 struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
154 struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
155{
156 GNUNET_assert (GNUNET_YES ==
157 GNUNET_CRYPTO_kdf (
158 skey,
159 sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
160 "Hash key derivation",
161 strlen ("Hash key derivation"),
162 hc, sizeof(struct GNUNET_HashCode),
163 NULL, 0));
164 GNUNET_assert (GNUNET_YES ==
165 GNUNET_CRYPTO_kdf (
166 iv,
167 sizeof(struct GNUNET_CRYPTO_SymmetricInitializationVector),
168 "Initialization vector derivation",
169 strlen ("Initialization vector derivation"),
170 hc, sizeof(struct GNUNET_HashCode),
171 NULL, 0));
172}
173
174
175unsigned int
176GNUNET_CRYPTO_hash_count_leading_zeros (const struct GNUNET_HashCode *h)
177{
178 const unsigned long long *llp = (const unsigned long long *) h;
179 unsigned int ret = 0;
180 unsigned int i;
181
182 GNUNET_static_assert (8 == sizeof (unsigned long long));
183 GNUNET_static_assert (0 == sizeof (*h) % sizeof (unsigned long long));
184 for (i = 0; i<sizeof (*h) / sizeof (*llp); i++)
185 {
186 if (0LLU != llp[i])
187 break;
188 ret += sizeof (*llp) * 8;
189 }
190 if (ret == 8 * sizeof (*h))
191 return ret;
192 ret += __builtin_clzll (GNUNET_ntohll ((uint64_t) llp[i]));
193 return ret;
194}
195
196
197unsigned int
198GNUNET_CRYPTO_hash_count_tailing_zeros (const struct GNUNET_HashCode *h)
199{
200 const unsigned long long *llp = (const unsigned long long *) h;
201 unsigned int ret = 0;
202 int i;
203
204 GNUNET_static_assert (8 == sizeof (unsigned long long));
205 GNUNET_static_assert (0 == sizeof (*h) % sizeof (unsigned long long));
206 for (i = sizeof (*h) / sizeof (*llp) - 1; i>=0; i--)
207 {
208 if (0LLU != llp[i])
209 break;
210 ret += sizeof (*llp) * 8;
211 }
212 if (ret == 8 * sizeof (*h))
213 return ret;
214 ret += __builtin_ctzll (GNUNET_ntohll ((uint64_t) llp[i]));
215 return ret;
216}
217
218
219int
220GNUNET_CRYPTO_hash_cmp (const struct GNUNET_HashCode *h1,
221 const struct GNUNET_HashCode *h2)
222{
223 unsigned int *i1;
224 unsigned int *i2;
225
226 i1 = (unsigned int *) h1;
227 i2 = (unsigned int *) h2;
228 for (ssize_t i = (sizeof(struct GNUNET_HashCode) / sizeof(unsigned int)) - 1;
229 i >= 0;
230 i--)
231 {
232 if (i1[i] > i2[i])
233 return 1;
234 if (i1[i] < i2[i])
235 return -1;
236 }
237 return 0;
238}
239
240
241int
242GNUNET_CRYPTO_hash_xorcmp (const struct GNUNET_HashCode *h1,
243 const struct GNUNET_HashCode *h2,
244 const struct GNUNET_HashCode *target)
245{
246 const unsigned long long *l1 = (const unsigned long long *) h1;
247 const unsigned long long *l2 = (const unsigned long long *) h2;
248 const unsigned long long *t = (const unsigned long long *) target;
249
250 GNUNET_static_assert (0 == sizeof (*h1) % sizeof (*l1));
251 for (size_t i = 0; i < sizeof(*h1) / sizeof(*l1); i++)
252 {
253 unsigned long long x1 = l1[i] ^ t[i];
254 unsigned long long x2 = l2[i] ^ t[i];
255
256 if (x1 > x2)
257 return 1;
258 if (x1 < x2)
259 return -1;
260 }
261 return 0;
262}
263
264
265void
266GNUNET_CRYPTO_hmac_derive_key (
267 struct GNUNET_CRYPTO_AuthKey *key,
268 const struct GNUNET_CRYPTO_SymmetricSessionKey *rkey,
269 const void *salt, size_t salt_len,
270 ...)
271{
272 va_list argp;
273
274 va_start (argp,
275 salt_len);
276 GNUNET_CRYPTO_hmac_derive_key_v (key,
277 rkey,
278 salt, salt_len,
279 argp);
280 va_end (argp);
281}
282
283
284void
285GNUNET_CRYPTO_hmac_derive_key_v (
286 struct GNUNET_CRYPTO_AuthKey *key,
287 const struct GNUNET_CRYPTO_SymmetricSessionKey *rkey,
288 const void *salt, size_t salt_len,
289 va_list argp)
290{
291 GNUNET_CRYPTO_kdf_v (key->key, sizeof(key->key),
292 salt, salt_len,
293 rkey, sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
294 argp);
295}
296
297
298void
299GNUNET_CRYPTO_hmac_raw (const void *key, size_t key_len,
300 const void *plaintext, size_t plaintext_len,
301 struct GNUNET_HashCode *hmac)
302{
303 static int once;
304 static gcry_md_hd_t md;
305 const unsigned char *mc;
306
307 if (! once)
308 {
309 once = 1;
310 GNUNET_assert (GPG_ERR_NO_ERROR ==
311 gcry_md_open (&md,
312 GCRY_MD_SHA512,
313 GCRY_MD_FLAG_HMAC));
314 }
315 else
316 {
317 gcry_md_reset (md);
318 }
319 gcry_md_setkey (md, key, key_len);
320 gcry_md_write (md, plaintext, plaintext_len);
321 mc = gcry_md_read (md, GCRY_MD_SHA512);
322 GNUNET_assert (NULL != mc);
323 GNUNET_memcpy (hmac->bits, mc, sizeof(hmac->bits));
324}
325
326
327void
328GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key,
329 const void *plaintext, size_t plaintext_len,
330 struct GNUNET_HashCode *hmac)
331{
332 GNUNET_CRYPTO_hmac_raw ((void *) key->key, sizeof(key->key),
333 plaintext, plaintext_len,
334 hmac);
335}
336
337
338struct GNUNET_HashContext
339{
340 /**
341 * Internal state of the hash function.
342 */
343 gcry_md_hd_t hd;
344};
345
346
347struct GNUNET_HashContext *
348GNUNET_CRYPTO_hash_context_start ()
349{
350 struct GNUNET_HashContext *hc;
351
352 BENCHMARK_START (hash_context_start);
353 hc = GNUNET_new (struct GNUNET_HashContext);
354 GNUNET_assert (0 ==
355 gcry_md_open (&hc->hd,
356 GCRY_MD_SHA512,
357 0));
358 BENCHMARK_END (hash_context_start);
359 return hc;
360}
361
362
363void
364GNUNET_CRYPTO_hash_context_read (struct GNUNET_HashContext *hc,
365 const void *buf,
366 size_t size)
367{
368 BENCHMARK_START (hash_context_read);
369 gcry_md_write (hc->hd, buf, size);
370 BENCHMARK_END (hash_context_read);
371}
372
373
374struct GNUNET_HashContext *
375GNUNET_CRYPTO_hash_context_copy (const struct GNUNET_HashContext *hc)
376{
377 struct GNUNET_HashContext *cp;
378
379 cp = GNUNET_new (struct GNUNET_HashContext);
380 GNUNET_assert (0 ==
381 gcry_md_copy (&cp->hd,
382 hc->hd));
383 return cp;
384}
385
386
387void
388GNUNET_CRYPTO_hash_context_finish (struct GNUNET_HashContext *hc,
389 struct GNUNET_HashCode *r_hash)
390{
391 const void *res = gcry_md_read (hc->hd, 0);
392
393 BENCHMARK_START (hash_context_finish);
394
395 GNUNET_assert (NULL != res);
396 if (NULL != r_hash)
397 GNUNET_memcpy (r_hash,
398 res,
399 sizeof(struct GNUNET_HashCode));
400 GNUNET_CRYPTO_hash_context_abort (hc);
401 BENCHMARK_END (hash_context_finish);
402}
403
404
405void
406GNUNET_CRYPTO_hash_context_abort (struct GNUNET_HashContext *hc)
407{
408 gcry_md_close (hc->hd);
409 GNUNET_free (hc);
410}
411
412
413/* 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 838e37d8d..000000000
--- a/src/util/crypto_hkdf.c
+++ /dev/null
@@ -1,368 +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,
78 const void *key,
79 size_t key_len,
80 const void *buf,
81 size_t buf_len)
82{
83 if (GPG_ERR_NO_ERROR !=
84 gcry_md_setkey (mac, key, key_len))
85 {
86 GNUNET_break (0);
87 return NULL;
88 }
89 gcry_md_write (mac,
90 buf,
91 buf_len);
92 return (const void *) gcry_md_read (mac, 0);
93}
94
95
96/**
97 * @brief Generate pseudo-random key
98 * @param mac gcrypt HMAC handle
99 * @param xts salt
100 * @param xts_len length of the @a xts salt
101 * @param skm source key material
102 * @param skm_len length of @a skm
103 * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes)
104 * @return #GNUNET_YES on success
105 */
106static enum GNUNET_GenericReturnValue
107getPRK (gcry_md_hd_t mac,
108 const void *xts,
109 size_t xts_len,
110 const void *skm,
111 size_t skm_len,
112 void *prk)
113{
114 const void *ret;
115 size_t dlen;
116
117 dlen = gcry_md_get_algo_dlen (gcry_md_get_algo (mac));
118
119 /* sanity check to bound stack allocation */
120 GNUNET_assert (dlen <= 512);
121
122 /* From RFC 5869:
123 * salt - optional salt value (a non-secret random value);
124 * if not provided, it is set to a string of HashLen zeros. */
125
126 if (0 == xts_len)
127 {
128 char zero_salt[dlen];
129
130 memset (zero_salt, 0, dlen);
131 ret = doHMAC (mac, zero_salt, dlen, skm, skm_len);
132 }
133 else
134 {
135 ret = doHMAC (mac, xts, xts_len, skm, skm_len);
136 }
137 if (NULL == ret)
138 return GNUNET_SYSERR;
139 GNUNET_memcpy (prk,
140 ret,
141 dlen);
142 return GNUNET_YES;
143}
144
145
146#if DEBUG_HKDF
147static void
148dump (const char *src,
149 const void *p,
150 unsigned int l)
151{
152 printf ("\n%s: ", src);
153 for (unsigned int i = 0; i < l; i++)
154 {
155 printf ("%2x", (int) ((const unsigned char *) p)[i]);
156 }
157 printf ("\n");
158}
159
160
161#endif
162
163
164enum GNUNET_GenericReturnValue
165GNUNET_CRYPTO_hkdf_v (void *result,
166 size_t out_len,
167 int xtr_algo,
168 int prf_algo,
169 const void *xts,
170 size_t xts_len,
171 const void *skm,
172 size_t skm_len,
173 va_list argp)
174{
175 gcry_md_hd_t xtr;
176 gcry_md_hd_t prf;
177 const void *hc;
178 unsigned long i;
179 unsigned long t;
180 unsigned long d;
181 unsigned int k = gcry_md_get_algo_dlen (prf_algo);
182 unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo);
183 char prk[xtr_len];
184 int ret;
185 size_t ctx_len;
186 va_list args;
187
188 BENCHMARK_START (hkdf);
189
190 if (0 == k)
191 return GNUNET_SYSERR;
192 if (GPG_ERR_NO_ERROR !=
193 gcry_md_open (&xtr,
194 xtr_algo,
195 GCRY_MD_FLAG_HMAC))
196 return GNUNET_SYSERR;
197 if (GPG_ERR_NO_ERROR !=
198 gcry_md_open (&prf,
199 prf_algo,
200 GCRY_MD_FLAG_HMAC))
201 {
202 gcry_md_close (xtr);
203 return GNUNET_SYSERR;
204 }
205 va_copy (args, argp);
206
207 ctx_len = 0;
208 while (NULL != va_arg (args, void *))
209 {
210 size_t nxt = va_arg (args, size_t);
211 if (nxt + ctx_len < nxt)
212 {
213 /* integer overflow */
214 GNUNET_break (0);
215 va_end (args);
216 goto hkdf_error;
217 }
218 ctx_len += nxt;
219 }
220
221 va_end (args);
222
223 if ( (k + ctx_len < ctx_len) ||
224 (k + ctx_len + 1 < ctx_len) )
225 {
226 /* integer overflow */
227 GNUNET_break (0);
228 goto hkdf_error;
229 }
230
231 memset (result, 0, out_len);
232 if (GNUNET_YES !=
233 getPRK (xtr, xts, xts_len, skm, skm_len, prk))
234 goto hkdf_error;
235#if DEBUG_HKDF
236 dump ("PRK", prk, xtr_len);
237#endif
238
239 t = out_len / k;
240 d = out_len % k;
241
242 /* K(1) */
243 {
244 size_t plain_len = k + ctx_len + 1;
245 char *plain;
246 const void *ctx;
247 char *dst;
248
249 plain = GNUNET_malloc (plain_len);
250 dst = plain + k;
251 va_copy (args, argp);
252 while ((ctx = va_arg (args, void *)))
253 {
254 size_t len;
255
256 len = va_arg (args, size_t);
257 GNUNET_memcpy (dst, ctx, len);
258 dst += len;
259 }
260 va_end (args);
261
262 if (t > 0)
263 {
264 plain[k + ctx_len] = (char) 1;
265#if DEBUG_HKDF
266 dump ("K(1)", plain, plain_len);
267#endif
268 hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
269 if (hc == NULL)
270 {
271 GNUNET_free (plain);
272 goto hkdf_error;
273 }
274 GNUNET_memcpy (result, hc, k);
275 result += k;
276 }
277
278 /* K(i+1) */
279 for (i = 1; i < t; i++)
280 {
281 GNUNET_memcpy (plain, result - k, k);
282 plain[k + ctx_len] = (char) (i + 1);
283 gcry_md_reset (prf);
284#if DEBUG_HKDF
285 dump ("K(i+1)", plain, plain_len);
286#endif
287 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
288 if (NULL == hc)
289 {
290 GNUNET_free (plain);
291 goto hkdf_error;
292 }
293 GNUNET_memcpy (result, hc, k);
294 result += k;
295 }
296
297 /* K(t):d */
298 if (d > 0)
299 {
300 if (t > 0)
301 {
302 GNUNET_memcpy (plain, result - k, k);
303 i++;
304 }
305 plain[k + ctx_len] = (char) i;
306 gcry_md_reset (prf);
307#if DEBUG_HKDF
308 dump ("K(t):d", plain, plain_len);
309#endif
310 if (t > 0)
311 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
312 else
313 hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
314 if (hc == NULL)
315 {
316 GNUNET_free (plain);
317 goto hkdf_error;
318 }
319 GNUNET_memcpy (result, hc, d);
320 }
321#if DEBUG_HKDF
322 dump ("result", result - k, out_len);
323#endif
324
325 ret = GNUNET_YES;
326 GNUNET_free (plain);
327 goto hkdf_ok;
328 }
329hkdf_error:
330 ret = GNUNET_SYSERR;
331hkdf_ok:
332 gcry_md_close (xtr);
333 gcry_md_close (prf);
334 BENCHMARK_END (hkdf);
335 return ret;
336}
337
338
339enum GNUNET_GenericReturnValue
340GNUNET_CRYPTO_hkdf (void *result,
341 size_t out_len,
342 int xtr_algo,
343 int prf_algo,
344 const void *xts,
345 size_t xts_len,
346 const void *skm,
347 size_t skm_len, ...)
348{
349 va_list argp;
350 enum GNUNET_GenericReturnValue ret;
351
352 va_start (argp, skm_len);
353 ret =
354 GNUNET_CRYPTO_hkdf_v (result,
355 out_len,
356 xtr_algo,
357 prf_algo,
358 xts,
359 xts_len,
360 skm,
361 skm_len,
362 argp);
363 va_end (argp);
364 return ret;
365}
366
367
368/* end of crypto_hkdf.c */
diff --git a/src/util/crypto_kdf.c b/src/util/crypto_kdf.c
deleted file mode 100644
index f577e0f7a..000000000
--- a/src/util/crypto_kdf.c
+++ /dev/null
@@ -1,144 +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
36enum GNUNET_GenericReturnValue
37GNUNET_CRYPTO_kdf_v (void *result,
38 size_t out_len,
39 const void *xts,
40 size_t xts_len,
41 const void *skm,
42 size_t skm_len,
43 va_list argp)
44{
45 /*
46 * "Finally, we point out to a particularly advantageous instantiation using
47 * HMAC-SHA512 as XTR and HMAC-SHA256 in PRF* (in which case the output from SHA-512 is
48 * truncated to 256 bits). This makes sense in two ways: First, the extraction part is where we need a
49 * stronger hash function due to the unconventional demand from the hash function in the extraction
50 * setting. Second, as shown in Section 6, using HMAC with a truncated output as an extractor
51 * allows to prove the security of HKDF under considerably weaker assumptions on the underlying
52 * hash function."
53 *
54 * http://eprint.iacr.org/2010/264
55 */
56 return GNUNET_CRYPTO_hkdf_v (result,
57 out_len,
58 GCRY_MD_SHA512,
59 GCRY_MD_SHA256,
60 xts,
61 xts_len,
62 skm,
63 skm_len,
64 argp);
65}
66
67
68enum GNUNET_GenericReturnValue
69GNUNET_CRYPTO_kdf (void *result,
70 size_t out_len,
71 const void *xts,
72 size_t xts_len,
73 const void *skm,
74 size_t skm_len, ...)
75{
76 va_list argp;
77 int ret;
78
79 va_start (argp, skm_len);
80 ret = GNUNET_CRYPTO_kdf_v (result,
81 out_len,
82 xts,
83 xts_len,
84 skm,
85 skm_len,
86 argp);
87 va_end (argp);
88
89 return ret;
90}
91
92
93void
94GNUNET_CRYPTO_kdf_mod_mpi (gcry_mpi_t *r,
95 gcry_mpi_t n,
96 const void *xts, size_t xts_len,
97 const void *skm, size_t skm_len,
98 const char *ctx)
99{
100 gcry_error_t rc;
101 unsigned int nbits;
102 size_t rsize;
103 uint16_t ctr;
104
105 nbits = gcry_mpi_get_nbits (n);
106 /* GNUNET_assert (nbits > 512); */
107 ctr = 0;
108 while (1)
109 {
110 /* Ain't clear if n is always divisible by 8 */
111 size_t bsize = (nbits - 1) / 8 + 1;
112 uint8_t buf[bsize];
113 uint16_t ctr_nbo = htons (ctr);
114
115 rc = GNUNET_CRYPTO_kdf (buf,
116 bsize,
117 xts, xts_len,
118 skm, skm_len,
119 ctx, strlen (ctx),
120 &ctr_nbo, sizeof(ctr_nbo),
121 NULL, 0);
122 GNUNET_assert (GNUNET_YES == rc);
123 rc = gcry_mpi_scan (r,
124 GCRYMPI_FMT_USG,
125 (const unsigned char *) buf,
126 bsize,
127 &rsize);
128 GNUNET_assert (GPG_ERR_NO_ERROR == rc); /* Allocation error? */
129 GNUNET_assert (rsize == bsize);
130 gcry_mpi_clear_highbit (*r,
131 nbits);
132 GNUNET_assert (0 ==
133 gcry_mpi_test_bit (*r,
134 nbits));
135 ++ctr;
136 /* We reject this FDH if either *r > n and retry with another ctr */
137 if (0 > gcry_mpi_cmp (*r, n))
138 break;
139 gcry_mpi_release (*r);
140 }
141}
142
143
144/* 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 dc2794554..000000000
--- a/src/util/crypto_random.c
+++ /dev/null
@@ -1,425 +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#ifdef OPENBSD
100 srandom_deterministic (seed);
101#else
102 srandom (seed);
103#endif
104}
105
106
107/**
108 * @ingroup crypto
109 * Zero out @a buffer, securely against compiler optimizations.
110 * Used to delete key material.
111 *
112 * @param buffer the buffer to zap
113 * @param length buffer length
114 */
115void
116GNUNET_CRYPTO_zero_keys (void *buffer, size_t length)
117{
118#if HAVE_MEMSET_S
119 memset_s (buffer, length, 0, length);
120#elif HAVE_EXPLICIT_BZERO
121 explicit_bzero (buffer, length);
122#else
123 volatile unsigned char *p = buffer;
124 while (length--)
125 *p++ = 0;
126#endif
127}
128
129
130/**
131 * @ingroup crypto
132 * Fill block with a random values.
133 *
134 * @param mode desired quality of the random number
135 * @param buffer the buffer to fill
136 * @param length buffer length
137 */
138void
139GNUNET_CRYPTO_random_block (enum GNUNET_CRYPTO_Quality mode,
140 void *buffer,
141 size_t length)
142{
143#ifdef gcry_fast_random_poll
144 static unsigned int invokeCount;
145#endif
146 switch (mode)
147 {
148 case GNUNET_CRYPTO_QUALITY_STRONG:
149 /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
150#ifdef gcry_fast_random_poll
151 if ((invokeCount++ % 256) == 0)
152 gcry_fast_random_poll ();
153#endif
154 gcry_randomize (buffer, length, GCRY_STRONG_RANDOM);
155 return;
156
157 case GNUNET_CRYPTO_QUALITY_NONCE:
158 gcry_create_nonce (buffer, length);
159 return;
160
161 case GNUNET_CRYPTO_QUALITY_WEAK:
162 /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
163#ifdef gcry_fast_random_poll
164 if ((invokeCount++ % 256) == 0)
165 gcry_fast_random_poll ();
166#endif
167 gcry_randomize (buffer, length, GCRY_WEAK_RANDOM);
168 return;
169
170 default:
171 GNUNET_assert (0);
172 }
173}
174
175
176/**
177 * Produce a random unsigned 32-bit number modulo @a i.
178 *
179 * @param mode desired quality of the random number
180 * @param i the upper limit (exclusive) for the random number
181 * @return a random value in the interval [0,i[.
182 */
183uint32_t
184GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode,
185 uint32_t i)
186{
187#ifdef gcry_fast_random_poll
188 static unsigned int invokeCount;
189#endif
190 uint32_t ret;
191 uint32_t ul;
192
193 GNUNET_assert (i > 0);
194
195 switch (mode)
196 {
197 case GNUNET_CRYPTO_QUALITY_STRONG:
198 /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
199#ifdef gcry_fast_random_poll
200 if ((invokeCount++ % 256) == 0)
201 gcry_fast_random_poll ();
202#endif
203 ul = UINT32_MAX - (UINT32_MAX % i);
204 do
205 {
206 gcry_randomize ((unsigned char *) &ret,
207 sizeof(uint32_t),
208 GCRY_STRONG_RANDOM);
209 }
210 while (ret >= ul);
211 return ret % i;
212
213 case GNUNET_CRYPTO_QUALITY_NONCE:
214 ul = UINT32_MAX - (UINT32_MAX % i);
215 do
216 {
217 gcry_create_nonce (&ret, sizeof(ret));
218 }
219 while (ret >= ul);
220 return ret % i;
221
222 case GNUNET_CRYPTO_QUALITY_WEAK:
223 ret = i * get_weak_random ();
224 if (ret >= i)
225 ret = i - 1;
226 return ret;
227
228 default:
229 GNUNET_assert (0);
230 }
231 return 0;
232}
233
234
235/**
236 * Get an array with a random permutation of the
237 * numbers 0...n-1.
238 * @param mode #GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive)
239 * PRNG should be used, #GNUNET_RANDOM_QUALITY_WEAK otherwise
240 * @param n the size of the array
241 * @return the permutation array (allocated from heap)
242 */
243unsigned int *
244GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode,
245 unsigned int n)
246{
247 unsigned int *ret;
248 unsigned int i;
249 unsigned int tmp;
250 uint32_t x;
251
252 GNUNET_assert (n > 0);
253 ret = GNUNET_malloc (n * sizeof(unsigned int));
254 for (i = 0; i < n; i++)
255 ret[i] = i;
256 for (i = n - 1; i > 0; i--)
257 {
258 x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
259 tmp = ret[x];
260 ret[x] = ret[i];
261 ret[i] = tmp;
262 }
263 return ret;
264}
265
266
267/**
268 * Generate random unsigned 64-bit value.
269 *
270 * @param mode desired quality of the random number
271 * @param max value returned will be in range [0,max) (exclusive)
272 * @return random 64-bit number
273 */
274uint64_t
275GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode,
276 uint64_t max)
277{
278 uint64_t ret;
279 uint64_t ul;
280
281 GNUNET_assert (max > 0);
282 switch (mode)
283 {
284 case GNUNET_CRYPTO_QUALITY_STRONG:
285 ul = UINT64_MAX - (UINT64_MAX % max);
286 do
287 {
288 gcry_randomize ((unsigned char *) &ret,
289 sizeof(uint64_t),
290 GCRY_STRONG_RANDOM);
291 }
292 while (ret >= ul);
293 return ret % max;
294
295 case GNUNET_CRYPTO_QUALITY_NONCE:
296 ul = UINT64_MAX - (UINT64_MAX % max);
297 do
298 {
299 gcry_create_nonce (&ret, sizeof(ret));
300 }
301 while (ret >= ul);
302
303 return ret % max;
304
305 case GNUNET_CRYPTO_QUALITY_WEAK:
306 ret = max * get_weak_random ();
307 if (ret >= max)
308 ret = max - 1;
309 return ret;
310
311 default:
312 GNUNET_assert (0);
313 }
314 return 0;
315}
316
317
318/**
319 * @ingroup crypto
320 * Fill UUID with a timeflake pseudo-random value. Note that
321 * timeflakes use only 80 bits of randomness and 48 bits
322 * to encode a timestamp in milliseconds. So what we return
323 * here is not a completely random number.
324 *
325 * @param mode desired quality of the random number
326 * @param uuid the value to fill
327 */
328void
329GNUNET_CRYPTO_random_timeflake (enum GNUNET_CRYPTO_Quality mode,
330 struct GNUNET_Uuid *uuid)
331{
332 struct GNUNET_TIME_Absolute now;
333 uint64_t ms;
334 uint64_t be;
335 char *base;
336
337 GNUNET_CRYPTO_random_block (mode,
338 uuid,
339 sizeof (struct GNUNET_Uuid));
340 now = GNUNET_TIME_absolute_get ();
341 ms = now.abs_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
342 be = GNUNET_htonll (ms);
343 base = (char *) &be;
344 memcpy (uuid,
345 base + 2,
346 sizeof (be) - 2);
347}
348
349
350/**
351 * Allocation wrapper for libgcrypt, used to avoid bad locking
352 * strategy of libgcrypt implementation.
353 */
354static void *
355w_malloc (size_t n)
356{
357 return calloc (n, 1);
358}
359
360
361/**
362 * Allocation wrapper for libgcrypt, used to avoid bad locking
363 * strategy of libgcrypt implementation.
364 */
365static int
366w_check (const void *p)
367{
368 (void) p;
369 return 0; /* not secure memory */
370}
371
372
373/**
374 * Initialize libgcrypt.
375 */
376void __attribute__ ((constructor))
377GNUNET_CRYPTO_random_init ()
378{
379 gcry_error_t rc;
380
381 if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
382 {
383 fprintf (
384 stderr,
385 _ ("libgcrypt has not the expected version (version %s is required).\n"),
386 NEED_LIBGCRYPT_VERSION);
387 GNUNET_assert (0);
388 }
389 /* set custom allocators */
390 gcry_set_allocation_handler (&w_malloc, &w_malloc, &w_check, &realloc, &free);
391 /* Disable use of secure memory */
392 if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
393 fprintf (stderr,
394 "Failed to set libgcrypt option %s: %s\n",
395 "DISABLE_SECMEM",
396 gcry_strerror (rc));
397 /* Otherwise gnunet-ecc takes forever to complete, besides
398 we are fine with "just" using GCRY_STRONG_RANDOM */
399 if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0)))
400 fprintf (stderr,
401 "Failed to set libgcrypt option %s: %s\n",
402 "ENABLE_QUICK_RANDOM",
403 gcry_strerror (rc));
404 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
405 gcry_fast_random_poll ();
406 GNUNET_CRYPTO_seed_weak_random (
407 time (NULL)
408 ^ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
409}
410
411
412/**
413 * Nicely shut down libgcrypt.
414 */
415void __attribute__ ((destructor))
416GNUNET_CRYPTO_random_fini ()
417{
418 gcry_set_progress_handler (NULL, NULL);
419#ifdef GCRYCTL_CLOSE_RANDOM_DEVICE
420 (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
421#endif
422}
423
424
425/* end of crypto_random.c */
diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c
deleted file mode 100644
index 4b8e5a5ce..000000000
--- a/src/util/crypto_rsa.c
+++ /dev/null
@@ -1,1262 +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,
501 gcry_mpi_t n)
502{
503 gcry_mpi_t g;
504 int t;
505
506 g = gcry_mpi_new (0);
507 t = gcry_mpi_gcd (g, r, n);
508 gcry_mpi_release (g);
509 return t;
510}
511
512
513/**
514 * Create a blinding key
515 *
516 * @param len length of the key in bits (e.g. 2048)
517 * @param bks pre-secret to use to derive the blinding key
518 * @return the newly created blinding key, NULL if RSA key is malicious
519 */
520static struct RsaBlindingKey *
521rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
522 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks)
523{
524 const char *xts = "Blinding KDF extractor HMAC key"; /* Trusts bks' randomness more */
525 struct RsaBlindingKey *blind;
526 gcry_mpi_t n;
527
528 blind = GNUNET_new (struct RsaBlindingKey);
529
530 /* Extract the composite n from the RSA public key */
531 GNUNET_assert (0 ==
532 key_from_sexp (&n,
533 pkey->sexp,
534 "rsa",
535 "n"));
536 /* Assert that it at least looks like an RSA key */
537 GNUNET_assert (0 ==
538 gcry_mpi_get_flag (n,
539 GCRYMPI_FLAG_OPAQUE));
540 GNUNET_CRYPTO_kdf_mod_mpi (&blind->r,
541 n,
542 xts, strlen (xts),
543 bks, sizeof(*bks),
544 "Blinding KDF");
545 if (0 == rsa_gcd_validate (blind->r,
546 n))
547 {
548 gcry_mpi_release (blind->r);
549 GNUNET_free (blind);
550 blind = NULL;
551 }
552 gcry_mpi_release (n);
553 return blind;
554}
555
556
557/*
558 We originally added GNUNET_CRYPTO_kdf_mod_mpi for the benefit of the
559 previous routine.
560
561 There was previously a call to GNUNET_CRYPTO_kdf in
562 bkey = rsa_blinding_key_derive (len, bks);
563 that gives exactly len bits where
564 len = GNUNET_CRYPTO_rsa_public_key_len (pkey);
565
566 Now r = 2^(len-1)/pkey.n is the probability that a set high bit being
567 okay, meaning bkey < pkey.n. It follows that (1-r)/2 of the time bkey >
568 pkey.n making the effective bkey be
569 bkey mod pkey.n = bkey - pkey.n
570 so the effective bkey has its high bit set with probability r/2.
571
572 We expect r to be close to 1/2 if the exchange is honest, but the
573 exchange can choose r otherwise.
574
575 In blind signing, the exchange sees
576 B = bkey * S mod pkey.n
577 On deposit, the exchange sees S so they can compute bkey' = B/S mod
578 pkey.n for all B they recorded to see if bkey' has it's high bit set.
579 Also, note the exchange can compute 1/S efficiently since they know the
580 factors of pkey.n.
581
582 I suppose that happens with probability r/(1+r) if its the wrong B, not
583 completely sure. If otoh we've the right B, then we've the probability
584 r/2 of a set high bit in the effective bkey.
585
586 Interestingly, r^2-r has a maximum at the default r=1/2 anyways, giving
587 the wrong and right probabilities 1/3 and 1/4, respectively.
588
589 I feared this gives the exchange a meaningful fraction of a bit of
590 information per coin involved in the transaction. It sounds damaging if
591 numerous coins were involved. And it could run across transactions in
592 some scenarios.
593
594 We fixed this by using a more uniform deterministic pseudo-random number
595 generator for blinding factors. I do not believe this to be a problem
596 for the rsa_full_domain_hash routine, but better safe than sorry.
597 */
598
599
600int
601GNUNET_CRYPTO_rsa_signature_cmp (const struct GNUNET_CRYPTO_RsaSignature *s1,
602 const struct GNUNET_CRYPTO_RsaSignature *s2)
603{
604 void *b1;
605 void *b2;
606 size_t z1;
607 size_t z2;
608 int ret;
609
610 z1 = GNUNET_CRYPTO_rsa_signature_encode (s1,
611 &b1);
612 z2 = GNUNET_CRYPTO_rsa_signature_encode (s2,
613 &b2);
614 if (z1 != z2)
615 ret = 1;
616 else
617 ret = memcmp (b1,
618 b2,
619 z1);
620 GNUNET_free (b1);
621 GNUNET_free (b2);
622 return ret;
623}
624
625
626int
627GNUNET_CRYPTO_rsa_public_key_cmp (const struct GNUNET_CRYPTO_RsaPublicKey *p1,
628 const struct GNUNET_CRYPTO_RsaPublicKey *p2)
629{
630 void *b1;
631 void *b2;
632 size_t z1;
633 size_t z2;
634 int ret;
635
636 z1 = GNUNET_CRYPTO_rsa_public_key_encode (p1,
637 &b1);
638 z2 = GNUNET_CRYPTO_rsa_public_key_encode (p2,
639 &b2);
640 if (z1 != z2)
641 ret = 1;
642 else
643 ret = memcmp (b1,
644 b2,
645 z1);
646 GNUNET_free (b1);
647 GNUNET_free (b2);
648 return ret;
649}
650
651
652int
653GNUNET_CRYPTO_rsa_private_key_cmp (const struct GNUNET_CRYPTO_RsaPrivateKey *p1,
654 const struct GNUNET_CRYPTO_RsaPrivateKey *p2)
655{
656 void *b1;
657 void *b2;
658 size_t z1;
659 size_t z2;
660 int ret;
661
662 z1 = GNUNET_CRYPTO_rsa_private_key_encode (p1,
663 &b1);
664 z2 = GNUNET_CRYPTO_rsa_private_key_encode (p2,
665 &b2);
666 if (z1 != z2)
667 ret = 1;
668 else
669 ret = memcmp (b1,
670 b2,
671 z1);
672 GNUNET_free (b1);
673 GNUNET_free (b2);
674 return ret;
675}
676
677
678unsigned int
679GNUNET_CRYPTO_rsa_public_key_len (const struct GNUNET_CRYPTO_RsaPublicKey *key)
680{
681 gcry_mpi_t n;
682 unsigned int rval;
683
684 if (0 != key_from_sexp (&n, key->sexp, "rsa", "n"))
685 { /* Not an RSA public key */
686 GNUNET_break (0);
687 return 0;
688 }
689 rval = gcry_mpi_get_nbits (n);
690 gcry_mpi_release (n);
691 return rval;
692}
693
694
695/**
696 * Destroy a blinding key
697 *
698 * @param bkey the blinding key to destroy
699 */
700static void
701rsa_blinding_key_free (struct RsaBlindingKey *bkey)
702{
703 gcry_mpi_release (bkey->r);
704 GNUNET_free (bkey);
705}
706
707
708/**
709 * Print an MPI to a newly created buffer
710 *
711 * @param v MPI to print.
712 * @param[out] newly allocated buffer containing the result
713 * @return number of bytes stored in @a buffer
714 */
715static size_t
716numeric_mpi_alloc_n_print (gcry_mpi_t v,
717 char **buffer)
718{
719 size_t n;
720 char *b;
721 size_t rsize;
722
723 gcry_mpi_print (GCRYMPI_FMT_USG,
724 NULL,
725 0,
726 &n,
727 v);
728 b = GNUNET_malloc (n);
729 GNUNET_assert (0 ==
730 gcry_mpi_print (GCRYMPI_FMT_USG,
731 (unsigned char *) b,
732 n,
733 &rsize,
734 v));
735 *buffer = b;
736 return n;
737}
738
739
740/**
741 * Computes a full domain hash seeded by the given public key.
742 * This gives a measure of provable security to the Taler exchange
743 * against one-more forgery attacks. See:
744 * https://eprint.iacr.org/2001/002.pdf
745 * http://www.di.ens.fr/~pointche/Documents/Papers/2001_fcA.pdf
746 *
747 * @param hash initial hash of the message to sign
748 * @param pkey the public key of the signer
749 * @param rsize If not NULL, the number of bytes actually stored in buffer
750 * @return MPI value set to the FDH, NULL if RSA key is malicious
751 */
752static gcry_mpi_t
753rsa_full_domain_hash (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
754 const struct GNUNET_HashCode *hash)
755{
756 gcry_mpi_t r, n;
757 void *xts;
758 size_t xts_len;
759 int ok;
760
761 /* Extract the composite n from the RSA public key */
762 GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n"));
763 /* Assert that it at least looks like an RSA key */
764 GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE));
765
766 /* We key with the public denomination key as a homage to RSA-PSS by *
767 * Mihir Bellare and Phillip Rogaway. Doing this lowers the degree *
768 * of the hypothetical polyomial-time attack on RSA-KTI created by a *
769 * polynomial-time one-more forgary attack. Yey seeding! */
770 xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
771 &xts);
772
773 GNUNET_CRYPTO_kdf_mod_mpi (&r,
774 n,
775 xts, xts_len,
776 hash, sizeof(*hash),
777 "RSA-FDA FTpsW!");
778 GNUNET_free (xts);
779 ok = rsa_gcd_validate (r, n);
780 gcry_mpi_release (n);
781 if (ok)
782 return r;
783 gcry_mpi_release (r);
784 return NULL;
785}
786
787
788enum GNUNET_GenericReturnValue
789GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash,
790 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
791 struct GNUNET_CRYPTO_RsaPublicKey *pkey,
792 void **buf,
793 size_t *buf_size)
794{
795 struct RsaBlindingKey *bkey;
796 gcry_mpi_t data;
797 gcry_mpi_t ne[2];
798 gcry_mpi_t r_e;
799 gcry_mpi_t data_r_e;
800 int ret;
801
802 BENCHMARK_START (rsa_blind);
803
804 GNUNET_assert (buf != NULL);
805 GNUNET_assert (buf_size != NULL);
806 ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne");
807 if (0 != ret)
808 ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne");
809 if (0 != ret)
810 {
811 GNUNET_break (0);
812 *buf = NULL;
813 *buf_size = 0;
814 return GNUNET_NO;
815 }
816
817 data = rsa_full_domain_hash (pkey, hash);
818 if (NULL == data)
819 goto rsa_gcd_validate_failure;
820
821 bkey = rsa_blinding_key_derive (pkey, bks);
822 if (NULL == bkey)
823 {
824 gcry_mpi_release (data);
825 goto rsa_gcd_validate_failure;
826 }
827
828 r_e = gcry_mpi_new (0);
829 gcry_mpi_powm (r_e,
830 bkey->r,
831 ne[1],
832 ne[0]);
833 data_r_e = gcry_mpi_new (0);
834 gcry_mpi_mulm (data_r_e,
835 data,
836 r_e,
837 ne[0]);
838 gcry_mpi_release (data);
839 gcry_mpi_release (ne[0]);
840 gcry_mpi_release (ne[1]);
841 gcry_mpi_release (r_e);
842 rsa_blinding_key_free (bkey);
843
844 *buf_size = numeric_mpi_alloc_n_print (data_r_e,
845 (char **) buf);
846 gcry_mpi_release (data_r_e);
847
848 BENCHMARK_END (rsa_blind);
849
850 return GNUNET_YES;
851
852rsa_gcd_validate_failure:
853 /* We know the RSA key is malicious here, so warn the wallet. */
854 /* GNUNET_break_op (0); */
855 gcry_mpi_release (ne[0]);
856 gcry_mpi_release (ne[1]);
857 *buf = NULL;
858 *buf_size = 0;
859 return GNUNET_NO;
860}
861
862
863/**
864 * Convert an MPI to an S-expression suitable for signature operations.
865 *
866 * @param value pointer to the data to convert
867 * @return converted s-expression
868 */
869static gcry_sexp_t
870mpi_to_sexp (gcry_mpi_t value)
871{
872 gcry_sexp_t data = NULL;
873
874 GNUNET_assert (0 ==
875 gcry_sexp_build (&data,
876 NULL,
877 "(data (flags raw) (value %M))",
878 value));
879 return data;
880}
881
882
883/**
884 * Sign the given MPI.
885 *
886 * @param key private key to use for the signing
887 * @param value the MPI to sign
888 * @return NULL on error, signature on success
889 */
890static struct GNUNET_CRYPTO_RsaSignature *
891rsa_sign_mpi (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
892 gcry_mpi_t value)
893{
894 struct GNUNET_CRYPTO_RsaSignature *sig;
895 gcry_sexp_t data;
896 gcry_sexp_t result;
897 int rc;
898
899 data = mpi_to_sexp (value);
900
901 if (0 !=
902 (rc = gcry_pk_sign (&result,
903 data,
904 key->sexp)))
905 {
906 LOG (GNUNET_ERROR_TYPE_WARNING,
907 _ ("RSA signing failed at %s:%d: %s\n"),
908 __FILE__,
909 __LINE__,
910 gcry_strerror (rc));
911 gcry_sexp_release (data);
912 GNUNET_break (0);
913 return NULL;
914 }
915
916 /* Lenstra protection was first added to libgcrypt 1.6.4
917 * with commit c17f84bd02d7ee93845e92e20f6ddba814961588.
918 */
919#if GCRYPT_VERSION_NUMBER < 0x010604
920 /* verify signature (guards against Lenstra's attack with fault injection...) */
921 struct GNUNET_CRYPTO_RsaPublicKey *public_key =
922 GNUNET_CRYPTO_rsa_private_key_get_public (key);
923 if (0 !=
924 gcry_pk_verify (result,
925 data,
926 public_key->sexp))
927 {
928 GNUNET_break (0);
929 GNUNET_CRYPTO_rsa_public_key_free (public_key);
930 gcry_sexp_release (data);
931 gcry_sexp_release (result);
932 return NULL;
933 }
934 GNUNET_CRYPTO_rsa_public_key_free (public_key);
935#endif
936
937 /* return signature */
938 gcry_sexp_release (data);
939 sig = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
940 sig->sexp = result;
941 return sig;
942}
943
944
945struct GNUNET_CRYPTO_RsaSignature *
946GNUNET_CRYPTO_rsa_sign_blinded (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
947 const void *msg,
948 size_t msg_len)
949{
950 gcry_mpi_t v = NULL;
951 struct GNUNET_CRYPTO_RsaSignature *sig;
952
953 BENCHMARK_START (rsa_sign_blinded);
954
955 GNUNET_assert (0 ==
956 gcry_mpi_scan (&v,
957 GCRYMPI_FMT_USG,
958 msg,
959 msg_len,
960 NULL));
961
962 sig = rsa_sign_mpi (key, v);
963 gcry_mpi_release (v);
964 BENCHMARK_END (rsa_sign_blinded);
965 return sig;
966}
967
968
969struct GNUNET_CRYPTO_RsaSignature *
970GNUNET_CRYPTO_rsa_sign_fdh (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
971 const struct GNUNET_HashCode *hash)
972{
973 struct GNUNET_CRYPTO_RsaPublicKey *pkey;
974 gcry_mpi_t v = NULL;
975 struct GNUNET_CRYPTO_RsaSignature *sig;
976
977 pkey = GNUNET_CRYPTO_rsa_private_key_get_public (key);
978 v = rsa_full_domain_hash (pkey, hash);
979 GNUNET_CRYPTO_rsa_public_key_free (pkey);
980 if (NULL == v) /* rsa_gcd_validate failed meaning */
981 return NULL; /* our *own* RSA key is malicious. */
982
983 sig = rsa_sign_mpi (key, v);
984 gcry_mpi_release (v);
985 return sig;
986}
987
988
989void
990GNUNET_CRYPTO_rsa_signature_free (struct GNUNET_CRYPTO_RsaSignature *sig)
991{
992 gcry_sexp_release (sig->sexp);
993 GNUNET_free (sig);
994}
995
996
997size_t
998GNUNET_CRYPTO_rsa_signature_encode (
999 const struct GNUNET_CRYPTO_RsaSignature *sig,
1000 void **buffer)
1001{
1002 gcry_mpi_t s;
1003 size_t buf_size;
1004 size_t rsize;
1005 unsigned char *buf;
1006 int ret;
1007
1008 ret = key_from_sexp (&s,
1009 sig->sexp,
1010 "sig-val",
1011 "s");
1012 if (0 != ret)
1013 ret = key_from_sexp (&s,
1014 sig->sexp,
1015 "rsa",
1016 "s");
1017 GNUNET_assert (0 == ret);
1018 gcry_mpi_print (GCRYMPI_FMT_USG,
1019 NULL,
1020 0,
1021 &buf_size,
1022 s);
1023 buf = GNUNET_malloc (buf_size);
1024 GNUNET_assert (0 ==
1025 gcry_mpi_print (GCRYMPI_FMT_USG,
1026 buf,
1027 buf_size,
1028 &rsize,
1029 s));
1030 GNUNET_assert (rsize == buf_size);
1031 *buffer = (void *) buf;
1032 gcry_mpi_release (s);
1033 return buf_size;
1034}
1035
1036
1037struct GNUNET_CRYPTO_RsaSignature *
1038GNUNET_CRYPTO_rsa_signature_decode (const void *buf,
1039 size_t buf_size)
1040{
1041 struct GNUNET_CRYPTO_RsaSignature *sig;
1042 gcry_mpi_t s;
1043 gcry_sexp_t data;
1044
1045 if (0 !=
1046 gcry_mpi_scan (&s,
1047 GCRYMPI_FMT_USG,
1048 buf,
1049 buf_size,
1050 NULL))
1051 {
1052 GNUNET_break_op (0);
1053 return NULL;
1054 }
1055
1056 if (0 !=
1057 gcry_sexp_build (&data,
1058 NULL,
1059 "(sig-val(rsa(s %M)))",
1060 s))
1061 {
1062 GNUNET_break (0);
1063 gcry_mpi_release (s);
1064 return NULL;
1065 }
1066 gcry_mpi_release (s);
1067 sig = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1068 sig->sexp = data;
1069 return sig;
1070}
1071
1072
1073struct GNUNET_CRYPTO_RsaPublicKey *
1074GNUNET_CRYPTO_rsa_public_key_dup (const struct GNUNET_CRYPTO_RsaPublicKey *key)
1075{
1076 struct GNUNET_CRYPTO_RsaPublicKey *dup;
1077 gcry_sexp_t dup_sexp;
1078 size_t erroff;
1079
1080 /* check if we really are exporting a public key */
1081 dup_sexp = gcry_sexp_find_token (key->sexp, "public-key", 0);
1082 GNUNET_assert (NULL != dup_sexp);
1083 gcry_sexp_release (dup_sexp);
1084 /* copy the sexp */
1085 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", key->sexp));
1086 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaPublicKey);
1087 dup->sexp = dup_sexp;
1088 return dup;
1089}
1090
1091
1092struct GNUNET_CRYPTO_RsaSignature *
1093GNUNET_CRYPTO_rsa_unblind (const struct GNUNET_CRYPTO_RsaSignature *sig,
1094 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
1095 struct GNUNET_CRYPTO_RsaPublicKey *pkey)
1096{
1097 struct RsaBlindingKey *bkey;
1098 gcry_mpi_t n;
1099 gcry_mpi_t s;
1100 gcry_mpi_t r_inv;
1101 gcry_mpi_t ubsig;
1102 int ret;
1103 struct GNUNET_CRYPTO_RsaSignature *sret;
1104
1105 BENCHMARK_START (rsa_unblind);
1106
1107 ret = key_from_sexp (&n, pkey->sexp, "public-key", "n");
1108 if (0 != ret)
1109 ret = key_from_sexp (&n, pkey->sexp, "rsa", "n");
1110 if (0 != ret)
1111 {
1112 GNUNET_break_op (0);
1113 return NULL;
1114 }
1115 ret = key_from_sexp (&s, sig->sexp, "sig-val", "s");
1116 if (0 != ret)
1117 ret = key_from_sexp (&s, sig->sexp, "rsa", "s");
1118 if (0 != ret)
1119 {
1120 gcry_mpi_release (n);
1121 GNUNET_break_op (0);
1122 return NULL;
1123 }
1124
1125 bkey = rsa_blinding_key_derive (pkey, bks);
1126 if (NULL == bkey)
1127 {
1128 /* RSA key is malicious since rsa_gcd_validate failed here.
1129 * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
1130 * so the exchange is being malicious in an unfamilair way, maybe
1131 * just trying to crash us. */
1132 GNUNET_break_op (0);
1133 gcry_mpi_release (n);
1134 gcry_mpi_release (s);
1135 return NULL;
1136 }
1137
1138 r_inv = gcry_mpi_new (0);
1139 if (1 !=
1140 gcry_mpi_invm (r_inv,
1141 bkey->r,
1142 n))
1143 {
1144 /* We cannot find r mod n, so gcd(r,n) != 1, which should get *
1145 * caught above, but we handle it the same here. */
1146 GNUNET_break_op (0);
1147 gcry_mpi_release (r_inv);
1148 rsa_blinding_key_free (bkey);
1149 gcry_mpi_release (n);
1150 gcry_mpi_release (s);
1151 return NULL;
1152 }
1153
1154 ubsig = gcry_mpi_new (0);
1155 gcry_mpi_mulm (ubsig, s, r_inv, n);
1156 gcry_mpi_release (n);
1157 gcry_mpi_release (r_inv);
1158 gcry_mpi_release (s);
1159 rsa_blinding_key_free (bkey);
1160
1161 sret = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1162 GNUNET_assert (0 ==
1163 gcry_sexp_build (&sret->sexp,
1164 NULL,
1165 "(sig-val (rsa (s %M)))",
1166 ubsig));
1167 gcry_mpi_release (ubsig);
1168 BENCHMARK_END (rsa_unblind);
1169 return sret;
1170}
1171
1172
1173enum GNUNET_GenericReturnValue
1174GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash,
1175 const struct GNUNET_CRYPTO_RsaSignature *sig,
1176 const struct GNUNET_CRYPTO_RsaPublicKey *pkey)
1177{
1178 gcry_sexp_t data;
1179 gcry_mpi_t r;
1180 int rc;
1181
1182 BENCHMARK_START (rsa_verify);
1183
1184 r = rsa_full_domain_hash (pkey, hash);
1185 if (NULL == r)
1186 {
1187 GNUNET_break_op (0);
1188 /* RSA key is malicious since rsa_gcd_validate failed here.
1189 * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
1190 * so the exchange is being malicious in an unfamilair way, maybe
1191 * just trying to crash us. Arguably, we've only an internal error
1192 * though because we should've detected this in our previous call
1193 * to GNUNET_CRYPTO_rsa_unblind. *///
1194 return GNUNET_NO;
1195 }
1196
1197 data = mpi_to_sexp (r);
1198 gcry_mpi_release (r);
1199
1200 rc = gcry_pk_verify (sig->sexp,
1201 data,
1202 pkey->sexp);
1203 gcry_sexp_release (data);
1204 if (0 != rc)
1205 {
1206 LOG (GNUNET_ERROR_TYPE_WARNING,
1207 _ ("RSA signature verification failed at %s:%d: %s\n"),
1208 __FILE__,
1209 __LINE__,
1210 gcry_strerror (rc));
1211 BENCHMARK_END (rsa_verify);
1212 return GNUNET_SYSERR;
1213 }
1214 BENCHMARK_END (rsa_verify);
1215 return GNUNET_OK;
1216}
1217
1218
1219struct GNUNET_CRYPTO_RsaPrivateKey *
1220GNUNET_CRYPTO_rsa_private_key_dup (
1221 const struct GNUNET_CRYPTO_RsaPrivateKey *key)
1222{
1223 struct GNUNET_CRYPTO_RsaPrivateKey *dup;
1224 gcry_sexp_t dup_sexp;
1225 size_t erroff;
1226
1227 /* check if we really are exporting a private key */
1228 dup_sexp = gcry_sexp_find_token (key->sexp, "private-key", 0);
1229 GNUNET_assert (NULL != dup_sexp);
1230 gcry_sexp_release (dup_sexp);
1231 /* copy the sexp */
1232 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", key->sexp));
1233 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaPrivateKey);
1234 dup->sexp = dup_sexp;
1235 return dup;
1236}
1237
1238
1239struct GNUNET_CRYPTO_RsaSignature *
1240GNUNET_CRYPTO_rsa_signature_dup (const struct GNUNET_CRYPTO_RsaSignature *sig)
1241{
1242 struct GNUNET_CRYPTO_RsaSignature *dup;
1243 gcry_sexp_t dup_sexp;
1244 size_t erroff;
1245 gcry_mpi_t s;
1246 int ret;
1247
1248 /* verify that this is an RSA signature */
1249 ret = key_from_sexp (&s, sig->sexp, "sig-val", "s");
1250 if (0 != ret)
1251 ret = key_from_sexp (&s, sig->sexp, "rsa", "s");
1252 GNUNET_assert (0 == ret);
1253 gcry_mpi_release (s);
1254 /* copy the sexp */
1255 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", sig->sexp));
1256 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1257 dup->sexp = dup_sexp;
1258 return dup;
1259}
1260
1261
1262/* 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 c2f2a441f..000000000
--- a/src/util/dnsstub.c
+++ /dev/null
@@ -1,732 +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 (ds->ss.ss_family != addr.ss_family)
328 continue;
329 if (addr.ss_family == AF_INET)
330 {
331 struct sockaddr_in *v4 = (struct sockaddr_in *) &addr;
332 struct sockaddr_in *ds_v4 = (struct sockaddr_in *) &ds->ss;
333
334
335 if ((0 == memcmp (&v4->sin_addr,
336 &ds_v4->sin_addr,
337 sizeof(struct sockaddr_in))) &&
338 (v4->sin_port == ds_v4->sin_port))
339 {
340 found = GNUNET_YES;
341 break;
342 }
343 }
344 else
345 {
346 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) &addr;
347 struct sockaddr_in6 *ds_v6 = (struct sockaddr_in6 *) &ds->ss;
348
349 if (0 == memcmp (&v6->sin6_addr,
350 &ds_v6->sin6_addr,
351 sizeof (v6->sin6_addr)) &&
352 (v6->sin6_port == ds_v6->sin6_port))
353 {
354 found = GNUNET_YES;
355 break;
356 }
357
358 }
359 }
360 if (GNUNET_NO == found)
361 {
362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
363 "Received DNS response from server we never asked (ignored)\n");
364
365 return GNUNET_NO;
366 }
367 if (sizeof(struct GNUNET_TUN_DnsHeader) > (size_t) r)
368 {
369 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
370 _ ("Received DNS response that is too small (%u bytes)\n"),
371 (unsigned int) r);
372 return GNUNET_NO;
373 }
374 dns = (struct GNUNET_TUN_DnsHeader *) buf;
375 if (NULL == rs->rc)
376 {
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378 "Request timeout or cancelled; ignoring reply\n");
379 return GNUNET_NO;
380 }
381 rs->rc (rs->rc_cls, dns, r);
382 }
383 return GNUNET_OK;
384}
385
386
387/**
388 * Read a DNS response from the (unhindered) UDP-Socket
389 *
390 * @param cls socket to read from
391 */
392static void
393read_response (void *cls);
394
395
396/**
397 * Schedule #read_response() task for @a rs.
398 *
399 * @param rs request to schedule read operation for
400 */
401static void
402schedule_read (struct GNUNET_DNSSTUB_RequestSocket *rs)
403{
404 struct GNUNET_NETWORK_FDSet *rset;
405
406 if (NULL != rs->read_task)
407 GNUNET_SCHEDULER_cancel (rs->read_task);
408 rset = GNUNET_NETWORK_fdset_create ();
409 if (NULL != rs->dnsout4)
410 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
411 if (NULL != rs->dnsout6)
412 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
413 rs->read_task =
414 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
415 GNUNET_TIME_UNIT_FOREVER_REL,
416 rset,
417 NULL,
418 &read_response,
419 rs);
420 GNUNET_NETWORK_fdset_destroy (rset);
421}
422
423
424/**
425 * Read a DNS response from the (unhindered) UDP-Socket
426 *
427 * @param cls `struct GNUNET_DNSSTUB_RequestSocket` to read from
428 */
429static void
430read_response (void *cls)
431{
432 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
433 const struct GNUNET_SCHEDULER_TaskContext *tc;
434
435 rs->read_task = NULL;
436 tc = GNUNET_SCHEDULER_get_task_context ();
437 /* read and process ready sockets */
438 if ((NULL != rs->dnsout4) &&
439 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
440 (GNUNET_SYSERR == do_dns_read (rs, rs->dnsout4)))
441 rs->dnsout4 = NULL;
442 if ((NULL != rs->dnsout6) &&
443 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
444 (GNUNET_SYSERR == do_dns_read (rs, rs->dnsout6)))
445 rs->dnsout6 = NULL;
446 /* re-schedule read task */
447 schedule_read (rs);
448}
449
450
451/**
452 * Task to (re)transmit the DNS query, possibly repeatedly until
453 * we succeed.
454 *
455 * @param cls our `struct GNUNET_DNSSTUB_RequestSocket *`
456 */
457static void
458transmit_query (void *cls)
459{
460 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
461 struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
462 const struct sockaddr *sa;
463 socklen_t salen;
464 struct DnsServer *ds;
465 struct GNUNET_NETWORK_Handle *dnsout;
466
467 rs->retry_task =
468 GNUNET_SCHEDULER_add_delayed (ctx->retry_freq, &transmit_query, rs);
469 ds = rs->ds_pos;
470 rs->ds_pos = ds->next;
471 if (NULL == rs->ds_pos)
472 rs->ds_pos = ctx->dns_head;
473 GNUNET_assert (NULL != ds);
474 dnsout = NULL;
475 switch (ds->ss.ss_family)
476 {
477 case AF_INET:
478 if (NULL == rs->dnsout4)
479 rs->dnsout4 = open_socket (AF_INET);
480 dnsout = rs->dnsout4;
481 sa = (const struct sockaddr *) &ds->ss;
482 salen = sizeof(struct sockaddr_in);
483 break;
484
485 case AF_INET6:
486 if (NULL == rs->dnsout6)
487 rs->dnsout6 = open_socket (AF_INET6);
488 dnsout = rs->dnsout6;
489 sa = (const struct sockaddr *) &ds->ss;
490 salen = sizeof(struct sockaddr_in6);
491 break;
492
493 default:
494 return;
495 }
496 if (NULL == dnsout)
497 {
498 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
499 "Unable to use configure DNS server, skipping\n");
500 return;
501 }
502 if (GNUNET_SYSERR == GNUNET_NETWORK_socket_sendto (dnsout,
503 rs->request,
504 rs->request_len,
505 sa,
506 salen))
507 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
508 _ ("Failed to send DNS request to %s: %s\n"),
509 GNUNET_a2s (sa, salen),
510 strerror (errno));
511 else
512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
513 _ ("Sent DNS request to %s\n"),
514 GNUNET_a2s (sa, salen));
515 schedule_read (rs);
516}
517
518
519/**
520 * Perform DNS resolution using our default IP from init.
521 *
522 * @param ctx stub resolver to use
523 * @param request DNS request to transmit
524 * @param request_len number of bytes in msg
525 * @param rc function to call with result
526 * @param rc_cls closure for 'rc'
527 * @return socket used for the request, NULL on error
528 */
529struct GNUNET_DNSSTUB_RequestSocket *
530GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
531 const void *request,
532 size_t request_len,
533 GNUNET_DNSSTUB_ResultCallback rc,
534 void *rc_cls)
535{
536 struct GNUNET_DNSSTUB_RequestSocket *rs;
537
538 if (NULL == ctx->dns_head)
539 {
540 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
541 "No DNS server configured for resolution\n");
542 return NULL;
543 }
544 if (NULL == (rs = get_request_socket (ctx)))
545 {
546 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
547 "No request socket available for DNS resolution\n");
548 return NULL;
549 }
550 rs->ds_pos = ctx->dns_head;
551 rs->rc = rc;
552 rs->rc_cls = rc_cls;
553 rs->request = GNUNET_memdup (request, request_len);
554 rs->request_len = request_len;
555 rs->retry_task = GNUNET_SCHEDULER_add_now (&transmit_query, rs);
556 return rs;
557}
558
559
560/**
561 * Cancel DNS resolution.
562 *
563 * @param rs resolution to cancel
564 */
565void
566GNUNET_DNSSTUB_resolve_cancel (struct GNUNET_DNSSTUB_RequestSocket *rs)
567{
568 rs->rc = NULL;
569 if (NULL != rs->retry_task)
570 {
571 GNUNET_SCHEDULER_cancel (rs->retry_task);
572 rs->retry_task = NULL;
573 }
574 if (NULL != rs->read_task)
575 {
576 GNUNET_SCHEDULER_cancel (rs->read_task);
577 rs->read_task = NULL;
578 }
579}
580
581
582/**
583 * Start a DNS stub resolver.
584 *
585 * @param num_sockets how many sockets should we open
586 * in parallel for DNS queries for this stub?
587 * @return NULL on error
588 */
589struct GNUNET_DNSSTUB_Context *
590GNUNET_DNSSTUB_start (unsigned int num_sockets)
591{
592 struct GNUNET_DNSSTUB_Context *ctx;
593
594 if (0 == num_sockets)
595 {
596 GNUNET_break (0);
597 return NULL;
598 }
599 ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context);
600 ctx->num_sockets = num_sockets;
601 ctx->sockets =
602 GNUNET_new_array (num_sockets, struct GNUNET_DNSSTUB_RequestSocket);
603 ctx->retry_freq = DNS_RETRANSMIT_DELAY;
604 return ctx;
605}
606
607
608/**
609 * Add nameserver for use by the DNSSTUB. We will use
610 * all provided nameservers for resolution (round-robin).
611 *
612 * @param ctx resolver context to modify
613 * @param dns_ip target IP address to use (as string)
614 * @return #GNUNET_OK on success
615 */
616int
617GNUNET_DNSSTUB_add_dns_ip (struct GNUNET_DNSSTUB_Context *ctx,
618 const char *dns_ip)
619{
620 struct DnsServer *ds;
621 struct in_addr i4;
622 struct in6_addr i6;
623
624 ds = GNUNET_new (struct DnsServer);
625 if (1 == inet_pton (AF_INET, dns_ip, &i4))
626 {
627 struct sockaddr_in *s4 = (struct sockaddr_in *) &ds->ss;
628
629 s4->sin_family = AF_INET;
630 s4->sin_port = htons (53);
631 s4->sin_addr = i4;
632#if HAVE_SOCKADDR_IN_SIN_LEN
633 s4->sin_len = (u_char) sizeof(struct sockaddr_in);
634#endif
635 }
636 else if (1 == inet_pton (AF_INET6, dns_ip, &i6))
637 {
638 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ds->ss;
639
640 s6->sin6_family = AF_INET6;
641 s6->sin6_port = htons (53);
642 s6->sin6_addr = i6;
643#if HAVE_SOCKADDR_IN_SIN_LEN
644 s6->sin6_len = (u_char) sizeof(struct sockaddr_in6);
645#endif
646 }
647 else
648 {
649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
650 "Malformed IP address `%s' for DNS server\n",
651 dns_ip);
652 GNUNET_free (ds);
653 return GNUNET_SYSERR;
654 }
655 GNUNET_CONTAINER_DLL_insert (ctx->dns_head, ctx->dns_tail, ds);
656 return GNUNET_OK;
657}
658
659
660/**
661 * Add nameserver for use by the DNSSTUB. We will use
662 * all provided nameservers for resolution (round-robin).
663 *
664 * @param ctx resolver context to modify
665 * @param sa socket address of DNS resolver to use
666 * @return #GNUNET_OK on success
667 */
668int
669GNUNET_DNSSTUB_add_dns_sa (struct GNUNET_DNSSTUB_Context *ctx,
670 const struct sockaddr *sa)
671{
672 struct DnsServer *ds;
673
674 ds = GNUNET_new (struct DnsServer);
675 switch (sa->sa_family)
676 {
677 case AF_INET :
678 GNUNET_memcpy (&ds->ss, sa, sizeof(struct sockaddr_in));
679 break;
680
681 case AF_INET6:
682 GNUNET_memcpy (&ds->ss, sa, sizeof(struct sockaddr_in6));
683 break;
684
685 default:
686 GNUNET_break (0);
687 GNUNET_free (ds);
688 return GNUNET_SYSERR;
689 }
690 GNUNET_CONTAINER_DLL_insert (ctx->dns_head, ctx->dns_tail, ds);
691 return GNUNET_OK;
692}
693
694
695/**
696 * How long should we try requests before timing out?
697 * Only effective for requests issued after this call.
698 *
699 * @param ctx resolver context to modify
700 * @param retry_freq how long to wait between retries
701 */
702void
703GNUNET_DNSSTUB_set_retry (struct GNUNET_DNSSTUB_Context *ctx,
704 struct GNUNET_TIME_Relative retry_freq)
705{
706 ctx->retry_freq = retry_freq;
707}
708
709
710/**
711 * Cleanup DNSSTUB resolver.
712 *
713 * @param ctx stub resolver to clean up
714 */
715void
716GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx)
717{
718 struct DnsServer *ds;
719
720 while (NULL != (ds = ctx->dns_head))
721 {
722 GNUNET_CONTAINER_DLL_remove (ctx->dns_head, ctx->dns_tail, ds);
723 GNUNET_free (ds);
724 }
725 for (unsigned int i = 0; i < ctx->num_sockets; i++)
726 cleanup_rs (&ctx->sockets[i]);
727 GNUNET_free (ctx->sockets);
728 GNUNET_free (ctx);
729}
730
731
732/* 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 96aee40e3..000000000
--- a/src/util/getopt_helpers.c
+++ /dev/null
@@ -1,1016 +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 enum GNUNET_GenericReturnValue
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
56struct GNUNET_GETOPT_CommandLineOption
57GNUNET_GETOPT_option_version (const char *version)
58{
59 struct GNUNET_GETOPT_CommandLineOption clo = {
60 .shortName = 'v',
61 .name = "version",
62 .description = gettext_noop (
63 "print the version number"),
64 .option_exclusive = 1,
65 .processor = &print_version,
66 .scls = (void *) version
67 };
68
69 return clo;
70}
71
72
73/**
74 * At what offset does the help text start?
75 */
76#define BORDER 29
77
78/**
79 * Print out details on command line options (implements --help).
80 *
81 * @param ctx command line processing context
82 * @param scls additional closure (points to about text)
83 * @param option name of the option
84 * @param value not used (NULL)
85 * @return #GNUNET_NO (do not continue, not an error)
86 */
87static enum GNUNET_GenericReturnValue
88format_help (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
89 void *scls,
90 const char *option,
91 const char *value)
92{
93 const char *about = scls;
94 size_t slen;
95 unsigned int i;
96 int j;
97 size_t ml;
98 size_t p;
99 char *scp;
100 const char *trans;
101 const struct GNUNET_GETOPT_CommandLineOption *opt;
102 const struct GNUNET_OS_ProjectData *pd;
103
104 (void) option;
105 (void) value;
106 if (NULL != about)
107 {
108 printf ("%s\n%s\n", ctx->binaryOptions, gettext (about));
109 printf (_ (
110 "Arguments mandatory for long options are also mandatory for short options.\n"));
111 }
112 i = 0;
113 opt = ctx->allOptions;
114 while (NULL != opt[i].description)
115 {
116 if (opt[i].shortName == '\0')
117 printf (" ");
118 else
119 printf (" -%c, ", opt[i].shortName);
120 printf ("--%s", opt[i].name);
121 slen = 8 + strlen (opt[i].name);
122 if (NULL != opt[i].argumentHelp)
123 {
124 printf ("=%s", opt[i].argumentHelp);
125 slen += 1 + strlen (opt[i].argumentHelp);
126 }
127 if (slen > BORDER)
128 {
129 printf ("\n%*s", BORDER, "");
130 slen = BORDER;
131 }
132 if (slen < BORDER)
133 {
134 printf ("%*s", (int) (BORDER - slen), "");
135 slen = BORDER;
136 }
137 if (0 < strlen (opt[i].description))
138 trans = gettext (opt[i].description);
139 else
140 trans = "";
141 ml = strlen (trans);
142 p = 0;
143OUTER:
144 while (ml - p > 78 - slen)
145 {
146 for (j = p + 78 - slen; j > (int) p; j--)
147 {
148 if (isspace ((unsigned char) trans[j]))
149 {
150 scp = GNUNET_malloc (j - p + 1);
151 GNUNET_memcpy (scp, &trans[p], j - p);
152 scp[j - p] = '\0';
153 printf ("%s\n%*s", scp, BORDER + 2, "");
154 GNUNET_free (scp);
155 p = j + 1;
156 slen = BORDER + 2;
157 goto OUTER;
158 }
159 }
160 /* could not find space to break line */
161 scp = GNUNET_malloc (78 - slen + 1);
162 GNUNET_memcpy (scp, &trans[p], 78 - slen);
163 scp[78 - slen] = '\0';
164 printf ("%s\n%*s", scp, BORDER + 2, "");
165 GNUNET_free (scp);
166 slen = BORDER + 2;
167 p = p + 78 - slen;
168 }
169 /* print rest */
170 if (p < ml)
171 printf ("%s\n", &trans[p]);
172 if (strlen (trans) == 0)
173 printf ("\n");
174 i++;
175 }
176 pd = GNUNET_OS_project_data_get ();
177 printf ("\n"
178 "Report bugs to %s.\n"
179 "Home page: %s\n",
180 pd->bug_email,
181 pd->homepage);
182
183 if (0 != pd->is_gnu)
184 printf ("General help using GNU software: http://www.gnu.org/gethelp/\n");
185
186 return GNUNET_NO;
187}
188
189
190struct GNUNET_GETOPT_CommandLineOption
191GNUNET_GETOPT_option_help (const char *about)
192{
193 struct GNUNET_GETOPT_CommandLineOption clo = {
194 .shortName = 'h',
195 .name = "help",
196 .description = gettext_noop (
197 "print this help"),
198 .option_exclusive = 1,
199 .processor = format_help,
200 .scls = (void *) about
201 };
202
203 return clo;
204}
205
206
207/**
208 * Set an option of type 'unsigned int' from the command line. Each
209 * time the option flag is given, the value is incremented by one.
210 * A pointer to this function should be passed as part of the
211 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
212 * of this type. It should be followed by a pointer to a value of
213 * type 'int'.
214 *
215 * @param ctx command line processing context
216 * @param scls additional closure (will point to the 'unsigned int')
217 * @param option name of the option
218 * @param value not used (NULL)
219 * @return #GNUNET_OK
220 */
221static enum GNUNET_GenericReturnValue
222increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
223 void *scls,
224 const char *option,
225 const char *value)
226{
227 unsigned int *val = scls;
228
229 (void) ctx;
230 (void) option;
231 (void) value;
232 (*val)++;
233 return GNUNET_OK;
234}
235
236
237struct GNUNET_GETOPT_CommandLineOption
238GNUNET_GETOPT_option_increment_uint (char shortName,
239 const char *name,
240 const char *description,
241 unsigned int *val)
242{
243 struct GNUNET_GETOPT_CommandLineOption clo = {
244 .shortName = shortName,
245 .name = name,
246 .description = description,
247 .processor = &increment_value,
248 .scls = (void *) val
249 };
250
251 return clo;
252}
253
254
255struct GNUNET_GETOPT_CommandLineOption
256GNUNET_GETOPT_option_verbose (unsigned int *level)
257{
258 struct GNUNET_GETOPT_CommandLineOption clo = {
259 .shortName = 'V',
260 .name = "verbose",
261 .description =
262 gettext_noop ("be verbose"),
263 .processor = &increment_value,
264 .scls = (void *) level
265 };
266
267 return clo;
268}
269
270
271/**
272 * Set an option of type 'int' from the command line to 1 if the
273 * given option is present.
274 * A pointer to this function should be passed as part of the
275 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
276 * of this type. It should be followed by a pointer to a value of
277 * type 'int'.
278 *
279 * @param ctx command line processing context
280 * @param scls additional closure (will point to the 'int')
281 * @param option name of the option
282 * @param value not used (NULL)
283 * @return #GNUNET_OK
284 */
285static enum GNUNET_GenericReturnValue
286set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
287 void *scls,
288 const char *option,
289 const char *value)
290{
291 int *val = scls;
292
293 (void) ctx;
294 (void) option;
295 (void) value;
296 *val = 1;
297 return GNUNET_OK;
298}
299
300
301struct GNUNET_GETOPT_CommandLineOption
302GNUNET_GETOPT_option_flag (char shortName,
303 const char *name,
304 const char *description,
305 int *val)
306{
307 struct GNUNET_GETOPT_CommandLineOption clo = {
308 .shortName = shortName,
309 .name = name,
310 .description = description,
311 .processor = &set_one,
312 .scls = (void *) val
313 };
314
315 return clo;
316}
317
318
319/**
320 * Set an option of type 'char *' from the command line.
321 * A pointer to this function should be passed as part of the
322 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
323 * of this type. It should be followed by a pointer to a value of
324 * type 'char *', which will be allocated with the requested string.
325 *
326 * @param ctx command line processing context
327 * @param scls additional closure (will point to the 'char *',
328 * which will be allocated)
329 * @param option name of the option
330 * @param value actual value of the option (a string)
331 * @return #GNUNET_OK
332 */
333static enum GNUNET_GenericReturnValue
334set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
335 void *scls,
336 const char *option,
337 const char *value)
338{
339 char **val = scls;
340
341 (void) ctx;
342 (void) option;
343 GNUNET_assert (NULL != value);
344 GNUNET_free (*val);
345 *val = GNUNET_strdup (value);
346 return GNUNET_OK;
347}
348
349
350struct GNUNET_GETOPT_CommandLineOption
351GNUNET_GETOPT_option_string (char shortName,
352 const char *name,
353 const char *argumentHelp,
354 const char *description,
355 char **str)
356{
357 struct GNUNET_GETOPT_CommandLineOption clo = {
358 .shortName = shortName,
359 .name = name,
360 .argumentHelp = argumentHelp,
361 .description = description,
362 .require_argument = 1,
363 .processor = &set_string,
364 .scls = (void *) str
365 };
366
367 return clo;
368}
369
370
371struct GNUNET_GETOPT_CommandLineOption
372GNUNET_GETOPT_option_loglevel (char **level)
373{
374 struct GNUNET_GETOPT_CommandLineOption clo = {
375 .shortName = 'L',
376 .name = "log",
377 .argumentHelp = "LOGLEVEL",
378 .description = gettext_noop ("configure logging to use LOGLEVEL"),
379 .require_argument = 1,
380 .processor = &set_string,
381 .scls = (void *) level
382 };
383
384 return clo;
385}
386
387
388/**
389 * Set an option of type 'char *' from the command line with
390 * filename expansion a la #GNUNET_STRINGS_filename_expand().
391 *
392 * @param ctx command line processing context
393 * @param scls additional closure (will point to the `char *`,
394 * which will be allocated)
395 * @param option name of the option
396 * @param value actual value of the option (a string)
397 * @return #GNUNET_OK
398 */
399static enum GNUNET_GenericReturnValue
400set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
401 void *scls,
402 const char *option,
403 const char *value)
404{
405 char **val = scls;
406
407 (void) ctx;
408 (void) option;
409 GNUNET_assert (NULL != value);
410 GNUNET_free (*val);
411 *val = GNUNET_STRINGS_filename_expand (value);
412 return GNUNET_OK;
413}
414
415
416struct GNUNET_GETOPT_CommandLineOption
417GNUNET_GETOPT_option_filename (char shortName,
418 const char *name,
419 const char *argumentHelp,
420 const char *description,
421 char **str)
422{
423 struct GNUNET_GETOPT_CommandLineOption clo = {
424 .shortName = shortName,
425 .name = name,
426 .argumentHelp = argumentHelp,
427 .description = description,
428 .require_argument = 1,
429 .processor = &set_filename,
430 .scls = (void *) str
431 };
432
433 return clo;
434}
435
436
437struct GNUNET_GETOPT_CommandLineOption
438GNUNET_GETOPT_option_logfile (char **logfn)
439{
440 struct GNUNET_GETOPT_CommandLineOption clo = {
441 .shortName = 'l',
442 .name = "logfile",
443 .argumentHelp = "FILENAME",
444 .description =
445 gettext_noop ("configure logging to write logs to FILENAME"),
446 .require_argument = 1,
447 .processor = &set_filename,
448 .scls = (void *) logfn
449 };
450
451 return clo;
452}
453
454
455struct GNUNET_GETOPT_CommandLineOption
456GNUNET_GETOPT_option_cfgfile (char **fn)
457{
458 struct GNUNET_GETOPT_CommandLineOption clo = {
459 .shortName = 'c',
460 .name = "config",
461 .argumentHelp = "FILENAME",
462 .description = gettext_noop ("use configuration file FILENAME"),
463 .require_argument = 1,
464 .processor = &set_filename,
465 .scls = (void *) fn
466 };
467
468 return clo;
469}
470
471
472/**
473 * Set an option of type 'unsigned long long' from the command line.
474 * A pointer to this function should be passed as part of the
475 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
476 * of this type. It should be followed by a pointer to a value of
477 * type 'unsigned long long'.
478 *
479 * @param ctx command line processing context
480 * @param scls additional closure (will point to the 'unsigned long long')
481 * @param option name of the option
482 * @param value actual value of the option as a string.
483 * @return #GNUNET_OK if parsing the value worked
484 */
485static enum GNUNET_GenericReturnValue
486set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
487 void *scls,
488 const char *option,
489 const char *value)
490{
491 unsigned long long *val = scls;
492 char dummy[2];
493
494 (void) ctx;
495 if (1 != sscanf (value, "%llu%1s", val, dummy))
496 {
497 fprintf (stderr,
498 _ ("You must pass a number to the `%s' option.\n"),
499 option);
500 return GNUNET_SYSERR;
501 }
502 return GNUNET_OK;
503}
504
505
506struct GNUNET_GETOPT_CommandLineOption
507GNUNET_GETOPT_option_ulong (char shortName,
508 const char *name,
509 const char *argumentHelp,
510 const char *description,
511 unsigned long long *val)
512{
513 struct GNUNET_GETOPT_CommandLineOption clo = {
514 .shortName = shortName,
515 .name = name,
516 .argumentHelp = argumentHelp,
517 .description = description,
518 .require_argument = 1,
519 .processor = &set_ulong,
520 .scls = (void *) val
521 };
522
523 return clo;
524}
525
526
527/**
528 * Set an option of type 'struct GNUNET_TIME_Relative' from the command line.
529 * A pointer to this function should be passed as part of the
530 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
531 * of this type. It should be followed by a pointer to a value of
532 * type 'struct GNUNET_TIME_Relative'.
533 *
534 * @param ctx command line processing context
535 * @param scls additional closure (will point to the 'struct GNUNET_TIME_Relative')
536 * @param option name of the option
537 * @param value actual value of the option as a string.
538 * @return #GNUNET_OK if parsing the value worked
539 */
540static enum GNUNET_GenericReturnValue
541set_timetravel_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
542 void *scls,
543 const char *option,
544 const char *value)
545{
546 long long delta;
547 long long minus;
548 struct GNUNET_TIME_Relative rt;
549
550 (void) scls;
551 (void) ctx;
552 while (isspace (value[0]))
553 value++;
554 minus = 1;
555 if (value[0] == '-')
556 {
557 minus = -1;
558 value++;
559 }
560 else if (value[0] == '+')
561 {
562 value++;
563 }
564 if (GNUNET_OK !=
565 GNUNET_STRINGS_fancy_time_to_relative (value,
566 &rt))
567 {
568 fprintf (stderr,
569 _ (
570 "You must pass a relative time (optionally with sign) to the `%s' option.\n"),
571 option);
572 return GNUNET_SYSERR;
573 }
574 if (rt.rel_value_us > LLONG_MAX)
575 {
576 fprintf (stderr,
577 _ ("Value given for time travel `%s' option is too big.\n"),
578 option);
579 return GNUNET_SYSERR;
580 }
581 delta = (long long) rt.rel_value_us;
582 delta *= minus;
583 GNUNET_TIME_set_offset (delta);
584 return GNUNET_OK;
585}
586
587
588struct GNUNET_GETOPT_CommandLineOption
589GNUNET_GETOPT_option_timetravel (char shortName,
590 const char *name)
591{
592 struct GNUNET_GETOPT_CommandLineOption clo = {
593 .shortName = shortName,
594 .name = name,
595 .argumentHelp = _ ("[+/-]MICROSECONDS"),
596 .description = _ (
597 "modify system time by given offset (for debugging/testing only)"),
598 .require_argument = 1,
599 .processor = &set_timetravel_time
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 enum GNUNET_GenericReturnValue
620set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
621 void *scls,
622 const char *option,
623 const char *value)
624{
625 struct GNUNET_TIME_Relative *val = scls;
626
627 (void) ctx;
628 if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (value, val))
629 {
630 fprintf (stderr,
631 _ ("You must pass relative time to the `%s' option.\n"),
632 option);
633 return GNUNET_SYSERR;
634 }
635 return GNUNET_OK;
636}
637
638
639struct GNUNET_GETOPT_CommandLineOption
640GNUNET_GETOPT_option_relative_time (char shortName,
641 const char *name,
642 const char *argumentHelp,
643 const char *description,
644 struct GNUNET_TIME_Relative *val)
645{
646 struct GNUNET_GETOPT_CommandLineOption clo = {
647 .shortName = shortName,
648 .name = name,
649 .argumentHelp = argumentHelp,
650 .description = description,
651 .require_argument = 1,
652 .processor = &set_relative_time,
653 .scls = (void *) val
654 };
655
656 return clo;
657}
658
659
660/**
661 * Set an option of type 'struct GNUNET_TIME_Absolute' from the command line.
662 * A pointer to this function should be passed as part of the
663 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
664 * of this type. It should be followed by a pointer to a value of
665 * type 'struct GNUNET_TIME_Absolute'.
666 *
667 * @param ctx command line processing context
668 * @param scls additional closure (will point to the `struct GNUNET_TIME_Absolute`)
669 * @param option name of the option
670 * @param value actual value of the option as a string.
671 * @return #GNUNET_OK if parsing the value worked
672 */
673static enum GNUNET_GenericReturnValue
674set_absolute_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
675 void *scls,
676 const char *option,
677 const char *value)
678{
679 struct GNUNET_TIME_Absolute *val = scls;
680
681 (void) ctx;
682 if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (value, val))
683 {
684 fprintf (stderr,
685 _ ("You must pass absolute time to the `%s' option.\n"),
686 option);
687 return GNUNET_SYSERR;
688 }
689 return GNUNET_OK;
690}
691
692
693struct GNUNET_GETOPT_CommandLineOption
694GNUNET_GETOPT_option_absolute_time (char shortName,
695 const char *name,
696 const char *argumentHelp,
697 const char *description,
698 struct GNUNET_TIME_Absolute *val)
699{
700 struct GNUNET_GETOPT_CommandLineOption clo = {
701 .shortName = shortName,
702 .name = name,
703 .argumentHelp = argumentHelp,
704 .description = description,
705 .require_argument = 1,
706 .processor = &set_absolute_time,
707 .scls = (void *) val
708 };
709
710 return clo;
711}
712
713
714/**
715 * Set an option of type 'struct GNUNET_TIME_Timestamp' from the command line.
716 * A pointer to this function should be passed as part of the
717 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
718 * of this type. It should be followed by a pointer to a value of
719 * type 'struct GNUNET_TIME_Absolute'.
720 *
721 * @param ctx command line processing context
722 * @param scls additional closure (will point to the `struct GNUNET_TIME_Absolute`)
723 * @param option name of the option
724 * @param value actual value of the option as a string.
725 * @return #GNUNET_OK if parsing the value worked
726 */
727static enum GNUNET_GenericReturnValue
728set_timestamp (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
729 void *scls,
730 const char *option,
731 const char *value)
732{
733 struct GNUNET_TIME_Timestamp *t = scls;
734 struct GNUNET_TIME_Absolute abs;
735
736 (void) ctx;
737 if (GNUNET_OK !=
738 GNUNET_STRINGS_fancy_time_to_absolute (value,
739 &abs))
740 {
741 fprintf (stderr,
742 _ ("You must pass a timestamp to the `%s' option.\n"),
743 option);
744 return GNUNET_SYSERR;
745 }
746 if (0 != abs.abs_value_us % GNUNET_TIME_UNIT_SECONDS.rel_value_us)
747 {
748 fprintf (stderr,
749 _ ("The maximum precision allowed for timestamps is seconds.\n"));
750 return GNUNET_SYSERR;
751 }
752 t->abs_time = abs;
753 return GNUNET_OK;
754}
755
756
757struct GNUNET_GETOPT_CommandLineOption
758GNUNET_GETOPT_option_timestamp (char shortName,
759 const char *name,
760 const char *argumentHelp,
761 const char *description,
762 struct GNUNET_TIME_Timestamp *val)
763{
764 struct GNUNET_GETOPT_CommandLineOption clo = {
765 .shortName = shortName,
766 .name = name,
767 .argumentHelp = argumentHelp,
768 .description = description,
769 .require_argument = 1,
770 .processor = &set_timestamp,
771 .scls = (void *) val
772 };
773
774 return clo;
775}
776
777
778/**
779 * Set an option of type 'unsigned int' from the command line.
780 * A pointer to this function should be passed as part of the
781 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
782 * of this type. It should be followed by a pointer to a value of
783 * type 'unsigned int'.
784 *
785 * @param ctx command line processing context
786 * @param scls additional closure (will point to the 'unsigned int')
787 * @param option name of the option
788 * @param value actual value of the option as a string.
789 * @return #GNUNET_OK if parsing the value worked
790 */
791static enum GNUNET_GenericReturnValue
792set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
793 void *scls,
794 const char *option,
795 const char *value)
796{
797 unsigned int *val = scls;
798 char dummy[2];
799
800 (void) ctx;
801 if ('-' == *value)
802 {
803 fprintf (stderr,
804 _ (
805 "Your input for the '%s' option has to be a non negative number\n"),
806 option);
807 return GNUNET_SYSERR;
808 }
809 if (1 != sscanf (value, "%u%1s", val, dummy))
810 {
811 fprintf (stderr,
812 _ ("You must pass a number to the `%s' option.\n"),
813 option);
814 return GNUNET_SYSERR;
815 }
816 return GNUNET_OK;
817}
818
819
820struct GNUNET_GETOPT_CommandLineOption
821GNUNET_GETOPT_option_uint (char shortName,
822 const char *name,
823 const char *argumentHelp,
824 const char *description,
825 unsigned int *val)
826{
827 struct GNUNET_GETOPT_CommandLineOption clo = {
828 .shortName = shortName,
829 .name = name,
830 .argumentHelp = argumentHelp,
831 .description = description,
832 .require_argument = 1,
833 .processor = &set_uint,
834 .scls = (void *) val
835 };
836
837 return clo;
838}
839
840
841/**
842 * Set an option of type 'uint16_t' from the command line.
843 * A pointer to this function should be passed as part of the
844 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
845 * of this type. It should be followed by a pointer to a value of
846 * type 'uint16_t'.
847 *
848 * @param ctx command line processing context
849 * @param scls additional closure (will point to the 'unsigned int')
850 * @param option name of the option
851 * @param value actual value of the option as a string.
852 * @return #GNUNET_OK if parsing the value worked
853 */
854static enum GNUNET_GenericReturnValue
855set_uint16 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
856 void *scls,
857 const char *option,
858 const char *value)
859{
860 uint16_t *val = scls;
861 unsigned int v;
862 char dummy[2];
863
864 (void) ctx;
865 if (1 != sscanf (value, "%u%1s", &v, dummy))
866 {
867 fprintf (stderr,
868 _ ("You must pass a number to the `%s' option.\n"),
869 option);
870 return GNUNET_SYSERR;
871 }
872 if (v > UINT16_MAX)
873 {
874 fprintf (stderr,
875 _ ("You must pass a number below %u to the `%s' option.\n"),
876 (unsigned int) UINT16_MAX,
877 option);
878 return GNUNET_SYSERR;
879 }
880 *val = (uint16_t) v;
881 return GNUNET_OK;
882}
883
884
885struct GNUNET_GETOPT_CommandLineOption
886GNUNET_GETOPT_option_uint16 (char shortName,
887 const char *name,
888 const char *argumentHelp,
889 const char *description,
890 uint16_t *val)
891{
892 struct GNUNET_GETOPT_CommandLineOption clo = {
893 .shortName = shortName,
894 .name = name,
895 .argumentHelp = argumentHelp,
896 .description = description,
897 .require_argument = 1,
898 .processor = &set_uint16,
899 .scls = (void *) val
900 };
901
902 return clo;
903}
904
905
906/**
907 * Closure for #set_base32().
908 */
909struct Base32Context
910{
911 /**
912 * Value to initialize (already allocated)
913 */
914 void *val;
915
916 /**
917 * Number of bytes expected for @e val.
918 */
919 size_t val_size;
920};
921
922
923/**
924 * Set an option of type 'unsigned int' from the command line.
925 * A pointer to this function should be passed as part of the
926 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
927 * of this type. It should be followed by a pointer to a value of
928 * type 'unsigned int'.
929 *
930 * @param ctx command line processing context
931 * @param scls additional closure (will point to the 'unsigned int')
932 * @param option name of the option
933 * @param value actual value of the option as a string.
934 * @return #GNUNET_OK if parsing the value worked
935 */
936static enum GNUNET_GenericReturnValue
937set_base32 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
938 void *scls,
939 const char *option,
940 const char *value)
941{
942 struct Base32Context *bc = scls;
943
944 (void) ctx;
945 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (value,
946 strlen (value),
947 bc->val,
948 bc->val_size))
949 {
950 fprintf (
951 stderr,
952 _ (
953 "Argument `%s' malformed. Expected base32 (Crockford) encoded value.\n"),
954 option);
955 return GNUNET_SYSERR;
956 }
957 return GNUNET_OK;
958}
959
960
961/**
962 * Helper function to clean up after
963 * #GNUNET_GETOPT_option_base32_fixed_size.
964 *
965 * @param cls value to GNUNET_free()
966 */
967static void
968free_bc (void *cls)
969{
970 GNUNET_free (cls);
971}
972
973
974struct GNUNET_GETOPT_CommandLineOption
975GNUNET_GETOPT_option_base32_fixed_size (char shortName,
976 const char *name,
977 const char *argumentHelp,
978 const char *description,
979 void *val,
980 size_t val_size)
981{
982 struct Base32Context *bc = GNUNET_new (struct Base32Context);
983 struct GNUNET_GETOPT_CommandLineOption clo = {
984 .shortName = shortName,
985 .name = name,
986 .argumentHelp = argumentHelp,
987 .description = description,
988 .require_argument = 1,
989 .processor = &set_base32,
990 .cleaner = &free_bc,
991 .scls = (void *) bc
992 };
993
994 bc->val = val;
995 bc->val_size = val_size;
996 return clo;
997}
998
999
1000struct GNUNET_GETOPT_CommandLineOption
1001GNUNET_GETOPT_option_mandatory (struct GNUNET_GETOPT_CommandLineOption opt)
1002{
1003 opt.option_mandatory = 1;
1004 return opt;
1005}
1006
1007
1008struct GNUNET_GETOPT_CommandLineOption
1009GNUNET_GETOPT_option_exclusive (struct GNUNET_GETOPT_CommandLineOption opt)
1010{
1011 opt.option_exclusive = 1;
1012 return opt;
1013}
1014
1015
1016/* 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 76c379784..000000000
--- a/src/util/gnunet-crypto-tvg.c
+++ /dev/null
@@ -1,1542 +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 if (0 == strcmp (operation, "cs_blind_signing"))
676 {
677 struct GNUNET_CRYPTO_CsPrivateKey priv;
678 struct GNUNET_CRYPTO_CsPublicKey pub;
679 struct GNUNET_CRYPTO_CsBlindingSecret bs[2];
680 struct GNUNET_CRYPTO_CsRSecret r_priv[2];
681 struct GNUNET_CRYPTO_CsRPublic r_pub[2];
682 struct GNUNET_CRYPTO_CsRPublic r_pub_blind[2];
683 struct GNUNET_CRYPTO_CsC c[2];
684 struct GNUNET_CRYPTO_CsS signature_scalar;
685 struct GNUNET_CRYPTO_CsBlindS blinded_s;
686 struct GNUNET_CRYPTO_CsSignature sig;
687 struct GNUNET_CRYPTO_CsNonce nonce;
688 struct GNUNET_HashCode message_hash;
689 unsigned int b;
690
691 if (GNUNET_OK != expect_data_fixed (vec,
692 "message_hash",
693 &message_hash,
694 sizeof (message_hash)))
695 {
696 GNUNET_break (0);
697 return GNUNET_SYSERR;
698 }
699 if (GNUNET_OK != expect_data_fixed (vec,
700 "cs_public_key",
701 &pub,
702 sizeof (pub)))
703 {
704 GNUNET_break (0);
705 return GNUNET_SYSERR;
706 }
707
708 if (GNUNET_OK != expect_data_fixed (vec,
709 "cs_private_key",
710 &priv,
711 sizeof (priv)))
712 {
713 GNUNET_break (0);
714 return GNUNET_SYSERR;
715 }
716 if (GNUNET_OK != expect_data_fixed (vec,
717 "cs_nonce",
718 &nonce,
719 sizeof (nonce)))
720 {
721 GNUNET_break (0);
722 return GNUNET_SYSERR;
723 }
724 if (GNUNET_OK != expect_data_fixed (vec,
725 "cs_r_priv_0",
726 &r_priv[0],
727 sizeof (r_priv[0])))
728 {
729 GNUNET_break (0);
730 return GNUNET_SYSERR;
731 }
732 if (GNUNET_OK != expect_data_fixed (vec,
733 "cs_r_priv_1",
734 &r_priv[1],
735 sizeof (r_priv[1])))
736 {
737 GNUNET_break (0);
738 return GNUNET_SYSERR;
739 }
740 if (GNUNET_OK != expect_data_fixed (vec,
741 "cs_r_pub_0",
742 &r_pub[0],
743 sizeof (r_pub[0])))
744 {
745 GNUNET_break (0);
746 return GNUNET_SYSERR;
747 }
748 if (GNUNET_OK != expect_data_fixed (vec,
749 "cs_r_pub_1",
750 &r_pub[1],
751 sizeof (r_pub[1])))
752 {
753 GNUNET_break (0);
754 return GNUNET_SYSERR;
755 }
756
757 if (GNUNET_OK != expect_data_fixed (vec,
758 "cs_bs_alpha_0",
759 &bs[0].alpha,
760 sizeof (bs[0].alpha)))
761 {
762 GNUNET_break (0);
763 return GNUNET_SYSERR;
764 }
765 if (GNUNET_OK != expect_data_fixed (vec,
766 "cs_bs_alpha_1",
767 &bs[1].alpha,
768 sizeof (bs[1].alpha)))
769 {
770 GNUNET_break (0);
771 return GNUNET_SYSERR;
772 }
773 if (GNUNET_OK != expect_data_fixed (vec,
774 "cs_bs_beta_0",
775 &bs[0].beta,
776 sizeof (bs[0].beta)))
777 {
778 GNUNET_break (0);
779 return GNUNET_SYSERR;
780 }
781 if (GNUNET_OK != expect_data_fixed (vec,
782 "cs_bs_beta_1",
783 &bs[1].beta,
784 sizeof (bs[1].beta)))
785 {
786 GNUNET_break (0);
787 return GNUNET_SYSERR;
788 }
789 if (GNUNET_OK != expect_data_fixed (vec,
790 "cs_r_pub_blind_0",
791 &r_pub_blind[0],
792 sizeof (r_pub_blind[0])))
793 {
794 GNUNET_break (0);
795 return GNUNET_SYSERR;
796 }
797 if (GNUNET_OK != expect_data_fixed (vec,
798 "cs_r_pub_blind_1",
799 &r_pub_blind[1],
800 sizeof (r_pub_blind[1])))
801 {
802 GNUNET_break (0);
803 return GNUNET_SYSERR;
804 }
805 if (GNUNET_OK != expect_data_fixed (vec,
806 "cs_c_0",
807 &c[0],
808 sizeof (c[0])))
809 {
810 GNUNET_break (0);
811 return GNUNET_SYSERR;
812 }
813 if (GNUNET_OK != expect_data_fixed (vec,
814 "cs_c_1",
815 &c[1],
816 sizeof (c[1])))
817 {
818 GNUNET_break (0);
819 return GNUNET_SYSERR;
820 }
821 if (GNUNET_OK != expect_data_fixed (vec,
822 "cs_blind_s",
823 &blinded_s,
824 sizeof (blinded_s)))
825 {
826 GNUNET_break (0);
827 return GNUNET_SYSERR;
828 }
829 if (GNUNET_OK != expect_data_fixed (vec,
830 "cs_b",
831 &b,
832 sizeof (b)))
833 {
834 GNUNET_break (0);
835 return GNUNET_SYSERR;
836 }
837 if (GNUNET_OK != expect_data_fixed (vec,
838 "cs_sig_s",
839 &signature_scalar,
840 sizeof (signature_scalar)))
841 {
842 GNUNET_break (0);
843 return GNUNET_SYSERR;
844 }
845 sig.s_scalar = signature_scalar;
846 if (GNUNET_OK != expect_data_fixed (vec,
847 "cs_sig_R",
848 &sig.r_point,
849 sizeof (sig.r_point)))
850 {
851 GNUNET_break (0);
852 return GNUNET_SYSERR;
853 }
854
855 if ((b != 1) && (b != 0))
856 {
857 GNUNET_break (0);
858 return GNUNET_SYSERR;
859 }
860
861 struct GNUNET_CRYPTO_CsRSecret r_priv_comp[2];
862 struct GNUNET_CRYPTO_CsRPublic r_pub_comp[2];
863 struct GNUNET_CRYPTO_CsBlindingSecret bs_comp[2];
864 struct GNUNET_CRYPTO_CsC c_comp[2];
865 struct GNUNET_CRYPTO_CsRPublic r_pub_blind_comp[2];
866 struct GNUNET_CRYPTO_CsBlindS blinded_s_comp;
867 struct GNUNET_CRYPTO_CsS signature_scalar_comp;
868 struct GNUNET_CRYPTO_CsSignature sig_comp;
869 unsigned int b_comp;
870
871
872 GNUNET_CRYPTO_cs_r_derive (&nonce,
873 "rw",
874 &priv,
875 r_priv_comp);
876 GNUNET_CRYPTO_cs_r_get_public (&r_priv_comp[0],
877 &r_pub_comp[0]);
878 GNUNET_CRYPTO_cs_r_get_public (&r_priv_comp[1],
879 &r_pub_comp[1]);
880 GNUNET_assert (0 == memcmp (&r_priv_comp,
881 &r_priv,
882 sizeof(struct GNUNET_CRYPTO_CsRSecret) * 2));
883 GNUNET_assert (0 == memcmp (&r_pub_comp,
884 &r_pub,
885 sizeof(struct GNUNET_CRYPTO_CsRPublic) * 2));
886
887 GNUNET_CRYPTO_cs_blinding_secrets_derive (&nonce,
888 bs_comp);
889 GNUNET_assert (0 == memcmp (&bs_comp,
890 &bs,
891 sizeof(struct GNUNET_CRYPTO_CsBlindingSecret)
892 * 2));
893 GNUNET_CRYPTO_cs_calc_blinded_c (bs_comp,
894 r_pub_comp,
895 &pub,
896 &message_hash,
897 sizeof(message_hash),
898 c_comp,
899 r_pub_blind_comp);
900 GNUNET_assert (0 == memcmp (&c_comp,
901 &c,
902 sizeof(struct GNUNET_CRYPTO_CsC) * 2));
903 GNUNET_assert (0 == memcmp (&r_pub_blind_comp,
904 &r_pub_blind,
905 sizeof(struct GNUNET_CRYPTO_CsRPublic) * 2));
906 b_comp = GNUNET_CRYPTO_cs_sign_derive (&priv,
907 r_priv_comp,
908 c_comp,
909 &nonce,
910 &blinded_s_comp);
911 GNUNET_assert (0 == memcmp (&blinded_s_comp,
912 &blinded_s,
913 sizeof(blinded_s)));
914 GNUNET_assert (0 == memcmp (&b_comp,
915 &b,
916 sizeof(b)));
917 GNUNET_CRYPTO_cs_unblind (&blinded_s_comp,
918 &bs_comp[b_comp],
919 &signature_scalar_comp);
920 GNUNET_assert (0 == memcmp (&signature_scalar_comp,
921 &signature_scalar,
922 sizeof(signature_scalar_comp)));
923 sig_comp.r_point = r_pub_blind_comp[b_comp];
924 sig_comp.s_scalar = signature_scalar_comp;
925 GNUNET_assert (0 == memcmp (&sig_comp,
926 &sig,
927 sizeof(sig_comp)));
928 if (GNUNET_OK != GNUNET_CRYPTO_cs_verify (&sig_comp,
929 &pub,
930 &message_hash,
931 sizeof(message_hash)))
932 {
933 GNUNET_break (0);
934 return GNUNET_SYSERR;
935 }
936 }
937 else
938 {
939 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
940 "unsupported operation '%s'\n", operation);
941 }
942
943 return GNUNET_OK;
944}
945
946
947/**
948 * Check test vectors from stdin.
949 *
950 * @returns global exit code
951 */
952static int
953check_vectors ()
954{
955 json_error_t err;
956 json_t *vecfile = json_loadf (stdin, 0, &err);
957 const char *encoding;
958 json_t *vectors;
959
960 if (NULL == vecfile)
961 {
962 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unable to parse JSON\n");
963 return 1;
964 }
965 encoding = json_string_value (json_object_get (vecfile,
966 "encoding"));
967 if ( (NULL == encoding) || (0 != strcmp (encoding, "base32crockford")) )
968 {
969 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unsupported or missing encoding\n");
970 json_decref (vecfile);
971 return 1;
972 }
973 vectors = json_object_get (vecfile, "vectors");
974 if (! json_is_array (vectors))
975 {
976 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bad vectors\n");
977 json_decref (vecfile);
978 return 1;
979 }
980 {
981 /* array is a JSON array */
982 size_t index;
983 json_t *value;
984 int ret;
985
986 json_array_foreach (vectors, index, value) {
987 const char *op = json_string_value (json_object_get (value,
988 "operation"));
989
990 if (NULL == op)
991 {
992 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
993 "missing operation\n");
994 ret = GNUNET_SYSERR;
995 break;
996 }
997 ret = checkvec (op, value);
998 if (GNUNET_OK != ret)
999 {
1000 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1001 "bad vector %u\n",
1002 (unsigned int) index);
1003 break;
1004 }
1005 }
1006 return (ret == GNUNET_OK) ? 0 : 1;
1007 }
1008}
1009
1010
1011/**
1012 * Output test vectors.
1013 *
1014 * @returns global exit code
1015 */
1016static int
1017output_vectors ()
1018{
1019 json_t *vecfile = json_object ();
1020 json_t *vecs = json_array ();
1021
1022 json_object_set_new (vecfile,
1023 "encoding",
1024 json_string ("base32crockford"));
1025 json_object_set_new (vecfile,
1026 "producer",
1027 json_string ("GNUnet " PACKAGE_VERSION " " VCS_VERSION));
1028 json_object_set_new (vecfile,
1029 "vectors",
1030 vecs);
1031
1032 {
1033 json_t *vec = vec_for (vecs, "hash");
1034 struct GNUNET_HashCode hc;
1035 char *str = "Hello, GNUnet";
1036
1037 GNUNET_CRYPTO_hash (str, strlen (str), &hc);
1038
1039 d2j (vec, "input", str, strlen (str));
1040 d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode));
1041 }
1042 {
1043 json_t *vec = vec_for (vecs, "ecc_ecdh");
1044 struct GNUNET_CRYPTO_EcdhePrivateKey priv1;
1045 struct GNUNET_CRYPTO_EcdhePublicKey pub1;
1046 struct GNUNET_CRYPTO_EcdhePrivateKey priv2;
1047 struct GNUNET_HashCode skm;
1048
1049 GNUNET_CRYPTO_ecdhe_key_create (&priv1);
1050 GNUNET_CRYPTO_ecdhe_key_create (&priv2);
1051 GNUNET_CRYPTO_ecdhe_key_get_public (&priv1,
1052 &pub1);
1053 GNUNET_assert (GNUNET_OK ==
1054 GNUNET_CRYPTO_ecc_ecdh (&priv2,
1055 &pub1,
1056 &skm));
1057
1058 d2j (vec,
1059 "priv1",
1060 &priv1,
1061 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1062 d2j (vec,
1063 "pub1",
1064 &pub1,
1065 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1066 d2j (vec,
1067 "priv2",
1068 &priv2,
1069 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1070 d2j (vec,
1071 "skm",
1072 &skm,
1073 sizeof (struct GNUNET_HashCode));
1074 }
1075
1076 {
1077 json_t *vec = vec_for (vecs, "eddsa_key_derivation");
1078 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
1079 struct GNUNET_CRYPTO_EddsaPublicKey pub;
1080
1081 GNUNET_CRYPTO_eddsa_key_create (&priv);
1082 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
1083 &pub);
1084
1085 d2j (vec,
1086 "priv",
1087 &priv,
1088 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
1089 d2j (vec,
1090 "pub",
1091 &pub,
1092 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
1093 }
1094 {
1095 json_t *vec = vec_for (vecs, "eddsa_signing");
1096 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
1097 struct GNUNET_CRYPTO_EddsaPublicKey pub;
1098 struct GNUNET_CRYPTO_EddsaSignature sig;
1099 struct TestSignatureDataPS data = { 0 };
1100
1101 GNUNET_CRYPTO_eddsa_key_create (&priv);
1102 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
1103 &pub);
1104 data.purpose.size = htonl (sizeof (data));
1105 data.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
1106 GNUNET_CRYPTO_eddsa_sign (&priv,
1107 &data,
1108 &sig);
1109 GNUNET_assert (GNUNET_OK ==
1110 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST,
1111 &data,
1112 &sig,
1113 &pub));
1114
1115 d2j (vec,
1116 "priv",
1117 &priv,
1118 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
1119 d2j (vec,
1120 "pub",
1121 &pub,
1122 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
1123 d2j (vec,
1124 "data",
1125 &data,
1126 sizeof (struct TestSignatureDataPS));
1127 d2j (vec,
1128 "sig",
1129 &sig,
1130 sizeof (struct GNUNET_CRYPTO_EddsaSignature));
1131 }
1132
1133 {
1134 json_t *vec = vec_for (vecs, "kdf");
1135 size_t out_len = 64;
1136 char out[out_len];
1137 char *ikm = "I'm the secret input key material";
1138 char *salt = "I'm very salty";
1139 char *ctx = "I'm a context chunk, also known as 'info' in the RFC";
1140
1141 GNUNET_assert (GNUNET_OK ==
1142 GNUNET_CRYPTO_kdf (&out,
1143 out_len,
1144 salt,
1145 strlen (salt),
1146 ikm,
1147 strlen (ikm),
1148 ctx,
1149 strlen (ctx),
1150 NULL));
1151
1152 d2j (vec,
1153 "salt",
1154 salt,
1155 strlen (salt));
1156 d2j (vec,
1157 "ikm",
1158 ikm,
1159 strlen (ikm));
1160 d2j (vec,
1161 "ctx",
1162 ctx,
1163 strlen (ctx));
1164 uint2j (vec,
1165 "out_len",
1166 (unsigned int) out_len);
1167 d2j (vec,
1168 "out",
1169 out,
1170 out_len);
1171 }
1172 {
1173 json_t *vec = vec_for (vecs, "eddsa_ecdh");
1174 struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdhe;
1175 struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe;
1176 struct GNUNET_CRYPTO_EddsaPrivateKey priv_eddsa;
1177 struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa;
1178 struct GNUNET_HashCode key_material;
1179
1180 GNUNET_CRYPTO_ecdhe_key_create (&priv_ecdhe);
1181 GNUNET_CRYPTO_ecdhe_key_get_public (&priv_ecdhe, &pub_ecdhe);
1182 GNUNET_CRYPTO_eddsa_key_create (&priv_eddsa);
1183 GNUNET_CRYPTO_eddsa_key_get_public (&priv_eddsa, &pub_eddsa);
1184 GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdhe, &pub_eddsa, &key_material);
1185
1186 d2j (vec, "priv_ecdhe",
1187 &priv_ecdhe,
1188 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1189 d2j (vec, "pub_ecdhe",
1190 &pub_ecdhe,
1191 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1192 d2j (vec, "priv_eddsa",
1193 &priv_eddsa,
1194 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
1195 d2j (vec, "pub_eddsa",
1196 &pub_eddsa,
1197 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
1198 d2j (vec, "key_material",
1199 &key_material,
1200 sizeof (struct GNUNET_HashCode));
1201 }
1202
1203 {
1204 json_t *vec = vec_for (vecs, "edx25519_derive");
1205 struct GNUNET_CRYPTO_Edx25519PrivateKey priv1_edx;
1206 struct GNUNET_CRYPTO_Edx25519PublicKey pub1_edx;
1207 struct GNUNET_CRYPTO_Edx25519PrivateKey priv2_edx;
1208 struct GNUNET_CRYPTO_Edx25519PublicKey pub2_edx;
1209 struct GNUNET_HashCode seed;
1210
1211 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1212 &seed,
1213 sizeof (struct GNUNET_HashCode));
1214 GNUNET_CRYPTO_edx25519_key_create (&priv1_edx);
1215 GNUNET_CRYPTO_edx25519_key_get_public (&priv1_edx, &pub1_edx);
1216 GNUNET_CRYPTO_edx25519_private_key_derive (&priv1_edx,
1217 &seed,
1218 sizeof (seed),
1219 &priv2_edx);
1220 GNUNET_CRYPTO_edx25519_public_key_derive (&pub1_edx,
1221 &seed,
1222 sizeof (seed),
1223 &pub2_edx);
1224
1225 d2j (vec, "priv1_edx",
1226 &priv1_edx,
1227 sizeof (struct GNUNET_CRYPTO_Edx25519PrivateKey));
1228 d2j (vec, "pub1_edx",
1229 &pub1_edx,
1230 sizeof (struct GNUNET_CRYPTO_Edx25519PublicKey));
1231 d2j (vec, "seed",
1232 &seed,
1233 sizeof (struct GNUNET_HashCode));
1234 d2j (vec, "priv2_edx",
1235 &priv2_edx,
1236 sizeof (struct GNUNET_CRYPTO_Edx25519PrivateKey));
1237 d2j (vec, "pub2_edx",
1238 &pub2_edx,
1239 sizeof (struct GNUNET_CRYPTO_Edx25519PublicKey));
1240 }
1241
1242 {
1243 json_t *vec = vec_for (vecs, "rsa_blind_signing");
1244
1245 struct GNUNET_CRYPTO_RsaPrivateKey *skey;
1246 struct GNUNET_CRYPTO_RsaPublicKey *pkey;
1247 struct GNUNET_HashCode message_hash;
1248 struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
1249 struct GNUNET_CRYPTO_RsaSignature *blinded_sig;
1250 struct GNUNET_CRYPTO_RsaSignature *sig;
1251 void *blinded_data;
1252 size_t blinded_len;
1253 void *public_enc_data;
1254 size_t public_enc_len;
1255 void *secret_enc_data;
1256 size_t secret_enc_len;
1257 void *blinded_sig_enc_data;
1258 size_t blinded_sig_enc_length;
1259 void *sig_enc_data;
1260 size_t sig_enc_length;
1261
1262 skey = GNUNET_CRYPTO_rsa_private_key_create (2048);
1263 pkey = GNUNET_CRYPTO_rsa_private_key_get_public (skey);
1264 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1265 &message_hash,
1266 sizeof (struct GNUNET_HashCode));
1267 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1268 &bks,
1269 sizeof (struct
1270 GNUNET_CRYPTO_RsaBlindingKeySecret));
1271 GNUNET_assert (GNUNET_YES ==
1272 GNUNET_CRYPTO_rsa_blind (&message_hash,
1273 &bks,
1274 pkey,
1275 &blinded_data,
1276 &blinded_len));
1277 blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey, blinded_data,
1278 blinded_len);
1279 sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig, &bks, pkey);
1280 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_verify (&message_hash, sig,
1281 pkey));
1282 public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
1283 &public_enc_data);
1284 secret_enc_len = GNUNET_CRYPTO_rsa_private_key_encode (skey,
1285 &secret_enc_data);
1286 blinded_sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (blinded_sig,
1287 &
1288 blinded_sig_enc_data);
1289 sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (sig, &sig_enc_data);
1290 d2j (vec,
1291 "message_hash",
1292 &message_hash,
1293 sizeof (struct GNUNET_HashCode));
1294 d2j (vec,
1295 "rsa_public_key",
1296 public_enc_data,
1297 public_enc_len);
1298 d2j (vec,
1299 "rsa_private_key",
1300 secret_enc_data,
1301 secret_enc_len);
1302 d2j (vec,
1303 "blinding_key_secret",
1304 &bks,
1305 sizeof (struct GNUNET_CRYPTO_RsaBlindingKeySecret));
1306 d2j (vec,
1307 "blinded_message",
1308 blinded_data,
1309 blinded_len);
1310 d2j (vec,
1311 "blinded_sig",
1312 blinded_sig_enc_data,
1313 blinded_sig_enc_length);
1314 d2j (vec,
1315 "sig",
1316 sig_enc_data,
1317 sig_enc_length);
1318 GNUNET_CRYPTO_rsa_private_key_free (skey);
1319 GNUNET_CRYPTO_rsa_public_key_free (pkey);
1320 GNUNET_CRYPTO_rsa_signature_free (sig);
1321 GNUNET_CRYPTO_rsa_signature_free (blinded_sig);
1322 GNUNET_free (public_enc_data);
1323 GNUNET_free (blinded_data);
1324 GNUNET_free (sig_enc_data);
1325 GNUNET_free (blinded_sig_enc_data);
1326 GNUNET_free (secret_enc_data);
1327 }
1328
1329 {
1330 json_t *vec = vec_for (vecs, "cs_blind_signing");
1331
1332 struct GNUNET_CRYPTO_CsPrivateKey priv;
1333 struct GNUNET_CRYPTO_CsPublicKey pub;
1334 struct GNUNET_CRYPTO_CsBlindingSecret bs[2];
1335 struct GNUNET_CRYPTO_CsRSecret r_priv[2];
1336 struct GNUNET_CRYPTO_CsRPublic r_pub[2];
1337 struct GNUNET_CRYPTO_CsRPublic r_pub_blind[2];
1338 struct GNUNET_CRYPTO_CsC c[2];
1339 struct GNUNET_CRYPTO_CsS signature_scalar;
1340 struct GNUNET_CRYPTO_CsBlindS blinded_s;
1341 struct GNUNET_CRYPTO_CsSignature sig;
1342 struct GNUNET_CRYPTO_CsNonce nonce;
1343 unsigned int b;
1344 struct GNUNET_HashCode message_hash;
1345
1346 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1347 &message_hash,
1348 sizeof (struct GNUNET_HashCode));
1349
1350 GNUNET_CRYPTO_cs_private_key_generate (&priv);
1351 GNUNET_CRYPTO_cs_private_key_get_public (&priv, &pub);
1352
1353 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_hkdf (nonce.nonce,
1354 sizeof(nonce.nonce),
1355 GCRY_MD_SHA512,
1356 GCRY_MD_SHA256,
1357 "nonce",
1358 strlen ("nonce"),
1359 "nonce_secret",
1360 strlen ("nonce_secret"),
1361 NULL,
1362 0));
1363 GNUNET_CRYPTO_cs_r_derive (&nonce,
1364 "rw",
1365 &priv,
1366 r_priv);
1367 GNUNET_CRYPTO_cs_r_get_public (&r_priv[0],
1368 &r_pub[0]);
1369 GNUNET_CRYPTO_cs_r_get_public (&r_priv[1],
1370 &r_pub[1]);
1371 GNUNET_CRYPTO_cs_blinding_secrets_derive (&nonce,
1372 bs);
1373 GNUNET_CRYPTO_cs_calc_blinded_c (bs,
1374 r_pub,
1375 &pub,
1376 &message_hash,
1377 sizeof(message_hash),
1378 c,
1379 r_pub_blind);
1380 b = GNUNET_CRYPTO_cs_sign_derive (&priv,
1381 r_priv,
1382 c,
1383 &nonce,
1384 &blinded_s);
1385 GNUNET_CRYPTO_cs_unblind (&blinded_s, &bs[b], &signature_scalar);
1386 sig.r_point = r_pub_blind[b];
1387 sig.s_scalar = signature_scalar;
1388 if (GNUNET_OK != GNUNET_CRYPTO_cs_verify (&sig,
1389 &pub,
1390 &message_hash,
1391 sizeof(message_hash)))
1392 {
1393 GNUNET_break (0);
1394 return GNUNET_SYSERR;
1395 }
1396 d2j (vec,
1397 "message_hash",
1398 &message_hash,
1399 sizeof (struct GNUNET_HashCode));
1400 d2j (vec,
1401 "cs_public_key",
1402 &pub,
1403 sizeof(pub));
1404 d2j (vec,
1405 "cs_private_key",
1406 &priv,
1407 sizeof(priv));
1408 d2j (vec,
1409 "cs_nonce",
1410 &nonce,
1411 sizeof(nonce));
1412 d2j (vec,
1413 "cs_r_priv_0",
1414 &r_priv[0],
1415 sizeof(r_priv[0]));
1416 d2j (vec,
1417 "cs_r_priv_1",
1418 &r_priv[1],
1419 sizeof(r_priv[1]));
1420 d2j (vec,
1421 "cs_r_pub_0",
1422 &r_pub[0],
1423 sizeof(r_pub[0]));
1424 d2j (vec,
1425 "cs_r_pub_1",
1426 &r_pub[1],
1427 sizeof(r_pub[1]));
1428 d2j (vec,
1429 "cs_bs_alpha_0",
1430 &bs[0].alpha,
1431 sizeof(bs[0].alpha));
1432 d2j (vec,
1433 "cs_bs_alpha_1",
1434 &bs[1].alpha,
1435 sizeof(bs[1].alpha));
1436 d2j (vec,
1437 "cs_bs_beta_0",
1438 &bs[0].beta,
1439 sizeof(bs[0].beta));
1440 d2j (vec,
1441 "cs_bs_beta_1",
1442 &bs[1].beta,
1443 sizeof(bs[1].beta));
1444 d2j (vec,
1445 "cs_r_pub_blind_0",
1446 &r_pub_blind[0],
1447 sizeof(r_pub_blind[0]));
1448 d2j (vec,
1449 "cs_r_pub_blind_1",
1450 &r_pub_blind[1],
1451 sizeof(r_pub_blind[1]));
1452 d2j (vec,
1453 "cs_c_0",
1454 &c[0],
1455 sizeof(c[0]));
1456 d2j (vec,
1457 "cs_c_1",
1458 &c[1],
1459 sizeof(c[1]));
1460 d2j (vec,
1461 "cs_blind_s",
1462 &blinded_s,
1463 sizeof(blinded_s));
1464 d2j (vec,
1465 "cs_b",
1466 &b,
1467 sizeof(b));
1468 d2j (vec,
1469 "cs_sig_s",
1470 &signature_scalar,
1471 sizeof(signature_scalar));
1472 d2j (vec,
1473 "cs_sig_R",
1474 &r_pub_blind[b],
1475 sizeof(r_pub_blind[b]));
1476 }
1477
1478 json_dumpf (vecfile, stdout, JSON_INDENT (2));
1479 json_decref (vecfile);
1480 printf ("\n");
1481
1482 return 0;
1483}
1484
1485
1486/**
1487 * Main function that will be run.
1488 *
1489 * @param cls closure
1490 * @param args remaining command-line arguments
1491 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1492 * @param cfg configuration
1493 */
1494static void
1495run (void *cls,
1496 char *const *args,
1497 const char *cfgfile,
1498 const struct GNUNET_CONFIGURATION_Handle *cfg)
1499{
1500 if (GNUNET_YES == verify_flag)
1501 global_ret = check_vectors ();
1502 else
1503 global_ret = output_vectors ();
1504}
1505
1506
1507/**
1508 * The main function of the test vector generation tool.
1509 *
1510 * @param argc number of arguments from the command line
1511 * @param argv command line arguments
1512 * @return 0 ok, 1 on error
1513 */
1514int
1515main (int argc,
1516 char *const *argv)
1517{
1518 const struct GNUNET_GETOPT_CommandLineOption options[] = {
1519 GNUNET_GETOPT_option_flag ('V',
1520 "verify",
1521 gettext_noop (
1522 "verify a test vector from stdin"),
1523 &verify_flag),
1524 GNUNET_GETOPT_OPTION_END
1525 };
1526
1527 GNUNET_assert (GNUNET_OK ==
1528 GNUNET_log_setup ("gnunet-crypto-tvg",
1529 "INFO",
1530 NULL));
1531 if (GNUNET_OK !=
1532 GNUNET_PROGRAM_run (argc, argv,
1533 "gnunet-crypto-tvg",
1534 "Generate test vectors for cryptographic operations",
1535 options,
1536 &run, NULL))
1537 return 1;
1538 return global_ret;
1539}
1540
1541
1542/* 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 ad46e3f39..000000000
--- a/src/util/gnunet-scrypt.c
+++ /dev/null
@@ -1,325 +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 * Find our proof of work.
82 *
83 * @param cls closure (unused)
84 * @param tc task context
85 */
86static void
87find_proof (void *cls)
88{
89#define ROUND_SIZE 10
90 uint64_t counter;
91 char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
92 + sizeof(uint64_t)] GNUNET_ALIGN;
93 struct GNUNET_HashCode result;
94 unsigned int i;
95 struct GNUNET_TIME_Absolute timestamp;
96 struct GNUNET_TIME_Relative elapsed;
97
98 (void) cls;
99 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
100 "Got Proof of Work %llu\n",
101 (unsigned long long) proof);
102 proof_task = NULL;
103 GNUNET_memcpy (&buf[sizeof(uint64_t)],
104 &pub,
105 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey));
106 i = 0;
107 counter = proof;
108 timestamp = GNUNET_TIME_absolute_get ();
109 while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
110 {
111 GNUNET_memcpy (buf, &counter, sizeof(uint64_t));
112 GNUNET_CRYPTO_pow_hash (&salt,
113 buf,
114 sizeof(buf),
115 &result);
116 if (nse_work_required <=
117 GNUNET_CRYPTO_hash_count_leading_zeros (&result))
118 {
119 proof = counter;
120 fprintf (stdout,
121 "Proof of work found: %llu!\n",
122 (unsigned long long) proof);
123 GNUNET_SCHEDULER_shutdown ();
124 return;
125 }
126 counter++;
127 i++;
128 }
129 elapsed = GNUNET_TIME_absolute_get_duration (timestamp);
130 elapsed = GNUNET_TIME_relative_divide (elapsed, ROUND_SIZE);
131 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
132 "Current: %llu [%s/proof]\n",
133 (unsigned long long) counter,
134 GNUNET_STRINGS_relative_time_to_string (elapsed, 0));
135 if (proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
136 {
137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
138 "Testing proofs currently at %llu\n",
139 (unsigned long long) counter);
140 /* remember progress every 100 rounds */
141 proof = counter;
142 shutdown_task (NULL);
143 }
144 else
145 {
146 proof = counter;
147 }
148 proof_task =
149 GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
150 GNUNET_SCHEDULER_PRIORITY_IDLE,
151 &find_proof,
152 NULL);
153}
154
155
156/**
157 * Main function that will be run by the scheduler.
158 *
159 * @param cls closure
160 * @param args remaining command-line arguments
161 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
162 * @param cfg configuration
163 */
164static void
165run (void *cls,
166 char *const *args,
167 const char *cfgfile,
168 const struct GNUNET_CONFIGURATION_Handle *config)
169{
170 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
171 char *pids;
172
173 (void) cls;
174 (void) args;
175 (void) cfgfile;
176 cfg = config;
177 /* load proof of work */
178 if (NULL == pwfn)
179 {
180 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
181 "NSE",
182 "PROOFFILE",
183 &pwfn))
184 {
185 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE");
186 GNUNET_SCHEDULER_shutdown ();
187 return;
188 }
189 }
190 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Proof of Work file: %s\n", pwfn);
191 if ((GNUNET_YES != GNUNET_DISK_file_test (pwfn)) ||
192 (sizeof(proof) != GNUNET_DISK_fn_read (pwfn, &proof, sizeof(proof))))
193 proof = 0;
194
195 /* load private key */
196 if (NULL == pkfn)
197 {
198 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
199 "PEER",
200 "PRIVATE_KEY",
201 &pkfn))
202 {
203 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
204 "PEER",
205 "PRIVATE_KEY");
206 return;
207 }
208 }
209 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Private Key file: %s\n", pkfn);
210 if (GNUNET_SYSERR ==
211 GNUNET_CRYPTO_eddsa_key_from_file (pkfn,
212 GNUNET_YES,
213 &pk))
214 {
215 fprintf (stderr, _ ("Loading hostkey from `%s' failed.\n"), pkfn);
216 GNUNET_free (pkfn);
217 return;
218 }
219 GNUNET_free (pkfn);
220 GNUNET_CRYPTO_eddsa_key_get_public (&pk,
221 &pub);
222 pids = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
223 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer ID: %s\n", pids);
224 GNUNET_free (pids);
225
226 /* get target bit amount */
227 if (0 == nse_work_required)
228 {
229 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
230 "NSE",
231 "WORKBITS",
232 &nse_work_required))
233 {
234 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS");
235 GNUNET_SCHEDULER_shutdown ();
236 return;
237 }
238 if (nse_work_required >= sizeof(struct GNUNET_HashCode) * 8)
239 {
240 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
241 "NSE",
242 "WORKBITS",
243 _ ("Value is too large.\n"));
244 GNUNET_SCHEDULER_shutdown ();
245 return;
246 }
247 else if (0 == nse_work_required)
248 {
249 GNUNET_SCHEDULER_shutdown ();
250 return;
251 }
252 }
253 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Bits: %llu\n", nse_work_required);
254
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
256 "Delay between tries: %s\n",
257 GNUNET_STRINGS_relative_time_to_string (proof_find_delay, 1));
258 proof_task =
259 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
260 &find_proof,
261 NULL);
262 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
263}
264
265
266/**
267 * Program to manipulate ECC key files.
268 *
269 * @param argc number of arguments from the command line
270 * @param argv command line arguments
271 * @return 0 ok, 1 on error
272 */
273int
274main (int argc, char *const *argv)
275{
276 struct GNUNET_GETOPT_CommandLineOption options[] = {
277 GNUNET_GETOPT_option_ulong (
278 'b',
279 "bits",
280 "BITS",
281 gettext_noop ("number of bits to require for the proof of work"),
282 &nse_work_required),
283 GNUNET_GETOPT_option_filename (
284 'k',
285 "keyfile",
286 "FILE",
287 gettext_noop ("file with private key, otherwise default is used"),
288 &pkfn),
289 GNUNET_GETOPT_option_filename (
290 'o',
291 "outfile",
292 "FILE",
293 gettext_noop ("file with proof of work, otherwise default is used"),
294 &pwfn),
295 GNUNET_GETOPT_option_relative_time ('t',
296 "timeout",
297 "TIME",
298 gettext_noop (
299 "time to wait between calculations"),
300 &proof_find_delay),
301 GNUNET_GETOPT_OPTION_END
302 };
303 int ret;
304
305 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
306 return 2;
307
308 ret =
309 (GNUNET_OK ==
310 GNUNET_PROGRAM_run (argc,
311 argv,
312 "gnunet-scrypt [OPTIONS] prooffile",
313 gettext_noop ("Manipulate GNUnet proof of work files"),
314 options,
315 &run,
316 NULL))
317 ? 0
318 : 1;
319 GNUNET_free_nz ((void *) argv);
320 GNUNET_free (pwfn);
321 return ret;
322}
323
324
325/* 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 8749d5d21..000000000
--- a/src/util/mq.c
+++ /dev/null
@@ -1,1032 +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 * True if GNUNET_MQ_impl_send_in_flight() was called.
180 */
181 bool in_flight;
182};
183
184
185void
186GNUNET_MQ_inject_message (struct GNUNET_MQ_Handle *mq,
187 const struct GNUNET_MessageHeader *mh)
188{
189 enum GNUNET_GenericReturnValue ret;
190
191 ret = GNUNET_MQ_handle_message (mq->handlers,
192 mh);
193 if (GNUNET_SYSERR == ret)
194 {
195 GNUNET_MQ_inject_error (mq,
196 GNUNET_MQ_ERROR_MALFORMED);
197 return;
198 }
199}
200
201
202enum GNUNET_GenericReturnValue
203GNUNET_MQ_handle_message (const struct GNUNET_MQ_MessageHandler *handlers,
204 const struct GNUNET_MessageHeader *mh)
205{
206 bool handled = false;
207 uint16_t msize = ntohs (mh->size);
208 uint16_t mtype = ntohs (mh->type);
209
210 LOG (GNUNET_ERROR_TYPE_DEBUG,
211 "Received message of type %u and size %u\n",
212 mtype,
213 msize);
214 if (NULL == handlers)
215 goto done;
216 for (const struct GNUNET_MQ_MessageHandler *handler = handlers;
217 NULL != handler->cb;
218 handler++)
219 {
220 if (handler->type == mtype)
221 {
222 handled = true;
223 if ( (handler->expected_size > msize) ||
224 ( (handler->expected_size != msize) &&
225 (NULL == handler->mv) ) )
226 {
227 /* Too small, or not an exact size and
228 no 'mv' handler to check rest */
229 LOG (GNUNET_ERROR_TYPE_ERROR,
230 "Received malformed message of type %u\n",
231 (unsigned int) handler->type);
232 return GNUNET_SYSERR;
233 }
234 if ( (NULL == handler->mv) ||
235 (GNUNET_OK ==
236 handler->mv (handler->cls,
237 mh)) )
238 {
239 /* message well-formed, pass to handler */
240 handler->cb (handler->cls, mh);
241 }
242 else
243 {
244 /* Message rejected by check routine */
245 LOG (GNUNET_ERROR_TYPE_ERROR,
246 "Received malformed message of type %u\n",
247 (unsigned int) handler->type);
248 return GNUNET_SYSERR;
249 }
250 break;
251 }
252 }
253done:
254 if (! handled)
255 {
256 LOG (GNUNET_ERROR_TYPE_INFO,
257 "No handler for message of type %u and size %u\n",
258 mtype,
259 msize);
260 return GNUNET_NO;
261 }
262 return GNUNET_OK;
263}
264
265
266void
267GNUNET_MQ_inject_error (struct GNUNET_MQ_Handle *mq,
268 enum GNUNET_MQ_Error error)
269{
270 if (NULL == mq->error_handler)
271 {
272 LOG (GNUNET_ERROR_TYPE_WARNING,
273 "Got error %d, but no handler installed\n",
274 (int) error);
275 return;
276 }
277 mq->error_handler (mq->error_handler_cls,
278 error);
279}
280
281
282void
283GNUNET_MQ_discard (struct GNUNET_MQ_Envelope *ev)
284{
285 GNUNET_assert (NULL == ev->parent_queue);
286 GNUNET_free (ev);
287}
288
289
290unsigned int
291GNUNET_MQ_get_length (struct GNUNET_MQ_Handle *mq)
292{
293 if (! mq->in_flight)
294 {
295 return mq->queue_length;
296 }
297 return mq->queue_length - 1;
298}
299
300
301void
302GNUNET_MQ_send (struct GNUNET_MQ_Handle *mq,
303 struct GNUNET_MQ_Envelope *ev)
304{
305 if (NULL == mq)
306 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307 "mq is NUll when sending message of type %u\n",
308 (unsigned int) ntohs (ev->mh->type));
309 GNUNET_assert (NULL != mq);
310 GNUNET_assert (NULL == ev->parent_queue);
311
312 mq->queue_length++;
313 if (mq->queue_length >= 10000000)
314 {
315 /* This would seem like a bug... */
316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
317 "MQ with %u entries extended by message of type %u (FC broken?)\n",
318 (unsigned int) mq->queue_length,
319 (unsigned int) ntohs (ev->mh->type));
320 }
321 ev->parent_queue = mq;
322 /* is the implementation busy? queue it! */
323 if ((NULL != mq->current_envelope) || (NULL != mq->send_task))
324 {
325 GNUNET_CONTAINER_DLL_insert_tail (mq->envelope_head,
326 mq->envelope_tail,
327 ev);
328 return;
329 }
330 GNUNET_assert (NULL == mq->envelope_head);
331 mq->current_envelope = ev;
332
333 LOG (GNUNET_ERROR_TYPE_DEBUG,
334 "sending message of type %u and size %u, queue empty (MQ: %p)\n",
335 ntohs (ev->mh->type),
336 ntohs (ev->mh->size),
337 mq);
338
339 mq->send_impl (mq,
340 ev->mh,
341 mq->impl_state);
342}
343
344
345struct GNUNET_MQ_Envelope *
346GNUNET_MQ_unsent_head (struct GNUNET_MQ_Handle *mq)
347{
348 struct GNUNET_MQ_Envelope *env;
349
350 env = mq->envelope_head;
351 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
352 mq->envelope_tail,
353 env);
354 mq->queue_length--;
355 env->parent_queue = NULL;
356 return env;
357}
358
359
360struct GNUNET_MQ_Envelope *
361GNUNET_MQ_env_copy (struct GNUNET_MQ_Envelope *env)
362{
363 GNUNET_assert (NULL == env->next);
364 GNUNET_assert (NULL == env->parent_queue);
365 GNUNET_assert (NULL == env->sent_cb);
366 GNUNET_assert (GNUNET_NO == env->have_custom_options);
367 return GNUNET_MQ_msg_copy (env->mh);
368}
369
370
371void
372GNUNET_MQ_send_copy (struct GNUNET_MQ_Handle *mq,
373 const struct GNUNET_MQ_Envelope *ev)
374{
375 struct GNUNET_MQ_Envelope *env;
376 uint16_t msize;
377
378 msize = ntohs (ev->mh->size);
379 env = GNUNET_malloc (sizeof(struct GNUNET_MQ_Envelope) + msize);
380 env->mh = (struct GNUNET_MessageHeader *) &env[1];
381 env->sent_cb = ev->sent_cb;
382 env->sent_cls = ev->sent_cls;
383 GNUNET_memcpy (&env[1], ev->mh, msize);
384 GNUNET_MQ_send (mq, env);
385}
386
387
388/**
389 * Task run to call the send implementation for the next queued
390 * message, if any. Only useful for implementing message queues,
391 * results in undefined behavior if not used carefully.
392 *
393 * @param cls message queue to send the next message with
394 */
395static void
396impl_send_continue (void *cls)
397{
398 struct GNUNET_MQ_Handle *mq = cls;
399
400 mq->send_task = NULL;
401 /* call is only valid if we're actually currently sending
402 * a message */
403 if (NULL == mq->envelope_head)
404 return;
405 mq->current_envelope = mq->envelope_head;
406 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
407 mq->envelope_tail,
408 mq->current_envelope);
409
410 LOG (GNUNET_ERROR_TYPE_DEBUG,
411 "sending message of type %u and size %u from queue (MQ: %p)\n",
412 ntohs (mq->current_envelope->mh->type),
413 ntohs (mq->current_envelope->mh->size),
414 mq);
415
416 mq->send_impl (mq,
417 mq->current_envelope->mh,
418 mq->impl_state);
419}
420
421
422void
423GNUNET_MQ_impl_send_continue (struct GNUNET_MQ_Handle *mq)
424{
425 struct GNUNET_MQ_Envelope *current_envelope;
426 GNUNET_SCHEDULER_TaskCallback cb;
427
428 GNUNET_assert (0 < mq->queue_length);
429 mq->queue_length--;
430 mq->in_flight = false;
431 current_envelope = mq->current_envelope;
432 current_envelope->parent_queue = NULL;
433 mq->current_envelope = NULL;
434 GNUNET_assert (NULL == mq->send_task);
435 mq->send_task = GNUNET_SCHEDULER_add_now (&impl_send_continue, mq);
436 if (NULL != (cb = current_envelope->sent_cb))
437 {
438 current_envelope->sent_cb = NULL;
439 cb (current_envelope->sent_cls);
440 }
441 GNUNET_free (current_envelope);
442}
443
444
445void
446GNUNET_MQ_impl_send_in_flight (struct GNUNET_MQ_Handle *mq)
447{
448 struct GNUNET_MQ_Envelope *current_envelope;
449 GNUNET_SCHEDULER_TaskCallback cb;
450
451 mq->in_flight = true;
452 /* call is only valid if we're actually currently sending
453 * a message */
454 current_envelope = mq->current_envelope;
455 GNUNET_assert (NULL != current_envelope);
456 /* can't call cancel from now on anymore */
457 current_envelope->parent_queue = NULL;
458 if (NULL != (cb = current_envelope->sent_cb))
459 {
460 current_envelope->sent_cb = NULL;
461 cb (current_envelope->sent_cls);
462 }
463}
464
465
466struct GNUNET_MQ_Handle *
467GNUNET_MQ_queue_for_callbacks (GNUNET_MQ_SendImpl send,
468 GNUNET_MQ_DestroyImpl destroy,
469 GNUNET_MQ_CancelImpl cancel,
470 void *impl_state,
471 const struct GNUNET_MQ_MessageHandler *handlers,
472 GNUNET_MQ_ErrorHandler error_handler,
473 void *error_handler_cls)
474{
475 struct GNUNET_MQ_Handle *mq;
476
477 mq = GNUNET_new (struct GNUNET_MQ_Handle);
478 mq->send_impl = send;
479 mq->destroy_impl = destroy;
480 mq->cancel_impl = cancel;
481 mq->handlers = GNUNET_MQ_copy_handlers (handlers);
482 mq->error_handler = error_handler;
483 mq->error_handler_cls = error_handler_cls;
484 mq->impl_state = impl_state;
485
486 return mq;
487}
488
489
490void
491GNUNET_MQ_set_handlers_closure (struct GNUNET_MQ_Handle *mq,
492 void *handlers_cls)
493{
494 if (NULL == mq->handlers)
495 return;
496 for (unsigned int i = 0; NULL != mq->handlers[i].cb; i++)
497 mq->handlers[i].cls = handlers_cls;
498}
499
500
501const struct GNUNET_MessageHeader *
502GNUNET_MQ_impl_current (struct GNUNET_MQ_Handle *mq)
503{
504 GNUNET_assert (NULL != mq->current_envelope);
505 GNUNET_assert (NULL != mq->current_envelope->mh);
506 return mq->current_envelope->mh;
507}
508
509
510void *
511GNUNET_MQ_impl_state (struct GNUNET_MQ_Handle *mq)
512{
513 return mq->impl_state;
514}
515
516
517struct GNUNET_MQ_Envelope *
518GNUNET_MQ_msg_ (struct GNUNET_MessageHeader **mhp,
519 uint16_t size,
520 uint16_t type)
521{
522 struct GNUNET_MQ_Envelope *ev;
523
524 ev = GNUNET_malloc (size + sizeof(struct GNUNET_MQ_Envelope));
525 ev->mh = (struct GNUNET_MessageHeader *) &ev[1];
526 ev->mh->size = htons (size);
527 ev->mh->type = htons (type);
528 if (NULL != mhp)
529 *mhp = ev->mh;
530 return ev;
531}
532
533
534struct GNUNET_MQ_Envelope *
535GNUNET_MQ_msg_copy (const struct GNUNET_MessageHeader *hdr)
536{
537 struct GNUNET_MQ_Envelope *mqm;
538 uint16_t size = ntohs (hdr->size);
539
540 mqm = GNUNET_malloc (sizeof(*mqm) + size);
541 mqm->mh = (struct GNUNET_MessageHeader *) &mqm[1];
542 GNUNET_memcpy (mqm->mh,
543 hdr,
544 size);
545 return mqm;
546}
547
548
549struct GNUNET_MQ_Envelope *
550GNUNET_MQ_msg_nested_mh_ (struct GNUNET_MessageHeader **mhp,
551 uint16_t base_size,
552 uint16_t type,
553 const struct GNUNET_MessageHeader *nested_mh)
554{
555 struct GNUNET_MQ_Envelope *mqm;
556 uint16_t size;
557
558 if (NULL == nested_mh)
559 return GNUNET_MQ_msg_ (mhp,
560 base_size,
561 type);
562 size = base_size + ntohs (nested_mh->size);
563 /* check for uint16_t overflow */
564 if (size < base_size)
565 return NULL;
566 mqm = GNUNET_MQ_msg_ (mhp,
567 size,
568 type);
569 GNUNET_memcpy ((char *) mqm->mh + base_size,
570 nested_mh,
571 ntohs (nested_mh->size));
572 return mqm;
573}
574
575
576uint32_t
577GNUNET_MQ_assoc_add (struct GNUNET_MQ_Handle *mq,
578 void *assoc_data)
579{
580 uint32_t id;
581
582 if (NULL == mq->assoc_map)
583 {
584 mq->assoc_map = GNUNET_CONTAINER_multihashmap32_create (8);
585 mq->assoc_id = 1;
586 }
587 id = mq->assoc_id++;
588 GNUNET_assert (GNUNET_OK ==
589 GNUNET_CONTAINER_multihashmap32_put (
590 mq->assoc_map,
591 id,
592 assoc_data,
593 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
594 return id;
595}
596
597
598/**
599 * Get the data associated with a @a request_id in a queue
600 *
601 * @param mq the message queue with the association
602 * @param request_id the request id we are interested in
603 * @return the associated data
604 */
605void *
606GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq,
607 uint32_t request_id)
608{
609 if (NULL == mq->assoc_map)
610 return NULL;
611 return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map,
612 request_id);
613}
614
615
616/**
617 * Remove the association for a @a request_id
618 *
619 * @param mq the message queue with the association
620 * @param request_id the request id we want to remove
621 * @return the associated data
622 */
623void *
624GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq,
625 uint32_t request_id)
626{
627 void *val;
628
629 if (NULL == mq->assoc_map)
630 return NULL;
631 val = GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map,
632 request_id);
633 GNUNET_CONTAINER_multihashmap32_remove_all (mq->assoc_map,
634 request_id);
635 return val;
636}
637
638
639void
640GNUNET_MQ_notify_sent (struct GNUNET_MQ_Envelope *ev,
641 GNUNET_SCHEDULER_TaskCallback cb,
642 void *cb_cls)
643{
644 /* allow setting *OR* clearing callback */
645 GNUNET_assert ((NULL == ev->sent_cb) || (NULL == cb));
646 ev->sent_cb = cb;
647 ev->sent_cls = cb_cls;
648}
649
650
651/**
652 * Handle we return for callbacks registered to be
653 * notified when #GNUNET_MQ_destroy() is called on a queue.
654 */
655struct GNUNET_MQ_DestroyNotificationHandle
656{
657 /**
658 * Kept in a DLL.
659 */
660 struct GNUNET_MQ_DestroyNotificationHandle *prev;
661
662 /**
663 * Kept in a DLL.
664 */
665 struct GNUNET_MQ_DestroyNotificationHandle *next;
666
667 /**
668 * Queue to notify about.
669 */
670 struct GNUNET_MQ_Handle *mq;
671
672 /**
673 * Function to call.
674 */
675 GNUNET_SCHEDULER_TaskCallback cb;
676
677 /**
678 * Closure for @e cb.
679 */
680 void *cb_cls;
681};
682
683
684void
685GNUNET_MQ_destroy (struct GNUNET_MQ_Handle *mq)
686{
687 struct GNUNET_MQ_DestroyNotificationHandle *dnh;
688
689 if (NULL != mq->destroy_impl)
690 {
691 mq->destroy_impl (mq, mq->impl_state);
692 }
693 if (NULL != mq->send_task)
694 {
695 GNUNET_SCHEDULER_cancel (mq->send_task);
696 mq->send_task = NULL;
697 }
698 while (NULL != mq->envelope_head)
699 {
700 struct GNUNET_MQ_Envelope *ev;
701
702 ev = mq->envelope_head;
703 ev->parent_queue = NULL;
704 GNUNET_CONTAINER_DLL_remove (mq->envelope_head, mq->envelope_tail, ev);
705 GNUNET_assert (0 < mq->queue_length);
706 mq->queue_length--;
707 LOG (GNUNET_ERROR_TYPE_DEBUG,
708 "MQ destroy drops message of type %u\n",
709 ntohs (ev->mh->type));
710 GNUNET_MQ_discard (ev);
711 }
712 if (NULL != mq->current_envelope)
713 {
714 /* we can only discard envelopes that
715 * are not queued! */
716 mq->current_envelope->parent_queue = NULL;
717 LOG (GNUNET_ERROR_TYPE_DEBUG,
718 "MQ destroy drops current message of type %u\n",
719 ntohs (mq->current_envelope->mh->type));
720 GNUNET_MQ_discard (mq->current_envelope);
721 mq->current_envelope = NULL;
722 GNUNET_assert (0 < mq->queue_length);
723 mq->queue_length--;
724 }
725 GNUNET_assert (0 == mq->queue_length);
726 while (NULL != (dnh = mq->dnh_head))
727 {
728 dnh->cb (dnh->cb_cls);
729 GNUNET_MQ_destroy_notify_cancel (dnh);
730 }
731 if (NULL != mq->assoc_map)
732 {
733 GNUNET_CONTAINER_multihashmap32_destroy (mq->assoc_map);
734 mq->assoc_map = NULL;
735 }
736 GNUNET_free (mq->handlers);
737 GNUNET_free (mq);
738}
739
740
741const struct GNUNET_MessageHeader *
742GNUNET_MQ_extract_nested_mh_ (const struct GNUNET_MessageHeader *mh,
743 uint16_t base_size)
744{
745 uint16_t whole_size;
746 uint16_t nested_size;
747 const struct GNUNET_MessageHeader *nested_msg;
748
749 whole_size = ntohs (mh->size);
750 GNUNET_assert (whole_size >= base_size);
751 nested_size = whole_size - base_size;
752 if (0 == nested_size)
753 return NULL;
754 if (nested_size < sizeof(struct GNUNET_MessageHeader))
755 {
756 GNUNET_break_op (0);
757 return NULL;
758 }
759 nested_msg = (const struct GNUNET_MessageHeader *) ((char *) mh + base_size);
760 if (ntohs (nested_msg->size) != nested_size)
761 {
762 GNUNET_break_op (0);
763 return NULL;
764 }
765 return nested_msg;
766}
767
768
769void
770GNUNET_MQ_send_cancel (struct GNUNET_MQ_Envelope *ev)
771{
772 struct GNUNET_MQ_Handle *mq = ev->parent_queue;
773
774 GNUNET_assert (NULL != mq);
775 GNUNET_assert (NULL != mq->cancel_impl);
776 GNUNET_assert (0 < mq->queue_length);
777 mq->queue_length--;
778 if (mq->current_envelope == ev)
779 {
780 /* complex case, we already started with transmitting
781 the message using the callbacks. */
782 GNUNET_assert (! mq->in_flight);
783 mq->cancel_impl (mq,
784 mq->impl_state);
785 /* continue sending the next message, if any */
786 mq->current_envelope = mq->envelope_head;
787 if (NULL != mq->current_envelope)
788 {
789 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
790 mq->envelope_tail,
791 mq->current_envelope);
792 LOG (GNUNET_ERROR_TYPE_DEBUG,
793 "sending canceled message of type %u queue\n",
794 ntohs (ev->mh->type));
795 mq->send_impl (mq,
796 mq->current_envelope->mh,
797 mq->impl_state);
798 }
799 }
800 else
801 {
802 /* simple case, message is still waiting in the queue */
803 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
804 mq->envelope_tail,
805 ev);
806 }
807 ev->parent_queue = NULL;
808 ev->mh = NULL;
809 /* also frees ev */
810 GNUNET_free (ev);
811}
812
813
814struct GNUNET_MQ_Envelope *
815GNUNET_MQ_get_current_envelope (struct GNUNET_MQ_Handle *mq)
816{
817 return mq->current_envelope;
818}
819
820
821struct GNUNET_MQ_Envelope *
822GNUNET_MQ_get_last_envelope (struct GNUNET_MQ_Handle *mq)
823{
824 if (NULL != mq->envelope_tail)
825 return mq->envelope_tail;
826
827 return mq->current_envelope;
828}
829
830
831void
832GNUNET_MQ_env_set_options (struct GNUNET_MQ_Envelope *env,
833 enum GNUNET_MQ_PriorityPreferences pp)
834{
835 env->priority = pp;
836 env->have_custom_options = GNUNET_YES;
837}
838
839
840enum GNUNET_MQ_PriorityPreferences
841GNUNET_MQ_env_get_options (struct GNUNET_MQ_Envelope *env)
842{
843 struct GNUNET_MQ_Handle *mq = env->parent_queue;
844
845 if (GNUNET_YES == env->have_custom_options)
846 return env->priority;
847 if (NULL == mq)
848 return 0;
849 return mq->priority;
850}
851
852
853enum GNUNET_MQ_PriorityPreferences
854GNUNET_MQ_env_combine_options (enum GNUNET_MQ_PriorityPreferences p1,
855 enum GNUNET_MQ_PriorityPreferences p2)
856{
857 enum GNUNET_MQ_PriorityPreferences ret;
858
859 ret = GNUNET_MAX (p1 & GNUNET_MQ_PRIORITY_MASK, p2 & GNUNET_MQ_PRIORITY_MASK);
860 ret |= ((p1 & GNUNET_MQ_PREF_UNRELIABLE) & (p2 & GNUNET_MQ_PREF_UNRELIABLE));
861 ret |=
862 ((p1 & GNUNET_MQ_PREF_LOW_LATENCY) | (p2 & GNUNET_MQ_PREF_LOW_LATENCY));
863 ret |=
864 ((p1 & GNUNET_MQ_PREF_CORK_ALLOWED) & (p2 & GNUNET_MQ_PREF_CORK_ALLOWED));
865 ret |= ((p1 & GNUNET_MQ_PREF_GOODPUT) & (p2 & GNUNET_MQ_PREF_GOODPUT));
866 ret |=
867 ((p1 & GNUNET_MQ_PREF_OUT_OF_ORDER) & (p2 & GNUNET_MQ_PREF_OUT_OF_ORDER));
868 return ret;
869}
870
871
872void
873GNUNET_MQ_set_options (struct GNUNET_MQ_Handle *mq,
874 enum GNUNET_MQ_PriorityPreferences pp)
875{
876 mq->priority = pp;
877}
878
879
880const struct GNUNET_MessageHeader *
881GNUNET_MQ_env_get_msg (const struct GNUNET_MQ_Envelope *env)
882{
883 return env->mh;
884}
885
886
887const struct GNUNET_MQ_Envelope *
888GNUNET_MQ_env_next (const struct GNUNET_MQ_Envelope *env)
889{
890 return env->next;
891}
892
893
894struct GNUNET_MQ_DestroyNotificationHandle *
895GNUNET_MQ_destroy_notify (struct GNUNET_MQ_Handle *mq,
896 GNUNET_SCHEDULER_TaskCallback cb,
897 void *cb_cls)
898{
899 struct GNUNET_MQ_DestroyNotificationHandle *dnh;
900
901 dnh = GNUNET_new (struct GNUNET_MQ_DestroyNotificationHandle);
902 dnh->mq = mq;
903 dnh->cb = cb;
904 dnh->cb_cls = cb_cls;
905 GNUNET_CONTAINER_DLL_insert (mq->dnh_head,
906 mq->dnh_tail,
907 dnh);
908 return dnh;
909}
910
911
912void
913GNUNET_MQ_destroy_notify_cancel (
914 struct GNUNET_MQ_DestroyNotificationHandle *dnh)
915{
916 struct GNUNET_MQ_Handle *mq = dnh->mq;
917
918 GNUNET_CONTAINER_DLL_remove (mq->dnh_head,
919 mq->dnh_tail,
920 dnh);
921 GNUNET_free (dnh);
922}
923
924
925void
926GNUNET_MQ_dll_insert_head (struct GNUNET_MQ_Envelope **env_head,
927 struct GNUNET_MQ_Envelope **env_tail,
928 struct GNUNET_MQ_Envelope *env)
929{
930 GNUNET_CONTAINER_DLL_insert (*env_head,
931 *env_tail,
932 env);
933}
934
935
936void
937GNUNET_MQ_dll_insert_tail (struct GNUNET_MQ_Envelope **env_head,
938 struct GNUNET_MQ_Envelope **env_tail,
939 struct GNUNET_MQ_Envelope *env)
940{
941 GNUNET_CONTAINER_DLL_insert_tail (*env_head,
942 *env_tail,
943 env);
944}
945
946
947void
948GNUNET_MQ_dll_remove (struct GNUNET_MQ_Envelope **env_head,
949 struct GNUNET_MQ_Envelope **env_tail,
950 struct GNUNET_MQ_Envelope *env)
951{
952 GNUNET_CONTAINER_DLL_remove (*env_head,
953 *env_tail,
954 env);
955}
956
957
958struct GNUNET_MQ_MessageHandler *
959GNUNET_MQ_copy_handlers (const struct GNUNET_MQ_MessageHandler *handlers)
960{
961 struct GNUNET_MQ_MessageHandler *copy;
962 unsigned int count;
963
964 if (NULL == handlers)
965 return NULL;
966 count = GNUNET_MQ_count_handlers (handlers);
967 copy = GNUNET_new_array (count + 1,
968 struct GNUNET_MQ_MessageHandler);
969 GNUNET_memcpy (copy,
970 handlers,
971 count * sizeof(struct GNUNET_MQ_MessageHandler));
972 return copy;
973}
974
975
976struct GNUNET_MQ_MessageHandler *
977GNUNET_MQ_copy_handlers2 (const struct GNUNET_MQ_MessageHandler *handlers,
978 GNUNET_MQ_MessageCallback agpl_handler,
979 void *agpl_cls)
980{
981 struct GNUNET_MQ_MessageHandler *copy;
982 unsigned int count;
983
984 if (NULL == handlers)
985 return NULL;
986 count = GNUNET_MQ_count_handlers (handlers);
987 copy = GNUNET_new_array (count + 2,
988 struct GNUNET_MQ_MessageHandler);
989 GNUNET_memcpy (copy,
990 handlers,
991 count * sizeof(struct GNUNET_MQ_MessageHandler));
992 copy[count].mv = NULL;
993 copy[count].cb = agpl_handler;
994 copy[count].cls = agpl_cls;
995 copy[count].type = GNUNET_MESSAGE_TYPE_REQUEST_AGPL;
996 copy[count].expected_size = sizeof(struct GNUNET_MessageHeader);
997 return copy;
998}
999
1000
1001unsigned int
1002GNUNET_MQ_count_handlers (const struct GNUNET_MQ_MessageHandler *handlers)
1003{
1004 unsigned int i;
1005
1006 if (NULL == handlers)
1007 return 0;
1008 for (i = 0; NULL != handlers[i].cb; i++)
1009 ;
1010 return i;
1011}
1012
1013
1014const char *
1015GNUNET_MQ_preference_to_string (enum GNUNET_MQ_PreferenceKind type)
1016{
1017 switch (type)
1018 {
1019 case GNUNET_MQ_PREFERENCE_NONE:
1020 return "NONE";
1021 case GNUNET_MQ_PREFERENCE_BANDWIDTH:
1022 return "BANDWIDTH";
1023 case GNUNET_MQ_PREFERENCE_LATENCY:
1024 return "LATENCY";
1025 case GNUNET_MQ_PREFERENCE_RELIABILITY:
1026 return "RELIABILITY";
1027 }
1028 return NULL;
1029}
1030
1031
1032/* end of mq.c */
diff --git a/src/util/mst.c b/src/util/mst.c
deleted file mode 100644
index 2236f2883..000000000
--- a/src/util/mst.c
+++ /dev/null
@@ -1,425 +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 (%u/%u) bytes already in private buffer\n",
133 (unsigned int) size,
134 (unsigned int) (mst->pos - mst->off),
135 (unsigned int) mst->pos,
136 (unsigned int) mst->off);
137 ret = GNUNET_OK;
138 ibuf = (char *) mst->hdr;
139 while (mst->pos > 0)
140 {
141 do_align:
142 GNUNET_assert (mst->pos >= mst->off);
143 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
144 (0 != (mst->off % ALIGN_FACTOR)))
145 {
146 /* need to align or need more space */
147 mst->pos -= mst->off;
148 memmove (ibuf,
149 &ibuf[mst->off],
150 mst->pos);
151 mst->off = 0;
152 }
153 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
154 {
155 delta
156 = GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
157 - (mst->pos - mst->off),
158 size);
159 GNUNET_memcpy (&ibuf[mst->pos],
160 buf,
161 delta);
162 mst->pos += delta;
163 buf += delta;
164 size -= delta;
165 }
166 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
167 {
168 if (purge)
169 {
170 mst->off = 0;
171 mst->pos = 0;
172 }
173 return GNUNET_OK;
174 }
175 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
176 want = ntohs (hdr->size);
177 LOG (GNUNET_ERROR_TYPE_DEBUG,
178 "We want to read message of size %u\n",
179 want);
180 if (want < sizeof(struct GNUNET_MessageHeader))
181 {
182 GNUNET_break_op (0);
183 return GNUNET_SYSERR;
184 }
185 if ((mst->curr_buf - mst->off < want) &&
186 (mst->off > 0))
187 {
188 /* can get more space by moving */
189 mst->pos -= mst->off;
190 memmove (ibuf,
191 &ibuf[mst->off],
192 mst->pos);
193 mst->off = 0;
194 }
195 if (mst->curr_buf < want)
196 {
197 /* need to get more space by growing buffer */
198 GNUNET_assert (0 == mst->off);
199 mst->hdr = GNUNET_realloc (mst->hdr,
200 want);
201 ibuf = (char *) mst->hdr;
202 mst->curr_buf = want;
203 }
204 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
205 if (mst->pos - mst->off < want)
206 {
207 delta = GNUNET_MIN (want - (mst->pos - mst->off),
208 size);
209 GNUNET_assert (mst->pos + delta <= mst->curr_buf);
210 GNUNET_memcpy (&ibuf[mst->pos],
211 buf,
212 delta);
213 mst->pos += delta;
214 buf += delta;
215 size -= delta;
216 }
217 if (mst->pos - mst->off < want)
218 {
219 if (purge)
220 {
221 mst->off = 0;
222 mst->pos = 0;
223 }
224 return GNUNET_OK;
225 }
226 if (one_shot == GNUNET_SYSERR)
227 {
228 /* cannot call callback again, but return value saying that
229 * we have another full message in the buffer */
230 ret = GNUNET_NO;
231 goto copy;
232 }
233 if (one_shot == GNUNET_YES)
234 one_shot = GNUNET_SYSERR;
235 mst->off += want;
236 if (GNUNET_OK !=
237 (cbret = mst->cb (mst->cb_cls,
238 hdr)))
239 {
240 if (GNUNET_SYSERR == cbret)
241 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
242 "Failure processing message of type %u and size %u\n",
243 ntohs (hdr->type),
244 ntohs (hdr->size));
245 return GNUNET_SYSERR;
246 }
247 if (mst->off == mst->pos)
248 {
249 /* reset to beginning of buffer, it's free right now! */
250 mst->off = 0;
251 mst->pos = 0;
252 }
253 }
254 GNUNET_assert (0 == mst->pos);
255 while (size > 0)
256 {
257 LOG (GNUNET_ERROR_TYPE_DEBUG,
258 "Server-mst has %u bytes left in inbound buffer\n",
259 (unsigned int) size);
260 if (size < sizeof(struct GNUNET_MessageHeader))
261 break;
262 offset = (unsigned long) buf;
263 need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
264 if (GNUNET_NO == need_align)
265 {
266 /* can try to do zero-copy and process directly from original buffer */
267 hdr = (const struct GNUNET_MessageHeader *) buf;
268 want = ntohs (hdr->size);
269 if (want < sizeof(struct GNUNET_MessageHeader))
270 {
271 GNUNET_break_op (0);
272 mst->off = 0;
273 return GNUNET_SYSERR;
274 }
275 if (size < want)
276 break; /* or not: buffer incomplete, so copy to private buffer... */
277 if (one_shot == GNUNET_SYSERR)
278 {
279 /* cannot call callback again, but return value saying that
280 * we have another full message in the buffer */
281 ret = GNUNET_NO;
282 goto copy;
283 }
284 if (one_shot == GNUNET_YES)
285 one_shot = GNUNET_SYSERR;
286 if (GNUNET_OK !=
287 (cbret = mst->cb (mst->cb_cls,
288 hdr)))
289 {
290 if (GNUNET_SYSERR == cbret)
291 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
292 "Failure processing message of type %u and size %u\n",
293 ntohs (hdr->type),
294 ntohs (hdr->size));
295 return GNUNET_SYSERR;
296 }
297 buf += want;
298 size -= want;
299 }
300 else
301 {
302 /* need to copy to private buffer to align;
303 * yes, we go a bit more spaghetti than usual here */
304 goto do_align;
305 }
306 }
307 copy:
308 if ((size > 0) && (! purge))
309 {
310 if (size + mst->pos > mst->curr_buf)
311 {
312 mst->hdr = GNUNET_realloc (mst->hdr,
313 size + mst->pos);
314 ibuf = (char *) mst->hdr;
315 mst->curr_buf = size + mst->pos;
316 }
317 GNUNET_assert (size + mst->pos <= mst->curr_buf);
318 GNUNET_memcpy (&ibuf[mst->pos],
319 buf,
320 size);
321 mst->pos += size;
322 }
323 if (purge)
324 {
325 mst->off = 0;
326 mst->pos = 0;
327 }
328 LOG (GNUNET_ERROR_TYPE_DEBUG,
329 "Server-mst leaves %u (%u/%u) bytes in private buffer\n",
330 (unsigned int) (mst->pos - mst->off),
331 (unsigned int) mst->pos,
332 (unsigned int) mst->off);
333 return ret;
334}
335
336
337/**
338 * Add incoming data to the receive buffer and call the
339 * callback for all complete messages.
340 *
341 * @param mst tokenizer to use
342 * @param buf input data to add
343 * @param size number of bytes in @a buf
344 * @param purge should any excess bytes in the buffer be discarded
345 * (i.e. for packet-based services like UDP)
346 * @param one_shot only call callback once, keep rest of message in buffer
347 * @return #GNUNET_OK if we are done processing (need more data)
348 * #GNUNET_NO if one_shot was set and we have another message ready
349 * #GNUNET_SYSERR if the data stream is corrupt
350 */
351int
352GNUNET_MST_read (struct GNUNET_MessageStreamTokenizer *mst,
353 struct GNUNET_NETWORK_Handle *sock,
354 int purge,
355 int one_shot)
356{
357 ssize_t ret;
358 size_t left;
359 char *buf;
360
361 left = mst->curr_buf - mst->pos;
362 buf = (char *) mst->hdr;
363 ret = GNUNET_NETWORK_socket_recv (sock,
364 &buf[mst->pos],
365 left);
366 if (-1 == ret)
367 {
368 if ((EAGAIN == errno) ||
369 (EINTR == errno))
370 return GNUNET_OK;
371 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
372 "recv");
373 return GNUNET_SYSERR;
374 }
375 if (0 == ret)
376 {
377 /* other side closed connection, treat as error */
378 return GNUNET_SYSERR;
379 }
380 mst->pos += ret;
381 return GNUNET_MST_from_buffer (mst,
382 NULL,
383 0,
384 purge,
385 one_shot);
386}
387
388
389/**
390 * Obtain the next message from the @a mst, assuming that
391 * there are more unprocessed messages in the internal buffer
392 * of the @a mst.
393 *
394 * @param mst tokenizer to use
395 * @param one_shot only call callback once, keep rest of message in buffer
396 * @return #GNUNET_OK if we are done processing (need more data)
397 * #GNUNET_NO if one_shot was set and we have another message ready
398 * #GNUNET_SYSERR if the data stream is corrupt
399 */
400int
401GNUNET_MST_next (struct GNUNET_MessageStreamTokenizer *mst,
402 int one_shot)
403{
404 return GNUNET_MST_from_buffer (mst,
405 NULL,
406 0,
407 GNUNET_NO,
408 one_shot);
409}
410
411
412/**
413 * Destroys a tokenizer.
414 *
415 * @param mst tokenizer to destroy
416 */
417void
418GNUNET_MST_destroy (struct GNUNET_MessageStreamTokenizer *mst)
419{
420 GNUNET_free (mst->hdr);
421 GNUNET_free (mst);
422}
423
424
425/* 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 2f77bc54e..000000000
--- a/src/util/network.c
+++ /dev/null
@@ -1,1334 +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 ==
354 GNUNET_NETWORK_socket_close (h));
355 errno = EMFILE;
356 return GNUNET_SYSERR;
357 }
358
359 if (GNUNET_OK != socket_set_inheritable (h))
360 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
361 "socket_set_inheritable");
362
363 if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (h, GNUNET_NO))
364 {
365 eno = errno;
366 GNUNET_break (0);
367 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
368 errno = eno;
369 return GNUNET_SYSERR;
370 }
371#ifdef DARWIN
372 if (GNUNET_SYSERR == socket_set_nosigpipe (h))
373 {
374 eno = errno;
375 GNUNET_break (0);
376 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
377 errno = eno;
378 return GNUNET_SYSERR;
379 }
380#endif
381 if ((type == SOCK_STREAM)
382#ifdef AF_UNIX
383 && (af != AF_UNIX)
384#endif
385 )
386 socket_set_nodelay (h);
387 return GNUNET_OK;
388}
389
390
391struct GNUNET_NETWORK_Handle *
392GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
393 struct sockaddr *address,
394 socklen_t *address_len)
395{
396 struct GNUNET_NETWORK_Handle *ret;
397 int eno;
398
399 ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
400#if DEBUG_NETWORK
401 {
402 struct sockaddr_storage name;
403 socklen_t namelen = sizeof(name);
404
405 int gsn = getsockname (desc->fd,
406 (struct sockaddr *) &name,
407 &namelen);
408
409 if (0 == gsn)
410 LOG (GNUNET_ERROR_TYPE_DEBUG,
411 "Accepting connection on `%s'\n",
412 GNUNET_a2s ((const struct sockaddr *) &name,
413 namelen));
414 }
415#endif
416 ret->fd = accept (desc->fd,
417 address,
418 address_len);
419 if (-1 == ret->fd)
420 {
421 eno = errno;
422 GNUNET_free (ret);
423 errno = eno;
424 return NULL;
425 }
426 if (GNUNET_OK !=
427 initialize_network_handle (ret,
428 (NULL != address) ? address->sa_family :
429 desc->af,
430 SOCK_STREAM))
431 {
432 return NULL;
433 }
434 return ret;
435}
436
437
438enum GNUNET_GenericReturnValue
439GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
440 const struct sockaddr *address,
441 socklen_t address_len)
442{
443 int ret;
444
445#ifdef IPV6_V6ONLY
446#ifdef IPPROTO_IPV6
447 {
448 const int on = 1;
449
450 if (AF_INET6 == desc->af)
451 if (setsockopt (desc->fd,
452 IPPROTO_IPV6,
453 IPV6_V6ONLY,
454 (const void *) &on,
455 sizeof(on)))
456 LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
457 "setsockopt");
458 }
459#endif
460#endif
461 if (AF_UNIX == address->sa_family)
462 GNUNET_NETWORK_unix_precheck ((const struct sockaddr_un *) address);
463
464 {
465 const int on = 1;
466
467 if ( (SOCK_STREAM == desc->type) &&
468 (0 != setsockopt (desc->fd,
469 SOL_SOCKET,
470 SO_REUSEADDR,
471 &on, sizeof(on))) )
472 LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
473 "setsockopt");
474 }
475 {
476 /* set permissions of newly created non-abstract UNIX domain socket to
477 "user-only"; applications can choose to relax this later */
478 mode_t old_mask = 0; /* assigned to make compiler happy */
479 const struct sockaddr_un *un = (const struct sockaddr_un *) address;
480 int not_abstract = 0;
481
482 if ((AF_UNIX == address->sa_family)
483 && ('\0' != un->sun_path[0])) /* Not an abstract socket */
484 not_abstract = 1;
485 if (not_abstract)
486 old_mask = umask (S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH
487 | S_IXOTH);
488
489 ret = bind (desc->fd,
490 address,
491 address_len);
492
493 if (not_abstract)
494 (void) umask (old_mask);
495 }
496 if (0 != ret)
497 return GNUNET_SYSERR;
498
499 desc->addr = GNUNET_malloc (address_len);
500 GNUNET_memcpy (desc->addr, address, address_len);
501 desc->addrlen = address_len;
502
503 return GNUNET_OK;
504}
505
506
507enum GNUNET_GenericReturnValue
508GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
509{
510 int ret;
511
512 ret = close (desc->fd);
513
514 const struct sockaddr_un *un = (const struct sockaddr_un *) desc->addr;
515
516 /* Cleanup the UNIX domain socket and its parent directories in case of non
517 abstract sockets */
518 if ((AF_UNIX == desc->af) &&
519 (NULL != desc->addr) &&
520 ('\0' != un->sun_path[0]))
521 {
522 char *dirname = GNUNET_strndup (un->sun_path,
523 sizeof(un->sun_path));
524
525 if (0 != unlink (dirname))
526 {
527 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
528 "unlink",
529 dirname);
530 }
531 else
532 {
533 size_t len;
534
535 len = strlen (dirname);
536 while ((len > 0) && (dirname[len] != DIR_SEPARATOR))
537 len--;
538 dirname[len] = '\0';
539 if ((0 != len) && (0 != rmdir (dirname)))
540 {
541 switch (errno)
542 {
543 case EACCES:
544 case ENOTEMPTY:
545 case EPERM:
546 /* these are normal and can just be ignored */
547 break;
548
549 default:
550 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
551 "rmdir",
552 dirname);
553 break;
554 }
555 }
556 }
557 GNUNET_free (dirname);
558 }
559 GNUNET_NETWORK_socket_free_memory_only_ (desc);
560 return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;
561}
562
563
564/**
565 * Only free memory of a socket, keep the file descriptor untouched.
566 *
567 * @param desc socket
568 */
569void
570GNUNET_NETWORK_socket_free_memory_only_ (struct GNUNET_NETWORK_Handle *desc)
571{
572 GNUNET_free (desc->addr);
573 GNUNET_free (desc);
574}
575
576
577/**
578 * Box a native socket (and check that it is a socket).
579 *
580 * @param fd socket to box
581 * @return NULL on error (including not supported on target platform)
582 */
583struct GNUNET_NETWORK_Handle *
584GNUNET_NETWORK_socket_box_native (int fd)
585{
586 struct GNUNET_NETWORK_Handle *ret;
587
588 if (fcntl (fd, F_GETFD) < 0)
589 return NULL; /* invalid FD */
590 ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
591 ret->fd = fd;
592 ret->af = AF_UNSPEC;
593 return ret;
594}
595
596
597/**
598 * Connect a socket to some remote address.
599 *
600 * @param desc socket
601 * @param address peer address
602 * @param address_len length of @a address
603 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
604 */
605int
606GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,
607 const struct sockaddr *address,
608 socklen_t address_len)
609{
610 int ret;
611
612 ret = connect (desc->fd,
613 address,
614 address_len);
615
616 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
617}
618
619
620/**
621 * Get socket options
622 *
623 * @param desc socket
624 * @param level protocol level of the option
625 * @param optname identifier of the option
626 * @param optval options
627 * @param optlen length of @a optval
628 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
629 */
630int
631GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,
632 int level,
633 int optname,
634 void *optval,
635 socklen_t *optlen)
636{
637 int ret;
638
639 ret = getsockopt (desc->fd,
640 level,
641 optname,
642 optval, optlen);
643
644 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
645}
646
647
648/**
649 * Listen on a socket
650 *
651 * @param desc socket
652 * @param backlog length of the listen queue
653 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
654 */
655int
656GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
657 int backlog)
658{
659 int ret;
660
661 ret = listen (desc->fd,
662 backlog);
663
664 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
665}
666
667
668/**
669 * How much data is available to be read on this descriptor?
670 *
671 * @param desc socket
672 * @returns #GNUNET_SYSERR if no data is available, or on error!
673 */
674ssize_t
675GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle *desc)
676{
677 int error;
678
679 /* How much is there to be read? */
680 int pending;
681
682 error = ioctl (desc->fd,
683 FIONREAD,
684 &pending);
685 if (0 == error)
686 return (ssize_t) pending;
687 return GNUNET_SYSERR;
688}
689
690
691/**
692 * Read data from a socket (always non-blocking).
693 *
694 * @param desc socket
695 * @param buffer buffer
696 * @param length length of @a buffer
697 * @param src_addr either the source to recv from, or all zeroes
698 * to be filled in by recvfrom
699 * @param addrlen length of the @a src_addr
700 */
701ssize_t
702GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle *desc,
703 void *buffer,
704 size_t length,
705 struct sockaddr *src_addr,
706 socklen_t *addrlen)
707{
708 int flags = 0;
709
710#ifdef MSG_DONTWAIT
711 flags |= MSG_DONTWAIT;
712#endif
713 return recvfrom (desc->fd,
714 buffer,
715 length,
716 flags,
717 src_addr,
718 addrlen);
719}
720
721
722/**
723 * Read data from a connected socket (always non-blocking).
724 *
725 * @param desc socket
726 * @param buffer buffer
727 * @param length length of @a buffer
728 * @return number of bytes received, -1 on error
729 */
730ssize_t
731GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle *desc,
732 void *buffer,
733 size_t length)
734{
735 int ret;
736 int flags;
737
738 flags = 0;
739
740#ifdef MSG_DONTWAIT
741 flags |= MSG_DONTWAIT;
742#endif
743 ret = recv (desc->fd,
744 buffer,
745 length,
746 flags);
747 return ret;
748}
749
750
751/**
752 * Send data (always non-blocking).
753 *
754 * @param desc socket
755 * @param buffer data to send
756 * @param length size of the @a buffer
757 * @return number of bytes sent, #GNUNET_SYSERR on error
758 */
759ssize_t
760GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle *desc,
761 const void *buffer,
762 size_t length)
763{
764 int ret;
765 int flags;
766
767 flags = 0;
768#ifdef MSG_DONTWAIT
769 flags |= MSG_DONTWAIT;
770#endif
771#ifdef MSG_NOSIGNAL
772 flags |= MSG_NOSIGNAL;
773#endif
774 ret = send (desc->fd,
775 buffer,
776 length,
777 flags);
778 return ret;
779}
780
781
782/**
783 * Send data to a particular destination (always non-blocking).
784 * This function only works for UDP sockets.
785 *
786 * @param desc socket
787 * @param message data to send
788 * @param length size of the @a message
789 * @param dest_addr destination address
790 * @param dest_len length of @a address
791 * @return number of bytes sent, #GNUNET_SYSERR on error
792 */
793ssize_t
794GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle *desc,
795 const void *message,
796 size_t length,
797 const struct sockaddr *dest_addr,
798 socklen_t dest_len)
799{
800 int flags = 0;
801
802#ifdef MSG_DONTWAIT
803 flags |= MSG_DONTWAIT;
804#endif
805#ifdef MSG_NOSIGNAL
806 flags |= MSG_NOSIGNAL;
807#endif
808 return sendto (desc->fd,
809 message,
810 length,
811 flags,
812 dest_addr,
813 dest_len);
814}
815
816
817/**
818 * Set socket option
819 *
820 * @param fd socket
821 * @param level protocol level of the option
822 * @param option_name option identifier
823 * @param option_value value to set
824 * @param option_len size of @a option_value
825 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
826 */
827int
828GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd,
829 int level,
830 int option_name,
831 const void *option_value,
832 socklen_t option_len)
833{
834 return (0 == setsockopt (fd->fd,
835 level,
836 option_name,
837 option_value,
838 option_len))
839 ? GNUNET_OK
840 : GNUNET_SYSERR;
841}
842
843
844/**
845 * Create a new socket. Configure it for non-blocking IO and
846 * mark it as non-inheritable to child processes (set the
847 * close-on-exec flag).
848 *
849 * @param domain domain of the socket
850 * @param type socket type
851 * @param protocol network protocol
852 * @return new socket, NULL on error
853 */
854struct GNUNET_NETWORK_Handle *
855GNUNET_NETWORK_socket_create (int domain,
856 int type,
857 int protocol)
858{
859 struct GNUNET_NETWORK_Handle *ret;
860 int fd;
861
862 fd = socket (domain, type, protocol);
863 if (-1 == fd)
864 return NULL;
865 ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
866 ret->fd = fd;
867 if (GNUNET_OK !=
868 initialize_network_handle (ret,
869 domain,
870 type))
871 return NULL;
872 return ret;
873}
874
875
876/**
877 * Shut down socket operations
878 * @param desc socket
879 * @param how type of shutdown
880 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
881 */
882int
883GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc,
884 int how)
885{
886 int ret;
887
888 ret = shutdown (desc->fd, how);
889
890 return (0 == ret) ? GNUNET_OK : GNUNET_SYSERR;
891}
892
893
894/**
895 * Disable the "CORK" feature for communication with the given socket,
896 * forcing the OS to immediately flush the buffer on transmission
897 * instead of potentially buffering multiple messages. Essentially
898 * reduces the OS send buffers to zero.
899 *
900 * @param desc socket
901 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
902 */
903int
904GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc)
905{
906 int ret = 0;
907
908#ifdef __linux__
909 int value = 0;
910
911 if (0 !=
912 (ret =
913 setsockopt (desc->fd,
914 SOL_SOCKET,
915 SO_SNDBUF,
916 &value,
917 sizeof(value))))
918 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
919 "setsockopt");
920 if (0 !=
921 (ret =
922 setsockopt (desc->fd,
923 SOL_SOCKET,
924 SO_RCVBUF,
925 &value,
926 sizeof(value))))
927 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
928 "setsockopt");
929#endif
930 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
931}
932
933
934/**
935 * Reset FD set
936 *
937 * @param fds fd set
938 */
939void
940GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
941{
942 FD_ZERO (&fds->sds);
943 fds->nsds = 0;
944}
945
946
947/**
948 * Add a socket to the FD set
949 *
950 * @param fds fd set
951 * @param desc socket to add
952 */
953void
954GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,
955 const struct GNUNET_NETWORK_Handle *desc)
956{
957 FD_SET (desc->fd,
958 &fds->sds);
959 fds->nsds = GNUNET_MAX (fds->nsds,
960 desc->fd + 1);
961}
962
963
964/**
965 * Check whether a socket is part of the fd set
966 *
967 * @param fds fd set
968 * @param desc socket
969 * @return 0 if the FD is not set
970 */
971int
972GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,
973 const struct GNUNET_NETWORK_Handle *desc)
974{
975 return FD_ISSET (desc->fd,
976 &fds->sds);
977}
978
979
980/**
981 * Add one fd set to another
982 *
983 * @param dst the fd set to add to
984 * @param src the fd set to add from
985 */
986void
987GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
988 const struct GNUNET_NETWORK_FDSet *src)
989{
990 int nfds;
991
992 for (nfds = src->nsds; nfds >= 0; nfds--)
993 if (FD_ISSET (nfds, &src->sds))
994 FD_SET (nfds, &dst->sds);
995 dst->nsds = GNUNET_MAX (dst->nsds,
996 src->nsds);
997}
998
999
1000/**
1001 * Copy one fd set to another
1002 *
1003 * @param to destination
1004 * @param from source
1005 */
1006void
1007GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
1008 const struct GNUNET_NETWORK_FDSet *from)
1009{
1010 FD_COPY (&from->sds,
1011 &to->sds);
1012 to->nsds = from->nsds;
1013}
1014
1015
1016/**
1017 * Return file descriptor for this network handle
1018 *
1019 * @param desc wrapper to process
1020 * @return POSIX file descriptor
1021 */
1022int
1023GNUNET_NETWORK_get_fd (const struct GNUNET_NETWORK_Handle *desc)
1024{
1025 return desc->fd;
1026}
1027
1028
1029/**
1030 * Return sockaddr for this network handle
1031 *
1032 * @param desc wrapper to process
1033 * @return sockaddr
1034 */
1035struct sockaddr*
1036GNUNET_NETWORK_get_addr (const struct GNUNET_NETWORK_Handle *desc)
1037{
1038 return desc->addr;
1039}
1040
1041
1042/**
1043 * Return sockaddr length for this network handle
1044 *
1045 * @param desc wrapper to process
1046 * @return socklen_t for sockaddr
1047 */
1048socklen_t
1049GNUNET_NETWORK_get_addrlen (const struct GNUNET_NETWORK_Handle *desc)
1050{
1051 return desc->addrlen;
1052}
1053
1054
1055/**
1056 * Copy a native fd set
1057 *
1058 * @param to destination
1059 * @param from native source set
1060 * @param nfds the biggest socket number in from + 1
1061 */
1062void
1063GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
1064 const fd_set *from,
1065 int nfds)
1066{
1067 FD_COPY (from,
1068 &to->sds);
1069 to->nsds = nfds;
1070}
1071
1072
1073/**
1074 * Set a native fd in a set
1075 *
1076 * @param to destination
1077 * @param nfd native FD to set
1078 */
1079void
1080GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to,
1081 int nfd)
1082{
1083 GNUNET_assert ((nfd >= 0) && (nfd < FD_SETSIZE));
1084 FD_SET (nfd, &to->sds);
1085 to->nsds = GNUNET_MAX (nfd + 1,
1086 to->nsds);
1087}
1088
1089
1090/**
1091 * Test native fd in a set
1092 *
1093 * @param to set to test, NULL for empty set
1094 * @param nfd native FD to test, or -1 for none
1095 * @return #GNUNET_YES if FD is set in the set
1096 */
1097int
1098GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to,
1099 int nfd)
1100{
1101 if ((-1 == nfd) ||
1102 (NULL == to))
1103 return GNUNET_NO;
1104 return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO;
1105}
1106
1107
1108/**
1109 * Add a file handle to the fd set
1110 * @param fds fd set
1111 * @param h the file handle to add
1112 */
1113void
1114GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
1115 const struct GNUNET_DISK_FileHandle *h)
1116{
1117 int fd;
1118
1119 GNUNET_assert (GNUNET_OK ==
1120 GNUNET_DISK_internal_file_handle_ (h,
1121 &fd,
1122 sizeof(int)));
1123 FD_SET (fd,
1124 &fds->sds);
1125 fds->nsds = GNUNET_MAX (fd + 1,
1126 fds->nsds);
1127}
1128
1129
1130/**
1131 * Add a file handle to the fd set
1132 * @param fds fd set
1133 * @param h the file handle to add
1134 */
1135void
1136GNUNET_NETWORK_fdset_handle_set_first (struct GNUNET_NETWORK_FDSet *fds,
1137 const struct GNUNET_DISK_FileHandle *h)
1138{
1139 GNUNET_NETWORK_fdset_handle_set (fds, h);
1140}
1141
1142
1143/**
1144 * Check if a file handle is part of an fd set
1145 *
1146 * @param fds fd set
1147 * @param h file handle
1148 * @return #GNUNET_YES if the file handle is part of the set
1149 */
1150int
1151GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
1152 const struct GNUNET_DISK_FileHandle *h)
1153{
1154 return FD_ISSET (h->fd,
1155 &fds->sds);
1156}
1157
1158
1159/**
1160 * Checks if two fd sets overlap
1161 *
1162 * @param fds1 first fd set
1163 * @param fds2 second fd set
1164 * @return #GNUNET_YES if they do overlap, #GNUNET_NO otherwise
1165 */
1166int
1167GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
1168 const struct GNUNET_NETWORK_FDSet *fds2)
1169{
1170 int nfds;
1171
1172 nfds = GNUNET_MIN (fds1->nsds,
1173 fds2->nsds);
1174 while (nfds > 0)
1175 {
1176 nfds--;
1177 if ((FD_ISSET (nfds,
1178 &fds1->sds)) &&
1179 (FD_ISSET (nfds,
1180 &fds2->sds)))
1181 return GNUNET_YES;
1182 }
1183 return GNUNET_NO;
1184}
1185
1186
1187/**
1188 * Creates an fd set
1189 *
1190 * @return a new fd set
1191 */
1192struct GNUNET_NETWORK_FDSet *
1193GNUNET_NETWORK_fdset_create ()
1194{
1195 struct GNUNET_NETWORK_FDSet *fds;
1196
1197 fds = GNUNET_new (struct GNUNET_NETWORK_FDSet);
1198 GNUNET_NETWORK_fdset_zero (fds);
1199 return fds;
1200}
1201
1202
1203/**
1204 * Releases the associated memory of an fd set
1205 *
1206 * @param fds fd set
1207 */
1208void
1209GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
1210{
1211 GNUNET_free (fds);
1212}
1213
1214
1215/**
1216 * Test if the given @a port is available.
1217 *
1218 * @param ipproto transport protocol to test (e.g. IPPROTO_TCP)
1219 * @param port port number to test
1220 * @return #GNUNET_OK if the port is available, #GNUNET_NO if not
1221 */
1222int
1223GNUNET_NETWORK_test_port_free (int ipproto,
1224 uint16_t port)
1225{
1226 struct GNUNET_NETWORK_Handle *socket;
1227 int bind_status;
1228 int socktype;
1229 char open_port_str[6];
1230 struct addrinfo hint;
1231 struct addrinfo *ret;
1232 struct addrinfo *ai;
1233
1234 GNUNET_snprintf (open_port_str,
1235 sizeof(open_port_str),
1236 "%u",
1237 (unsigned int) port);
1238 socktype = (IPPROTO_TCP == ipproto) ? SOCK_STREAM : SOCK_DGRAM;
1239 ret = NULL;
1240 memset (&hint, 0, sizeof(hint));
1241 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
1242 hint.ai_socktype = socktype;
1243 hint.ai_protocol = ipproto;
1244 hint.ai_addrlen = 0;
1245 hint.ai_addr = NULL;
1246 hint.ai_canonname = NULL;
1247 hint.ai_next = NULL;
1248 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
1249 GNUNET_assert (0 == getaddrinfo (NULL,
1250 open_port_str,
1251 &hint,
1252 &ret));
1253 bind_status = GNUNET_NO;
1254 for (ai = ret; NULL != ai; ai = ai->ai_next)
1255 {
1256 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
1257 ai->ai_socktype,
1258 ai->ai_protocol);
1259 if (NULL == socket)
1260 continue;
1261 bind_status = GNUNET_NETWORK_socket_bind (socket,
1262 ai->ai_addr,
1263 ai->ai_addrlen);
1264 GNUNET_NETWORK_socket_close (socket);
1265 if (GNUNET_OK != bind_status)
1266 break;
1267 }
1268 freeaddrinfo (ret);
1269 return bind_status;
1270}
1271
1272
1273/**
1274 * Check if sockets or pipes meet certain conditions
1275 *
1276 * @param rfds set of sockets or pipes to be checked for readability
1277 * @param wfds set of sockets or pipes to be checked for writability
1278 * @param efds set of sockets or pipes to be checked for exceptions
1279 * @param timeout relative value when to return
1280 * @return number of selected sockets or pipes, #GNUNET_SYSERR on error
1281 */
1282int
1283GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1284 struct GNUNET_NETWORK_FDSet *wfds,
1285 struct GNUNET_NETWORK_FDSet *efds,
1286 const struct GNUNET_TIME_Relative timeout)
1287{
1288 int nfds;
1289 struct timeval tv;
1290
1291 if (NULL != rfds)
1292 nfds = rfds->nsds;
1293 else
1294 nfds = 0;
1295 if (NULL != wfds)
1296 nfds = GNUNET_MAX (nfds,
1297 wfds->nsds);
1298 if (NULL != efds)
1299 nfds = GNUNET_MAX (nfds,
1300 efds->nsds);
1301 if ((0 == nfds) &&
1302 (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us))
1303 {
1304 GNUNET_break (0);
1305 LOG (GNUNET_ERROR_TYPE_ERROR,
1306 _ (
1307 "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),
1308 "select");
1309 }
1310 if (timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us > (unsigned
1311 long long)
1312 LONG_MAX)
1313 {
1314 tv.tv_sec = LONG_MAX;
1315 tv.tv_usec = 999999L;
1316 }
1317 else
1318 {
1319 tv.tv_sec = (long) (timeout.rel_value_us
1320 / GNUNET_TIME_UNIT_SECONDS.rel_value_us);
1321 tv.tv_usec =
1322 (timeout.rel_value_us
1323 - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value_us));
1324 }
1325 return select (nfds,
1326 (NULL != rfds) ? &rfds->sds : NULL,
1327 (NULL != wfds) ? &wfds->sds : NULL,
1328 (NULL != efds) ? &efds->sds : NULL,
1329 (timeout.rel_value_us ==
1330 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) ? NULL : &tv);
1331}
1332
1333
1334/* 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 1835c6e84..000000000
--- a/src/util/os_installation.c
+++ /dev/null
@@ -1,833 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006-2018, 2022 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 * PD for which gettext has been initialized last.
84 * Note that the gettext initialization done within
85 * GNUNET_PROGRAM_run2 is for the specific application.
86 */
87static const struct GNUNET_OS_ProjectData *gettextinit;
88
89
90/**
91 * Return default project data used by 'libgnunetutil' for GNUnet.
92 */
93const struct GNUNET_OS_ProjectData *
94GNUNET_OS_project_data_default (void)
95{
96 return &default_pd;
97}
98
99
100/**
101 * @return current project data.
102 */
103const struct GNUNET_OS_ProjectData *
104GNUNET_OS_project_data_get ()
105{
106 if (current_pd != gettextinit)
107 {
108 char *path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
109
110 if (NULL != path)
111 bindtextdomain (PACKAGE,
112 path);
113 GNUNET_free (path);
114 gettextinit = current_pd;
115 }
116 return current_pd;
117}
118
119
120/**
121 * Setup OS subsystem with project data.
122 *
123 * @param pd project data used to determine paths
124 */
125void
126GNUNET_OS_init (const struct GNUNET_OS_ProjectData *pd)
127{
128 GNUNET_assert (NULL != pd);
129 current_pd = pd;
130 if (pd != gettextinit)
131 {
132 char *path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
133
134 if (NULL != path)
135 bindtextdomain (PACKAGE,
136 path);
137 GNUNET_free (path);
138 gettextinit = pd;
139 }
140}
141
142
143#ifdef __linux__
144/**
145 * Try to determine path by reading /proc/PID/exe
146 *
147 * @return NULL on error
148 */
149static char *
150get_path_from_proc_maps (void)
151{
152 char fn[64];
153 char line[1024];
154 char dir[1024];
155 FILE *f;
156 char *lgu;
157
158 if (NULL == current_pd->libname)
159 return NULL;
160 GNUNET_snprintf (fn,
161 sizeof(fn),
162 "/proc/%u/maps",
163 getpid ());
164 if (NULL == (f = fopen (fn, "r")))
165 return NULL;
166 while (NULL != fgets (line, sizeof(line), f))
167 {
168 if ((1 == sscanf (line,
169 "%*p-%*p %*c%*c%*c%*c %*x %*x:%*x %*u%*[ ]%1023s",
170 dir)) &&
171 (NULL != (lgu = strstr (dir,
172 current_pd->libname))))
173 {
174 lgu[0] = '\0';
175 fclose (f);
176 return GNUNET_strdup (dir);
177 }
178 }
179 fclose (f);
180 return NULL;
181}
182
183
184/**
185 * Try to determine path by reading /proc/PID/exe
186 *
187 * @return NULL on error
188 */
189static char *
190get_path_from_proc_exe (void)
191{
192 char fn[64];
193 char lnk[1024];
194 ssize_t size;
195 char *lep;
196
197 GNUNET_snprintf (fn, sizeof(fn), "/proc/%u/exe", getpid ());
198 size = readlink (fn, lnk, sizeof(lnk) - 1);
199 if (size <= 0)
200 {
201 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
202 return NULL;
203 }
204 GNUNET_assert (((size_t) size) < sizeof(lnk));
205 lnk[size] = '\0';
206 while ((lnk[size] != '/') && (size > 0))
207 size--;
208 GNUNET_asprintf (&lep, "/%s/libexec/", current_pd->project_dirname);
209 /* test for being in lib/gnunet/libexec/ or lib/MULTIARCH/gnunet/libexec */
210 if ((((size_t) size) > strlen (lep)) &&
211 (0 == strcmp (lep, &lnk[size - strlen (lep)])))
212 size -= strlen (lep) - 1;
213 GNUNET_free (lep);
214 if ((size < 4) || (lnk[size - 4] != '/'))
215 {
216 /* not installed in "/bin/" -- binary path probably useless */
217 return NULL;
218 }
219 lnk[size] = '\0';
220 return GNUNET_strdup (lnk);
221}
222
223
224#endif
225
226
227#if DARWIN
228/**
229 * Signature of the '_NSGetExecutablePath" function.
230 *
231 * @param buf where to write the path
232 * @param number of bytes available in @a buf
233 * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
234 */
235typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t *bufsize);
236
237
238/**
239 * Try to obtain the path of our executable using '_NSGetExecutablePath'.
240 *
241 * @return NULL on error
242 */
243static char *
244get_path_from_NSGetExecutablePath (void)
245{
246 static char zero = '\0';
247 char *path;
248 size_t len;
249 MyNSGetExecutablePathProto func;
250
251 path = NULL;
252 if (NULL ==
253 (func = (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT,
254 "_NSGetExecutablePath")))
255 return NULL;
256 path = &zero;
257 len = 0;
258 /* get the path len, including the trailing \0 */
259 (void) func (path, &len);
260 if (0 == len)
261 return NULL;
262 path = GNUNET_malloc (len);
263 if (0 != func (path, &len))
264 {
265 GNUNET_free (path);
266 return NULL;
267 }
268 len = strlen (path);
269 while ((path[len] != '/') && (len > 0))
270 len--;
271 path[len] = '\0';
272 return path;
273}
274
275
276/**
277 * Try to obtain the path of our executable using '_dyld_image' API.
278 *
279 * @return NULL on error
280 */
281static char *
282get_path_from_dyld_image (void)
283{
284 const char *path;
285 char *p;
286 char *s;
287 unsigned int i;
288 int c;
289
290 c = _dyld_image_count ();
291 for (i = 0; i < c; i++)
292 {
293 if (((const void *) _dyld_get_image_header (i)) !=
294 ((const void *) &_mh_dylib_header))
295 continue;
296 path = _dyld_get_image_name (i);
297 if ((NULL == path) || (0 == strlen (path)))
298 continue;
299 p = GNUNET_strdup (path);
300 s = p + strlen (p);
301 while ((s > p) && ('/' != *s))
302 s--;
303 s++;
304 *s = '\0';
305 return p;
306 }
307 return NULL;
308}
309
310
311#endif
312
313
314/**
315 * Return the actual path to a file found in the current
316 * PATH environment variable.
317 *
318 * @param binary the name of the file to find
319 * @return path to binary, NULL if not found
320 */
321static char *
322get_path_from_PATH (const char *binary)
323{
324 char *path;
325 char *pos;
326 char *end;
327 char *buf;
328 const char *p;
329
330 if (NULL == (p = getenv ("PATH")))
331 return NULL;
332
333 path = GNUNET_strdup (p); /* because we write on it */
334
335 buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
336 pos = path;
337 while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
338 {
339 *end = '\0';
340 sprintf (buf, "%s/%s", pos, binary);
341 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
342 {
343 pos = GNUNET_strdup (pos);
344 GNUNET_free (buf);
345 GNUNET_free (path);
346 return pos;
347 }
348 pos = end + 1;
349 }
350 sprintf (buf, "%s/%s", pos, binary);
351 if (GNUNET_YES == GNUNET_DISK_file_test (buf))
352 {
353 pos = GNUNET_strdup (pos);
354 GNUNET_free (buf);
355 GNUNET_free (path);
356 return pos;
357 }
358 GNUNET_free (buf);
359 GNUNET_free (path);
360 return NULL;
361}
362
363
364/**
365 * Try to obtain the installation path using the "GNUNET_PREFIX" environment
366 * variable.
367 *
368 * @return NULL on error (environment variable not set)
369 */
370static char *
371get_path_from_GNUNET_PREFIX (void)
372{
373 const char *p;
374
375 if ((NULL != current_pd->env_varname) &&
376 (NULL != (p = getenv (current_pd->env_varname))))
377 return GNUNET_strdup (p);
378 if ((NULL != current_pd->env_varname_alt) &&
379 (NULL != (p = getenv (current_pd->env_varname_alt))))
380 return GNUNET_strdup (p);
381 return NULL;
382}
383
384
385/**
386 * @brief get the path to GNUnet bin/ or lib/, preferring the lib/ path
387 * @author Milan
388 *
389 * @return a pointer to the executable path, or NULL on error
390 */
391static char *
392os_get_gnunet_path (void)
393{
394 char *ret;
395
396 if (NULL != (ret = get_path_from_GNUNET_PREFIX ()))
397 return ret;
398#ifdef __linux__
399 if (NULL != (ret = get_path_from_proc_maps ()))
400 return ret;
401 /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
402 if ((NULL != current_pd->binary_name) &&
403 (NULL != (ret = get_path_from_PATH (current_pd->binary_name))))
404 return ret;
405 if (NULL != (ret = get_path_from_proc_exe ()))
406 return ret;
407#endif
408#if DARWIN
409 if (NULL != (ret = get_path_from_dyld_image ()))
410 return ret;
411 if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
412 return ret;
413#endif
414 if ((NULL != current_pd->binary_name) &&
415 (NULL != (ret = get_path_from_PATH (current_pd->binary_name))))
416 return ret;
417 /* other attempts here */
418 LOG (GNUNET_ERROR_TYPE_ERROR,
419 _ (
420 "Could not determine installation path for %s. Set `%s' environment variable.\n"),
421 current_pd->project_dirname,
422 current_pd->env_varname);
423 return NULL;
424}
425
426
427/**
428 * @brief get the path to current app's bin/
429 * @return a pointer to the executable path, or NULL on error
430 */
431static char *
432os_get_exec_path ()
433{
434 char *ret = NULL;
435
436#ifdef __linux__
437 if (NULL != (ret = get_path_from_proc_exe ()))
438 return ret;
439#endif
440#if DARWIN
441 if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
442 return ret;
443#endif
444 /* other attempts here */
445 return ret;
446}
447
448
449/**
450 * @brief get the path to a specific GNUnet installation directory or,
451 * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory
452 * @return a pointer to the dir path (to be freed by the caller)
453 */
454char *
455GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
456{
457 size_t n;
458 char *dirname;
459 char *execpath = NULL;
460 char *tmp;
461 char *multiarch;
462 char *libdir;
463 int isbasedir;
464
465 /* if wanted, try to get the current app's bin/ */
466 if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
467 execpath = os_get_exec_path ();
468
469 /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
470 * guess for the current app */
471 if (NULL == execpath)
472 execpath = os_get_gnunet_path ();
473 if (NULL == execpath)
474 return NULL;
475
476 n = strlen (execpath);
477 if (0 == n)
478 {
479 /* should never happen, but better safe than sorry */
480 GNUNET_free (execpath);
481 return NULL;
482 }
483 /* remove filename itself */
484 while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
485 execpath[--n] = '\0';
486
487 isbasedir = 1;
488 if ((n > 6) && ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
489 (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
490 {
491 if ((GNUNET_OS_IPK_LIBDIR != dirkind) &&
492 (GNUNET_OS_IPK_LIBEXECDIR != dirkind))
493 {
494 /* strip '/lib32' or '/lib64' */
495 execpath[n - 6] = '\0';
496 n -= 6;
497 }
498 else
499 isbasedir = 0;
500 }
501 else if ((n > 4) && ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
502 (0 == strcasecmp (&execpath[n - 4], "/lib"))))
503 {
504 /* strip '/bin' or '/lib' */
505 execpath[n - 4] = '\0';
506 n -= 4;
507 }
508 multiarch = NULL;
509 if (NULL != (libdir = strstr (execpath, "/lib/")))
510 {
511 /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
512 here we need to re-add 'multiarch' to lib and libexec paths later! */
513 multiarch = &libdir[5];
514 if (NULL == strchr (multiarch, '/'))
515 libdir[0] =
516 '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
517 else
518 multiarch =
519 NULL; /* maybe not, multiarch still has a '/', which is not OK */
520 }
521 /* in case this was a directory named foo-bin, remove "foo-" */
522 while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
523 execpath[--n] = '\0';
524 switch (dirkind)
525 {
526 case GNUNET_OS_IPK_PREFIX:
527 case GNUNET_OS_IPK_SELF_PREFIX:
528 dirname = GNUNET_strdup (DIR_SEPARATOR_STR);
529 break;
530
531 case GNUNET_OS_IPK_BINDIR:
532 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR);
533 break;
534
535 case GNUNET_OS_IPK_LIBDIR:
536 if (isbasedir)
537 {
538 GNUNET_asprintf (&tmp,
539 "%s%s%s%s%s%s%s",
540 execpath,
541 DIR_SEPARATOR_STR "lib",
542 (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
543 (NULL != multiarch) ? multiarch : "",
544 DIR_SEPARATOR_STR,
545 current_pd->project_dirname,
546 DIR_SEPARATOR_STR);
547 if (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES))
548 {
549 GNUNET_free (execpath);
550 return tmp;
551 }
552 GNUNET_free (tmp);
553 tmp = NULL;
554 dirname = NULL;
555 if (4 == sizeof(void *))
556 {
557 GNUNET_asprintf (&dirname,
558 DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR
559 "%s" DIR_SEPARATOR_STR,
560 current_pd->project_dirname);
561 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
562 }
563 if (8 == sizeof(void *))
564 {
565 GNUNET_asprintf (&dirname,
566 DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR
567 "%s" DIR_SEPARATOR_STR,
568 current_pd->project_dirname);
569 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
570 }
571
572 if ((NULL != tmp) &&
573 (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES)))
574 {
575 GNUNET_free (execpath);
576 GNUNET_free (dirname);
577 return tmp;
578 }
579 GNUNET_free (tmp);
580 GNUNET_free (dirname);
581 }
582 GNUNET_asprintf (&dirname,
583 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR,
584 current_pd->project_dirname);
585 break;
586
587 case GNUNET_OS_IPK_DATADIR:
588 GNUNET_asprintf (&dirname,
589 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
590 "%s" DIR_SEPARATOR_STR,
591 current_pd->project_dirname);
592 break;
593
594 case GNUNET_OS_IPK_LOCALEDIR:
595 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
596 "locale" DIR_SEPARATOR_STR);
597 break;
598
599 case GNUNET_OS_IPK_ICONDIR:
600 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
601 "icons" DIR_SEPARATOR_STR);
602 break;
603
604 case GNUNET_OS_IPK_DOCDIR:
605 GNUNET_asprintf (&dirname,
606 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
607 "doc" DIR_SEPARATOR_STR
608 "%s" DIR_SEPARATOR_STR,
609 current_pd->project_dirname);
610 break;
611
612 case GNUNET_OS_IPK_LIBEXECDIR:
613 if (isbasedir)
614 {
615 GNUNET_asprintf (&dirname,
616 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR
617 "libexec" DIR_SEPARATOR_STR,
618 current_pd->project_dirname);
619 GNUNET_asprintf (&tmp,
620 "%s%s%s%s",
621 execpath,
622 DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
623 (NULL != multiarch) ? multiarch : "",
624 dirname);
625 GNUNET_free (dirname);
626 if (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES))
627 {
628 GNUNET_free (execpath);
629 return tmp;
630 }
631 GNUNET_free (tmp);
632 tmp = NULL;
633 dirname = NULL;
634 if (4 == sizeof(void *))
635 {
636 GNUNET_asprintf (&dirname,
637 DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR
638 "%s" DIR_SEPARATOR_STR
639 "libexec" DIR_SEPARATOR_STR,
640 current_pd->project_dirname);
641 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
642 }
643 if (8 == sizeof(void *))
644 {
645 GNUNET_asprintf (&dirname,
646 DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR
647 "%s" DIR_SEPARATOR_STR
648 "libexec" DIR_SEPARATOR_STR,
649 current_pd->project_dirname);
650 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
651 }
652 if ((NULL != tmp) &&
653 (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES)))
654 {
655 GNUNET_free (execpath);
656 GNUNET_free (dirname);
657 return tmp;
658 }
659 GNUNET_free (tmp);
660 GNUNET_free (dirname);
661 }
662 GNUNET_asprintf (&dirname,
663 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR
664 "libexec" DIR_SEPARATOR_STR,
665 current_pd->project_dirname);
666 break;
667
668 default:
669 GNUNET_free (execpath);
670 return NULL;
671 }
672 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
673 GNUNET_free (dirname);
674 GNUNET_free (execpath);
675 return tmp;
676}
677
678
679/**
680 * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon
681 * binary, try to prefix it with the libexec/-directory to get the
682 * full path.
683 *
684 * @param progname name of the binary
685 * @return full path to the binary, if possible, otherwise copy of 'progname'
686 */
687char *
688GNUNET_OS_get_libexec_binary_path (const char *progname)
689{
690 static char *cache;
691 char *libexecdir;
692 char *binary;
693
694 if ((DIR_SEPARATOR == progname[0]) ||
695 (GNUNET_YES ==
696 GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)))
697 return GNUNET_strdup (progname);
698 if (NULL != cache)
699 libexecdir = cache;
700 else
701 libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
702 if (NULL == libexecdir)
703 return GNUNET_strdup (progname);
704 GNUNET_asprintf (&binary, "%s%s", libexecdir, progname);
705 cache = libexecdir;
706 return binary;
707}
708
709
710/**
711 * Given the name of a helper, service or daemon binary construct the full
712 * path to the binary using the SUID_BINARY_PATH in the PATHS section of the
713 * configuration. If that option is not present, fall back to
714 * GNUNET_OS_get_libexec_binary_path. If @a progname is an absolute path, a
715 * copy of this path is returned.
716 *
717 * @param cfg configuration to inspect
718 * @param progname name of the binary
719 * @return full path to the binary, if possible, a copy of @a progname
720 * otherwise
721 */
722char *
723GNUNET_OS_get_suid_binary_path (const struct GNUNET_CONFIGURATION_Handle *cfg,
724 const char *progname)
725{
726 static char *cache;
727 char *binary = NULL;
728 char *path = NULL;
729 size_t path_len;
730
731 if (GNUNET_YES ==
732 GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL))
733 {
734 return GNUNET_strdup (progname);
735 }
736 if (NULL != cache)
737 path = cache;
738 else
739 GNUNET_CONFIGURATION_get_value_string (cfg,
740 "PATHS",
741 "SUID_BINARY_PATH",
742 &path);
743 if ((NULL == path) || (0 == strlen (path)))
744 {
745 if (NULL != path)
746 GNUNET_free (path);
747 cache = NULL;
748 return GNUNET_OS_get_libexec_binary_path (progname);
749 }
750 path_len = strlen (path);
751 GNUNET_asprintf (&binary,
752 "%s%s%s",
753 path,
754 (path[path_len - 1] == DIR_SEPARATOR) ? ""
755 : DIR_SEPARATOR_STR,
756 progname);
757 cache = path;
758 return binary;
759}
760
761
762enum GNUNET_GenericReturnValue
763GNUNET_OS_check_helper_binary (const char *binary,
764 bool check_suid,
765 const char *params)
766{
767 struct stat statbuf;
768 char *p;
769 char *pf;
770
771 if ((GNUNET_YES ==
772 GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO, NULL, NULL)) ||
773 (0 == strncmp (binary, "./", 2)))
774 {
775 p = GNUNET_strdup (binary);
776 }
777 else
778 {
779 p = get_path_from_PATH (binary);
780 if (NULL != p)
781 {
782 GNUNET_asprintf (&pf, "%s/%s", p, binary);
783 GNUNET_free (p);
784 p = pf;
785 }
786 }
787
788 if (NULL == p)
789 {
790 LOG (GNUNET_ERROR_TYPE_INFO,
791 _ ("Could not find binary `%s' in PATH!\n"),
792 binary);
793 return GNUNET_SYSERR;
794 }
795 if (0 != access (p, X_OK))
796 {
797 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p);
798 GNUNET_free (p);
799 return GNUNET_SYSERR;
800 }
801
802 if (0 == getuid ())
803 {
804 /* as we run as root, we don't insist on SUID */
805 GNUNET_free (p);
806 return GNUNET_YES;
807 }
808
809 if (0 != stat (p, &statbuf))
810 {
811 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p);
812 GNUNET_free (p);
813 return GNUNET_SYSERR;
814 }
815 if (check_suid)
816 {
817 (void) params;
818 if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
819 {
820 GNUNET_free (p);
821 return GNUNET_YES;
822 }
823 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
824 _ ("Binary `%s' exists, but is not SUID\n"),
825 p);
826 /* binary exists, but not SUID */
827 }
828 GNUNET_free (p);
829 return GNUNET_NO;
830}
831
832
833/* 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 843b4734c..000000000
--- a/src/util/os_priority.c
+++ /dev/null
@@ -1,1190 +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 enum GNUNET_GenericReturnValue
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,
888 &status,
889 options);
890 if (ret < 0)
891 {
892 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
893 "waitpid");
894 return GNUNET_SYSERR;
895 }
896 if (0 == ret)
897 {
898 *type = GNUNET_OS_PROCESS_RUNNING;
899 *code = 0;
900 return GNUNET_NO;
901 }
902 if (proc->pid != ret)
903 {
904 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
905 "waitpid");
906 return GNUNET_SYSERR;
907 }
908 if (WIFEXITED (status))
909 {
910 *type = GNUNET_OS_PROCESS_EXITED;
911 *code = WEXITSTATUS (status);
912 }
913 else if (WIFSIGNALED (status))
914 {
915 *type = GNUNET_OS_PROCESS_SIGNALED;
916 *code = WTERMSIG (status);
917 }
918 else if (WIFSTOPPED (status))
919 {
920 *type = GNUNET_OS_PROCESS_SIGNALED;
921 *code = WSTOPSIG (status);
922 }
923#ifdef WIFCONTINUED
924 else if (WIFCONTINUED (status))
925 {
926 *type = GNUNET_OS_PROCESS_RUNNING;
927 *code = 0;
928 }
929#endif
930 else
931 {
932 *type = GNUNET_OS_PROCESS_UNKNOWN;
933 *code = 0;
934 }
935
936 return GNUNET_OK;
937}
938
939
940/**
941 * Retrieve the status of a process.
942 * Nonblocking version.
943 *
944 * @param proc process ID
945 * @param type status type
946 * @param code return code/signal number
947 * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
948 */
949enum GNUNET_GenericReturnValue
950GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
951 enum GNUNET_OS_ProcessStatusType *type,
952 unsigned long *code)
953{
954 return process_status (proc, type, code, WNOHANG);
955}
956
957
958/**
959 * Retrieve the status of a process, waiting on it if dead.
960 * Blocking version.
961 *
962 * @param proc pointer to process structure
963 * @param type status type
964 * @param code return code/signal number
965 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
966 */
967enum GNUNET_GenericReturnValue
968GNUNET_OS_process_wait_status (struct GNUNET_OS_Process *proc,
969 enum GNUNET_OS_ProcessStatusType *type,
970 unsigned long *code)
971{
972 return process_status (proc, type, code, 0);
973}
974
975
976/**
977 * Wait for a process to terminate. The return code is discarded.
978 * You must not use #GNUNET_OS_process_status() on the same process
979 * after calling this function! This function is blocking and should
980 * thus only be used if the child process is known to have terminated
981 * or to terminate very soon.
982 *
983 * @param proc pointer to process structure
984 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
985 */
986int
987GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
988{
989 pid_t pid = proc->pid;
990 pid_t ret;
991
992 while ((pid != (ret = waitpid (pid, NULL, 0))) && (EINTR == errno))
993 ;
994 if (pid != ret)
995 {
996 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
997 return GNUNET_SYSERR;
998 }
999 return GNUNET_OK;
1000}
1001
1002
1003/**
1004 * Handle to a command.
1005 */
1006struct GNUNET_OS_CommandHandle
1007{
1008 /**
1009 * Process handle.
1010 */
1011 struct GNUNET_OS_Process *eip;
1012
1013 /**
1014 * Handle to the output pipe.
1015 */
1016 struct GNUNET_DISK_PipeHandle *opipe;
1017
1018 /**
1019 * Read-end of output pipe.
1020 */
1021 const struct GNUNET_DISK_FileHandle *r;
1022
1023 /**
1024 * Function to call on each line of output.
1025 */
1026 GNUNET_OS_LineProcessor proc;
1027
1028 /**
1029 * Closure for @e proc.
1030 */
1031 void *proc_cls;
1032
1033 /**
1034 * Buffer for the output.
1035 */
1036 char buf[1024];
1037
1038 /**
1039 * Task reading from pipe.
1040 */
1041 struct GNUNET_SCHEDULER_Task *rtask;
1042
1043 /**
1044 * When to time out.
1045 */
1046 struct GNUNET_TIME_Absolute timeout;
1047
1048 /**
1049 * Current read offset in buf.
1050 */
1051 size_t off;
1052};
1053
1054
1055/**
1056 * Stop/kill a command. Must ONLY be called either from
1057 * the callback after 'NULL' was passed for 'line' *OR*
1058 * from an independent task (not within the line processor).
1059 *
1060 * @param cmd handle to the process
1061 */
1062void
1063GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
1064{
1065 if (NULL != cmd->proc)
1066 {
1067 GNUNET_assert (NULL != cmd->rtask);
1068 GNUNET_SCHEDULER_cancel (cmd->rtask);
1069 }
1070 (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1071 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip));
1072 GNUNET_OS_process_destroy (cmd->eip);
1073 GNUNET_DISK_pipe_close (cmd->opipe);
1074 GNUNET_free (cmd);
1075}
1076
1077
1078/**
1079 * Read from the process and call the line processor.
1080 *
1081 * @param cls the `struct GNUNET_OS_CommandHandle *`
1082 */
1083static void
1084cmd_read (void *cls)
1085{
1086 struct GNUNET_OS_CommandHandle *cmd = cls;
1087 const struct GNUNET_SCHEDULER_TaskContext *tc;
1088 GNUNET_OS_LineProcessor proc;
1089 char *end;
1090 ssize_t ret;
1091
1092 cmd->rtask = NULL;
1093 tc = GNUNET_SCHEDULER_get_task_context ();
1094 if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
1095 {
1096 /* timeout */
1097 proc = cmd->proc;
1098 cmd->proc = NULL;
1099 proc (cmd->proc_cls, NULL);
1100 return;
1101 }
1102 ret = GNUNET_DISK_file_read (cmd->r,
1103 &cmd->buf[cmd->off],
1104 sizeof(cmd->buf) - cmd->off);
1105 if (ret <= 0)
1106 {
1107 if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1108 {
1109 cmd->buf[cmd->off] = '\0';
1110 cmd->proc (cmd->proc_cls, cmd->buf);
1111 }
1112 proc = cmd->proc;
1113 cmd->proc = NULL;
1114 proc (cmd->proc_cls, NULL);
1115 return;
1116 }
1117 end = memchr (&cmd->buf[cmd->off], '\n', ret);
1118 cmd->off += ret;
1119 while (NULL != end)
1120 {
1121 *end = '\0';
1122 cmd->proc (cmd->proc_cls, cmd->buf);
1123 memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1124 cmd->off -= (end + 1 - cmd->buf);
1125 end = memchr (cmd->buf, '\n', cmd->off);
1126 }
1127 cmd->rtask =
1128 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining (
1129 cmd->timeout),
1130 cmd->r,
1131 &cmd_read,
1132 cmd);
1133}
1134
1135
1136/**
1137 * Run the given command line and call the given function
1138 * for each line of the output.
1139 *
1140 * @param proc function to call for each line of the output
1141 * @param proc_cls closure for @a proc
1142 * @param timeout when to time out
1143 * @param binary command to run
1144 * @param ... arguments to command
1145 * @return NULL on error
1146 */
1147struct GNUNET_OS_CommandHandle *
1148GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc,
1149 void *proc_cls,
1150 struct GNUNET_TIME_Relative timeout,
1151 const char *binary,
1152 ...)
1153{
1154 struct GNUNET_OS_CommandHandle *cmd;
1155 struct GNUNET_OS_Process *eip;
1156 struct GNUNET_DISK_PipeHandle *opipe;
1157 va_list ap;
1158
1159 opipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
1160 if (NULL == opipe)
1161 return NULL;
1162 va_start (ap, binary);
1163 /* redirect stdout, don't inherit stderr/stdin */
1164 eip =
1165 GNUNET_OS_start_process_va (GNUNET_OS_INHERIT_STD_NONE,
1166 NULL,
1167 opipe,
1168 NULL,
1169 binary,
1170 ap);
1171 va_end (ap);
1172 if (NULL == eip)
1173 {
1174 GNUNET_DISK_pipe_close (opipe);
1175 return NULL;
1176 }
1177 GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
1178 cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
1179 cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1180 cmd->eip = eip;
1181 cmd->opipe = opipe;
1182 cmd->proc = proc;
1183 cmd->proc_cls = proc_cls;
1184 cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
1185 cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1186 return cmd;
1187}
1188
1189
1190/* 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_cs.c b/src/util/perf_crypto_cs.c
deleted file mode 100644
index 54c9c8e0e..000000000
--- a/src/util/perf_crypto_cs.c
+++ /dev/null
@@ -1,183 +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 Lucien Heuzeveldt <lucienclaude.heuzeveldt@students.bfh.ch>
23 * @author Gian Demarmels <gian@demarmels.org>
24 * @file util/perf_crypto_cs.c
25 * @brief measure performance of Clause Blind Schnorr Signatures
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include <gauger.h>
31
32#define ITER 10
33
34/**
35 * Evaluate Clause Blind Schnorr Signature performance.
36 *
37 */
38static void
39eval ()
40{
41 struct GNUNET_TIME_Absolute start;
42 unsigned int i;
43
44 struct GNUNET_CRYPTO_CsPrivateKey priv;
45 struct GNUNET_CRYPTO_CsPublicKey pub;
46
47 struct GNUNET_CRYPTO_CsRSecret r_priv[2];
48 struct GNUNET_CRYPTO_CsRPublic r_pub[2];
49
50 char message[] = "test message";
51 size_t message_len = strlen ("test message");
52
53 // derive a test nonce
54 struct GNUNET_CRYPTO_CsNonce nonce;
55 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_hkdf (nonce.nonce,
56 sizeof(nonce.nonce),
57 GCRY_MD_SHA512,
58 GCRY_MD_SHA256,
59 "nonce",
60 strlen ("nonce"),
61 "nonce_secret",
62 strlen ("nonce_secret"),
63 NULL,
64 0));
65
66 struct GNUNET_CRYPTO_CsBlindingSecret bs[2];
67 struct GNUNET_CRYPTO_CsC blinded_cs[2];
68 struct GNUNET_CRYPTO_CsRPublic blinded_r_pub[2];
69 struct GNUNET_CRYPTO_CsBlindS blinded_s;
70 struct GNUNET_CRYPTO_CsS signature_scalar;
71 struct GNUNET_CRYPTO_CsSignature sig;
72
73 // BENCHMARK keygen
74 start = GNUNET_TIME_absolute_get ();
75
76 for (i = 0; i < ITER; i++)
77 {
78 GNUNET_CRYPTO_cs_private_key_generate (&priv);
79 GNUNET_CRYPTO_cs_private_key_get_public (&priv, &pub);
80 }
81 printf ("10x key generation took %s\n",
82 GNUNET_STRINGS_relative_time_to_string (
83 GNUNET_TIME_absolute_get_duration (start),
84 GNUNET_YES));
85
86
87 // BENCHMARK r derive and calc R pub
88 start = GNUNET_TIME_absolute_get ();
89 for (i = 0; i < ITER; i++)
90 {
91 GNUNET_CRYPTO_cs_r_derive (&nonce, &priv, r_priv);
92 GNUNET_CRYPTO_cs_r_get_public (&r_priv[0], &r_pub[0]);
93 GNUNET_CRYPTO_cs_r_get_public (&r_priv[1], &r_pub[1]);
94 }
95 printf ("10x r0, r1 derive and R1,R2 calculation took %s\n",
96 GNUNET_STRINGS_relative_time_to_string (
97 GNUNET_TIME_absolute_get_duration (start),
98 GNUNET_YES));
99
100
101 // BENCHMARK derive blinding secrets
102 start = GNUNET_TIME_absolute_get ();
103 for (i = 0; i < ITER; i++)
104 {
105 GNUNET_CRYPTO_cs_blinding_secrets_derive (&nonce,
106 bs);
107 }
108 printf ("10x derive blinding secrets took %s\n",
109 GNUNET_STRINGS_relative_time_to_string (
110 GNUNET_TIME_absolute_get_duration (start),
111 GNUNET_YES));
112
113
114 // BENCHMARK calculating C
115 start = GNUNET_TIME_absolute_get ();
116 for (i = 0; i < ITER; i++)
117 {
118 GNUNET_CRYPTO_cs_calc_blinded_c (bs,
119 r_pub,
120 &pub,
121 message,
122 message_len,
123 blinded_cs,
124 blinded_r_pub);
125 }
126 printf ("10x calculating the blinded c took %s\n",
127 GNUNET_STRINGS_relative_time_to_string (
128 GNUNET_TIME_absolute_get_duration (start),
129 GNUNET_YES));
130
131
132 // BENCHMARK sign derive
133 unsigned int b;
134 start = GNUNET_TIME_absolute_get ();
135 for (i = 0; i < ITER; i++)
136 {
137 b = GNUNET_CRYPTO_cs_sign_derive (&priv,
138 r_priv,
139 blinded_cs,
140 &nonce,
141 &blinded_s);
142 }
143 printf ("10x signing blinded c took %s\n",
144 GNUNET_STRINGS_relative_time_to_string (
145 GNUNET_TIME_absolute_get_duration (start),
146 GNUNET_YES));
147
148
149 // BENCHMARK unblind signature
150 start = GNUNET_TIME_absolute_get ();
151
152 for (i = 0; i < ITER; i++)
153 {
154 GNUNET_CRYPTO_cs_unblind (&blinded_s, &bs[b], &signature_scalar);
155 sig.r_point = blinded_r_pub[b];
156 sig.s_scalar = signature_scalar;
157 }
158 printf ("10x unblinding s took %s\n",
159 GNUNET_STRINGS_relative_time_to_string (
160 GNUNET_TIME_absolute_get_duration (start),
161 GNUNET_YES));
162
163 // BENCHMARK verify signature
164 start = GNUNET_TIME_absolute_get ();
165 for (i = 0; i < ITER; i++)
166 {
167 GNUNET_CRYPTO_cs_verify (&sig,
168 &pub,
169 message,
170 message_len);
171 }
172 printf ("10x verifying signatures took %s\n",
173 GNUNET_STRINGS_relative_time_to_string (
174 GNUNET_TIME_absolute_get_duration (start),
175 GNUNET_YES));
176}
177
178int
179main (int argc, char *argv[])
180{
181 eval ();
182 return 0;
183}
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 3806fe43d..000000000
--- a/src/util/perf_crypto_rsa.c
+++ /dev/null
@@ -1,212 +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 (3072);
207 eval (4096);
208 return 0;
209}
210
211
212/* 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 6ee41eec9..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 == prev)
293 plugins = pos->next;
294 else
295 prev->next = pos->next;
296 if (NULL != done)
297 ret = done (arg);
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 7e035ae3d..000000000
--- a/src/util/scheduler.c
+++ /dev/null
@@ -1,2567 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009-2017, 2022 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 if (p > work_priority)
520 work_priority = p;
521 task->in_ready_list = GNUNET_YES;
522 ready_count++;
523}
524
525
526/**
527 * Request the shutdown of a scheduler. Marks all tasks
528 * awaiting shutdown as ready. Note that tasks
529 * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call
530 * will be delayed until the next shutdown signal.
531 */
532void
533GNUNET_SCHEDULER_shutdown ()
534{
535 struct GNUNET_SCHEDULER_Task *pos;
536
537 LOG (GNUNET_ERROR_TYPE_DEBUG,
538 "GNUNET_SCHEDULER_shutdown\n");
539 if (NULL != install_parent_control_task)
540 {
541 GNUNET_SCHEDULER_cancel (install_parent_control_task);
542 install_parent_control_task = NULL;
543 }
544 if (NULL != shutdown_pipe_task)
545 {
546 GNUNET_SCHEDULER_cancel (shutdown_pipe_task);
547 shutdown_pipe_task = NULL;
548 }
549 while (NULL != (pos = shutdown_head))
550 {
551 GNUNET_CONTAINER_DLL_remove (shutdown_head,
552 shutdown_tail,
553 pos);
554 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
555 queue_ready_task (pos);
556 }
557}
558
559
560/**
561 * Output stack trace of task @a t.
562 *
563 * @param t task to dump stack trace of
564 */
565static void
566dump_backtrace (struct GNUNET_SCHEDULER_Task *t)
567{
568#if EXECINFO
569 for (unsigned int i = 0; i < t->num_backtrace_strings; i++)
570 LOG (GNUNET_ERROR_TYPE_WARNING,
571 "Task %p trace %u: %s\n",
572 t,
573 i,
574 t->backtrace_strings[i]);
575#else
576 (void) t;
577#endif
578}
579
580
581/**
582 * Destroy a task (release associated resources)
583 *
584 * @param t task to destroy
585 */
586static void
587destroy_task (struct GNUNET_SCHEDULER_Task *t)
588{
589 LOG (GNUNET_ERROR_TYPE_DEBUG,
590 "destroying task %p\n",
591 t);
592
593 if (GNUNET_YES == t->own_handles)
594 {
595 for (unsigned int i = 0; i != t->fds_len; ++i)
596 {
597 const struct GNUNET_NETWORK_Handle *fd = t->fds[i].fd;
598 const struct GNUNET_DISK_FileHandle *fh = t->fds[i].fh;
599 if (fd)
600 {
601 GNUNET_NETWORK_socket_free_memory_only_ (
602 (struct GNUNET_NETWORK_Handle *) fd);
603 }
604 if (fh)
605 {
606 // FIXME: on WIN32 this is not enough! A function
607 // GNUNET_DISK_file_free_memory_only would be nice
608 GNUNET_free_nz ((void *) fh);
609 }
610 }
611 }
612 if (t->fds_len > 1)
613 {
614 GNUNET_array_grow (t->fds, t->fds_len, 0);
615 }
616#if EXECINFO
617 GNUNET_free (t->backtrace_strings);
618#endif
619 GNUNET_free (t);
620}
621
622
623/**
624 * Pipe used to communicate shutdown via signal.
625 */
626static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle;
627
628/**
629 * Process ID of this process at the time we installed the various
630 * signal handlers.
631 */
632static pid_t my_pid;
633
634/**
635 * Signal handler called for SIGPIPE.
636 */
637static void
638sighandler_pipe ()
639{
640 return;
641}
642
643
644/**
645 * Signal handler called for signals that should cause us to shutdown.
646 */
647static void
648sighandler_shutdown (void)
649{
650 static char c;
651 int old_errno = errno; /* backup errno */
652
653 if (getpid () != my_pid)
654 _exit (1); /* we have fork'ed since the signal handler was created,
655 * ignore the signal, see https://gnunet.org/vfork discussion */
656 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (
657 shutdown_pipe_handle,
658 GNUNET_DISK_PIPE_END_WRITE),
659 &c, sizeof(c));
660 errno = old_errno;
661}
662
663
664static void
665shutdown_if_no_lifeness (void)
666{
667 struct GNUNET_SCHEDULER_Task *t;
668
669 if (ready_count > 0)
670 return;
671 for (t = pending_head; NULL != t; t = t->next)
672 if (GNUNET_YES == t->lifeness)
673 return;
674 for (t = shutdown_head; NULL != t; t = t->next)
675 if (GNUNET_YES == t->lifeness)
676 return;
677 for (t = pending_timeout_head; NULL != t; t = t->next)
678 if (GNUNET_YES == t->lifeness)
679 return;
680 /* No lifeness! */
681 GNUNET_SCHEDULER_shutdown ();
682}
683
684
685static int
686select_loop (struct GNUNET_SCHEDULER_Handle *sh,
687 struct DriverContext *context);
688
689
690/**
691 * Initialize and run scheduler. This function will return when all
692 * tasks have completed. On systems with signals, receiving a SIGTERM
693 * (and other similar signals) will cause #GNUNET_SCHEDULER_shutdown()
694 * to be run after the active task is complete. As a result, SIGTERM
695 * causes all active tasks to be scheduled with reason
696 * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added
697 * afterwards will execute normally!). Note that any particular signal
698 * will only shut down one scheduler; applications should always only
699 * create a single scheduler.
700 *
701 * @param task task to run immediately
702 * @param task_cls closure of @a task
703 */
704void
705GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task,
706 void *task_cls)
707{
708 struct GNUNET_SCHEDULER_Handle *sh;
709 struct GNUNET_SCHEDULER_Driver *driver;
710 struct DriverContext context = {
711 .scheduled_head = NULL,
712 .scheduled_tail = NULL,
713 .timeout = GNUNET_TIME_absolute_get ()
714 };
715
716 driver = GNUNET_SCHEDULER_driver_select ();
717 driver->cls = &context;
718 sh = GNUNET_SCHEDULER_driver_init (driver);
719 GNUNET_SCHEDULER_add_with_reason_and_priority (task,
720 task_cls,
721 GNUNET_SCHEDULER_REASON_STARTUP,
722 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
723 select_loop (sh,
724 &context);
725 GNUNET_SCHEDULER_driver_done (sh);
726 GNUNET_free (driver);
727}
728
729
730/**
731 * Obtain the task context, giving the reason why the current task was
732 * started.
733 *
734 * @return current tasks' scheduler context
735 */
736const struct GNUNET_SCHEDULER_TaskContext *
737GNUNET_SCHEDULER_get_task_context ()
738{
739 GNUNET_assert (NULL != active_task);
740 return &tc;
741}
742
743
744/**
745 * Get information about the current load of this scheduler. Use this
746 * function to determine if an elective task should be added or simply
747 * dropped (if the decision should be made based on the number of
748 * tasks ready to run).
749 *
750 * @param p priority level to look at
751 * @return number of tasks pending right now
752 */
753unsigned int
754GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p)
755{
756 unsigned int ret;
757
758 GNUNET_assert (NULL != active_task);
759 if (p == GNUNET_SCHEDULER_PRIORITY_COUNT)
760 return ready_count;
761 if (p == GNUNET_SCHEDULER_PRIORITY_KEEP)
762 p = current_priority;
763 ret = 0;
764 for (struct GNUNET_SCHEDULER_Task *pos = ready_head[check_priority (p)];
765 NULL != pos;
766 pos = pos->next)
767 ret++;
768 return ret;
769}
770
771
772void
773init_fd_info (struct GNUNET_SCHEDULER_Task *t,
774 const struct GNUNET_NETWORK_Handle *const *read_nh,
775 unsigned int read_nh_len,
776 const struct GNUNET_NETWORK_Handle *const *write_nh,
777 unsigned int write_nh_len,
778 const struct GNUNET_DISK_FileHandle *const *read_fh,
779 unsigned int read_fh_len,
780 const struct GNUNET_DISK_FileHandle *const *write_fh,
781 unsigned int write_fh_len)
782{
783 // FIXME: if we have exactly two network handles / exactly two file handles
784 // and they are equal, we can make one FdInfo with both
785 // GNUNET_SCHEDULER_ET_IN and GNUNET_SCHEDULER_ET_OUT set.
786 struct GNUNET_SCHEDULER_FdInfo *fdi;
787
788 t->fds_len = read_nh_len + write_nh_len + read_fh_len + write_fh_len;
789 if (1 == t->fds_len)
790 {
791 fdi = &t->fdx;
792 t->fds = fdi;
793 if (1 == read_nh_len)
794 {
795 GNUNET_assert (NULL != read_nh);
796 GNUNET_assert (NULL != *read_nh);
797 fdi->fd = *read_nh;
798 fdi->et = GNUNET_SCHEDULER_ET_IN;
799 fdi->sock = GNUNET_NETWORK_get_fd (*read_nh);
800 t->read_fd = fdi->sock;
801 t->write_fd = -1;
802 }
803 else if (1 == write_nh_len)
804 {
805 GNUNET_assert (NULL != write_nh);
806 GNUNET_assert (NULL != *write_nh);
807 fdi->fd = *write_nh;
808 fdi->et = GNUNET_SCHEDULER_ET_OUT;
809 fdi->sock = GNUNET_NETWORK_get_fd (*write_nh);
810 t->read_fd = -1;
811 t->write_fd = fdi->sock;
812 }
813 else if (1 == read_fh_len)
814 {
815 GNUNET_assert (NULL != read_fh);
816 GNUNET_assert (NULL != *read_fh);
817 fdi->fh = *read_fh;
818 fdi->et = GNUNET_SCHEDULER_ET_IN;
819 fdi->sock = (*read_fh)->fd; // FIXME: does not work under WIN32
820 t->read_fd = fdi->sock;
821 t->write_fd = -1;
822 }
823 else
824 {
825 GNUNET_assert (NULL != write_fh);
826 GNUNET_assert (NULL != *write_fh);
827 fdi->fh = *write_fh;
828 fdi->et = GNUNET_SCHEDULER_ET_OUT;
829 fdi->sock = (*write_fh)->fd; // FIXME: does not work under WIN32
830 t->read_fd = -1;
831 t->write_fd = fdi->sock;
832 }
833 }
834 else
835 {
836 fdi = GNUNET_new_array (t->fds_len, struct GNUNET_SCHEDULER_FdInfo);
837 t->fds = fdi;
838 t->read_fd = -1;
839 t->write_fd = -1;
840 unsigned int i;
841 for (i = 0; i != read_nh_len; ++i)
842 {
843 fdi->fd = read_nh[i];
844 GNUNET_assert (NULL != fdi->fd);
845 fdi->et = GNUNET_SCHEDULER_ET_IN;
846 fdi->sock = GNUNET_NETWORK_get_fd (read_nh[i]);
847 ++fdi;
848 }
849 for (i = 0; i != write_nh_len; ++i)
850 {
851 fdi->fd = write_nh[i];
852 GNUNET_assert (NULL != fdi->fd);
853 fdi->et = GNUNET_SCHEDULER_ET_OUT;
854 fdi->sock = GNUNET_NETWORK_get_fd (write_nh[i]);
855 ++fdi;
856 }
857 for (i = 0; i != read_fh_len; ++i)
858 {
859 fdi->fh = read_fh[i];
860 GNUNET_assert (NULL != fdi->fh);
861 fdi->et = GNUNET_SCHEDULER_ET_IN;
862 fdi->sock = (read_fh[i])->fd; // FIXME: does not work under WIN32
863 ++fdi;
864 }
865 for (i = 0; i != write_fh_len; ++i)
866 {
867 fdi->fh = write_fh[i];
868 GNUNET_assert (NULL != fdi->fh);
869 fdi->et = GNUNET_SCHEDULER_ET_OUT;
870 fdi->sock = (write_fh[i])->fd; // FIXME: does not work under WIN32
871 ++fdi;
872 }
873 }
874}
875
876
877/**
878 * calls the given function @a func on each FdInfo related to @a t.
879 * Optionally updates the event type field in each FdInfo after calling
880 * @a func.
881 *
882 * @param t the task
883 * @param driver_func the function to call with each FdInfo contained in
884 * in @a t
885 * @param if_not_ready only call @a driver_func on FdInfos that are not
886 * ready
887 * @param et the event type to be set in each FdInfo after calling
888 * @a driver_func on it, or -1 if no updating not desired.
889 */
890static void
891driver_add_multiple (struct GNUNET_SCHEDULER_Task *t)
892{
893 struct GNUNET_SCHEDULER_FdInfo *fdi;
894 int success = GNUNET_YES;
895
896 for (unsigned int i = 0; i != t->fds_len; ++i)
897 {
898 fdi = &t->fds[i];
899 success = scheduler_driver->add (scheduler_driver->cls,
900 t,
901 fdi) && success;
902 fdi->et = GNUNET_SCHEDULER_ET_NONE;
903 }
904 if (GNUNET_YES != success)
905 {
906 LOG (GNUNET_ERROR_TYPE_ERROR,
907 "driver could not add task\n");
908 }
909}
910
911
912static void
913install_parent_control_handler (void *cls)
914{
915 (void) cls;
916 install_parent_control_task = NULL;
917 GNUNET_OS_install_parent_control_handler (NULL);
918}
919
920
921static void
922shutdown_pipe_cb (void *cls)
923{
924 char c;
925 const struct GNUNET_DISK_FileHandle *pr;
926
927 (void) cls;
928 shutdown_pipe_task = NULL;
929 pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
930 GNUNET_DISK_PIPE_END_READ);
931 GNUNET_assert (! GNUNET_DISK_handle_invalid (pr));
932 /* consume the signal */
933 GNUNET_DISK_file_read (pr, &c, sizeof(c));
934 /* mark all active tasks as ready due to shutdown */
935 GNUNET_SCHEDULER_shutdown ();
936 shutdown_pipe_task =
937 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
938 pr,
939 &shutdown_pipe_cb,
940 NULL);
941}
942
943
944/**
945 * Cancel the task with the specified identifier.
946 * The task must not yet have run. Only allowed to be called as long as the
947 * scheduler is running, that is one of the following conditions is met:
948 *
949 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
950 * - #GNUNET_SCHEDULER_driver_init has been run and
951 * #GNUNET_SCHEDULER_driver_done has not been called yet
952 *
953 * @param task id of the task to cancel
954 * @return original closure of the task
955 */
956void *
957GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task)
958{
959 enum GNUNET_SCHEDULER_Priority p;
960 int is_fd_task;
961 void *ret;
962
963 LOG (GNUNET_ERROR_TYPE_DEBUG,
964 "canceling task %p\n",
965 task);
966
967 /* scheduler must be running */
968 GNUNET_assert (NULL != scheduler_driver);
969 is_fd_task = (NULL != task->fds);
970 if (is_fd_task)
971 {
972 int del_result = scheduler_driver->del (scheduler_driver->cls, task);
973 if (GNUNET_OK != del_result)
974 {
975 LOG (GNUNET_ERROR_TYPE_ERROR,
976 "driver could not delete task\n");
977 GNUNET_assert (0);
978 }
979 }
980 if (! task->in_ready_list)
981 {
982 if (is_fd_task)
983 {
984 GNUNET_CONTAINER_DLL_remove (pending_head,
985 pending_tail,
986 task);
987 }
988 else if (GNUNET_YES == task->on_shutdown)
989 {
990 GNUNET_CONTAINER_DLL_remove (shutdown_head,
991 shutdown_tail,
992 task);
993 }
994 else
995 {
996 GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
997 pending_timeout_tail,
998 task);
999 if (pending_timeout_last == task)
1000 pending_timeout_last = NULL;
1001 }
1002 }
1003 else
1004 {
1005 p = check_priority (task->priority);
1006 GNUNET_CONTAINER_DLL_remove (ready_head[p],
1007 ready_tail[p],
1008 task);
1009 ready_count--;
1010 }
1011 ret = task->callback_cls;
1012 destroy_task (task);
1013 return ret;
1014}
1015
1016
1017/**
1018 * Initialize backtrace data for task @a t
1019 *
1020 * @param t task to initialize
1021 */
1022static void
1023init_backtrace (struct GNUNET_SCHEDULER_Task *t)
1024{
1025#if EXECINFO
1026 void *backtrace_array[MAX_TRACE_DEPTH];
1027
1028 t->num_backtrace_strings
1029 = backtrace (backtrace_array, MAX_TRACE_DEPTH);
1030 t->backtrace_strings =
1031 backtrace_symbols (backtrace_array,
1032 t->num_backtrace_strings);
1033 dump_backtrace (t);
1034#else
1035 (void) t;
1036#endif
1037}
1038
1039
1040/**
1041 * Continue the current execution with the given function. This is
1042 * similar to the other "add" functions except that there is no delay
1043 * and the reason code can be specified.
1044 *
1045 * @param task main function of the task
1046 * @param task_cls closure for @a task
1047 * @param reason reason for task invocation
1048 * @param priority priority to use for the task
1049 */
1050void
1051GNUNET_SCHEDULER_add_with_reason_and_priority (GNUNET_SCHEDULER_TaskCallback
1052 task,
1053 void *task_cls,
1054 enum GNUNET_SCHEDULER_Reason
1055 reason,
1056 enum GNUNET_SCHEDULER_Priority
1057 priority)
1058{
1059 struct GNUNET_SCHEDULER_Task *t;
1060
1061 /* scheduler must be running */
1062 GNUNET_assert (NULL != scheduler_driver);
1063 GNUNET_assert (NULL != task);
1064 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1065 t->read_fd = -1;
1066 t->write_fd = -1;
1067 t->callback = task;
1068 t->callback_cls = task_cls;
1069#if PROFILE_DELAYS
1070 t->start_time = GNUNET_TIME_absolute_get ();
1071#endif
1072 t->reason = reason;
1073 t->priority = check_priority (priority);
1074 t->lifeness = current_lifeness;
1075 LOG (GNUNET_ERROR_TYPE_DEBUG,
1076 "Adding continuation task %p\n",
1077 t);
1078 init_backtrace (t);
1079 queue_ready_task (t);
1080}
1081
1082
1083/**
1084 * Schedule a new task to be run at the specified time. The task
1085 * will be scheduled for execution at time @a at.
1086 *
1087 * @param at time when the operation should run
1088 * @param priority priority to use for the task
1089 * @param task main function of the task
1090 * @param task_cls closure of @a task
1091 * @return unique task identifier for the job
1092 * only valid until @a task is started!
1093 */
1094struct GNUNET_SCHEDULER_Task *
1095GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at,
1096 enum GNUNET_SCHEDULER_Priority priority,
1097 GNUNET_SCHEDULER_TaskCallback task,
1098 void *task_cls)
1099{
1100 struct GNUNET_SCHEDULER_Task *t;
1101 struct GNUNET_SCHEDULER_Task *pos;
1102 struct GNUNET_SCHEDULER_Task *prev;
1103 struct GNUNET_TIME_Relative left;
1104
1105 /* scheduler must be running */
1106 GNUNET_assert (NULL != scheduler_driver);
1107 GNUNET_assert (NULL != task);
1108 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1109 GNUNET_async_scope_get (&t->scope);
1110 t->callback = task;
1111 t->callback_cls = task_cls;
1112 t->read_fd = -1;
1113 t->write_fd = -1;
1114#if PROFILE_DELAYS
1115 t->start_time = GNUNET_TIME_absolute_get ();
1116#endif
1117 t->timeout = at;
1118 t->priority = check_priority (priority);
1119 t->lifeness = current_lifeness;
1120 init_backtrace (t);
1121
1122 left = GNUNET_TIME_absolute_get_remaining (at);
1123 if (0 == left.rel_value_us)
1124 {
1125 queue_ready_task (t);
1126 if (priority > work_priority)
1127 work_priority = priority;
1128 return t;
1129 }
1130
1131 /* try tail first (optimization in case we are
1132 * appending to a long list of tasks with timeouts) */
1133 if ((NULL == pending_timeout_head) ||
1134 (at.abs_value_us < pending_timeout_head->timeout.abs_value_us))
1135 {
1136 GNUNET_CONTAINER_DLL_insert (pending_timeout_head,
1137 pending_timeout_tail,
1138 t);
1139 }
1140 else
1141 {
1142 /* first move from heuristic start backwards to before start time */
1143 prev = pending_timeout_last;
1144 while ((NULL != prev) &&
1145 (prev->timeout.abs_value_us > t->timeout.abs_value_us))
1146 prev = prev->prev;
1147 /* now, move from heuristic start (or head of list) forward to insertion point */
1148 if (NULL == prev)
1149 pos = pending_timeout_head;
1150 else
1151 pos = prev->next;
1152 while ((NULL != pos) && (pos->timeout.abs_value_us <=
1153 t->timeout.abs_value_us))
1154 {
1155 prev = pos;
1156 pos = pos->next;
1157 }
1158 GNUNET_CONTAINER_DLL_insert_after (pending_timeout_head,
1159 pending_timeout_tail,
1160 prev,
1161 t);
1162 }
1163 /* finally, update heuristic insertion point to last insertion... */
1164 pending_timeout_last = t;
1165 LOG (GNUNET_ERROR_TYPE_DEBUG,
1166 "Adding task %p\n",
1167 t);
1168 return t;
1169}
1170
1171
1172/**
1173 * Schedule a new task to be run with a specified delay. The task
1174 * will be scheduled for execution once the delay has expired.
1175 *
1176 * @param delay when should this operation time out?
1177 * @param priority priority to use for the task
1178 * @param task main function of the task
1179 * @param task_cls closure of @a task
1180 * @return unique task identifier for the job
1181 * only valid until @a task is started!
1182 */
1183struct GNUNET_SCHEDULER_Task *
1184GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
1185 enum GNUNET_SCHEDULER_Priority
1186 priority,
1187 GNUNET_SCHEDULER_TaskCallback task,
1188 void *task_cls)
1189{
1190 return GNUNET_SCHEDULER_add_at_with_priority (
1191 GNUNET_TIME_relative_to_absolute (delay),
1192 priority,
1193 task,
1194 task_cls);
1195}
1196
1197
1198/**
1199 * Schedule a new task to be run with a specified priority.
1200 *
1201 * @param prio how important is the new task?
1202 * @param task main function of the task
1203 * @param task_cls closure of @a task
1204 * @return unique task identifier for the job
1205 * only valid until @a task is started!
1206 */
1207struct GNUNET_SCHEDULER_Task *
1208GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
1209 GNUNET_SCHEDULER_TaskCallback task,
1210 void *task_cls)
1211{
1212 return GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_ZERO,
1213 prio,
1214 task,
1215 task_cls);
1216}
1217
1218
1219/**
1220 * Schedule a new task to be run at the specified time. The task
1221 * will be scheduled for execution once specified time has been
1222 * reached. It will be run with the DEFAULT priority.
1223 *
1224 * @param at time at which this operation should run
1225 * @param task main function of the task
1226 * @param task_cls closure of @a task
1227 * @return unique task identifier for the job
1228 * only valid until @a task is started!
1229 */
1230struct GNUNET_SCHEDULER_Task *
1231GNUNET_SCHEDULER_add_at (struct GNUNET_TIME_Absolute at,
1232 GNUNET_SCHEDULER_TaskCallback task,
1233 void *task_cls)
1234{
1235 return GNUNET_SCHEDULER_add_at_with_priority (at,
1236 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1237 task,
1238 task_cls);
1239}
1240
1241
1242/**
1243 * Schedule a new task to be run with a specified delay. The task
1244 * will be scheduled for execution once the delay has expired. It
1245 * will be run with the DEFAULT priority.
1246 *
1247 * @param delay when should this operation time out?
1248 * @param task main function of the task
1249 * @param task_cls closure of @a task
1250 * @return unique task identifier for the job
1251 * only valid until @a task is started!
1252 */
1253struct GNUNET_SCHEDULER_Task *
1254GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
1255 GNUNET_SCHEDULER_TaskCallback task,
1256 void *task_cls)
1257{
1258 return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
1259 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1260 task,
1261 task_cls);
1262}
1263
1264
1265/**
1266 * Schedule a new task to be run as soon as possible. Note that this
1267 * does not guarantee that this will be the next task that is being
1268 * run, as other tasks with higher priority (or that are already ready
1269 * to run) might get to run first. Just as with delays, clients must
1270 * not rely on any particular order of execution between tasks
1271 * scheduled concurrently.
1272 *
1273 * The task will be run with the DEFAULT priority.
1274 *
1275 * @param task main function of the task
1276 * @param task_cls closure of @a task
1277 * @return unique task identifier for the job
1278 * only valid until @a task is started!
1279 */
1280struct GNUNET_SCHEDULER_Task *
1281GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task,
1282 void *task_cls)
1283{
1284 struct GNUNET_SCHEDULER_Task *t;
1285
1286 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1287 GNUNET_async_scope_get (&t->scope);
1288 t->callback = task;
1289 t->callback_cls = task_cls;
1290 t->read_fd = -1;
1291 t->write_fd = -1;
1292#if PROFILE_DELAYS
1293 t->start_time = GNUNET_TIME_absolute_get ();
1294#endif
1295 t->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1296 t->priority = current_priority;
1297 t->on_shutdown = GNUNET_YES;
1298 t->lifeness = current_lifeness;
1299 queue_ready_task (t);
1300 init_backtrace (t);
1301 return t;
1302}
1303
1304
1305/**
1306 * Schedule a new task to be run on shutdown, that is when a CTRL-C
1307 * signal is received, or when #GNUNET_SCHEDULER_shutdown() is being
1308 * invoked.
1309 *
1310 * @param task main function of the task
1311 * @param task_cls closure of @a task
1312 * @return unique task identifier for the job
1313 * only valid until @a task is started!
1314 */
1315struct GNUNET_SCHEDULER_Task *
1316GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task,
1317 void *task_cls)
1318{
1319 struct GNUNET_SCHEDULER_Task *t;
1320
1321 /* scheduler must be running */
1322 GNUNET_assert (NULL != scheduler_driver);
1323 GNUNET_assert (NULL != task);
1324 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1325 GNUNET_async_scope_get (&t->scope);
1326 t->callback = task;
1327 t->callback_cls = task_cls;
1328 t->read_fd = -1;
1329 t->write_fd = -1;
1330#if PROFILE_DELAYS
1331 t->start_time = GNUNET_TIME_absolute_get ();
1332#endif
1333 t->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1334 t->priority = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN;
1335 t->on_shutdown = GNUNET_YES;
1336 t->lifeness = GNUNET_NO;
1337 GNUNET_CONTAINER_DLL_insert (shutdown_head,
1338 shutdown_tail,
1339 t);
1340 LOG (GNUNET_ERROR_TYPE_DEBUG,
1341 "Adding shutdown task %p\n",
1342 t);
1343 init_backtrace (t);
1344 return t;
1345}
1346
1347
1348/**
1349 * Schedule a new task to be run as soon as possible with the
1350 * (transitive) ignore-shutdown flag either explicitly set or
1351 * explicitly enabled. This task (and all tasks created from it,
1352 * other than by another call to this function) will either count or
1353 * not count for the "lifeness" of the process. This API is only
1354 * useful in a few special cases.
1355 *
1356 * @param lifeness #GNUNET_YES if the task counts for lifeness, #GNUNET_NO if not.
1357 * @param task main function of the task
1358 * @param task_cls closure of @a task
1359 * @return unique task identifier for the job
1360 * only valid until @a task is started!
1361 */
1362struct GNUNET_SCHEDULER_Task *
1363GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
1364 GNUNET_SCHEDULER_TaskCallback task,
1365 void *task_cls)
1366{
1367 struct GNUNET_SCHEDULER_Task *ret;
1368
1369 ret = GNUNET_SCHEDULER_add_now (task, task_cls);
1370 ret->lifeness = lifeness;
1371 return ret;
1372}
1373
1374
1375#if DEBUG_FDS
1376/**
1377 * check a raw file descriptor and abort if it is bad (for debugging purposes)
1378 *
1379 * @param t the task related to the file descriptor
1380 * @param raw_fd the raw file descriptor to check
1381 */
1382void
1383check_fd (struct GNUNET_SCHEDULER_Task *t, int raw_fd)
1384{
1385 if (-1 != raw_fd)
1386 {
1387 int flags = fcntl (raw_fd, F_GETFD);
1388
1389 if ((flags == -1) && (errno == EBADF))
1390 {
1391 LOG (GNUNET_ERROR_TYPE_ERROR,
1392 "Got invalid file descriptor %d!\n",
1393 raw_fd);
1394 init_backtrace (t);
1395 GNUNET_assert (0);
1396 }
1397 }
1398}
1399
1400
1401#endif
1402
1403
1404/**
1405 * Schedule a new task to be run with a specified delay or when any of
1406 * the specified file descriptor sets is ready. The delay can be used
1407 * as a timeout on the socket(s) being ready. The task will be
1408 * scheduled for execution once either the delay has expired or any of
1409 * the socket operations is ready. This is the most general
1410 * function of the "add" family. Note that the "prerequisite_task"
1411 * must be satisfied in addition to any of the other conditions. In
1412 * other words, the task will be started when
1413 * <code>
1414 * (prerequisite-run)
1415 * && (delay-ready
1416 * || any-rs-ready
1417 * || any-ws-ready)
1418 * </code>
1419 *
1420 * @param delay how long should we wait?
1421 * @param priority priority to use
1422 * @param rfd file descriptor we want to read (can be -1)
1423 * @param wfd file descriptors we want to write (can be -1)
1424 * @param task main function of the task
1425 * @param task_cls closure of @a task
1426 * @return unique task identifier for the job
1427 * only valid until @a task is started!
1428 */
1429static struct GNUNET_SCHEDULER_Task *
1430add_without_sets (struct GNUNET_TIME_Relative delay,
1431 enum GNUNET_SCHEDULER_Priority priority,
1432 const struct GNUNET_NETWORK_Handle *read_nh,
1433 const struct GNUNET_NETWORK_Handle *write_nh,
1434 const struct GNUNET_DISK_FileHandle *read_fh,
1435 const struct GNUNET_DISK_FileHandle *write_fh,
1436 GNUNET_SCHEDULER_TaskCallback task,
1437 void *task_cls)
1438{
1439 struct GNUNET_SCHEDULER_Task *t;
1440
1441 /* scheduler must be running */
1442 GNUNET_assert (NULL != scheduler_driver);
1443 GNUNET_assert (NULL != task);
1444 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1445 GNUNET_async_scope_get (&t->scope);
1446 init_fd_info (t,
1447 &read_nh,
1448 read_nh ? 1 : 0,
1449 &write_nh,
1450 write_nh ? 1 : 0,
1451 &read_fh,
1452 read_fh ? 1 : 0,
1453 &write_fh,
1454 write_fh ? 1 : 0);
1455 t->callback = task;
1456 t->callback_cls = task_cls;
1457#if DEBUG_FDS
1458 check_fd (t, NULL != read_nh ? GNUNET_NETWORK_get_fd (read_nh) : -1);
1459 check_fd (t, NULL != write_nh ? GNUNET_NETWORK_get_fd (write_nh) : -1);
1460 check_fd (t, NULL != read_fh ? read_fh->fd : -1);
1461 check_fd (t, NULL != write_fh ? write_fh->fd : -1);
1462#endif
1463#if PROFILE_DELAYS
1464 t->start_time = GNUNET_TIME_absolute_get ();
1465#endif
1466 t->timeout = GNUNET_TIME_relative_to_absolute (delay);
1467 t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ?
1468 current_priority : priority);
1469 t->lifeness = current_lifeness;
1470 GNUNET_CONTAINER_DLL_insert (pending_head,
1471 pending_tail,
1472 t);
1473 driver_add_multiple (t);
1474 max_priority_added = GNUNET_MAX (max_priority_added,
1475 t->priority);
1476 init_backtrace (t);
1477 return t;
1478}
1479
1480
1481/**
1482 * Schedule a new task to be run with a specified delay or when the
1483 * specified file descriptor is ready for reading. The delay can be
1484 * used as a timeout on the socket being ready. The task will be
1485 * scheduled for execution once either the delay has expired or the
1486 * socket operation is ready. It will be run with the DEFAULT priority.
1487 * Only allowed to be called as long as the scheduler is running, that
1488 * is one of the following conditions is met:
1489 *
1490 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1491 * - #GNUNET_SCHEDULER_driver_init has been run and
1492 * #GNUNET_SCHEDULER_driver_done has not been called yet
1493 *
1494 * @param delay when should this operation time out?
1495 * @param rfd read file-descriptor
1496 * @param task main function of the task
1497 * @param task_cls closure of @a task
1498 * @return unique task identifier for the job
1499 * only valid until @a task is started!
1500 */
1501struct GNUNET_SCHEDULER_Task *
1502GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
1503 struct GNUNET_NETWORK_Handle *rfd,
1504 GNUNET_SCHEDULER_TaskCallback task,
1505 void *task_cls)
1506{
1507 return GNUNET_SCHEDULER_add_read_net_with_priority (delay,
1508 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1509 rfd, task, task_cls);
1510}
1511
1512
1513/**
1514 * Schedule a new task to be run with a specified priority and to be
1515 * run after the specified delay or when the specified file descriptor
1516 * is ready for reading. The delay can be used as a timeout on the
1517 * socket being ready. The task will be scheduled for execution once
1518 * either the delay has expired or the socket operation is ready. It
1519 * will be run with the DEFAULT priority.
1520 * Only allowed to be called as long as the scheduler is running, that
1521 * is one of the following conditions is met:
1522 *
1523 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1524 * - #GNUNET_SCHEDULER_driver_init has been run and
1525 * #GNUNET_SCHEDULER_driver_done has not been called yet
1526 *
1527 * @param delay when should this operation time out?
1528 * @param priority priority to use for the task
1529 * @param rfd read file-descriptor
1530 * @param task main function of the task
1531 * @param task_cls closure of @a task
1532 * @return unique task identifier for the job
1533 * only valid until @a task is started!
1534 */
1535struct GNUNET_SCHEDULER_Task *
1536GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay,
1537 enum GNUNET_SCHEDULER_Priority
1538 priority,
1539 struct GNUNET_NETWORK_Handle *rfd,
1540 GNUNET_SCHEDULER_TaskCallback task,
1541 void *task_cls)
1542{
1543 return GNUNET_SCHEDULER_add_net_with_priority (delay, priority,
1544 rfd,
1545 GNUNET_YES,
1546 GNUNET_NO,
1547 task, task_cls);
1548}
1549
1550
1551/**
1552 * Schedule a new task to be run with a specified delay or when the
1553 * specified file descriptor is ready for writing. The delay can be
1554 * used as a timeout on the socket being ready. The task will be
1555 * scheduled for execution once either the delay has expired or the
1556 * socket operation is ready. It will be run with the priority of
1557 * the calling task.
1558 * Only allowed to be called as long as the scheduler is running, that
1559 * is one of the following conditions is met:
1560 *
1561 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1562 * - #GNUNET_SCHEDULER_driver_init has been run and
1563 * #GNUNET_SCHEDULER_driver_done has not been called yet
1564 *
1565 * @param delay when should this operation time out?
1566 * @param wfd write file-descriptor
1567 * @param task main function of the task
1568 * @param task_cls closure of @a task
1569 * @return unique task identifier for the job
1570 * only valid until @a task is started!
1571 */
1572struct GNUNET_SCHEDULER_Task *
1573GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
1574 struct GNUNET_NETWORK_Handle *wfd,
1575 GNUNET_SCHEDULER_TaskCallback task,
1576 void *task_cls)
1577{
1578 return GNUNET_SCHEDULER_add_net_with_priority (delay,
1579 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1580 wfd,
1581 GNUNET_NO, GNUNET_YES,
1582 task, task_cls);
1583}
1584
1585
1586/**
1587 * Schedule a new task to be run with a specified delay or when the
1588 * specified file descriptor is ready. The delay can be
1589 * used as a timeout on the socket being ready. The task will be
1590 * scheduled for execution once either the delay has expired or the
1591 * socket operation is ready.
1592 * Only allowed to be called as long as the scheduler is running, that
1593 * is one of the following conditions is met:
1594 *
1595 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1596 * - #GNUNET_SCHEDULER_driver_init has been run and
1597 * #GNUNET_SCHEDULER_driver_done has not been called yet
1598 *
1599 * @param delay when should this operation time out?
1600 * @param priority priority of the task
1601 * @param fd file-descriptor
1602 * @param on_read whether to poll the file-descriptor for readability
1603 * @param on_write whether to poll the file-descriptor for writability
1604 * @param task main function of the task
1605 * @param task_cls closure of task
1606 * @return unique task identifier for the job
1607 * only valid until "task" is started!
1608 */
1609struct GNUNET_SCHEDULER_Task *
1610GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay,
1611 enum GNUNET_SCHEDULER_Priority priority,
1612 struct GNUNET_NETWORK_Handle *fd,
1613 int on_read,
1614 int on_write,
1615 GNUNET_SCHEDULER_TaskCallback task,
1616 void *task_cls)
1617{
1618 /* scheduler must be running */
1619 GNUNET_assert (NULL != scheduler_driver);
1620 GNUNET_assert (on_read || on_write);
1621 GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0);
1622 return add_without_sets (delay, priority,
1623 on_read ? fd : NULL,
1624 on_write ? fd : NULL,
1625 NULL,
1626 NULL,
1627 task, task_cls);
1628}
1629
1630
1631/**
1632 * Schedule a new task to be run with a specified delay or when the
1633 * specified file descriptor is ready for reading. The delay can be
1634 * used as a timeout on the socket being ready. The task will be
1635 * scheduled for execution once either the delay has expired or the
1636 * socket operation is ready. It will be run with the DEFAULT priority.
1637 * Only allowed to be called as long as the scheduler is running, that
1638 * is one of the following conditions is met:
1639 *
1640 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1641 * - #GNUNET_SCHEDULER_driver_init has been run and
1642 * #GNUNET_SCHEDULER_driver_done has not been called yet
1643 *
1644 * @param delay when should this operation time out?
1645 * @param rfd read file-descriptor
1646 * @param task main function of the task
1647 * @param task_cls closure of @a task
1648 * @return unique task identifier for the job
1649 * only valid until @a task is started!
1650 */
1651struct GNUNET_SCHEDULER_Task *
1652GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
1653 const struct GNUNET_DISK_FileHandle *rfd,
1654 GNUNET_SCHEDULER_TaskCallback task,
1655 void *task_cls)
1656{
1657 return GNUNET_SCHEDULER_add_file_with_priority (
1658 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1659 rfd, GNUNET_YES, GNUNET_NO,
1660 task, task_cls);
1661}
1662
1663
1664/**
1665 * Schedule a new task to be run with a specified delay or when the
1666 * specified file descriptor is ready for writing. The delay can be
1667 * used as a timeout on the socket being ready. The task will be
1668 * scheduled for execution once either the delay has expired or the
1669 * socket operation is ready. It will be run with the DEFAULT priority.
1670 * Only allowed to be called as long as the scheduler is running, that
1671 * is one of the following conditions is met:
1672 *
1673 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1674 * - #GNUNET_SCHEDULER_driver_init has been run and
1675 * #GNUNET_SCHEDULER_driver_done has not been called yet
1676 *
1677 * @param delay when should this operation time out?
1678 * @param wfd write file-descriptor
1679 * @param task main function of the task
1680 * @param task_cls closure of @a task
1681 * @return unique task identifier for the job
1682 * only valid until @a task is started!
1683 */
1684struct GNUNET_SCHEDULER_Task *
1685GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
1686 const struct GNUNET_DISK_FileHandle *wfd,
1687 GNUNET_SCHEDULER_TaskCallback task,
1688 void *task_cls)
1689{
1690 return GNUNET_SCHEDULER_add_file_with_priority (
1691 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1692 wfd, GNUNET_NO, GNUNET_YES,
1693 task, task_cls);
1694}
1695
1696
1697/**
1698 * Schedule a new task to be run with a specified delay or when the
1699 * specified file descriptor is ready. The delay can be
1700 * used as a timeout on the socket being ready. The task will be
1701 * scheduled for execution once either the delay has expired or the
1702 * socket operation is ready.
1703 * Only allowed to be called as long as the scheduler is running, that
1704 * is one of the following conditions is met:
1705 *
1706 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1707 * - #GNUNET_SCHEDULER_driver_init has been run and
1708 * #GNUNET_SCHEDULER_driver_done has not been called yet
1709 *
1710 * @param delay when should this operation time out?
1711 * @param priority priority of the task
1712 * @param fd file-descriptor
1713 * @param on_read whether to poll the file-descriptor for readability
1714 * @param on_write whether to poll the file-descriptor for writability
1715 * @param task main function of the task
1716 * @param task_cls closure of @a task
1717 * @return unique task identifier for the job
1718 * only valid until @a task is started!
1719 */
1720struct GNUNET_SCHEDULER_Task *
1721GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay,
1722 enum GNUNET_SCHEDULER_Priority
1723 priority,
1724 const struct
1725 GNUNET_DISK_FileHandle *fd,
1726 int on_read, int on_write,
1727 GNUNET_SCHEDULER_TaskCallback task,
1728 void *task_cls)
1729{
1730 /* scheduler must be running */
1731 GNUNET_assert (NULL != scheduler_driver);
1732 GNUNET_assert (on_read || on_write);
1733 GNUNET_assert (fd->fd >= 0);
1734 return add_without_sets (delay, priority,
1735 NULL,
1736 NULL,
1737 on_read ? fd : NULL,
1738 on_write ? fd : NULL,
1739 task, task_cls);
1740}
1741
1742
1743void
1744extract_handles (const struct GNUNET_NETWORK_FDSet *fdset,
1745 const struct GNUNET_NETWORK_Handle ***ntarget,
1746 unsigned int *extracted_nhandles,
1747 const struct GNUNET_DISK_FileHandle ***ftarget,
1748 unsigned int *extracted_fhandles)
1749{
1750 // FIXME: this implementation only works for unix, for WIN32 the file handles
1751 // in fdset must be handled separately
1752 const struct GNUNET_NETWORK_Handle **nhandles;
1753 const struct GNUNET_DISK_FileHandle **fhandles;
1754 unsigned int nhandles_len;
1755 unsigned int fhandles_len;
1756
1757 nhandles = NULL;
1758 fhandles = NULL;
1759 nhandles_len = 0;
1760 fhandles_len = 0;
1761 for (int sock = 0; sock != fdset->nsds; ++sock)
1762 {
1763 if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (fdset, sock))
1764 {
1765 struct GNUNET_NETWORK_Handle *nhandle;
1766 struct GNUNET_DISK_FileHandle *fhandle;
1767
1768 nhandle = GNUNET_NETWORK_socket_box_native (sock);
1769 if (NULL != nhandle)
1770 {
1771 GNUNET_array_append (nhandles, nhandles_len, nhandle);
1772 }
1773 else
1774 {
1775 fhandle = GNUNET_DISK_get_handle_from_int_fd (sock);
1776 if (NULL != fhandle)
1777 {
1778 GNUNET_array_append (fhandles, fhandles_len, fhandle);
1779 }
1780 else
1781 {
1782 GNUNET_assert (0);
1783 }
1784 }
1785 }
1786 }
1787 *ntarget = nhandles_len > 0 ? nhandles : NULL;
1788 *ftarget = fhandles_len > 0 ? fhandles : NULL;
1789 *extracted_nhandles = nhandles_len;
1790 *extracted_fhandles = fhandles_len;
1791}
1792
1793
1794/**
1795 * Schedule a new task to be run with a specified delay or when any of
1796 * the specified file descriptor sets is ready. The delay can be used
1797 * as a timeout on the socket(s) being ready. The task will be
1798 * scheduled for execution once either the delay has expired or any of
1799 * the socket operations is ready. This is the most general
1800 * function of the "add" family. Note that the "prerequisite_task"
1801 * must be satisfied in addition to any of the other conditions. In
1802 * other words, the task will be started when
1803 * <code>
1804 * (prerequisite-run)
1805 * && (delay-ready
1806 * || any-rs-ready
1807 * || any-ws-ready) )
1808 * </code>
1809 * Only allowed to be called as long as the scheduler is running, that
1810 * is one of the following conditions is met:
1811 *
1812 * - #GNUNET_SCHEDULER_run has been called and has not returned yet
1813 * - #GNUNET_SCHEDULER_driver_init has been run and
1814 * #GNUNET_SCHEDULER_driver_done has not been called yet
1815 *
1816 * @param prio how important is this task?
1817 * @param delay how long should we wait?
1818 * @param rs set of file descriptors we want to read (can be NULL)
1819 * @param ws set of file descriptors we want to write (can be NULL)
1820 * @param task main function of the task
1821 * @param task_cls closure of @a task
1822 * @return unique task identifier for the job
1823 * only valid until @a task is started!
1824 */
1825struct GNUNET_SCHEDULER_Task *
1826GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1827 struct GNUNET_TIME_Relative delay,
1828 const struct GNUNET_NETWORK_FDSet *rs,
1829 const struct GNUNET_NETWORK_FDSet *ws,
1830 GNUNET_SCHEDULER_TaskCallback task,
1831 void *task_cls)
1832{
1833 struct GNUNET_SCHEDULER_Task *t;
1834 const struct GNUNET_NETWORK_Handle **read_nhandles = NULL;
1835 const struct GNUNET_NETWORK_Handle **write_nhandles = NULL;
1836 const struct GNUNET_DISK_FileHandle **read_fhandles = NULL;
1837 const struct GNUNET_DISK_FileHandle **write_fhandles = NULL;
1838 unsigned int read_nhandles_len = 0;
1839 unsigned int write_nhandles_len = 0;
1840 unsigned int read_fhandles_len = 0;
1841 unsigned int write_fhandles_len = 0;
1842
1843 /* scheduler must be running */
1844 GNUNET_assert (NULL != scheduler_driver);
1845 GNUNET_assert (NULL != task);
1846 int no_rs = (NULL == rs);
1847 int no_ws = (NULL == ws);
1848 int empty_rs = (NULL != rs) && (0 == rs->nsds);
1849 int empty_ws = (NULL != ws) && (0 == ws->nsds);
1850 int no_fds = (no_rs && no_ws) ||
1851 (empty_rs && empty_ws) ||
1852 (no_rs && empty_ws) ||
1853 (no_ws && empty_rs);
1854 if (! no_fds)
1855 {
1856 if (NULL != rs)
1857 {
1858 extract_handles (rs,
1859 &read_nhandles,
1860 &read_nhandles_len,
1861 &read_fhandles,
1862 &read_fhandles_len);
1863 }
1864 if (NULL != ws)
1865 {
1866 extract_handles (ws,
1867 &write_nhandles,
1868 &write_nhandles_len,
1869 &write_fhandles,
1870 &write_fhandles_len);
1871 }
1872 }
1873 /**
1874 * here we consider the case that a GNUNET_NETWORK_FDSet might be empty
1875 * although its maximum FD number (nsds) is greater than 0. We handle
1876 * this case gracefully because some libraries such as libmicrohttpd
1877 * only provide a hint what the maximum FD number in an FD set might be
1878 * and not the exact FD number (see e.g. gnunet-rest-service.c)
1879 */int no_fds_extracted = (0 == read_nhandles_len) &&
1880 (0 == read_fhandles_len) &&
1881 (0 == write_nhandles_len) &&
1882 (0 == write_fhandles_len);
1883 if (no_fds || no_fds_extracted)
1884 return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
1885 prio,
1886 task,
1887 task_cls);
1888 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1889 GNUNET_async_scope_get (&t->scope);
1890 init_fd_info (t,
1891 read_nhandles,
1892 read_nhandles_len,
1893 write_nhandles,
1894 write_nhandles_len,
1895 read_fhandles,
1896 read_fhandles_len,
1897 write_fhandles,
1898 write_fhandles_len);
1899 t->callback = task;
1900 t->callback_cls = task_cls;
1901 t->own_handles = GNUNET_YES;
1902 /* free the arrays of pointers to network / file handles, the actual
1903 * handles will be freed in destroy_task */
1904 GNUNET_array_grow (read_nhandles, read_nhandles_len, 0);
1905 GNUNET_array_grow (write_nhandles, write_nhandles_len, 0);
1906 GNUNET_array_grow (read_fhandles, read_fhandles_len, 0);
1907 GNUNET_array_grow (write_fhandles, write_fhandles_len, 0);
1908#if PROFILE_DELAYS
1909 t->start_time = GNUNET_TIME_absolute_get ();
1910#endif
1911 t->timeout = GNUNET_TIME_relative_to_absolute (delay);
1912 t->priority =
1913 check_priority ((prio ==
1914 GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority :
1915 prio);
1916 t->lifeness = current_lifeness;
1917 GNUNET_CONTAINER_DLL_insert (pending_head,
1918 pending_tail,
1919 t);
1920 driver_add_multiple (t);
1921 max_priority_added = GNUNET_MAX (max_priority_added,
1922 t->priority);
1923 LOG (GNUNET_ERROR_TYPE_DEBUG,
1924 "Adding task %p\n",
1925 t);
1926 init_backtrace (t);
1927 return t;
1928}
1929
1930
1931/**
1932 * Function used by event-loop implementations to signal the scheduler
1933 * that a particular @a task is ready due to an event specified in the
1934 * et field of @a fdi.
1935 *
1936 * This function will then queue the task to notify the application
1937 * that the task is ready (with the respective priority).
1938 *
1939 * @param task the task that is ready
1940 * @param fdi information about the related FD
1941 */
1942void
1943GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task,
1944 struct GNUNET_SCHEDULER_FdInfo *fdi)
1945{
1946 enum GNUNET_SCHEDULER_Reason reason;
1947
1948 reason = task->reason;
1949 if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1950 (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)))
1951 reason |= GNUNET_SCHEDULER_REASON_READ_READY;
1952 if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
1953 (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)))
1954 reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
1955 reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
1956 task->reason = reason;
1957 if (GNUNET_NO == task->in_ready_list)
1958 {
1959 GNUNET_CONTAINER_DLL_remove (pending_head,
1960 pending_tail,
1961 task);
1962 queue_ready_task (task);
1963 }
1964}
1965
1966
1967/**
1968 * Function called by external event loop implementations to tell the
1969 * scheduler to run some of the tasks that are ready. Must be called
1970 * only after #GNUNET_SCHEDULER_driver_init has been called and before
1971 * #GNUNET_SCHEDULER_driver_done is called.
1972 * This function may return even though there are tasks left to run
1973 * just to give other tasks a chance as well. If we return #GNUNET_YES,
1974 * the event loop implementation should call this function again as
1975 * soon as possible, while if we return #GNUNET_NO it must block until
1976 * either the operating system has more work (the scheduler has no more
1977 * work to do right now) or the timeout set by the scheduler (using the
1978 * set_wakeup callback) is reached.
1979 *
1980 * @param sh scheduler handle that was returned by
1981 * #GNUNET_SCHEDULER_driver_init
1982 * @return #GNUNET_YES if there are more tasks that are ready,
1983 * and thus we would like to run more (yield to avoid
1984 * blocking other activities for too long) #GNUNET_NO
1985 * if we are done running tasks (yield to block)
1986 */
1987int
1988GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
1989{
1990 struct GNUNET_SCHEDULER_Task *pos;
1991 struct GNUNET_TIME_Absolute now;
1992
1993 /* check for tasks that reached the timeout! */
1994 now = GNUNET_TIME_absolute_get ();
1995 pos = pending_timeout_head;
1996 while (NULL != pos)
1997 {
1998 struct GNUNET_SCHEDULER_Task *next = pos->next;
1999 if (now.abs_value_us >= pos->timeout.abs_value_us)
2000 pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
2001 if (0 == pos->reason)
2002 break;
2003 GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
2004 pending_timeout_tail,
2005 pos);
2006 if (pending_timeout_last == pos)
2007 pending_timeout_last = NULL;
2008 queue_ready_task (pos);
2009 pos = next;
2010 }
2011 pos = pending_head;
2012 while (NULL != pos)
2013 {
2014 struct GNUNET_SCHEDULER_Task *next = pos->next;
2015 if (now.abs_value_us >= pos->timeout.abs_value_us)
2016 {
2017 pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
2018 GNUNET_CONTAINER_DLL_remove (pending_head,
2019 pending_tail,
2020 pos);
2021 queue_ready_task (pos);
2022 }
2023 pos = next;
2024 }
2025
2026 if (0 == ready_count)
2027 {
2028 struct GNUNET_TIME_Absolute timeout = get_timeout ();
2029
2030 if (timeout.abs_value_us > now.abs_value_us)
2031 {
2032 /**
2033 * The event loop called this function before the current timeout was
2034 * reached (and no FD tasks are ready). This is acceptable if
2035 *
2036 * - the system time was changed while the driver was waiting for
2037 * the timeout
2038 * - an external event loop called GNUnet API functions outside of
2039 * the callbacks called in GNUNET_SCHEDULER_do_work and thus
2040 * wasn't notified about the new timeout
2041 *
2042 * It might also mean we are busy-waiting because of a programming
2043 * error in the external event loop.
2044 */
2045 LOG (GNUNET_ERROR_TYPE_DEBUG,
2046 "GNUNET_SCHEDULER_do_work did not find any ready "
2047 "tasks and timeout has not been reached yet.\n");
2048 }
2049 else
2050 {
2051 /**
2052 * the current timeout was reached but no ready tasks were found,
2053 * internal scheduler error!
2054 */
2055 GNUNET_assert (0);
2056 }
2057 }
2058 else
2059 {
2060 struct GNUNET_SCHEDULER_Task *last;
2061
2062 /* find out which task priority level we are going to
2063 process this time */
2064 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
2065 GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
2066 /* yes, p>0 is correct, 0 is "KEEP" which should
2067 * always be an empty queue (see assertion)! */
2068 for (work_priority = GNUNET_SCHEDULER_PRIORITY_COUNT - 1;
2069 work_priority > 0;
2070 work_priority--)
2071 {
2072 pos = ready_head[work_priority];
2073 if (NULL != pos)
2074 break;
2075 }
2076 GNUNET_assert (NULL != pos); /* ready_count wrong? */
2077
2078 /* process all *existing* tasks at this priority
2079 level, then yield */
2080 last = ready_tail[work_priority];
2081 while (NULL != (pos = ready_head[work_priority]))
2082 {
2083 GNUNET_CONTAINER_DLL_remove (ready_head[work_priority],
2084 ready_tail[work_priority],
2085 pos);
2086 ready_count--;
2087 current_priority = pos->priority;
2088 current_lifeness = pos->lifeness;
2089 active_task = pos;
2090#if PROFILE_DELAYS
2091 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2092 DELAY_THRESHOLD.rel_value_us)
2093 {
2094 LOG (GNUNET_ERROR_TYPE_DEBUG,
2095 "Task %p took %s to be scheduled\n",
2096 pos,
2097 GNUNET_STRINGS_relative_time_to_string (
2098 GNUNET_TIME_absolute_get_duration (pos->start_time),
2099 GNUNET_YES));
2100 }
2101#endif
2102 tc.reason = pos->reason;
2103 GNUNET_NETWORK_fdset_zero (sh->rs);
2104 GNUNET_NETWORK_fdset_zero (sh->ws);
2105 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2106 tc.fds_len = pos->fds_len;
2107 tc.fds = pos->fds;
2108 for (unsigned int i = 0; i != pos->fds_len; ++i)
2109 {
2110 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i];
2111 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et))
2112 {
2113 GNUNET_NETWORK_fdset_set_native (sh->rs,
2114 fdi->sock);
2115 }
2116 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et))
2117 {
2118 GNUNET_NETWORK_fdset_set_native (sh->ws,
2119 fdi->sock);
2120 }
2121 }
2122 tc.read_ready = sh->rs;
2123 tc.write_ready = sh->ws;
2124 LOG (GNUNET_ERROR_TYPE_DEBUG,
2125 "Running task %p\n",
2126 pos);
2127 GNUNET_assert (NULL != pos->callback);
2128 {
2129 struct GNUNET_AsyncScopeSave old_scope;
2130 if (pos->scope.have_scope)
2131 GNUNET_async_scope_enter (&pos->scope.scope_id, &old_scope);
2132 else
2133 GNUNET_async_scope_get (&old_scope);
2134 pos->callback (pos->callback_cls);
2135 GNUNET_async_scope_restore (&old_scope);
2136 }
2137 if (NULL != pos->fds)
2138 {
2139 int del_result = scheduler_driver->del (scheduler_driver->cls,
2140 pos);
2141 if (GNUNET_OK != del_result)
2142 {
2143 LOG (GNUNET_ERROR_TYPE_ERROR,
2144 "driver could not delete task %p\n", pos);
2145 GNUNET_assert (0);
2146 }
2147 }
2148 active_task = NULL;
2149 dump_backtrace (pos);
2150 destroy_task (pos);
2151 /* pointer 'pos' was free'd, but we can still safely check for
2152 pointer equality still. */
2153 if (pos == last)
2154 break; /* All tasks that _were_ ready when we started were
2155 executed. New tasks may have been added in the
2156 meantime, but we should check with the OS to
2157 be sure no higher-priority actions are pending! */
2158 }
2159 }
2160 shutdown_if_no_lifeness ();
2161 if (0 == ready_count)
2162 {
2163 scheduler_driver->set_wakeup (scheduler_driver->cls,
2164 get_timeout ());
2165 return GNUNET_NO;
2166 }
2167 scheduler_driver->set_wakeup (scheduler_driver->cls,
2168 GNUNET_TIME_absolute_get ());
2169 return GNUNET_YES;
2170}
2171
2172
2173/**
2174 * Function called by external event loop implementations to initialize
2175 * the scheduler. An external implementation has to provide @a driver
2176 * which contains callbacks for the scheduler (see definition of struct
2177 * #GNUNET_SCHEDULER_Driver). The callbacks are used to instruct the
2178 * external implementation to watch for events. If it detects any of
2179 * those events it is expected to call #GNUNET_SCHEDULER_do_work to let
2180 * the scheduler handle it. If an event is related to a specific task
2181 * (e.g. the scheduler gave instructions to watch a file descriptor),
2182 * the external implementation is expected to mark that task ready
2183 * before by calling #GNUNET_SCHEDULER_task_ready.
2184
2185 * This function has to be called before any tasks are scheduled and
2186 * before GNUNET_SCHEDULER_do_work is called for the first time. It
2187 * allocates resources that have to be freed again by calling
2188 * #GNUNET_SCHEDULER_driver_done.
2189 *
2190 * This function installs the same signal handlers as
2191 * #GNUNET_SCHEDULER_run. This means SIGTERM (and other similar signals)
2192 * will induce a call to #GNUNET_SCHEDULER_shutdown during the next
2193 * call to #GNUNET_SCHEDULER_do_work. As a result, SIGTERM causes all
2194 * active tasks to be scheduled with reason
2195 * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added afterwards
2196 * will execute normally!). Note that any particular signal will only
2197 * shut down one scheduler; applications should always only create a
2198 * single scheduler.
2199 *
2200 * @param driver to use for the event loop
2201 * @return handle to be passed to #GNUNET_SCHEDULER_do_work and
2202 * #GNUNET_SCHEDULER_driver_done
2203 */
2204struct GNUNET_SCHEDULER_Handle *
2205GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
2206{
2207 struct GNUNET_SCHEDULER_Handle *sh;
2208 const struct GNUNET_DISK_FileHandle *pr;
2209
2210 /* scheduler must not be running */
2211 GNUNET_assert (NULL == scheduler_driver);
2212 GNUNET_assert (NULL == shutdown_pipe_handle);
2213 /* general set-up */
2214 sh = GNUNET_new (struct GNUNET_SCHEDULER_Handle);
2215 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
2216 GNUNET_assert (NULL != shutdown_pipe_handle);
2217 pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
2218 GNUNET_DISK_PIPE_END_READ);
2219 my_pid = getpid ();
2220 scheduler_driver = driver;
2221
2222 /* install signal handlers */
2223 LOG (GNUNET_ERROR_TYPE_DEBUG,
2224 "Registering signal handlers\n");
2225 sh->shc_int = GNUNET_SIGNAL_handler_install (SIGINT,
2226 &sighandler_shutdown);
2227 sh->shc_term = GNUNET_SIGNAL_handler_install (SIGTERM,
2228 &sighandler_shutdown);
2229#if (SIGTERM != GNUNET_TERM_SIG)
2230 sh->shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG,
2231 &sighandler_shutdown);
2232#endif
2233 sh->shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE,
2234 &sighandler_pipe);
2235 sh->shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT,
2236 &sighandler_shutdown);
2237 sh->shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP,
2238 &sighandler_shutdown);
2239
2240 /* Setup initial tasks */
2241 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
2242 current_lifeness = GNUNET_NO;
2243 /* ensure this task runs first, by using a priority level reserved for
2244 the scheduler (not really shutdown, but start-up ;-) */
2245 install_parent_control_task =
2246 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_SHUTDOWN,
2247 &install_parent_control_handler,
2248 NULL);
2249 shutdown_pipe_task =
2250 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2251 pr,
2252 &shutdown_pipe_cb,
2253 NULL);
2254 current_lifeness = GNUNET_YES;
2255 scheduler_driver->set_wakeup (scheduler_driver->cls,
2256 get_timeout ());
2257 /* begin main event loop */
2258 sh->rs = GNUNET_NETWORK_fdset_create ();
2259 sh->ws = GNUNET_NETWORK_fdset_create ();
2260 GNUNET_NETWORK_fdset_handle_set (sh->rs, pr);
2261 return sh;
2262}
2263
2264
2265/**
2266 * Counter-part of #GNUNET_SCHEDULER_driver_init. Has to be called
2267 * by external event loop implementations after the scheduler has
2268 * shut down. This is the case if both of the following conditions
2269 * are met:
2270 *
2271 * - all tasks the scheduler has added through the driver's add
2272 * callback have been removed again through the driver's del
2273 * callback
2274 * - the timeout the scheduler has set through the driver's
2275 * add_wakeup callback is FOREVER
2276 *
2277 * @param sh the handle returned by #GNUNET_SCHEDULER_driver_init
2278 */
2279void
2280GNUNET_SCHEDULER_driver_done (struct GNUNET_SCHEDULER_Handle *sh)
2281{
2282 GNUNET_assert (NULL == pending_head);
2283 GNUNET_assert (NULL == pending_timeout_head);
2284 GNUNET_assert (NULL == shutdown_head);
2285 for (int i = 0; i != GNUNET_SCHEDULER_PRIORITY_COUNT; ++i)
2286 {
2287 GNUNET_assert (NULL == ready_head[i]);
2288 }
2289 GNUNET_NETWORK_fdset_destroy (sh->rs);
2290 GNUNET_NETWORK_fdset_destroy (sh->ws);
2291
2292 /* uninstall signal handlers */
2293 GNUNET_SIGNAL_handler_uninstall (sh->shc_int);
2294 GNUNET_SIGNAL_handler_uninstall (sh->shc_term);
2295#if (SIGTERM != GNUNET_TERM_SIG)
2296 GNUNET_SIGNAL_handler_uninstall (sh->shc_gterm);
2297#endif
2298 GNUNET_SIGNAL_handler_uninstall (sh->shc_pipe);
2299 GNUNET_SIGNAL_handler_uninstall (sh->shc_quit);
2300 GNUNET_SIGNAL_handler_uninstall (sh->shc_hup);
2301 GNUNET_DISK_pipe_close (shutdown_pipe_handle);
2302 shutdown_pipe_handle = NULL;
2303 scheduler_driver = NULL;
2304 GNUNET_free (sh);
2305}
2306
2307
2308static int
2309select_loop (struct GNUNET_SCHEDULER_Handle *sh,
2310 struct DriverContext *context)
2311{
2312 struct GNUNET_NETWORK_FDSet *rs;
2313 struct GNUNET_NETWORK_FDSet *ws;
2314 int select_result;
2315
2316 GNUNET_assert (NULL != context);
2317 rs = GNUNET_NETWORK_fdset_create ();
2318 ws = GNUNET_NETWORK_fdset_create ();
2319 while ((NULL != context->scheduled_head) ||
2320 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
2321 context->timeout.abs_value_us))
2322 {
2323 struct GNUNET_TIME_Relative time_remaining;
2324
2325 LOG (GNUNET_ERROR_TYPE_DEBUG,
2326 "select timeout = %s\n",
2327 GNUNET_STRINGS_absolute_time_to_string (context->timeout));
2328
2329 GNUNET_NETWORK_fdset_zero (rs);
2330 GNUNET_NETWORK_fdset_zero (ws);
2331
2332 for (struct Scheduled *pos = context->scheduled_head;
2333 NULL != pos;
2334 pos = pos->next)
2335 {
2336 if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et))
2337 {
2338 GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock);
2339 }
2340 if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et))
2341 {
2342 GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock);
2343 }
2344 }
2345 time_remaining = GNUNET_TIME_absolute_get_remaining (context->timeout);
2346 if (0 < ready_count)
2347 time_remaining = GNUNET_TIME_UNIT_ZERO;
2348 if (NULL == scheduler_select)
2349 {
2350 select_result = GNUNET_NETWORK_socket_select (rs,
2351 ws,
2352 NULL,
2353 time_remaining);
2354 }
2355 else
2356 {
2357 select_result = scheduler_select (scheduler_select_cls,
2358 rs,
2359 ws,
2360 NULL,
2361 time_remaining);
2362 }
2363 if (select_result == GNUNET_SYSERR)
2364 {
2365 if (errno == EINTR)
2366 continue;
2367
2368 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
2369 "select");
2370#if USE_LSOF
2371 char lsof[512];
2372
2373 snprintf (lsof,
2374 sizeof(lsof),
2375 "lsof -p %d",
2376 getpid ());
2377 (void) close (1);
2378 (void) dup2 (2, 1);
2379 if (0 != system (lsof))
2380 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
2381 "system");
2382#endif
2383#if DEBUG_FDS
2384 for (struct Scheduled *s = context->scheduled_head;
2385 NULL != s;
2386 s = s->next)
2387 {
2388 int flags = fcntl (s->fdi->sock,
2389 F_GETFD);
2390
2391 if ((flags == -1) &&
2392 (EBADF == errno))
2393 {
2394 LOG (GNUNET_ERROR_TYPE_ERROR,
2395 "Got invalid file descriptor %d!\n",
2396 s->fdi->sock);
2397#if EXECINFO
2398 dump_backtrace (s->task);
2399#endif
2400 }
2401 }
2402#endif
2403 GNUNET_assert (0);
2404 GNUNET_NETWORK_fdset_destroy (rs);
2405 GNUNET_NETWORK_fdset_destroy (ws);
2406 return GNUNET_SYSERR;
2407 }
2408 if (select_result > 0)
2409 {
2410 for (struct Scheduled *pos = context->scheduled_head;
2411 NULL != pos;
2412 pos = pos->next)
2413 {
2414 int is_ready = GNUNET_NO;
2415
2416 if ((0 != (GNUNET_SCHEDULER_ET_IN & pos->et)) &&
2417 (GNUNET_YES ==
2418 GNUNET_NETWORK_fdset_test_native (rs,
2419 pos->fdi->sock)) )
2420 {
2421 pos->fdi->et |= GNUNET_SCHEDULER_ET_IN;
2422 is_ready = GNUNET_YES;
2423 }
2424 if ((0 != (GNUNET_SCHEDULER_ET_OUT & pos->et)) &&
2425 (GNUNET_YES ==
2426 GNUNET_NETWORK_fdset_test_native (ws,
2427 pos->fdi->sock)) )
2428 {
2429 pos->fdi->et |= GNUNET_SCHEDULER_ET_OUT;
2430 is_ready = GNUNET_YES;
2431 }
2432 if (GNUNET_YES == is_ready)
2433 {
2434 GNUNET_SCHEDULER_task_ready (pos->task,
2435 pos->fdi);
2436 }
2437 }
2438 }
2439 if (GNUNET_YES == GNUNET_SCHEDULER_do_work (sh))
2440 {
2441 LOG (GNUNET_ERROR_TYPE_DEBUG,
2442 "scheduler has more tasks ready!\n");
2443 }
2444 }
2445 GNUNET_NETWORK_fdset_destroy (rs);
2446 GNUNET_NETWORK_fdset_destroy (ws);
2447 return GNUNET_OK;
2448}
2449
2450
2451static int
2452select_add (void *cls,
2453 struct GNUNET_SCHEDULER_Task *task,
2454 struct GNUNET_SCHEDULER_FdInfo *fdi)
2455{
2456 struct DriverContext *context = cls;
2457
2458 GNUNET_assert (NULL != context);
2459 GNUNET_assert (NULL != task);
2460 GNUNET_assert (NULL != fdi);
2461 GNUNET_assert (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et) ||
2462 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et));
2463
2464 if (! ((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0))
2465 {
2466 /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */
2467 return GNUNET_SYSERR;
2468 }
2469
2470 struct Scheduled *scheduled = GNUNET_new (struct Scheduled);
2471 scheduled->task = task;
2472 scheduled->fdi = fdi;
2473 scheduled->et = fdi->et;
2474
2475 GNUNET_CONTAINER_DLL_insert (context->scheduled_head,
2476 context->scheduled_tail,
2477 scheduled);
2478 return GNUNET_OK;
2479}
2480
2481
2482static int
2483select_del (void *cls,
2484 struct GNUNET_SCHEDULER_Task *task)
2485{
2486 struct DriverContext *context;
2487 struct Scheduled *pos;
2488 int ret;
2489
2490 GNUNET_assert (NULL != cls);
2491
2492 context = cls;
2493 ret = GNUNET_SYSERR;
2494 pos = context->scheduled_head;
2495 while (NULL != pos)
2496 {
2497 struct Scheduled *next = pos->next;
2498 if (pos->task == task)
2499 {
2500 GNUNET_CONTAINER_DLL_remove (context->scheduled_head,
2501 context->scheduled_tail,
2502 pos);
2503 GNUNET_free (pos);
2504 ret = GNUNET_OK;
2505 }
2506 pos = next;
2507 }
2508 return ret;
2509}
2510
2511
2512static void
2513select_set_wakeup (void *cls,
2514 struct GNUNET_TIME_Absolute dt)
2515{
2516 struct DriverContext *context = cls;
2517
2518 GNUNET_assert (NULL != context);
2519 context->timeout = dt;
2520}
2521
2522
2523/**
2524 * Obtain the driver for using select() as the event loop.
2525 *
2526 * @return NULL on error
2527 */
2528struct GNUNET_SCHEDULER_Driver *
2529GNUNET_SCHEDULER_driver_select ()
2530{
2531 struct GNUNET_SCHEDULER_Driver *select_driver;
2532
2533 select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver);
2534
2535 select_driver->add = &select_add;
2536 select_driver->del = &select_del;
2537 select_driver->set_wakeup = &select_set_wakeup;
2538
2539 return select_driver;
2540}
2541
2542
2543/**
2544 * Change the async scope for the currently executing task and (transitively)
2545 * for all tasks scheduled by the current task after calling this function.
2546 * Nested tasks can begin their own nested async scope.
2547 *
2548 * Once the current task is finished, the async scope ID is reset to
2549 * its previous value.
2550 *
2551 * Must only be called from a running task.
2552 *
2553 * @param aid the asynchronous scope id to enter
2554 */
2555void
2556GNUNET_SCHEDULER_begin_async_scope (struct GNUNET_AsyncScopeId *aid)
2557{
2558 struct GNUNET_AsyncScopeSave dummy_old_scope;
2559
2560 GNUNET_assert (NULL != active_task);
2561 /* Since we're in a task, the context will be automatically
2562 restored by the scheduler. */
2563 GNUNET_async_scope_enter (aid, &dummy_old_scope);
2564}
2565
2566
2567/* end of scheduler.c */
diff --git a/src/util/service.c b/src/util/service.c
deleted file mode 100644
index c48060437..000000000
--- a/src/util/service.c
+++ /dev/null
@@ -1,2448 +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,
674 const struct GNUNET_MessageHeader *message)
675{
676 struct GNUNET_SERVICE_Client *client = cls;
677
678 LOG (GNUNET_ERROR_TYPE_DEBUG,
679 "Received message of type %u and size %u from client\n",
680 ntohs (message->type),
681 ntohs (message->size));
682 GNUNET_assert (GNUNET_NO == client->needs_continue);
683 client->needs_continue = GNUNET_YES;
684 client->warn_type = ntohs (message->type);
685 client->warn_start = GNUNET_TIME_absolute_get ();
686 GNUNET_assert (NULL == client->warn_task);
687 client->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
688 &warn_no_client_continue,
689 client);
690 GNUNET_MQ_inject_message (client->mq, message);
691 if (NULL != client->drop_task)
692 return GNUNET_SYSERR;
693 return GNUNET_OK;
694}
695
696
697/**
698 * A client sent us data. Receive and process it. If we are done,
699 * reschedule this task.
700 *
701 * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
702 */
703static void
704service_client_recv (void *cls)
705{
706 struct GNUNET_SERVICE_Client *client = cls;
707 enum GNUNET_GenericReturnValue ret;
708
709 client->recv_task = NULL;
710 ret = GNUNET_MST_read (client->mst,
711 client->sock,
712 GNUNET_NO,
713 GNUNET_YES);
714 if (GNUNET_SYSERR == ret)
715 {
716 /* client closed connection (or IO error) */
717 if (NULL == client->drop_task)
718 {
719 GNUNET_assert (GNUNET_NO == client->needs_continue);
720 GNUNET_SERVICE_client_drop (client);
721 }
722 return;
723 }
724 if (GNUNET_NO == ret)
725 return; /* more messages in buffer, wait for application
726 to be done processing */
727 GNUNET_assert (GNUNET_OK == ret);
728 if (GNUNET_YES == client->needs_continue)
729 return;
730 if (NULL != client->recv_task)
731 return;
732 /* MST needs more data, re-schedule read job */
733 client->recv_task =
734 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
735 client->sock,
736 &service_client_recv,
737 client);
738}
739
740
741/**
742 * We have successfully accepted a connection from a client. Now
743 * setup the client (with the scheduler) and tell the application.
744 *
745 * @param sh service that accepted the client
746 * @param sock socket associated with the client
747 */
748static void
749start_client (struct GNUNET_SERVICE_Handle *sh,
750 struct GNUNET_NETWORK_Handle *csock)
751{
752 struct GNUNET_SERVICE_Client *client;
753
754 client = GNUNET_new (struct GNUNET_SERVICE_Client);
755 GNUNET_CONTAINER_DLL_insert (sh->clients_head, sh->clients_tail, client);
756 client->sh = sh;
757 client->sock = csock;
758 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
759 NULL,
760 &service_mq_cancel,
761 client,
762 sh->handlers,
763 &service_mq_error_handler,
764 client);
765 client->mst = GNUNET_MST_create (&service_client_mst_cb, client);
766 if (NULL != sh->connect_cb)
767 client->user_context = sh->connect_cb (sh->cb_cls, client, client->mq);
768 GNUNET_MQ_set_handlers_closure (client->mq, client->user_context);
769 client->recv_task =
770 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
771 client->sock,
772 &service_client_recv,
773 client);
774}
775
776
777/**
778 * We have a client. Accept the incoming socket(s) (and reschedule
779 * the listen task).
780 *
781 * @param cls the `struct ServiceListenContext` of the ready listen socket
782 */
783static void
784accept_client (void *cls)
785{
786 struct ServiceListenContext *slc = cls;
787 struct GNUNET_SERVICE_Handle *sh = slc->sh;
788
789 slc->listen_task = NULL;
790 while (1)
791 {
792 struct GNUNET_NETWORK_Handle *sock;
793 const struct sockaddr_in *v4;
794 const struct sockaddr_in6 *v6;
795 struct sockaddr_storage sa;
796 socklen_t addrlen;
797 int ok;
798
799 addrlen = sizeof(sa);
800 sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
801 (struct sockaddr *) &sa,
802 &addrlen);
803 if (NULL == sock)
804 {
805 if (EMFILE == errno)
806 do_suspend (sh, SUSPEND_STATE_EMFILE);
807 else if (EAGAIN != errno)
808 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
809 break;
810 }
811 switch (sa.ss_family)
812 {
813 case AF_INET:
814 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
815 v4 = (const struct sockaddr_in *) &sa;
816 ok = (((NULL == sh->v4_allowed) ||
817 (check_ipv4_listed (sh->v4_allowed, &v4->sin_addr))) &&
818 ((NULL == sh->v4_denied) ||
819 (! check_ipv4_listed (sh->v4_denied, &v4->sin_addr))));
820 break;
821
822 case AF_INET6:
823 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
824 v6 = (const struct sockaddr_in6 *) &sa;
825 ok = (((NULL == sh->v6_allowed) ||
826 (check_ipv6_listed (sh->v6_allowed, &v6->sin6_addr))) &&
827 ((NULL == sh->v6_denied) ||
828 (! check_ipv6_listed (sh->v6_denied, &v6->sin6_addr))));
829 break;
830
831 case AF_UNIX:
832 ok = GNUNET_OK; /* controlled using file-system ACL now */
833 break;
834
835 default:
836 LOG (GNUNET_ERROR_TYPE_WARNING,
837 _ ("Unknown address family %d\n"),
838 sa.ss_family);
839 return;
840 }
841 if (! ok)
842 {
843 LOG (GNUNET_ERROR_TYPE_DEBUG,
844 "Service rejected incoming connection from %s due to policy.\n",
845 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
846 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
847 continue;
848 }
849 LOG (GNUNET_ERROR_TYPE_DEBUG,
850 "Service accepted incoming connection from %s.\n",
851 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
852 start_client (slc->sh, sock);
853 }
854 if (0 != sh->suspend_state)
855 return;
856 slc->listen_task =
857 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
858 slc->listen_socket,
859 &accept_client,
860 slc);
861}
862
863
864/**
865 * Resume accepting connections from the listen socket.
866 *
867 * @param sh service to resume accepting connections.
868 * @param sr reason that is no longer causing the suspension,
869 * or #SUSPEND_STATE_NONE on first startup
870 */
871static void
872do_resume (struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
873{
874 struct ServiceListenContext *slc;
875
876 GNUNET_assert ((SUSPEND_STATE_NONE == sr) || (0 != (sh->suspend_state & sr)));
877 sh->suspend_state -= sr;
878 if (SUSPEND_STATE_NONE != sh->suspend_state)
879 return;
880 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
881 {
882 GNUNET_assert (NULL == slc->listen_task);
883 slc->listen_task =
884 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
885 slc->listen_socket,
886 &accept_client,
887 slc);
888 }
889}
890
891
892/**
893 * First task run by any service. Initializes our shutdown task,
894 * starts the listening operation on our listen sockets and launches
895 * the custom logic of the application service.
896 *
897 * @param cls our `struct GNUNET_SERVICE_Handle`
898 */
899static void
900service_main (void *cls)
901{
902 struct GNUNET_SERVICE_Handle *sh = cls;
903
904 if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN !=
905 (sh->options & GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK))
906 GNUNET_SCHEDULER_add_shutdown (&service_shutdown, sh);
907 do_resume (sh, SUSPEND_STATE_NONE);
908
909 if (-1 != sh->ready_confirm_fd)
910 {
911 GNUNET_break (1 == write (sh->ready_confirm_fd, ".", 1));
912 GNUNET_break (0 == close (sh->ready_confirm_fd));
913 sh->ready_confirm_fd = -1;
914 }
915
916 if (NULL != sh->service_init_cb)
917 sh->service_init_cb (sh->cb_cls, sh->cfg, sh);
918}
919
920
921/**
922 * Parse an IPv4 access control list.
923 *
924 * @param ret location where to write the ACL (set)
925 * @param sh service context to use to get the configuration
926 * @param option name of the ACL option to parse
927 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
928 * no ACL configured)
929 */
930static int
931process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
932 struct GNUNET_SERVICE_Handle *sh,
933 const char *option)
934{
935 char *opt;
936
937 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
938 {
939 *ret = NULL;
940 return GNUNET_OK;
941 }
942 GNUNET_break (GNUNET_OK ==
943 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
944 sh->service_name,
945 option,
946 &opt));
947 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
948 {
949 LOG (GNUNET_ERROR_TYPE_WARNING,
950 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
951 opt,
952 sh->service_name,
953 option);
954 GNUNET_free (opt);
955 return GNUNET_SYSERR;
956 }
957 GNUNET_free (opt);
958 return GNUNET_OK;
959}
960
961
962/**
963 * Parse an IPv6 access control list.
964 *
965 * @param ret location where to write the ACL (set)
966 * @param sh service context to use to get the configuration
967 * @param option name of the ACL option to parse
968 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
969 * no ACL configured)
970 */
971static int
972process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
973 struct GNUNET_SERVICE_Handle *sh,
974 const char *option)
975{
976 char *opt;
977
978 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
979 {
980 *ret = NULL;
981 return GNUNET_OK;
982 }
983 GNUNET_break (GNUNET_OK ==
984 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
985 sh->service_name,
986 option,
987 &opt));
988 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
989 {
990 LOG (GNUNET_ERROR_TYPE_WARNING,
991 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
992 opt,
993 sh->service_name,
994 option);
995 GNUNET_free (opt);
996 return GNUNET_SYSERR;
997 }
998 GNUNET_free (opt);
999 return GNUNET_OK;
1000}
1001
1002
1003/**
1004 * Add the given UNIX domain path as an address to the
1005 * list (as the first entry).
1006 *
1007 * @param saddrs array to update
1008 * @param saddrlens where to store the address length
1009 * @param unixpath path to add
1010 */
1011static void
1012add_unixpath (struct sockaddr **saddrs,
1013 socklen_t *saddrlens,
1014 const char *unixpath)
1015{
1016#ifdef AF_UNIX
1017 struct sockaddr_un *un;
1018
1019 un = GNUNET_new (struct sockaddr_un);
1020 un->sun_family = AF_UNIX;
1021 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
1022#if HAVE_SOCKADDR_UN_SUN_LEN
1023 un->sun_len = (u_char) sizeof(struct sockaddr_un);
1024#endif
1025 *saddrs = (struct sockaddr *) un;
1026 *saddrlens = sizeof(struct sockaddr_un);
1027#else
1028 /* this function should never be called
1029 * unless AF_UNIX is defined! */
1030 GNUNET_assert (0);
1031#endif
1032}
1033
1034
1035/**
1036 * Get the list of addresses that a server for the given service
1037 * should bind to.
1038 *
1039 * @param service_name name of the service
1040 * @param cfg configuration (which specifies the addresses)
1041 * @param addrs set (call by reference) to an array of pointers to the
1042 * addresses the server should bind to and listen on; the
1043 * array will be NULL-terminated (on success)
1044 * @param addr_lens set (call by reference) to an array of the lengths
1045 * of the respective `struct sockaddr` struct in the @a addrs
1046 * array (on success)
1047 * @return number of addresses found on success,
1048 * #GNUNET_SYSERR if the configuration
1049 * did not specify reasonable finding information or
1050 * if it specified a hostname that could not be resolved;
1051 * #GNUNET_NO if the number of addresses configured is
1052 * zero (in this case, `*addrs` and `*addr_lens` will be
1053 * set to NULL).
1054 */
1055static int
1056get_server_addresses (const char *service_name,
1057 const struct GNUNET_CONFIGURATION_Handle *cfg,
1058 struct sockaddr ***addrs,
1059 socklen_t **addr_lens)
1060{
1061 int disablev6;
1062 struct GNUNET_NETWORK_Handle *desc;
1063 unsigned long long port;
1064 char *unixpath;
1065 struct addrinfo hints;
1066 struct addrinfo *res;
1067 struct addrinfo *pos;
1068 struct addrinfo *next;
1069 unsigned int i;
1070 int resi;
1071 int ret;
1072 struct sockaddr **saddrs;
1073 socklen_t *saddrlens;
1074 char *hostname;
1075
1076 *addrs = NULL;
1077 *addr_lens = NULL;
1078 desc = NULL;
1079 disablev6 = GNUNET_NO;
1080 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
1081 (GNUNET_YES ==
1082 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1083 disablev6 = GNUNET_YES;
1084
1085 port = 0;
1086 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1087 {
1088 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1089 service_name,
1090 "PORT",
1091 &port))
1092 {
1093 LOG (GNUNET_ERROR_TYPE_ERROR,
1094 _ ("Require valid port number for service `%s' in configuration!\n"),
1095 service_name);
1096 }
1097 if (port > 65535)
1098 {
1099 LOG (GNUNET_ERROR_TYPE_ERROR,
1100 _ ("Require valid port number for service `%s' in configuration!\n"),
1101 service_name);
1102 return GNUNET_SYSERR;
1103 }
1104 }
1105
1106 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1107 {
1108 GNUNET_break (GNUNET_OK ==
1109 GNUNET_CONFIGURATION_get_value_string (cfg,
1110 service_name,
1111 "BINDTO",
1112 &hostname));
1113 }
1114 else
1115 hostname = NULL;
1116
1117 unixpath = NULL;
1118#ifdef AF_UNIX
1119 if ((GNUNET_YES ==
1120 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1121 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1122 service_name,
1123 "UNIXPATH",
1124 &unixpath)) &&
1125 (0 < strlen (unixpath)))
1126 {
1127 /* probe UNIX support */
1128 struct sockaddr_un s_un;
1129
1130 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1131 {
1132 LOG (GNUNET_ERROR_TYPE_WARNING,
1133 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1134 unixpath,
1135 (unsigned long long) sizeof(s_un.sun_path));
1136 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1137 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1138 }
1139 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath))
1140 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1141 }
1142 if (NULL != unixpath)
1143 {
1144 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1145 if (NULL == desc)
1146 {
1147 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1148 (EACCES == errno))
1149 {
1150 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
1151 GNUNET_free (hostname);
1152 GNUNET_free (unixpath);
1153 return GNUNET_SYSERR;
1154 }
1155 LOG (GNUNET_ERROR_TYPE_INFO,
1156 _ (
1157 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1158 service_name,
1159 strerror (errno));
1160 GNUNET_free (unixpath);
1161 unixpath = NULL;
1162 }
1163 else
1164 {
1165 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1166 desc = NULL;
1167 }
1168 }
1169#endif
1170
1171 if ((0 == port) && (NULL == unixpath))
1172 {
1173 LOG (GNUNET_ERROR_TYPE_ERROR,
1174 _ (
1175 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1176 service_name);
1177 GNUNET_free (hostname);
1178 return GNUNET_SYSERR;
1179 }
1180 if (0 == port)
1181 {
1182 saddrs = GNUNET_new_array (2, struct sockaddr *);
1183 saddrlens = GNUNET_new_array (2, socklen_t);
1184 add_unixpath (saddrs, saddrlens, unixpath);
1185 GNUNET_free (unixpath);
1186 GNUNET_free (hostname);
1187 *addrs = saddrs;
1188 *addr_lens = saddrlens;
1189 return 1;
1190 }
1191
1192 if (NULL != hostname)
1193 {
1194 LOG (GNUNET_ERROR_TYPE_DEBUG,
1195 "Resolving `%s' since that is where `%s' will bind to.\n",
1196 hostname,
1197 service_name);
1198 memset (&hints, 0, sizeof(struct addrinfo));
1199 if (disablev6)
1200 hints.ai_family = AF_INET;
1201 hints.ai_protocol = IPPROTO_TCP;
1202 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1203 (NULL == res))
1204 {
1205 LOG (GNUNET_ERROR_TYPE_ERROR,
1206 _ ("Failed to resolve `%s': %s\n"),
1207 hostname,
1208 gai_strerror (ret));
1209 GNUNET_free (hostname);
1210 GNUNET_free (unixpath);
1211 return GNUNET_SYSERR;
1212 }
1213 next = res;
1214 i = 0;
1215 while (NULL != (pos = next))
1216 {
1217 next = pos->ai_next;
1218 if ((disablev6) && (pos->ai_family == AF_INET6))
1219 continue;
1220 i++;
1221 }
1222 if (0 == i)
1223 {
1224 LOG (GNUNET_ERROR_TYPE_ERROR,
1225 _ ("Failed to find %saddress for `%s'.\n"),
1226 disablev6 ? "IPv4 " : "",
1227 hostname);
1228 freeaddrinfo (res);
1229 GNUNET_free (hostname);
1230 GNUNET_free (unixpath);
1231 return GNUNET_SYSERR;
1232 }
1233 resi = i;
1234 if (NULL != unixpath)
1235 resi++;
1236 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1237 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1238 i = 0;
1239 if (NULL != unixpath)
1240 {
1241 add_unixpath (saddrs, saddrlens, unixpath);
1242 i++;
1243 }
1244 next = res;
1245 while (NULL != (pos = next))
1246 {
1247 next = pos->ai_next;
1248 if ((disablev6) && (AF_INET6 == pos->ai_family))
1249 continue;
1250 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1251 continue; /* not TCP */
1252 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1253 continue; /* huh? */
1254 LOG (GNUNET_ERROR_TYPE_DEBUG,
1255 "Service `%s' will bind to `%s'\n",
1256 service_name,
1257 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1258 if (AF_INET == pos->ai_family)
1259 {
1260 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1261 saddrlens[i] = pos->ai_addrlen;
1262 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1263 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1264 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1265 }
1266 else
1267 {
1268 GNUNET_assert (AF_INET6 == pos->ai_family);
1269 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1270 saddrlens[i] = pos->ai_addrlen;
1271 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1272 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1273 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1274 }
1275 i++;
1276 }
1277 GNUNET_free (hostname);
1278 freeaddrinfo (res);
1279 resi = i;
1280 }
1281 else
1282 {
1283 /* will bind against everything, just set port */
1284 if (disablev6)
1285 {
1286 /* V4-only */
1287 resi = 1;
1288 if (NULL != unixpath)
1289 resi++;
1290 i = 0;
1291 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1292 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1293 if (NULL != unixpath)
1294 {
1295 add_unixpath (saddrs, saddrlens, unixpath);
1296 i++;
1297 }
1298 saddrlens[i] = sizeof(struct sockaddr_in);
1299 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1300#if HAVE_SOCKADDR_IN_SIN_LEN
1301 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1302#endif
1303 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1304 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1305 }
1306 else
1307 {
1308 /* dual stack */
1309 resi = 2;
1310 if (NULL != unixpath)
1311 resi++;
1312 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1313 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1314 i = 0;
1315 if (NULL != unixpath)
1316 {
1317 add_unixpath (saddrs, saddrlens, unixpath);
1318 i++;
1319 }
1320 saddrlens[i] = sizeof(struct sockaddr_in6);
1321 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1322#if HAVE_SOCKADDR_IN_SIN_LEN
1323 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1324#endif
1325 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1326 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1327 i++;
1328 saddrlens[i] = sizeof(struct sockaddr_in);
1329 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1330#if HAVE_SOCKADDR_IN_SIN_LEN
1331 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1332#endif
1333 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1334 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1335 }
1336 }
1337 GNUNET_free (unixpath);
1338 *addrs = saddrs;
1339 *addr_lens = saddrlens;
1340 return resi;
1341}
1342
1343
1344/**
1345 * Create and initialize a listen socket for the server.
1346 *
1347 * @param server_addr address to listen on
1348 * @param socklen length of @a server_addr
1349 * @return NULL on error, otherwise the listen socket
1350 */
1351static struct GNUNET_NETWORK_Handle *
1352open_listen_socket (const struct sockaddr *server_addr,
1353 socklen_t socklen)
1354{
1355 struct GNUNET_NETWORK_Handle *sock;
1356 uint16_t port;
1357 int eno;
1358
1359 switch (server_addr->sa_family)
1360 {
1361 case AF_INET:
1362 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
1363 break;
1364 case AF_INET6:
1365 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
1366 break;
1367 case AF_UNIX:
1368 port = 0;
1369 break;
1370 default:
1371 GNUNET_break (0);
1372 port = 0;
1373 break;
1374 }
1375 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
1376 SOCK_STREAM,
1377 0);
1378 if (NULL == sock)
1379 {
1380 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1381 "socket");
1382 errno = 0;
1383 return NULL;
1384 }
1385 /* bind the socket */
1386 if (GNUNET_OK !=
1387 GNUNET_NETWORK_socket_bind (sock,
1388 server_addr,
1389 socklen))
1390 {
1391 eno = errno;
1392 if (EADDRINUSE != errno)
1393 {
1394 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
1395 * fail if we already took the port on IPv6; if both IPv4 and
1396 * IPv6 binds fail, then our caller will log using the
1397 * errno preserved in 'eno' */
1398 if (0 != port)
1399 LOG (GNUNET_ERROR_TYPE_ERROR,
1400 _ ("`%s' failed for port %d (%s).\n"),
1401 "bind",
1402 port,
1403 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1404 else
1405 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
1406 eno = 0;
1407 }
1408 else
1409 {
1410 if (0 != port)
1411 LOG (GNUNET_ERROR_TYPE_WARNING,
1412 _ ("`%s' failed for port %d (%s): address already in use\n"),
1413 "bind",
1414 port,
1415 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1416 else if (AF_UNIX == server_addr->sa_family)
1417 {
1418 LOG (GNUNET_ERROR_TYPE_WARNING,
1419 _ ("`%s' failed for `%s': address already in use\n"),
1420 "bind",
1421 GNUNET_a2s (server_addr, socklen));
1422 }
1423 }
1424 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1425 errno = eno;
1426 return NULL;
1427 }
1428 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1429 {
1430 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "listen");
1431 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1432 errno = 0;
1433 return NULL;
1434 }
1435 if (0 != port)
1436 LOG (GNUNET_ERROR_TYPE_DEBUG,
1437 "Server starts to listen on port %u.\n",
1438 port);
1439 return sock;
1440}
1441
1442
1443/**
1444 * Setup service handle
1445 *
1446 * Configuration may specify:
1447 * - PORT (where to bind to for TCP)
1448 * - UNIXPATH (where to bind to for UNIX domain sockets)
1449 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
1450 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
1451 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
1452 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
1453 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
1454 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
1455 *
1456 * @param sh service context to initialize
1457 * @return #GNUNET_OK if configuration succeeded
1458 */
1459static int
1460setup_service (struct GNUNET_SERVICE_Handle *sh)
1461{
1462 int tolerant;
1463 struct GNUNET_NETWORK_Handle **csocks = NULL;
1464 struct GNUNET_NETWORK_Handle **lsocks;
1465 const char *nfds;
1466 unsigned int cnt;
1467 int flags;
1468 char dummy[2];
1469
1470 if (GNUNET_CONFIGURATION_have_value (sh->cfg,
1471 sh->service_name,
1472 "TOLERANT"))
1473 {
1474 if (GNUNET_SYSERR ==
1475 (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1476 sh->service_name,
1477 "TOLERANT")))
1478 {
1479 LOG (GNUNET_ERROR_TYPE_ERROR,
1480 _ ("Specified value for `%s' of service `%s' is invalid\n"),
1481 "TOLERANT",
1482 sh->service_name);
1483 return GNUNET_SYSERR;
1484 }
1485 }
1486 else
1487 tolerant = GNUNET_NO;
1488
1489 lsocks = NULL;
1490 errno = 0;
1491 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1492 (1 == sscanf (nfds, "%u%1s", &cnt, dummy)) && (cnt > 0) &&
1493 (cnt < FD_SETSIZE) && (cnt + 4 < FD_SETSIZE))
1494 {
1495 lsocks = GNUNET_new_array (cnt + 1, struct GNUNET_NETWORK_Handle *);
1496 while (0 < cnt--)
1497 {
1498 flags = fcntl (3 + cnt, F_GETFD);
1499 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
1500 (NULL == (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1501 {
1502 LOG (GNUNET_ERROR_TYPE_ERROR,
1503 _ (
1504 "Could not access pre-bound socket %u, will try to bind myself\n"),
1505 (unsigned int) 3 + cnt);
1506 cnt++;
1507 while (NULL != lsocks[cnt])
1508 GNUNET_break (GNUNET_OK ==
1509 GNUNET_NETWORK_socket_close (lsocks[cnt++]));
1510 GNUNET_free (lsocks);
1511 lsocks = NULL;
1512 break;
1513 }
1514 }
1515 unsetenv ("LISTEN_FDS");
1516 }
1517 if ( (0 != (GNUNET_SERVICE_OPTION_CLOSE_LSOCKS & sh->options)) &&
1518 (NULL != lsocks) )
1519 {
1520 csocks = lsocks;
1521 lsocks = NULL;
1522 }
1523
1524 if (NULL != lsocks)
1525 {
1526 /* listen only on inherited sockets if we have any */
1527 for (struct GNUNET_NETWORK_Handle **ls = lsocks; NULL != *ls; ls++)
1528 {
1529 struct ServiceListenContext *slc;
1530
1531 slc = GNUNET_new (struct ServiceListenContext);
1532 slc->sh = sh;
1533 slc->listen_socket = *ls;
1534 GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1535 }
1536 GNUNET_free (lsocks);
1537 }
1538 else
1539 {
1540 struct sockaddr **addrs;
1541 socklen_t *addrlens;
1542 int num;
1543
1544 num = get_server_addresses (sh->service_name, sh->cfg, &addrs, &addrlens);
1545 if (GNUNET_SYSERR == num)
1546 return GNUNET_SYSERR;
1547
1548 for (int i = 0; i < num; i++)
1549 {
1550 struct ServiceListenContext *slc;
1551
1552 slc = GNUNET_new (struct ServiceListenContext);
1553 slc->sh = sh;
1554 slc->listen_socket = open_listen_socket (addrs[i], addrlens[i]);
1555 GNUNET_free (addrs[i]);
1556 if (NULL == slc->listen_socket)
1557 {
1558 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1559 GNUNET_free (slc);
1560 continue;
1561 }
1562 GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1563 }
1564 GNUNET_free (addrlens);
1565 GNUNET_free (addrs);
1566 if ((0 != num) && (NULL == sh->slc_head))
1567 {
1568 /* All attempts to bind failed, hard failure */
1569 GNUNET_log (
1570 GNUNET_ERROR_TYPE_ERROR,
1571 _ (
1572 "Could not bind to any of the ports I was supposed to, refusing to run!\n"));
1573 GNUNET_free (csocks);
1574 return GNUNET_SYSERR;
1575 }
1576 }
1577 if (NULL != csocks)
1578 {
1579 /* close inherited sockets to signal parent that we are ready */
1580 for (struct GNUNET_NETWORK_Handle **ls = csocks; NULL != *ls; ls++)
1581 GNUNET_NETWORK_socket_close (*ls);
1582 GNUNET_free (csocks);
1583 }
1584 sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1585 sh->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1586 sh->service_name,
1587 "UNIX_MATCH_UID");
1588 sh->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1589 sh->service_name,
1590 "UNIX_MATCH_GID");
1591 process_acl4 (&sh->v4_denied, sh, "REJECT_FROM");
1592 process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM");
1593 process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6");
1594 process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6");
1595 return GNUNET_OK;
1596}
1597
1598
1599/**
1600 * Get the name of the user that'll be used
1601 * to provide the service.
1602 *
1603 * @param sh service context
1604 * @return value of the 'USERNAME' option
1605 */
1606static char *
1607get_user_name (struct GNUNET_SERVICE_Handle *sh)
1608{
1609 char *un;
1610
1611 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1612 sh->service_name,
1613 "USERNAME",
1614 &un))
1615 return NULL;
1616 return un;
1617}
1618
1619
1620/**
1621 * Set user ID.
1622 *
1623 * @param sh service context
1624 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1625 */
1626static int
1627set_user_id (struct GNUNET_SERVICE_Handle *sh)
1628{
1629 char *user;
1630
1631 if (NULL == (user = get_user_name (sh)))
1632 return GNUNET_OK; /* keep */
1633
1634 struct passwd *pws;
1635
1636 errno = 0;
1637 pws = getpwnam (user);
1638 if (NULL == pws)
1639 {
1640 LOG (GNUNET_ERROR_TYPE_ERROR,
1641 _ ("Cannot obtain information about user `%s': %s\n"),
1642 user,
1643 errno == 0 ? _ ("No such user") : strerror (errno));
1644 GNUNET_free (user);
1645 return GNUNET_SYSERR;
1646 }
1647 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1648#if HAVE_INITGROUPS
1649 (0 != initgroups (user, pws->pw_gid)) ||
1650#endif
1651 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1652 {
1653 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1654 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1655 {
1656 LOG (GNUNET_ERROR_TYPE_ERROR,
1657 _ ("Cannot change user/group to `%s': %s\n"),
1658 user,
1659 strerror (errno));
1660 GNUNET_free (user);
1661 return GNUNET_SYSERR;
1662 }
1663 }
1664
1665 GNUNET_free (user);
1666 return GNUNET_OK;
1667}
1668
1669
1670/**
1671 * Get the name of the file where we will
1672 * write the PID of the service.
1673 *
1674 * @param sh service context
1675 * @return name of the file for the process ID
1676 */
1677static char *
1678get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
1679{
1680 char *pif;
1681
1682 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1683 sh->service_name,
1684 "PIDFILE",
1685 &pif))
1686 return NULL;
1687 return pif;
1688}
1689
1690
1691/**
1692 * Delete the PID file that was created by our parent.
1693 *
1694 * @param sh service context
1695 */
1696static void
1697pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
1698{
1699 char *pif = get_pid_file_name (sh);
1700
1701 if (NULL == pif)
1702 return; /* no PID file */
1703 if (0 != unlink (pif))
1704 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1705 GNUNET_free (pif);
1706}
1707
1708
1709/**
1710 * Detach from terminal.
1711 *
1712 * @param sh service context
1713 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1714 */
1715static int
1716detach_terminal (struct GNUNET_SERVICE_Handle *sh)
1717{
1718 pid_t pid;
1719 int nullfd;
1720 int filedes[2];
1721
1722 if (0 != pipe (filedes))
1723 {
1724 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1725 return GNUNET_SYSERR;
1726 }
1727 pid = fork ();
1728 if (pid < 0)
1729 {
1730 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1731 return GNUNET_SYSERR;
1732 }
1733 if (0 != pid)
1734 {
1735 /* Parent */
1736 char c;
1737
1738 GNUNET_break (0 == close (filedes[1]));
1739 c = 'X';
1740 if (1 != read (filedes[0], &c, sizeof(char)))
1741 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1742 fflush (stdout);
1743 switch (c)
1744 {
1745 case '.':
1746 exit (0);
1747
1748 case 'I':
1749 LOG (GNUNET_ERROR_TYPE_INFO,
1750 _ ("Service process failed to initialize\n"));
1751 break;
1752
1753 case 'S':
1754 LOG (GNUNET_ERROR_TYPE_INFO,
1755 _ ("Service process could not initialize server function\n"));
1756 break;
1757
1758 case 'X':
1759 LOG (GNUNET_ERROR_TYPE_INFO,
1760 _ ("Service process failed to report status\n"));
1761 break;
1762 }
1763 exit (1); /* child reported error */
1764 }
1765 GNUNET_break (0 == close (0));
1766 GNUNET_break (0 == close (1));
1767 GNUNET_break (0 == close (filedes[0]));
1768 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1769 if (nullfd < 0)
1770 return GNUNET_SYSERR;
1771 /* set stdin/stdout to /dev/null */
1772 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1773 {
1774 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1775 (void) close (nullfd);
1776 return GNUNET_SYSERR;
1777 }
1778 (void) close (nullfd);
1779 /* Detach from controlling terminal */
1780 pid = setsid ();
1781 if (-1 == pid)
1782 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1783 sh->ready_confirm_fd = filedes[1];
1784
1785 return GNUNET_OK;
1786}
1787
1788
1789/**
1790 * Tear down the service, closing the listen sockets and
1791 * freeing the ACLs.
1792 *
1793 * @param sh handle to the service to tear down.
1794 */
1795static void
1796teardown_service (struct GNUNET_SERVICE_Handle *sh)
1797{
1798 struct ServiceListenContext *slc;
1799
1800 GNUNET_free (sh->v4_denied);
1801 GNUNET_free (sh->v6_denied);
1802 GNUNET_free (sh->v4_allowed);
1803 GNUNET_free (sh->v6_allowed);
1804 while (NULL != (slc = sh->slc_head))
1805 {
1806 GNUNET_CONTAINER_DLL_remove (sh->slc_head, sh->slc_tail, slc);
1807 if (NULL != slc->listen_task)
1808 GNUNET_SCHEDULER_cancel (slc->listen_task);
1809 GNUNET_break (GNUNET_OK ==
1810 GNUNET_NETWORK_socket_close (slc->listen_socket));
1811 GNUNET_free (slc);
1812 }
1813}
1814
1815
1816/**
1817 * Function to return link to AGPL source upon request.
1818 *
1819 * @param cls closure with the identification of the client
1820 * @param msg AGPL request
1821 */
1822static void
1823return_agpl (void *cls, const struct GNUNET_MessageHeader *msg)
1824{
1825 struct GNUNET_SERVICE_Client *client = cls;
1826 struct GNUNET_MQ_Handle *mq;
1827 struct GNUNET_MQ_Envelope *env;
1828 struct GNUNET_MessageHeader *res;
1829 size_t slen;
1830 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1831
1832 (void) msg;
1833 slen = strlen (pd->agpl_url) + 1;
1834 env = GNUNET_MQ_msg_extra (res, GNUNET_MESSAGE_TYPE_RESPONSE_AGPL, slen);
1835 memcpy (&res[1], GNUNET_AGPL_URL, slen);
1836 mq = GNUNET_SERVICE_client_get_mq (client);
1837 GNUNET_MQ_send (mq, env);
1838 GNUNET_SERVICE_client_continue (client);
1839}
1840
1841
1842/**
1843 * Low-level function to start a service if the scheduler
1844 * is already running. Should only be used directly in
1845 * special cases.
1846 *
1847 * The function will launch the service with the name @a service_name
1848 * using the @a service_options to configure its shutdown
1849 * behavior. When clients connect or disconnect, the respective
1850 * @a connect_cb or @a disconnect_cb functions will be called. For
1851 * messages received from the clients, the respective @a handlers will
1852 * be invoked; for the closure of the handlers we use the return value
1853 * from the @a connect_cb invocation of the respective client.
1854 *
1855 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1856 * message to receive further messages from this client. If
1857 * #GNUNET_SERVICE_client_continue() is not called within a short
1858 * time, a warning will be logged. If delays are expected, services
1859 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1860 * disable the warning.
1861 *
1862 * Clients sending invalid messages (based on @a handlers) will be
1863 * dropped. Additionally, clients can be dropped at any time using
1864 * #GNUNET_SERVICE_client_drop().
1865 *
1866 * The service must be stopped using #GNUNET_SERVICE_stop().
1867 *
1868 * @param service_name name of the service to run
1869 * @param cfg configuration to use
1870 * @param connect_cb function to call whenever a client connects
1871 * @param disconnect_cb function to call whenever a client disconnects
1872 * @param cls closure argument for @a connect_cb and @a disconnect_cb
1873 * @param handlers NULL-terminated array of message handlers for the service,
1874 * the closure will be set to the value returned by
1875 * the @a connect_cb for the respective connection
1876 * @return NULL on error
1877 */
1878struct GNUNET_SERVICE_Handle *
1879GNUNET_SERVICE_start (const char *service_name,
1880 const struct GNUNET_CONFIGURATION_Handle *cfg,
1881 GNUNET_SERVICE_ConnectHandler connect_cb,
1882 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1883 void *cls,
1884 const struct GNUNET_MQ_MessageHandler *handlers)
1885{
1886 struct GNUNET_SERVICE_Handle *sh;
1887
1888 sh = GNUNET_new (struct GNUNET_SERVICE_Handle);
1889 sh->service_name = service_name;
1890 sh->cfg = cfg;
1891 sh->connect_cb = connect_cb;
1892 sh->disconnect_cb = disconnect_cb;
1893 sh->cb_cls = cls;
1894 sh->handlers = GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL);
1895 if (GNUNET_OK != setup_service (sh))
1896 {
1897 GNUNET_free (sh->handlers);
1898 GNUNET_free (sh);
1899 return NULL;
1900 }
1901 do_resume (sh, SUSPEND_STATE_NONE);
1902 return sh;
1903}
1904
1905
1906/**
1907 * Stops a service that was started with #GNUNET_SERVICE_start().
1908 *
1909 * @param srv service to stop
1910 */
1911void
1912GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
1913{
1914 struct GNUNET_SERVICE_Client *client;
1915
1916 GNUNET_SERVICE_suspend (srv);
1917 while (NULL != (client = srv->clients_head))
1918 GNUNET_SERVICE_client_drop (client);
1919 teardown_service (srv);
1920 GNUNET_free (srv->handlers);
1921 GNUNET_free (srv);
1922}
1923
1924
1925/**
1926 * Creates the "main" function for a GNUnet service. You
1927 * should almost always use the #GNUNET_SERVICE_MAIN macro
1928 * instead of calling this function directly (except
1929 * for ARM, which should call this function directly).
1930 *
1931 * The function will launch the service with the name @a service_name
1932 * using the @a service_options to configure its shutdown
1933 * behavior. Once the service is ready, the @a init_cb will be called
1934 * for service-specific initialization. @a init_cb will be given the
1935 * service handler which can be used to control the service's
1936 * availability. When clients connect or disconnect, the respective
1937 * @a connect_cb or @a disconnect_cb functions will be called. For
1938 * messages received from the clients, the respective @a handlers will
1939 * be invoked; for the closure of the handlers we use the return value
1940 * from the @a connect_cb invocation of the respective client.
1941 *
1942 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1943 * message to receive further messages from this client. If
1944 * #GNUNET_SERVICE_client_continue() is not called within a short
1945 * time, a warning will be logged. If delays are expected, services
1946 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1947 * disable the warning.
1948 *
1949 * Clients sending invalid messages (based on @a handlers) will be
1950 * dropped. Additionally, clients can be dropped at any time using
1951 * #GNUNET_SERVICE_client_drop().
1952 *
1953 * @param argc number of command-line arguments in @a argv
1954 * @param argv array of command-line arguments
1955 * @param service_name name of the service to run
1956 * @param options options controlling shutdown of the service
1957 * @param service_init_cb function to call once the service is ready
1958 * @param connect_cb function to call whenever a client connects
1959 * @param disconnect_cb function to call whenever a client disconnects
1960 * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
1961 * @param handlers NULL-terminated array of message handlers for the service,
1962 * the closure will be set to the value returned by
1963 * the @a connect_cb for the respective connection
1964 * @return 0 on success, non-zero on error
1965 */
1966int
1967GNUNET_SERVICE_run_ (int argc,
1968 char *const *argv,
1969 const char *service_name,
1970 enum GNUNET_SERVICE_Options options,
1971 GNUNET_SERVICE_InitCallback service_init_cb,
1972 GNUNET_SERVICE_ConnectHandler connect_cb,
1973 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1974 void *cls,
1975 const struct GNUNET_MQ_MessageHandler *handlers)
1976{
1977 struct GNUNET_SERVICE_Handle sh;
1978
1979#if ENABLE_NLS
1980 char *path;
1981#endif
1982 char *cfg_filename;
1983 char *opt_cfg_filename;
1984 char *loglev;
1985 const char *xdg;
1986 char *logfile;
1987 int do_daemonize;
1988 unsigned long long skew_offset;
1989 unsigned long long skew_variance;
1990 long long clock_offset;
1991 struct GNUNET_CONFIGURATION_Handle *cfg;
1992 int ret;
1993 int err;
1994 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1995 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1996 GNUNET_GETOPT_option_cfgfile (&opt_cfg_filename),
1997 GNUNET_GETOPT_option_flag ('d',
1998 "daemonize",
1999 gettext_noop (
2000 "do daemonize (detach from terminal)"),
2001 &do_daemonize),
2002 GNUNET_GETOPT_option_help (NULL),
2003 GNUNET_GETOPT_option_loglevel (&loglev),
2004 GNUNET_GETOPT_option_logfile (&logfile),
2005 GNUNET_GETOPT_option_version (pd->version),
2006 GNUNET_GETOPT_OPTION_END
2007 };
2008
2009 err = 1;
2010 memset (&sh, 0, sizeof(sh));
2011 xdg = getenv ("XDG_CONFIG_HOME");
2012 if (NULL != xdg)
2013 GNUNET_asprintf (&cfg_filename,
2014 "%s%s%s",
2015 xdg,
2016 DIR_SEPARATOR_STR,
2017 pd->config_file);
2018 else
2019 cfg_filename = GNUNET_strdup (pd->user_config_file);
2020 sh.ready_confirm_fd = -1;
2021 sh.options = options;
2022 sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
2023 sh.service_init_cb = service_init_cb;
2024 sh.connect_cb = connect_cb;
2025 sh.disconnect_cb = disconnect_cb;
2026 sh.cb_cls = cls;
2027 sh.handlers = (NULL == pd->agpl_url)
2028 ? GNUNET_MQ_copy_handlers (handlers)
2029 : GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL);
2030 sh.service_name = service_name;
2031 sh.ret = 0;
2032 /* setup subsystems */
2033 loglev = NULL;
2034 logfile = NULL;
2035 opt_cfg_filename = NULL;
2036 do_daemonize = 0;
2037#if ENABLE_NLS
2038 if (NULL != pd->gettext_domain)
2039 {
2040 setlocale (LC_ALL, "");
2041 path = (NULL == pd->gettext_path) ?
2042 GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR) :
2043 GNUNET_strdup (pd->gettext_path);
2044 if (NULL != path)
2045 {
2046 bindtextdomain (pd->gettext_domain, path);
2047 GNUNET_free (path);
2048 }
2049 textdomain (pd->gettext_domain);
2050 }
2051#endif
2052 ret = GNUNET_GETOPT_run (service_name,
2053 service_options,
2054 argc,
2055 argv);
2056 if (GNUNET_SYSERR == ret)
2057 goto shutdown;
2058 if (GNUNET_NO == ret)
2059 {
2060 err = 0;
2061 goto shutdown;
2062 }
2063 if (GNUNET_OK != GNUNET_log_setup (service_name,
2064 loglev,
2065 logfile))
2066 {
2067 GNUNET_break (0);
2068 goto shutdown;
2069 }
2070 if (NULL != opt_cfg_filename)
2071 {
2072 if ((GNUNET_YES != GNUNET_DISK_file_test (opt_cfg_filename)) ||
2073 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_filename)))
2074 {
2075 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2076 _ ("Malformed configuration file `%s', exit ...\n"),
2077 opt_cfg_filename);
2078 goto shutdown;
2079 }
2080 }
2081 else
2082 {
2083 if (GNUNET_YES == GNUNET_DISK_file_test (cfg_filename))
2084 {
2085 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cfg_filename))
2086 {
2087 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2088 _ ("Malformed configuration file `%s', exit ...\n"),
2089 cfg_filename);
2090 goto shutdown;
2091 }
2092 }
2093 else
2094 {
2095 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
2096 {
2097 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2098 _ ("Malformed configuration, exit ...\n"));
2099 goto shutdown;
2100 }
2101 }
2102 }
2103 if (GNUNET_OK != setup_service (&sh))
2104 goto shutdown;
2105 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sh)))
2106 {
2107 GNUNET_break (0);
2108 goto shutdown;
2109 }
2110 if (GNUNET_OK != set_user_id (&sh))
2111 goto shutdown;
2112 LOG (GNUNET_ERROR_TYPE_DEBUG,
2113 "Service `%s' runs with configuration from `%s'\n",
2114 service_name,
2115 (NULL != opt_cfg_filename) ? opt_cfg_filename : cfg_filename);
2116 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sh.cfg,
2117 "TESTING",
2118 "SKEW_OFFSET",
2119 &skew_offset)) &&
2120 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sh.cfg,
2121 "TESTING",
2122 "SKEW_VARIANCE",
2123 &skew_variance)))
2124 {
2125 clock_offset = skew_offset - skew_variance;
2126 GNUNET_TIME_set_offset (clock_offset);
2127 LOG (GNUNET_ERROR_TYPE_DEBUG,
2128 "Skewing clock by %lld ms\n",
2129 (long long) clock_offset);
2130 }
2131 GNUNET_RESOLVER_connect (sh.cfg);
2132
2133 /* actually run service */
2134 err = 0;
2135 GNUNET_SCHEDULER_run (&service_main, &sh);
2136 /* shutdown */
2137 if (1 == do_daemonize)
2138 pid_file_delete (&sh);
2139
2140shutdown:
2141 if (-1 != sh.ready_confirm_fd)
2142 {
2143 if (1 != write (sh.ready_confirm_fd, err ? "I" : "S", 1))
2144 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
2145 GNUNET_break (0 == close (sh.ready_confirm_fd));
2146 }
2147#if HAVE_MALLINFO2
2148 {
2149 char *counter;
2150
2151 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sh.cfg,
2152 service_name,
2153 "GAUGER_HEAP")) &&
2154 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sh.cfg,
2155 service_name,
2156 "GAUGER_HEAP",
2157 &counter)))
2158 {
2159 struct mallinfo2 mi;
2160
2161 mi = mallinfo2 ();
2162 GAUGER (service_name, counter, mi.usmblks, "blocks");
2163 GNUNET_free (counter);
2164 }
2165 }
2166#endif
2167 teardown_service (&sh);
2168 GNUNET_free (sh.handlers);
2169 GNUNET_SPEEDUP_stop_ ();
2170 GNUNET_CONFIGURATION_destroy (cfg);
2171 GNUNET_free (logfile);
2172 GNUNET_free (loglev);
2173 GNUNET_free (cfg_filename);
2174 GNUNET_free (opt_cfg_filename);
2175
2176 return err ? GNUNET_SYSERR : sh.ret;
2177}
2178
2179
2180/**
2181 * Suspend accepting connections from the listen socket temporarily.
2182 * Resume activity using #GNUNET_SERVICE_resume.
2183 *
2184 * @param sh service to stop accepting connections.
2185 */
2186void
2187GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
2188{
2189 do_suspend (sh, SUSPEND_STATE_APP);
2190}
2191
2192
2193/**
2194 * Resume accepting connections from the listen socket.
2195 *
2196 * @param sh service to resume accepting connections.
2197 */
2198void
2199GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
2200{
2201 do_resume (sh, SUSPEND_STATE_APP);
2202}
2203
2204
2205/**
2206 * Task run to resume receiving data from the client after
2207 * the client called #GNUNET_SERVICE_client_continue().
2208 *
2209 * @param cls our `struct GNUNET_SERVICE_Client`
2210 */
2211static void
2212resume_client_receive (void *cls)
2213{
2214 struct GNUNET_SERVICE_Client *c = cls;
2215 int ret;
2216
2217 c->recv_task = NULL;
2218 /* first, check if there is still something in the buffer */
2219 ret = GNUNET_MST_next (c->mst, GNUNET_YES);
2220 if (GNUNET_SYSERR == ret)
2221 {
2222 if (NULL == c->drop_task)
2223 GNUNET_SERVICE_client_drop (c);
2224 return;
2225 }
2226 if (GNUNET_NO == ret)
2227 return; /* done processing, wait for more later */
2228 GNUNET_assert (GNUNET_OK == ret);
2229 if (GNUNET_YES == c->needs_continue)
2230 return; /* #GNUNET_MST_next() did give a message to the client */
2231 /* need to receive more data from the network first */
2232 if (NULL != c->recv_task)
2233 return;
2234 c->recv_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2235 c->sock,
2236 &service_client_recv,
2237 c);
2238}
2239
2240
2241/**
2242 * Continue receiving further messages from the given client.
2243 * Must be called after each message received.
2244 *
2245 * @param c the client to continue receiving from
2246 */
2247void
2248GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
2249{
2250 GNUNET_assert (NULL == c->drop_task);
2251 GNUNET_assert (GNUNET_YES == c->needs_continue);
2252 GNUNET_assert (NULL == c->recv_task);
2253 c->needs_continue = GNUNET_NO;
2254 if (NULL != c->warn_task)
2255 {
2256 GNUNET_SCHEDULER_cancel (c->warn_task);
2257 c->warn_task = NULL;
2258 }
2259 c->recv_task = GNUNET_SCHEDULER_add_now (&resume_client_receive, c);
2260}
2261
2262
2263/**
2264 * Disable the warning the server issues if a message is not
2265 * acknowledged in a timely fashion. Use this call if a client is
2266 * intentionally delayed for a while. Only applies to the current
2267 * message.
2268 *
2269 * @param c client for which to disable the warning
2270 */
2271void
2272GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
2273{
2274 GNUNET_break (NULL != c->warn_task);
2275 if (NULL != c->warn_task)
2276 {
2277 GNUNET_SCHEDULER_cancel (c->warn_task);
2278 c->warn_task = NULL;
2279 }
2280}
2281
2282
2283/**
2284 * Asynchronously finish dropping the client.
2285 *
2286 * @param cls the `struct GNUNET_SERVICE_Client`.
2287 */
2288static void
2289finish_client_drop (void *cls)
2290{
2291 struct GNUNET_SERVICE_Client *c = cls;
2292 struct GNUNET_SERVICE_Handle *sh = c->sh;
2293
2294 c->drop_task = NULL;
2295 GNUNET_assert (NULL == c->send_task);
2296 GNUNET_assert (NULL == c->recv_task);
2297 GNUNET_assert (NULL == c->warn_task);
2298 GNUNET_MST_destroy (c->mst);
2299 GNUNET_MQ_destroy (c->mq);
2300 if (GNUNET_NO == c->persist)
2301 {
2302 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (c->sock));
2303 if ((0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) &&
2304 (0 == (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)))
2305 do_resume (sh, SUSPEND_STATE_EMFILE);
2306 }
2307 else
2308 {
2309 GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
2310 }
2311 GNUNET_free (c);
2312 if ((0 != (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)) &&
2313 (GNUNET_NO == have_non_monitor_clients (sh)))
2314 GNUNET_SERVICE_shutdown (sh);
2315}
2316
2317
2318/**
2319 * Ask the server to disconnect from the given client. This is the
2320 * same as returning #GNUNET_SYSERR within the check procedure when
2321 * handling a message, wexcept that it allows dropping of a client even
2322 * when not handling a message from that client. The `disconnect_cb`
2323 * will be called on @a c even if the application closes the connection
2324 * using this function.
2325 *
2326 * @param c client to disconnect now
2327 */
2328void
2329GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
2330{
2331 struct GNUNET_SERVICE_Handle *sh = c->sh;
2332
2333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2334 "Client dropped: %p (MQ: %p)\n",
2335 c,
2336 c->mq);
2337#if EXECINFO
2338 {
2339 void *backtrace_array[MAX_TRACE_DEPTH];
2340 int num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH);
2341 char **backtrace_strings =
2342 backtrace_symbols (backtrace_array, t->num_backtrace_strings);
2343 for (unsigned int i = 0; i < num_backtrace_strings; i++)
2344 LOG (GNUNET_ERROR_TYPE_DEBUG,
2345 "client drop trace %u: %s\n",
2346 i,
2347 backtrace_strings[i]);
2348 }
2349#endif
2350 if (NULL != c->drop_task)
2351 {
2352 /* asked to drop twice! */
2353 GNUNET_assert (0);
2354 return;
2355 }
2356 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
2357 sh->clients_tail,
2358 c);
2359 if (NULL != sh->disconnect_cb)
2360 sh->disconnect_cb (sh->cb_cls,
2361 c,
2362 c->user_context);
2363 if (NULL != c->warn_task)
2364 {
2365 GNUNET_SCHEDULER_cancel (c->warn_task);
2366 c->warn_task = NULL;
2367 }
2368 if (NULL != c->recv_task)
2369 {
2370 GNUNET_SCHEDULER_cancel (c->recv_task);
2371 c->recv_task = NULL;
2372 }
2373 if (NULL != c->send_task)
2374 {
2375 GNUNET_SCHEDULER_cancel (c->send_task);
2376 c->send_task = NULL;
2377 }
2378 c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop, c);
2379}
2380
2381
2382/**
2383 * Explicitly stops the service.
2384 *
2385 * @param sh server to shutdown
2386 */
2387void
2388GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
2389{
2390 struct GNUNET_SERVICE_Client *client;
2391
2392 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
2393 do_suspend (sh, SUSPEND_STATE_SHUTDOWN);
2394 while (NULL != (client = sh->clients_head))
2395 GNUNET_SERVICE_client_drop (client);
2396}
2397
2398
2399/**
2400 * Set the 'monitor' flag on this client. Clients which have been
2401 * marked as 'monitors' won't prevent the server from shutting down
2402 * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is
2403 * that for "normal" clients we likely want to allow them to process
2404 * their requests; however, monitor-clients are likely to 'never'
2405 * disconnect during shutdown and thus will not be considered when
2406 * determining if the server should continue to exist after
2407 * shutdown has been triggered.
2408 *
2409 * @param c client to mark as a monitor
2410 */
2411void
2412GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
2413{
2414 c->is_monitor = GNUNET_YES;
2415 if (((0 != (SUSPEND_STATE_SHUTDOWN & c->sh->suspend_state)) &&
2416 (GNUNET_NO == have_non_monitor_clients (c->sh))))
2417 GNUNET_SERVICE_shutdown (c->sh);
2418}
2419
2420
2421/**
2422 * Set the persist option on this client. Indicates that the
2423 * underlying socket or fd should never really be closed. Used for
2424 * indicating process death.
2425 *
2426 * @param c client to persist the socket (never to be closed)
2427 */
2428void
2429GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
2430{
2431 c->persist = GNUNET_YES;
2432}
2433
2434
2435/**
2436 * Obtain the message queue of @a c. Convenience function.
2437 *
2438 * @param c the client to continue receiving from
2439 * @return the message queue of @a c
2440 */
2441struct GNUNET_MQ_Handle *
2442GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
2443{
2444 return c->mq;
2445}
2446
2447
2448/* 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 7e218cc59..000000000
--- a/src/util/strings.c
+++ /dev/null
@@ -1,1956 +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
72unsigned int
73GNUNET_STRINGS_buffer_tokenize (const char *buffer,
74 size_t size,
75 unsigned int count,
76 ...)
77{
78 unsigned int start;
79 unsigned int needed;
80 const char **r;
81 va_list ap;
82
83 needed = 0;
84 va_start (ap, count);
85 while (count > 0)
86 {
87 r = va_arg (ap, const char **);
88
89 start = needed;
90 while ((needed < size) && (buffer[needed] != '\0'))
91 needed++;
92 if (needed == size)
93 {
94 va_end (ap);
95 return 0; /* error */
96 }
97 *r = &buffer[start];
98 needed++; /* skip 0-termination */
99 count--;
100 }
101 va_end (ap);
102 return needed;
103}
104
105
106char *
107GNUNET_STRINGS_byte_size_fancy (unsigned long long size)
108{
109 const char *unit = /* size unit */ "b";
110 char *ret;
111
112 if (size > 5 * 1024)
113 {
114 size = size / 1024;
115 unit = "KiB";
116 if (size > 5 * 1024)
117 {
118 size = size / 1024;
119 unit = "MiB";
120 if (size > 5 * 1024)
121 {
122 size = size / 1024;
123 unit = "GiB";
124 if (size > 5 * 1024)
125 {
126 size = size / 1024;
127 unit = "TiB";
128 }
129 }
130 }
131 }
132 ret = GNUNET_malloc (32);
133 GNUNET_snprintf (ret, 32, "%llu %s", size, unit);
134 return ret;
135}
136
137
138size_t
139GNUNET_strlcpy (char *dst,
140 const char *src,
141 size_t n)
142{
143 size_t slen;
144
145 GNUNET_assert (0 != n);
146 slen = strnlen (src, n - 1);
147 memcpy (dst, src, slen);
148 dst[slen] = '\0';
149 return slen;
150}
151
152
153/**
154 * Unit conversion table entry for 'convert_with_table'.
155 */
156struct ConversionTable
157{
158 /**
159 * Name of the unit (or NULL for end of table).
160 */
161 const char *name;
162
163 /**
164 * Factor to apply for this unit.
165 */
166 unsigned long long value;
167};
168
169
170/**
171 * Convert a string of the form "4 X 5 Y" into a numeric value
172 * by interpreting "X" and "Y" as units and then multiplying
173 * the numbers with the values associated with the respective
174 * unit from the conversion table.
175 *
176 * @param input input string to parse
177 * @param table table with the conversion of unit names to numbers
178 * @param output where to store the result
179 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
180 */
181static enum GNUNET_GenericReturnValue
182convert_with_table (const char *input,
183 const struct ConversionTable *table,
184 unsigned long long *output)
185{
186 unsigned long long ret;
187 char *in;
188 const char *tok;
189 unsigned long long last;
190 unsigned int i;
191 char *sptr;
192
193 ret = 0;
194 last = 0;
195 in = GNUNET_strdup (input);
196 for (tok = strtok_r (in, " ", &sptr);
197 tok != NULL;
198 tok = strtok_r (NULL, " ", &sptr))
199 {
200 do
201 {
202 i = 0;
203 while ((table[i].name != NULL) && (0 != strcasecmp (table[i].name, tok)))
204 i++;
205 if (table[i].name != NULL)
206 {
207 last *= table[i].value;
208 break; /* next tok */
209 }
210 else
211 {
212 char *endptr;
213 ret += last;
214 errno = 0;
215 last = strtoull (tok, &endptr, 10);
216 if ((0 != errno) || (endptr == tok))
217 {
218 GNUNET_free (in);
219 return GNUNET_SYSERR; /* expected number */
220 }
221 if ('\0' == endptr[0])
222 break; /* next tok */
223 else
224 tok = endptr; /* and re-check (handles times like "10s") */
225 }
226 }
227 while (GNUNET_YES);
228 }
229 ret += last;
230 *output = ret;
231 GNUNET_free (in);
232 return GNUNET_OK;
233}
234
235
236enum GNUNET_GenericReturnValue
237GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size,
238 unsigned long long *size)
239{
240 static const struct ConversionTable table[] =
241 { { "B", 1 },
242 { "KiB", 1024 },
243 { "kB", 1000 },
244 { "MiB", 1024 * 1024 },
245 { "MB", 1000 * 1000 },
246 { "GiB", 1024 * 1024 * 1024 },
247 { "GB", 1000 * 1000 * 1000 },
248 { "TiB", 1024LL * 1024LL * 1024LL * 1024LL },
249 { "TB", 1000LL * 1000LL * 1000LL * 1024LL },
250 { "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL },
251 { "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL },
252 { "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL },
253 { "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL },
254 { NULL, 0 } };
255
256 return convert_with_table (fancy_size, table, size);
257}
258
259
260enum GNUNET_GenericReturnValue
261GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time,
262 struct GNUNET_TIME_Relative *rtime)
263{
264 static const struct ConversionTable table[] =
265 { { "us", 1 },
266 { "ms", 1000 },
267 { "s", 1000 * 1000LL },
268 { "second", 1000 * 1000LL },
269 { "seconds", 1000 * 1000LL },
270 { "\"", 1000 * 1000LL },
271 { "m", 60 * 1000 * 1000LL },
272 { "min", 60 * 1000 * 1000LL },
273 { "minute", 60 * 1000 * 1000LL },
274 { "minutes", 60 * 1000 * 1000LL },
275 { "'", 60 * 1000 * 1000LL },
276 { "h", 60 * 60 * 1000 * 1000LL },
277 { "hour", 60 * 60 * 1000 * 1000LL },
278 { "hours", 60 * 60 * 1000 * 1000LL },
279 { "d", 24 * 60 * 60 * 1000LL * 1000LL },
280 { "day", 24 * 60 * 60 * 1000LL * 1000LL },
281 { "days", 24 * 60 * 60 * 1000LL * 1000LL },
282 { "week", 7 * 24 * 60 * 60 * 1000LL * 1000LL },
283 { "weeks", 7 * 24 * 60 * 60 * 1000LL * 1000LL },
284 { "year", 31536000000000LL /* year */ },
285 { "years", 31536000000000LL /* year */ },
286 { "a", 31536000000000LL /* year */ },
287 { NULL, 0 } };
288 int ret;
289 unsigned long long val;
290
291 if (0 == strcasecmp ("forever", fancy_time))
292 {
293 *rtime = GNUNET_TIME_UNIT_FOREVER_REL;
294 return GNUNET_OK;
295 }
296 ret = convert_with_table (fancy_time, table, &val);
297 rtime->rel_value_us = (uint64_t) val;
298 return ret;
299}
300
301
302enum GNUNET_GenericReturnValue
303GNUNET_STRINGS_fancy_time_to_absolute (const char *fancy_time,
304 struct GNUNET_TIME_Absolute *atime)
305{
306 struct tm tv;
307 time_t t;
308 const char *eos;
309
310 if (0 == strcasecmp ("end of time", fancy_time))
311 {
312 *atime = GNUNET_TIME_UNIT_FOREVER_ABS;
313 return GNUNET_OK;
314 }
315 eos = &fancy_time[strlen (fancy_time)];
316 memset (&tv, 0, sizeof(tv));
317 if ((eos != strptime (fancy_time, "%a %b %d %H:%M:%S %Y", &tv)) &&
318 (eos != strptime (fancy_time, "%c", &tv)) &&
319 (eos != strptime (fancy_time, "%Ec", &tv)) &&
320 (eos != strptime (fancy_time, "%Y-%m-%d %H:%M:%S", &tv)) &&
321 (eos != strptime (fancy_time, "%Y-%m-%d %H:%M", &tv)) &&
322 (eos != strptime (fancy_time, "%x", &tv)) &&
323 (eos != strptime (fancy_time, "%Ex", &tv)) &&
324 (eos != strptime (fancy_time, "%Y-%m-%d", &tv)) &&
325 (eos != strptime (fancy_time, "%Y-%m", &tv)) &&
326 (eos != strptime (fancy_time, "%Y", &tv)))
327 return GNUNET_SYSERR;
328 t = mktime (&tv);
329 atime->abs_value_us = (uint64_t) ((uint64_t) t * 1000LL * 1000LL);
330 return GNUNET_OK;
331}
332
333
334enum GNUNET_GenericReturnValue
335GNUNET_STRINGS_fancy_time_to_timestamp (const char *fancy_time,
336 struct GNUNET_TIME_Timestamp *atime)
337{
338 return GNUNET_STRINGS_fancy_time_to_absolute (fancy_time,
339 &atime->abs_time);
340}
341
342
343char *
344GNUNET_STRINGS_conv (const char *input,
345 size_t len,
346 const char *input_charset,
347 const char *output_charset)
348{
349 char *ret;
350 uint8_t *u8_string;
351 char *encoded_string;
352 size_t u8_string_length;
353 size_t encoded_string_length;
354
355 u8_string = u8_conv_from_encoding (input_charset,
356 iconveh_error,
357 input,
358 len,
359 NULL,
360 NULL,
361 &u8_string_length);
362 if (NULL == u8_string)
363 {
364 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "u8_conv_from_encoding");
365 goto fail;
366 }
367 if (0 == strcmp (output_charset, "UTF-8"))
368 {
369 ret = GNUNET_malloc (u8_string_length + 1);
370 GNUNET_memcpy (ret, u8_string, u8_string_length);
371 ret[u8_string_length] = '\0';
372 free (u8_string);
373 return ret;
374 }
375 encoded_string = u8_conv_to_encoding (output_charset,
376 iconveh_error,
377 u8_string,
378 u8_string_length,
379 NULL,
380 NULL,
381 &encoded_string_length);
382 free (u8_string);
383 if (NULL == encoded_string)
384 {
385 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "u8_conv_to_encoding");
386 goto fail;
387 }
388 ret = GNUNET_malloc (encoded_string_length + 1);
389 GNUNET_memcpy (ret, encoded_string, encoded_string_length);
390 ret[encoded_string_length] = '\0';
391 free (encoded_string);
392 return ret;
393 fail:
394 LOG (GNUNET_ERROR_TYPE_WARNING,
395 _ ("Character sets requested were `%s'->`%s'\n"),
396 "UTF-8",
397 output_charset);
398 ret = GNUNET_malloc (len + 1);
399 GNUNET_memcpy (ret, input, len);
400 ret[len] = '\0';
401 return ret;
402}
403
404
405char *
406GNUNET_STRINGS_to_utf8 (const char *input,
407 size_t len,
408 const char *charset)
409{
410 return GNUNET_STRINGS_conv (input,
411 len,
412 charset,
413 "UTF-8");
414}
415
416
417char *
418GNUNET_STRINGS_from_utf8 (const char *input,
419 size_t len,
420 const char *charset)
421{
422 return GNUNET_STRINGS_conv (input,
423 len,
424 "UTF-8",
425 charset);
426}
427
428
429char *
430GNUNET_STRINGS_utf8_normalize (const char *input)
431{
432 uint8_t *tmp;
433 size_t len;
434 char *output;
435 tmp = u8_normalize (UNINORM_NFC,
436 (uint8_t *) input,
437 strlen ((char*) input),
438 NULL,
439 &len);
440 if (NULL == tmp)
441 return NULL;
442 output = GNUNET_malloc (len + 1);
443 GNUNET_memcpy (output, tmp, len);
444 output[len] = '\0';
445 free (tmp);
446 return output;
447}
448
449enum GNUNET_GenericReturnValue
450GNUNET_STRINGS_utf8_tolower (const char *input,
451 char *output)
452{
453 uint8_t *tmp_in;
454 size_t len;
455
456 tmp_in = u8_tolower ((uint8_t *) input,
457 strlen ((char *) input),
458 NULL,
459 UNINORM_NFD,
460 NULL,
461 &len);
462 if (NULL == tmp_in)
463 return GNUNET_SYSERR;
464 GNUNET_memcpy (output, tmp_in, len);
465 output[len] = '\0';
466 GNUNET_free (tmp_in);
467 return GNUNET_OK;
468}
469
470
471enum GNUNET_GenericReturnValue
472GNUNET_STRINGS_utf8_toupper (const char *input,
473 char *output)
474{
475 uint8_t *tmp_in;
476 size_t len;
477
478 tmp_in = u8_toupper ((uint8_t *) input,
479 strlen ((char *) input),
480 NULL,
481 UNINORM_NFD,
482 NULL,
483 &len);
484 if (NULL == tmp_in)
485 return GNUNET_SYSERR;
486 /* 0-terminator does not fit */
487 GNUNET_memcpy (output, tmp_in, len);
488 output[len] = '\0';
489 GNUNET_free (tmp_in);
490 return GNUNET_OK;
491}
492
493
494char *
495GNUNET_STRINGS_filename_expand (const char *fil)
496{
497 char *buffer;
498 size_t len;
499 char *fm;
500 const char *fil_ptr;
501
502 if (fil == NULL)
503 return NULL;
504
505 if (fil[0] == DIR_SEPARATOR)
506 /* absolute path, just copy */
507 return GNUNET_strdup (fil);
508 if (fil[0] == '~')
509 {
510 fm = getenv ("HOME");
511 if (fm == NULL)
512 {
513 LOG (GNUNET_ERROR_TYPE_WARNING,
514 _ ("Failed to expand `$HOME': environment variable `HOME' not set"));
515 return NULL;
516 }
517 fm = GNUNET_strdup (fm);
518 /* do not copy '~' */
519 fil_ptr = fil + 1;
520
521 /* skip over dir separator to be consistent */
522 if (fil_ptr[0] == DIR_SEPARATOR)
523 fil_ptr++;
524 }
525 else
526 {
527 /* relative path */
528 fil_ptr = fil;
529 len = 512;
530 fm = NULL;
531 while (1)
532 {
533 buffer = GNUNET_malloc (len);
534 if (getcwd (buffer, len) != NULL)
535 {
536 fm = buffer;
537 break;
538 }
539 if ((errno == ERANGE) && (len < 1024 * 1024 * 4))
540 {
541 len *= 2;
542 GNUNET_free (buffer);
543 continue;
544 }
545 GNUNET_free (buffer);
546 break;
547 }
548 if (fm == NULL)
549 {
550 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "getcwd");
551 buffer = getenv ("PWD"); /* alternative */
552 if (buffer != NULL)
553 fm = GNUNET_strdup (buffer);
554 }
555 if (fm == NULL)
556 fm = GNUNET_strdup ("./"); /* give up */
557 }
558 GNUNET_asprintf (&buffer,
559 "%s%s%s",
560 fm,
561 (fm[strlen (fm) - 1] == DIR_SEPARATOR) ? ""
562 : DIR_SEPARATOR_STR,
563 fil_ptr);
564 GNUNET_free (fm);
565 return buffer;
566}
567
568
569const char *
570GNUNET_STRINGS_relative_time_to_string (struct GNUNET_TIME_Relative delta,
571 int do_round)
572{
573 static GNUNET_THREAD_LOCAL char buf[128];
574 const char *unit = /* time unit */ "µs";
575 uint64_t dval = delta.rel_value_us;
576
577 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == delta.rel_value_us)
578 return "forever";
579 if (0 == delta.rel_value_us)
580 return "0 ms";
581 if (((GNUNET_YES == do_round) && (dval > 5 * 1000)) || (0 == (dval % 1000)))
582 {
583 dval = dval / 1000;
584 unit = /* time unit */ "ms";
585 if (((GNUNET_YES == do_round) && (dval > 5 * 1000)) || (0 == (dval % 1000)))
586 {
587 dval = dval / 1000;
588 unit = /* time unit */ "s";
589 if (((GNUNET_YES == do_round) && (dval > 5 * 60)) || (0 == (dval % 60)))
590 {
591 dval = dval / 60;
592 unit = /* time unit */ "m";
593 if (((GNUNET_YES == do_round) && (dval > 5 * 60)) || (0 == (dval % 60)))
594 {
595 dval = dval / 60;
596 unit = /* time unit */ "h";
597 if (((GNUNET_YES == do_round) && (dval > 5 * 24)) ||
598 (0 == (dval % 24)))
599 {
600 dval = dval / 24;
601 if (1 == dval)
602 unit = /* time unit */ "day";
603 else
604 unit = /* time unit */ "days";
605 }
606 }
607 }
608 }
609 }
610 GNUNET_snprintf (buf, sizeof(buf), "%llu %s",
611 (unsigned long long) dval, unit);
612 return buf;
613}
614
615
616const char *
617GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t)
618{
619 static GNUNET_THREAD_LOCAL char buf[255];
620 time_t tt;
621 struct tm *tp;
622
623 if (GNUNET_TIME_absolute_is_never (t))
624 return "end of time";
625 tt = t.abs_value_us / 1000LL / 1000LL;
626 tp = localtime (&tt);
627 /* This is hacky, but i don't know a way to detect libc character encoding.
628 * Just expect utf8 from glibc these days.
629 * As for msvcrt, use the wide variant, which always returns utf16
630 * (otherwise we'd have to detect current codepage or use W32API character
631 * set conversion routines to convert to UTF8).
632 */
633 strftime (buf, sizeof(buf), "%a %b %d %H:%M:%S %Y", tp);
634
635 return buf;
636}
637
638
639const char *
640GNUNET_STRINGS_get_short_name (const char *filename)
641{
642 const char *short_fn = filename;
643 const char *ss;
644
645 while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR)) && (ss[1] != '\0'))
646 short_fn = 1 + ss;
647 return short_fn;
648}
649
650
651/**
652 * Get the decoded value corresponding to a character according to Crockford
653 * Base32 encoding.
654 *
655 * @param a a character
656 * @return corresponding numeric value
657 */
658static unsigned int
659getValue__ (unsigned char a)
660{
661 unsigned int dec;
662
663 switch (a)
664 {
665 case 'O':
666 case 'o':
667 a = '0';
668 break;
669
670 case 'i':
671 case 'I':
672 case 'l':
673 case 'L':
674 a = '1';
675 break;
676
677 /* also consider U to be V */
678 case 'u':
679 case 'U':
680 a = 'V';
681 break;
682
683 default:
684 break;
685 }
686 if ((a >= '0') && (a <= '9'))
687 return a - '0';
688 if ((a >= 'a') && (a <= 'z'))
689 a = toupper (a);
690 /* return (a - 'a' + 10); */
691 dec = 0;
692 if ((a >= 'A') && (a <= 'Z'))
693 {
694 if ('I' < a)
695 dec++;
696 if ('L' < a)
697 dec++;
698 if ('O' < a)
699 dec++;
700 if ('U' < a)
701 dec++;
702 return(a - 'A' + 10 - dec);
703 }
704 return -1;
705}
706
707
708char *
709GNUNET_STRINGS_data_to_string (const void *data,
710 size_t size,
711 char *out,
712 size_t out_size)
713{
714 /**
715 * 32 characters for encoding
716 */
717 static char *encTable__ = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
718 unsigned int wpos;
719 unsigned int rpos;
720 unsigned int bits;
721 unsigned int vbit;
722 const unsigned char *udata;
723
724 GNUNET_assert (size < SIZE_MAX / 8 - 4);
725 udata = data;
726 if (out_size < (size * 8 + 4) / 5)
727 {
728 GNUNET_break (0);
729 return NULL;
730 }
731 vbit = 0;
732 wpos = 0;
733 rpos = 0;
734 bits = 0;
735 while ((rpos < size) || (vbit > 0))
736 {
737 if ((rpos < size) && (vbit < 5))
738 {
739 bits = (bits << 8) | udata[rpos++]; /* eat 8 more bits */
740 vbit += 8;
741 }
742 if (vbit < 5)
743 {
744 bits <<= (5 - vbit); /* zero-padding */
745 GNUNET_assert (vbit == ((size * 8) % 5));
746 vbit = 5;
747 }
748 if (wpos >= out_size)
749 {
750 GNUNET_break (0);
751 return NULL;
752 }
753 out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31];
754 vbit -= 5;
755 }
756 GNUNET_assert (0 == vbit);
757 if (wpos < out_size)
758 out[wpos] = '\0';
759 return &out[wpos];
760}
761
762
763char *
764GNUNET_STRINGS_data_to_string_alloc (const void *buf, size_t size)
765{
766 char *str_buf;
767 size_t len = size * 8;
768 char *end;
769
770 if (len % 5 > 0)
771 len += 5 - len % 5;
772 len /= 5;
773 str_buf = GNUNET_malloc (len + 1);
774 end = GNUNET_STRINGS_data_to_string (buf,
775 size,
776 str_buf,
777 len);
778 if (NULL == end)
779 {
780 GNUNET_free (str_buf);
781 return NULL;
782 }
783 *end = '\0';
784 return str_buf;
785}
786
787
788enum GNUNET_GenericReturnValue
789GNUNET_STRINGS_string_to_data (const char *enc,
790 size_t enclen,
791 void *out,
792 size_t out_size)
793{
794 size_t rpos;
795 size_t wpos;
796 unsigned int bits;
797 unsigned int vbit;
798 int ret;
799 int shift;
800 unsigned char *uout;
801 size_t encoded_len;
802
803 if (0 == enclen)
804 {
805 if (0 == out_size)
806 return GNUNET_OK;
807 return GNUNET_SYSERR;
808 }
809 GNUNET_assert (out_size < SIZE_MAX / 8);
810 encoded_len = out_size * 8;
811 uout = out;
812 wpos = out_size;
813 rpos = enclen;
814 if ((encoded_len % 5) > 0)
815 {
816 vbit = encoded_len % 5; /* padding! */
817 shift = 5 - vbit;
818 bits = (ret = getValue__ (enc[--rpos])) >> shift;
819 }
820 else
821 {
822 vbit = 5;
823 shift = 0;
824 bits = (ret = getValue__ (enc[--rpos]));
825 }
826 if ((encoded_len + shift) / 5 != enclen)
827 return GNUNET_SYSERR;
828 if (-1 == ret)
829 return GNUNET_SYSERR;
830 while (wpos > 0)
831 {
832 if (0 == rpos)
833 {
834 GNUNET_break (0);
835 return GNUNET_SYSERR;
836 }
837 bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits;
838 if (-1 == ret)
839 return GNUNET_SYSERR;
840 vbit += 5;
841 if (vbit >= 8)
842 {
843 uout[--wpos] = (unsigned char) bits;
844 bits >>= 8;
845 vbit -= 8;
846 }
847 }
848 if ((0 != rpos) || (0 != vbit))
849 return GNUNET_SYSERR;
850 return GNUNET_OK;
851}
852
853
854enum GNUNET_GenericReturnValue
855GNUNET_STRINGS_string_to_data_alloc (const char *enc,
856 size_t enclen,
857 void **out,
858 size_t *out_size)
859{
860 size_t size;
861 void *data;
862 int res;
863
864 size = (enclen * 5) / 8;
865 if (size >= GNUNET_MAX_MALLOC_CHECKED)
866 {
867 GNUNET_break_op (0);
868 return GNUNET_SYSERR;
869 }
870 data = GNUNET_malloc (size);
871 res = GNUNET_STRINGS_string_to_data (enc,
872 enclen,
873 data,
874 size);
875 if ( (0 < size) &&
876 (GNUNET_OK != res) )
877 {
878 size--;
879 res = GNUNET_STRINGS_string_to_data (enc,
880 enclen,
881 data,
882 size);
883 }
884 if (GNUNET_OK != res)
885 {
886 GNUNET_break_op (0);
887 GNUNET_free (data);
888 return GNUNET_SYSERR;
889 }
890 *out = data;
891 *out_size = size;
892 return GNUNET_OK;
893}
894
895
896enum GNUNET_GenericReturnValue
897GNUNET_STRINGS_parse_uri (const char *path,
898 char **scheme_part,
899 const char **path_part)
900{
901 size_t len;
902 size_t i;
903 int end;
904 int pp_state = 0;
905 const char *post_scheme_part = NULL;
906
907 len = strlen (path);
908 for (end = 0, i = 0; ! end && i < len; i++)
909 {
910 switch (pp_state)
911 {
912 case 0:
913 if ((path[i] == ':') && (i > 0))
914 {
915 pp_state += 1;
916 continue;
917 }
918 if (! (((path[i] >= 'A') && (path[i] <= 'Z') ) ||
919 ((path[i] >= 'a') && (path[i] <= 'z') ) ||
920 ((path[i] >= '0') && (path[i] <= '9') ) || (path[i] == '+') ||
921 (path[i] == '-') || (path[i] == '.')))
922 end = 1;
923 break;
924
925 case 1:
926 case 2:
927 if (path[i] == '/')
928 {
929 pp_state += 1;
930 continue;
931 }
932 end = 1;
933 break;
934
935 case 3:
936 post_scheme_part = &path[i];
937 end = 1;
938 break;
939
940 default:
941 end = 1;
942 }
943 }
944 if (post_scheme_part == NULL)
945 return GNUNET_NO;
946 if (scheme_part)
947 {
948 *scheme_part = GNUNET_malloc (post_scheme_part - path + 1);
949 GNUNET_memcpy (*scheme_part, path, post_scheme_part - path);
950 (*scheme_part)[post_scheme_part - path] = '\0';
951 }
952 if (path_part)
953 *path_part = post_scheme_part;
954 return GNUNET_YES;
955}
956
957
958enum GNUNET_GenericReturnValue
959GNUNET_STRINGS_path_is_absolute (const char *filename,
960 int can_be_uri,
961 int *r_is_uri,
962 char **r_uri_scheme)
963{
964 const char *post_scheme_path;
965 int is_uri;
966 char *uri;
967 /* consider POSIX paths to be absolute too, even on W32,
968 * as plibc expansion will fix them for us.
969 */
970 if (filename[0] == '/')
971 return GNUNET_YES;
972 if (can_be_uri)
973 {
974 is_uri = GNUNET_STRINGS_parse_uri (filename, &uri, &post_scheme_path);
975 if (r_is_uri)
976 *r_is_uri = is_uri;
977 if (is_uri)
978 {
979 if (r_uri_scheme)
980 *r_uri_scheme = uri;
981 else
982 GNUNET_free (uri);
983
984 return GNUNET_STRINGS_path_is_absolute (post_scheme_path,
985 GNUNET_NO,
986 NULL,
987 NULL);
988 }
989 }
990 else
991 {
992 if (r_is_uri)
993 *r_is_uri = GNUNET_NO;
994 }
995
996 return GNUNET_NO;
997}
998
999
1000enum GNUNET_GenericReturnValue
1001GNUNET_STRINGS_check_filename (const char *filename,
1002 enum GNUNET_STRINGS_FilenameCheck checks)
1003{
1004 struct stat st;
1005
1006 if ((NULL == filename) || (filename[0] == '\0'))
1007 return GNUNET_SYSERR;
1008 if (0 != (checks & GNUNET_STRINGS_CHECK_IS_ABSOLUTE))
1009 if (! GNUNET_STRINGS_path_is_absolute (filename, GNUNET_NO, NULL, NULL))
1010 return GNUNET_NO;
1011 if (0 != (checks
1012 & (GNUNET_STRINGS_CHECK_EXISTS | GNUNET_STRINGS_CHECK_IS_DIRECTORY
1013 | GNUNET_STRINGS_CHECK_IS_LINK)))
1014 {
1015 if (0 != lstat (filename, &st))
1016 {
1017 if (0 != (checks & GNUNET_STRINGS_CHECK_EXISTS))
1018 return GNUNET_NO;
1019 else
1020 return GNUNET_SYSERR;
1021 }
1022 }
1023 if (0 != (checks & GNUNET_STRINGS_CHECK_IS_DIRECTORY))
1024 if (! S_ISDIR (st.st_mode))
1025 return GNUNET_NO;
1026 if (0 != (checks & GNUNET_STRINGS_CHECK_IS_LINK))
1027 if (! S_ISLNK (st.st_mode))
1028 return GNUNET_NO;
1029 return GNUNET_YES;
1030}
1031
1032
1033enum GNUNET_GenericReturnValue
1034GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr,
1035 uint16_t addrlen,
1036 struct sockaddr_in6 *r_buf)
1037{
1038 char zbuf[addrlen + 1];
1039 int ret;
1040 char *port_colon;
1041 unsigned int port;
1042 char dummy[2];
1043
1044 if (addrlen < 6)
1045 return GNUNET_SYSERR;
1046 GNUNET_memcpy (zbuf, zt_addr, addrlen);
1047 if ('[' != zbuf[0])
1048 {
1049 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1050 _ ("IPv6 address did not start with `['\n"));
1051 return GNUNET_SYSERR;
1052 }
1053 zbuf[addrlen] = '\0';
1054 port_colon = strrchr (zbuf, ':');
1055 if (NULL == port_colon)
1056 {
1057 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1058 _ ("IPv6 address did contain ':' to separate port number\n"));
1059 return GNUNET_SYSERR;
1060 }
1061 if (']' != *(port_colon - 1))
1062 {
1063 GNUNET_log (
1064 GNUNET_ERROR_TYPE_WARNING,
1065 _ ("IPv6 address did contain ']' before ':' to separate port number\n"));
1066 return GNUNET_SYSERR;
1067 }
1068 ret = sscanf (port_colon, ":%u%1s", &port, dummy);
1069 if ((1 != ret) || (port > 65535))
1070 {
1071 GNUNET_log (
1072 GNUNET_ERROR_TYPE_WARNING,
1073 _ ("IPv6 address did contain a valid port number after the last ':'\n"));
1074 return GNUNET_SYSERR;
1075 }
1076 *(port_colon - 1) = '\0';
1077 memset (r_buf, 0, sizeof(struct sockaddr_in6));
1078 ret = inet_pton (AF_INET6, &zbuf[1], &r_buf->sin6_addr);
1079 if (ret <= 0)
1080 {
1081 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1082 _ ("Invalid IPv6 address `%s': %s\n"),
1083 &zbuf[1],
1084 strerror (errno));
1085 return GNUNET_SYSERR;
1086 }
1087 r_buf->sin6_port = htons (port);
1088 r_buf->sin6_family = AF_INET6;
1089#if HAVE_SOCKADDR_IN_SIN_LEN
1090 r_buf->sin6_len = (u_char) sizeof(struct sockaddr_in6);
1091#endif
1092 return GNUNET_OK;
1093}
1094
1095
1096enum GNUNET_GenericReturnValue
1097GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr,
1098 uint16_t addrlen,
1099 struct sockaddr_in *r_buf)
1100{
1101 unsigned int temps[4];
1102 unsigned int port;
1103 unsigned int cnt;
1104 char dummy[2];
1105
1106 if (addrlen < 9)
1107 return GNUNET_SYSERR;
1108 cnt = sscanf (zt_addr,
1109 "%u.%u.%u.%u:%u%1s",
1110 &temps[0],
1111 &temps[1],
1112 &temps[2],
1113 &temps[3],
1114 &port,
1115 dummy);
1116 if (5 != cnt)
1117 return GNUNET_SYSERR;
1118 for (cnt = 0; cnt < 4; cnt++)
1119 if (temps[cnt] > 0xFF)
1120 return GNUNET_SYSERR;
1121 if (port > 65535)
1122 return GNUNET_SYSERR;
1123 r_buf->sin_family = AF_INET;
1124 r_buf->sin_port = htons (port);
1125 r_buf->sin_addr.s_addr =
1126 htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + temps[3]);
1127#if HAVE_SOCKADDR_IN_SIN_LEN
1128 r_buf->sin_len = (u_char) sizeof(struct sockaddr_in);
1129#endif
1130 return GNUNET_OK;
1131}
1132
1133
1134enum GNUNET_GenericReturnValue
1135GNUNET_STRINGS_to_address_ip (const char *addr,
1136 uint16_t addrlen,
1137 struct sockaddr_storage *r_buf)
1138{
1139 if (addr[0] == '[')
1140 return GNUNET_STRINGS_to_address_ipv6 (addr,
1141 addrlen,
1142 (struct sockaddr_in6 *) r_buf);
1143 return GNUNET_STRINGS_to_address_ipv4 (addr,
1144 addrlen,
1145 (struct sockaddr_in *) r_buf);
1146}
1147
1148
1149size_t
1150GNUNET_STRINGS_parse_socket_addr (const char *addr,
1151 uint8_t *af,
1152 struct sockaddr **sa)
1153{
1154 char *cp = GNUNET_strdup (addr);
1155
1156 *af = AF_UNSPEC;
1157 if ('[' == *addr)
1158 {
1159 /* IPv6 */
1160 *sa = GNUNET_malloc (sizeof(struct sockaddr_in6));
1161 if (GNUNET_OK !=
1162 GNUNET_STRINGS_to_address_ipv6 (cp,
1163 strlen (cp),
1164 (struct sockaddr_in6 *) *sa))
1165 {
1166 GNUNET_free (*sa);
1167 *sa = NULL;
1168 GNUNET_free (cp);
1169 return 0;
1170 }
1171 *af = AF_INET6;
1172 GNUNET_free (cp);
1173 return sizeof(struct sockaddr_in6);
1174 }
1175 else
1176 {
1177 /* IPv4 */
1178 *sa = GNUNET_malloc (sizeof(struct sockaddr_in));
1179 if (GNUNET_OK !=
1180 GNUNET_STRINGS_to_address_ipv4 (cp,
1181 strlen (cp),
1182 (struct sockaddr_in *) *sa))
1183 {
1184 GNUNET_free (*sa);
1185 *sa = NULL;
1186 GNUNET_free (cp);
1187 return 0;
1188 }
1189 *af = AF_INET;
1190 GNUNET_free (cp);
1191 return sizeof(struct sockaddr_in);
1192 }
1193}
1194
1195
1196/**
1197 * Makes a copy of argv that consists of a single memory chunk that can be
1198 * freed with a single call to GNUNET_free();
1199 */
1200static char *const *
1201_make_continuous_arg_copy (int argc, char *const *argv)
1202{
1203 size_t argvsize = 0;
1204 char **new_argv;
1205 char *p;
1206
1207 for (int i = 0; i < argc; i++)
1208 argvsize += strlen (argv[i]) + 1 + sizeof(char *);
1209 new_argv = GNUNET_malloc (argvsize + sizeof(char *));
1210 p = (char *) &new_argv[argc + 1];
1211 for (int i = 0; i < argc; i++)
1212 {
1213 new_argv[i] = p;
1214 strcpy (p, argv[i]);
1215 p += strlen (argv[i]) + 1;
1216 }
1217 new_argv[argc] = NULL;
1218 return (char *const *) new_argv;
1219}
1220
1221
1222enum GNUNET_GenericReturnValue
1223GNUNET_STRINGS_get_utf8_args (int argc,
1224 char *const *argv,
1225 int *u8argc,
1226 char *const **u8argv)
1227{
1228 char *const *new_argv =
1229 (char *const *) _make_continuous_arg_copy (argc, argv);
1230 *u8argv = new_argv;
1231 *u8argc = argc;
1232 return GNUNET_OK;
1233}
1234
1235
1236/**
1237 * Parse the given port policy. The format is
1238 * "[!]SPORT[-DPORT]".
1239 *
1240 * @param port_policy string to parse
1241 * @param pp policy to fill in
1242 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
1243 * @a port_policy is malformed
1244 */
1245static enum GNUNET_GenericReturnValue
1246parse_port_policy (const char *port_policy,
1247 struct GNUNET_STRINGS_PortPolicy *pp)
1248{
1249 const char *pos;
1250 int s;
1251 int e;
1252 char eol[2];
1253
1254 pos = port_policy;
1255 if ('!' == *pos)
1256 {
1257 pp->negate_portrange = GNUNET_YES;
1258 pos++;
1259 }
1260 if (2 == sscanf (pos, "%u-%u%1s", &s, &e, eol))
1261 {
1262 if ((0 == s) || (s > 0xFFFF) || (e < s) || (e > 0xFFFF))
1263 {
1264 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Port not in range\n"));
1265 return GNUNET_SYSERR;
1266 }
1267 pp->start_port = (uint16_t) s;
1268 pp->end_port = (uint16_t) e;
1269 return GNUNET_OK;
1270 }
1271 if (1 == sscanf (pos, "%u%1s", &s, eol))
1272 {
1273 if ((0 == s) || (s > 0xFFFF))
1274 {
1275 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Port not in range\n"));
1276 return GNUNET_SYSERR;
1277 }
1278
1279 pp->start_port = (uint16_t) s;
1280 pp->end_port = (uint16_t) s;
1281 return GNUNET_OK;
1282 }
1283 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1284 _ ("Malformed port policy `%s'\n"),
1285 port_policy);
1286 return GNUNET_SYSERR;
1287}
1288
1289
1290struct GNUNET_STRINGS_IPv4NetworkPolicy *
1291GNUNET_STRINGS_parse_ipv4_policy (const char *routeListX)
1292{
1293 unsigned int count;
1294 unsigned int i;
1295 unsigned int j;
1296 unsigned int len;
1297 int cnt;
1298 unsigned int pos;
1299 unsigned int temps[8];
1300 int slash;
1301 struct GNUNET_STRINGS_IPv4NetworkPolicy *result;
1302 int colon;
1303 int end;
1304 char *routeList;
1305 char dummy[2];
1306
1307 if (NULL == routeListX)
1308 return NULL;
1309 len = strlen (routeListX);
1310 if (0 == len)
1311 return NULL;
1312 routeList = GNUNET_strdup (routeListX);
1313 count = 0;
1314 for (i = 0; i < len; i++)
1315 if (routeList[i] == ';')
1316 count++;
1317 result = GNUNET_malloc (sizeof(struct GNUNET_STRINGS_IPv4NetworkPolicy)
1318 * (count + 1));
1319 i = 0;
1320 pos = 0;
1321 while (i < count)
1322 {
1323 for (colon = pos; ':' != routeList[colon]; colon++)
1324 if ((';' == routeList[colon]) || ('\0' == routeList[colon]))
1325 break;
1326 for (end = colon; ';' != routeList[end]; end++)
1327 if ('\0' == routeList[end])
1328 break;
1329 if ('\0' == routeList[end])
1330 break;
1331 routeList[end] = '\0';
1332 if (':' == routeList[colon])
1333 {
1334 routeList[colon] = '\0';
1335 if (GNUNET_OK != parse_port_policy (&routeList[colon + 1], &result[i].pp))
1336 break;
1337 }
1338 cnt = sscanf (&routeList[pos],
1339 "%u.%u.%u.%u/%u.%u.%u.%u%1s",
1340 &temps[0],
1341 &temps[1],
1342 &temps[2],
1343 &temps[3],
1344 &temps[4],
1345 &temps[5],
1346 &temps[6],
1347 &temps[7],
1348 dummy);
1349 if (8 == cnt)
1350 {
1351 for (j = 0; j < 8; j++)
1352 if (temps[j] > 0xFF)
1353 {
1354 LOG (GNUNET_ERROR_TYPE_WARNING,
1355 _ ("Invalid format for IP: `%s'\n"),
1356 &routeList[pos]);
1357 GNUNET_free (result);
1358 GNUNET_free (routeList);
1359 return NULL;
1360 }
1361 result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16)
1362 + (temps[2] << 8) + temps[3]);
1363 result[i].netmask.s_addr = htonl ((temps[4] << 24) + (temps[5] << 16)
1364 + (temps[6] << 8) + temps[7]);
1365 pos = end + 1;
1366 i++;
1367 continue;
1368 }
1369 /* try second notation */
1370 cnt = sscanf (&routeList[pos],
1371 "%u.%u.%u.%u/%u%1s",
1372 &temps[0],
1373 &temps[1],
1374 &temps[2],
1375 &temps[3],
1376 &slash,
1377 dummy);
1378 if (5 == cnt)
1379 {
1380 for (j = 0; j < 4; j++)
1381 if (temps[j] > 0xFF)
1382 {
1383 LOG (GNUNET_ERROR_TYPE_WARNING,
1384 _ ("Invalid format for IP: `%s'\n"),
1385 &routeList[pos]);
1386 GNUNET_free (result);
1387 GNUNET_free (routeList);
1388 return NULL;
1389 }
1390 result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16)
1391 + (temps[2] << 8) + temps[3]);
1392 if ((slash <= 32) && (slash >= 0))
1393 {
1394 result[i].netmask.s_addr = 0;
1395 while (slash > 0)
1396 {
1397 result[i].netmask.s_addr =
1398 (result[i].netmask.s_addr >> 1) + 0x80000000;
1399 slash--;
1400 }
1401 result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
1402 pos = end + 1;
1403 i++;
1404 continue;
1405 }
1406 else
1407 {
1408 LOG (GNUNET_ERROR_TYPE_WARNING,
1409 _ ("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
1410 slash);
1411 GNUNET_free (result);
1412 GNUNET_free (routeList);
1413 return NULL; /* error */
1414 }
1415 }
1416 /* try third notation */
1417 slash = 32;
1418 cnt = sscanf (&routeList[pos],
1419 "%u.%u.%u.%u%1s",
1420 &temps[0],
1421 &temps[1],
1422 &temps[2],
1423 &temps[3],
1424 dummy);
1425 if (4 == cnt)
1426 {
1427 for (j = 0; j < 4; j++)
1428 if (temps[j] > 0xFF)
1429 {
1430 LOG (GNUNET_ERROR_TYPE_WARNING,
1431 _ ("Invalid format for IP: `%s'\n"),
1432 &routeList[pos]);
1433 GNUNET_free (result);
1434 GNUNET_free (routeList);
1435 return NULL;
1436 }
1437 result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16)
1438 + (temps[2] << 8) + temps[3]);
1439 result[i].netmask.s_addr = 0;
1440 while (slash > 0)
1441 {
1442 result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000;
1443 slash--;
1444 }
1445 result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
1446 pos = end + 1;
1447 i++;
1448 continue;
1449 }
1450 LOG (GNUNET_ERROR_TYPE_WARNING,
1451 _ ("Invalid format for IP: `%s'\n"),
1452 &routeList[pos]);
1453 GNUNET_free (result);
1454 GNUNET_free (routeList);
1455 return NULL; /* error */
1456 }
1457 if (pos < strlen (routeList))
1458 {
1459 LOG (GNUNET_ERROR_TYPE_WARNING,
1460 _ ("Invalid format: `%s'\n"),
1461 &routeListX[pos]);
1462 GNUNET_free (result);
1463 GNUNET_free (routeList);
1464 return NULL; /* oops */
1465 }
1466 GNUNET_free (routeList);
1467 return result; /* ok */
1468}
1469
1470
1471struct GNUNET_STRINGS_IPv6NetworkPolicy *
1472GNUNET_STRINGS_parse_ipv6_policy (const char *routeListX)
1473{
1474 unsigned int count;
1475 unsigned int i;
1476 unsigned int len;
1477 unsigned int pos;
1478 int start;
1479 int slash;
1480 int ret;
1481 char *routeList;
1482 struct GNUNET_STRINGS_IPv6NetworkPolicy *result;
1483 unsigned int bits;
1484 unsigned int off;
1485 int save;
1486 int colon;
1487 char dummy[2];
1488
1489 if (NULL == routeListX)
1490 return NULL;
1491 len = strlen (routeListX);
1492 if (0 == len)
1493 return NULL;
1494 routeList = GNUNET_strdup (routeListX);
1495 count = 0;
1496 for (i = 0; i < len; i++)
1497 if (';' == routeList[i])
1498 count++;
1499 if (';' != routeList[len - 1])
1500 {
1501 LOG (GNUNET_ERROR_TYPE_WARNING,
1502 _ ("Invalid network notation (does not end with ';': `%s')\n"),
1503 routeList);
1504 GNUNET_free (routeList);
1505 return NULL;
1506 }
1507
1508 result = GNUNET_malloc (sizeof(struct GNUNET_STRINGS_IPv6NetworkPolicy)
1509 * (count + 1));
1510 i = 0;
1511 pos = 0;
1512 while (i < count)
1513 {
1514 start = pos;
1515 while (';' != routeList[pos])
1516 pos++;
1517 slash = pos;
1518 while ((slash >= start) && (routeList[slash] != '/'))
1519 slash--;
1520
1521 if (slash < start)
1522 {
1523 memset (&result[i].netmask, 0xFF, sizeof(struct in6_addr));
1524 slash = pos;
1525 }
1526 else
1527 {
1528 routeList[pos] = '\0';
1529 for (colon = pos; ':' != routeList[colon]; colon--)
1530 if ('/' == routeList[colon])
1531 break;
1532 if (':' == routeList[colon])
1533 {
1534 routeList[colon] = '\0';
1535 if (GNUNET_OK !=
1536 parse_port_policy (&routeList[colon + 1], &result[i].pp))
1537 {
1538 GNUNET_free (result);
1539 GNUNET_free (routeList);
1540 return NULL;
1541 }
1542 }
1543 ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask);
1544 if (ret <= 0)
1545 {
1546 save = errno;
1547 if ((1 != sscanf (&routeList[slash + 1], "%u%1s", &bits, dummy)) ||
1548 (bits > 128))
1549 {
1550 if (0 == ret)
1551 LOG (GNUNET_ERROR_TYPE_WARNING,
1552 _ ("Wrong format `%s' for netmask\n"),
1553 &routeList[slash + 1]);
1554 else
1555 {
1556 errno = save;
1557 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_pton");
1558 }
1559 GNUNET_free (result);
1560 GNUNET_free (routeList);
1561 return NULL;
1562 }
1563 off = 0;
1564 while (bits > 8)
1565 {
1566 result[i].netmask.s6_addr[off++] = 0xFF;
1567 bits -= 8;
1568 }
1569 while (bits > 0)
1570 {
1571 result[i].netmask.s6_addr[off] =
1572 (result[i].netmask.s6_addr[off] >> 1) + 0x80;
1573 bits--;
1574 }
1575 }
1576 }
1577 routeList[slash] = '\0';
1578 ret = inet_pton (AF_INET6, &routeList[start], &result[i].network);
1579 if (ret <= 0)
1580 {
1581 if (0 == ret)
1582 LOG (GNUNET_ERROR_TYPE_WARNING,
1583 _ ("Wrong format `%s' for network\n"),
1584 &routeList[slash + 1]);
1585 else
1586 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
1587 GNUNET_free (result);
1588 GNUNET_free (routeList);
1589 return NULL;
1590 }
1591 pos++;
1592 i++;
1593 }
1594 GNUNET_free (routeList);
1595 return result;
1596}
1597
1598
1599/** ******************** Base64 encoding ***********/
1600
1601#define FILLCHAR '='
1602static char *cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1603 "abcdefghijklmnopqrstuvwxyz"
1604 "0123456789+/";
1605
1606
1607size_t
1608GNUNET_STRINGS_base64_encode (const void *in,
1609 size_t len,
1610 char **output)
1611{
1612 const char *data = in;
1613 size_t ret;
1614 char *opt;
1615
1616 ret = 0;
1617 GNUNET_assert (len < SIZE_MAX / 4 * 3);
1618 opt = GNUNET_malloc (2 + (len * 4 / 3) + 8);
1619 for (size_t i = 0; i < len; ++i)
1620 {
1621 char c;
1622
1623 c = (data[i] >> 2) & 0x3f;
1624 opt[ret++] = cvt[(int) c];
1625 c = (data[i] << 4) & 0x3f;
1626 if (++i < len)
1627 c |= (data[i] >> 4) & 0x0f;
1628 opt[ret++] = cvt[(int) c];
1629 if (i < len)
1630 {
1631 c = (data[i] << 2) & 0x3f;
1632 if (++i < len)
1633 c |= (data[i] >> 6) & 0x03;
1634 opt[ret++] = cvt[(int) c];
1635 }
1636 else
1637 {
1638 ++i;
1639 opt[ret++] = FILLCHAR;
1640 }
1641 if (i < len)
1642 {
1643 c = data[i] & 0x3f;
1644 opt[ret++] = cvt[(int) c];
1645 }
1646 else
1647 {
1648 opt[ret++] = FILLCHAR;
1649 }
1650 }
1651 *output = opt;
1652 return ret;
1653}
1654
1655
1656size_t
1657GNUNET_STRINGS_base64url_encode (const void *in,
1658 size_t len,
1659 char **output)
1660{
1661 char *enc;
1662 size_t pos;
1663
1664 GNUNET_STRINGS_base64_encode (in, len, output);
1665 enc = *output;
1666 /* Replace with correct characters for base64url */
1667 pos = 0;
1668 while ('\0' != enc[pos])
1669 {
1670 if ('+' == enc[pos])
1671 enc[pos] = '-';
1672 if ('/' == enc[pos])
1673 enc[pos] = '_';
1674 if ('=' == enc[pos])
1675 {
1676 enc[pos] = '\0';
1677 break;
1678 }
1679 pos++;
1680 }
1681 return strlen (enc);
1682}
1683
1684
1685#define cvtfind(a) \
1686 ((((a) >= 'A') && ((a) <= 'Z')) \
1687 ? (a) - 'A' \
1688 : (((a) >= 'a') && ((a) <= 'z')) \
1689 ? (a) - 'a' + 26 \
1690 : (((a) >= '0') && ((a) <= '9')) \
1691 ? (a) - '0' + 52 \
1692 : ((a) == '+') ? 62 : ((a) == '/') ? 63 : -1)
1693
1694
1695size_t
1696GNUNET_STRINGS_base64_decode (const char *data,
1697 size_t len,
1698 void **out)
1699{
1700 char *output;
1701 size_t ret = 0;
1702
1703#define CHECK_CRLF \
1704 while (data[i] == '\r' || data[i] == '\n') \
1705 { \
1706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, \
1707 "ignoring CR/LF\n"); \
1708 i++; \
1709 if (i >= len) \
1710 goto END; \
1711 }
1712
1713 GNUNET_assert (len / 3 < SIZE_MAX);
1714 output = GNUNET_malloc ((len * 3 / 4) + 8);
1715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1716 "base64_decode decoding len=%d\n",
1717 (int) len);
1718 for (size_t i = 0; i < len; ++i)
1719 {
1720 char c;
1721 char c1;
1722
1723 CHECK_CRLF;
1724 if (FILLCHAR == data[i])
1725 break;
1726 c = (char) cvtfind (data[i]);
1727 ++i;
1728 CHECK_CRLF;
1729 c1 = (char) cvtfind (data[i]);
1730 c = (c << 2) | ((c1 >> 4) & 0x3);
1731 output[ret++] = c;
1732 if (++i < len)
1733 {
1734 CHECK_CRLF;
1735 c = data[i];
1736 if (FILLCHAR == c)
1737 break;
1738 c = (char) cvtfind (c);
1739 c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
1740 output[ret++] = c1;
1741 }
1742 if (++i < len)
1743 {
1744 CHECK_CRLF;
1745 c1 = data[i];
1746 if (FILLCHAR == c1)
1747 break;
1748
1749 c1 = (char) cvtfind (c1);
1750 c = ((c << 6) & 0xc0) | c1;
1751 output[ret++] = c;
1752 }
1753 }
1754 END:
1755 *out = output;
1756 return ret;
1757}
1758
1759
1760size_t
1761GNUNET_STRINGS_base64url_decode (const char *data,
1762 size_t len,
1763 void **out)
1764{
1765 char *s;
1766 int padding;
1767 size_t ret;
1768
1769 /* make enough space for padding */
1770 GNUNET_assert (len < SIZE_MAX - 3);
1771 s = GNUNET_malloc (len + 3);
1772 memcpy (s, data, len);
1773
1774 for (int i = 0; i < strlen (s); i++)
1775 {
1776 if (s[i] == '-')
1777 s[i] = '+';
1778 if (s[i] == '_')
1779 s[i] = '/';
1780 }
1781 padding = len % 4;
1782 switch (padding) // Pad with trailing '='s
1783 {
1784 case 0:
1785 break; // No pad chars in this case
1786 case 2:
1787 memcpy (&s[len],
1788 "==",
1789 2);
1790 len += 2;
1791 break; // Two pad chars
1792 case 3:
1793 s[len] = '=';
1794 len++;
1795 break; // One pad char
1796 default:
1797 GNUNET_assert (0);
1798 break;
1799 }
1800 ret = GNUNET_STRINGS_base64_decode (s, len, out);
1801 GNUNET_free (s);
1802 return ret;
1803}
1804
1805
1806size_t
1807GNUNET_STRINGS_urldecode (const char *data,
1808 size_t len,
1809 char **out)
1810{
1811 const char *rpos = data;
1812 *out = GNUNET_malloc (len + 1); /* output should always fit into input */
1813 char *wpos = *out;
1814 size_t resl = 0;
1815
1816 while ( ('\0' != *rpos) &&
1817 (data + len != rpos) )
1818 {
1819 unsigned int num;
1820 switch (*rpos)
1821 {
1822 case '%':
1823 if (rpos + 3 > data + len)
1824 {
1825 GNUNET_break_op (0);
1826 GNUNET_free (*out);
1827 return 0;
1828 }
1829 if (1 != sscanf (rpos + 1, "%2x", &num))
1830 break;
1831 *wpos = (char) ((unsigned char) num);
1832 wpos++;
1833 resl++;
1834 rpos += 3;
1835 break;
1836 /* TODO: add bad sequence handling */
1837 /* intentional fall through! */
1838 default:
1839 *wpos = *rpos;
1840 wpos++;
1841 resl++;
1842 rpos++;
1843 }
1844 }
1845 *wpos = '\0'; /* add 0-terminator */
1846 return resl;
1847}
1848
1849
1850size_t
1851GNUNET_STRINGS_urlencode (const char *data,
1852 size_t len,
1853 char **out)
1854{
1855 struct GNUNET_Buffer buf = { 0 };
1856 const uint8_t *i8 = (uint8_t *) data;
1857
1858 while (0 != *i8)
1859 {
1860 if (0 == (0x80 & *i8))
1861 {
1862 /* traditional ASCII */
1863 if (isalnum (*i8) || (*i8 == '-') || (*i8 == '_') || (*i8 == '.') ||
1864 (*i8 == '~') )
1865 GNUNET_buffer_write (&buf, (const char*) i8, 1);
1866 else if (*i8 == ' ')
1867 GNUNET_buffer_write (&buf, "+", 1);
1868 else
1869 GNUNET_buffer_write_fstr (&buf,
1870 "%%%X%X",
1871 *i8 >> 4,
1872 *i8 & 15);
1873 i8++;
1874 continue;
1875 }
1876 if (0x80 + 0x40 == ((0x80 + 0x40 + 0x20) & *i8))
1877 {
1878 /* 2-byte value, percent-encode */
1879 GNUNET_buffer_write_fstr (&buf,
1880 "%%%X%X",
1881 *i8 >> 4,
1882 *i8 & 15);
1883 i8++;
1884 GNUNET_buffer_write_fstr (&buf,
1885 "%%%X%X",
1886 *i8 >> 4,
1887 *i8 & 15);
1888 i8++;
1889 continue;
1890 }
1891 if (0x80 + 0x40 + 0x20 == ((0x80 + 0x40 + 0x20 + 0x10) & *i8))
1892 {
1893 /* 3-byte value, percent-encode */
1894 for (unsigned int i = 0; i<3; i++)
1895 {
1896 GNUNET_buffer_write_fstr (&buf,
1897 "%%%X%X",
1898 *i8 >> 4,
1899 *i8 & 15);
1900 i8++;
1901 }
1902 continue;
1903 }
1904 if (0x80 + 0x40 + 0x20 + 0x10 == ((0x80 + 0x40 + 0x20 + 0x10 + 0x08) & *i8))
1905 {
1906 /* 4-byte value, percent-encode */
1907 for (unsigned int i = 0; i<4; i++)
1908 {
1909 GNUNET_buffer_write_fstr (&buf,
1910 "%%%X%X",
1911 *i8 >> 4,
1912 *i8 & 15);
1913 i8++;
1914 }
1915 continue;
1916 }
1917 if (0x80 + 0x40 + 0x20 + 0x10 + 0x08 == ((0x80 + 0x40 + 0x20 + 0x10 + 0x08
1918 + 0x04) & *i8))
1919 {
1920 /* 5-byte value, percent-encode (outside of UTF-8 modern standard, but so what) */
1921 for (unsigned int i = 0; i<5; i++)
1922 {
1923 GNUNET_buffer_write_fstr (&buf,
1924 "%%%X%X",
1925 *i8 >> 4,
1926 *i8 & 15);
1927 i8++;
1928 }
1929 continue;
1930 }
1931 if (0x80 + 0x40 + 0x20 + 0x10 + 0x08 + 0x04 == ((0x80 + 0x40 + 0x20 + 0x10
1932 + 0x08 + 0x04 + 0x02)
1933 & *i8))
1934 {
1935 /* 6-byte value, percent-encode (outside of UTF-8 modern standard, but so what) */
1936 for (unsigned int i = 0; i<6; i++)
1937 {
1938 GNUNET_buffer_write_fstr (&buf,
1939 "%%%X%X",
1940 *i8 >> 4,
1941 *i8 & 15);
1942 i8++;
1943 }
1944 continue;
1945 }
1946 /* really, really invalid UTF-8: fail */
1947 GNUNET_break (0);
1948 GNUNET_buffer_clear (&buf);
1949 return 0;
1950 }
1951 *out = GNUNET_buffer_reap_str (&buf);
1952 return strlen (*out);
1953}
1954
1955
1956/* 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 06a3fb500..000000000
--- a/src/util/test_container_bloomfilter.c
+++ /dev/null
@@ -1,301 +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
35static void
36bernd_interop (void)
37{
38 struct GNUNET_HashCode hc;
39 char val[128];
40 size_t len;
41 struct GNUNET_CONTAINER_BloomFilter *bf;
42
43 len = GNUNET_DNSPARSER_hex_to_bin (
44 "ac4d46b62f8ddaf3cefbc1c01e47536b7ff297cb081e27a396362b1e92e5729b",
45 val);
46 GNUNET_assert (len < 128);
47 GNUNET_CRYPTO_hash (val,
48 len,
49 &hc);
50 fprintf (stderr,
51 "sha512: %s\n",
52 GNUNET_DNSPARSER_bin_to_hex (&hc,
53 sizeof (hc)));
54 bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
55 128,
56 16);
57 GNUNET_CONTAINER_bloomfilter_add (bf,
58 &hc);
59 len = GNUNET_CONTAINER_bloomfilter_get_size (bf);
60 {
61 char raw[len];
62
63 GNUNET_CONTAINER_bloomfilter_get_raw_data (bf,
64 raw,
65 len);
66 fprintf (stderr,
67 "BF: %s\n",
68 GNUNET_DNSPARSER_bin_to_hex (raw,
69 len));
70 }
71
72}
73
74
75/**
76 * Generate a random hashcode.
77 */
78static void
79nextHC (struct GNUNET_HashCode *hc)
80{
81 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, hc);
82}
83
84
85static int
86add_iterator (void *cls, struct GNUNET_HashCode *next)
87{
88 int *ret = cls;
89 struct GNUNET_HashCode pos;
90
91 if (0 == (*ret)--)
92 return GNUNET_NO;
93 nextHC (&pos);
94 *next = pos;
95 return GNUNET_YES;
96}
97
98
99int
100main (int argc, char *argv[])
101{
102 struct GNUNET_CONTAINER_BloomFilter *bf;
103 struct GNUNET_CONTAINER_BloomFilter *bfi;
104 struct GNUNET_HashCode tmp;
105 int i;
106 int ok1;
107 int ok2;
108 int falseok;
109 char buf[SIZE];
110 struct stat sbuf;
111
112 GNUNET_log_setup ("test-container-bloomfilter",
113 "WARNING",
114 NULL);
115 if (0)
116 {
117 bernd_interop ();
118 return 0;
119 }
120 GNUNET_CRYPTO_seed_weak_random (1);
121 if (0 == stat (TESTFILE, &sbuf))
122 if (0 != unlink (TESTFILE))
123 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", TESTFILE);
124 bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K);
125
126 for (i = 0; i < 200; i++)
127 {
128 nextHC (&tmp);
129 GNUNET_CONTAINER_bloomfilter_add (bf, &tmp);
130 }
131 GNUNET_CRYPTO_seed_weak_random (1);
132 ok1 = 0;
133 for (i = 0; i < 200; i++)
134 {
135 nextHC (&tmp);
136 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
137 ok1++;
138 }
139 if (ok1 != 200)
140 {
141 printf ("Got %d elements out of"
142 "200 expected after insertion.\n",
143 ok1);
144 GNUNET_CONTAINER_bloomfilter_free (bf);
145 return -1;
146 }
147 if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_get_raw_data (bf, buf, SIZE))
148 {
149 GNUNET_CONTAINER_bloomfilter_free (bf);
150 return -1;
151 }
152
153 GNUNET_CONTAINER_bloomfilter_free (bf);
154
155 bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K);
156 GNUNET_assert (bf != NULL);
157 bfi = GNUNET_CONTAINER_bloomfilter_init (buf, SIZE, K);
158 GNUNET_assert (bfi != NULL);
159
160 GNUNET_CRYPTO_seed_weak_random (1);
161 ok1 = 0;
162 ok2 = 0;
163 for (i = 0; i < 200; i++)
164 {
165 nextHC (&tmp);
166 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
167 ok1++;
168 if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES)
169 ok2++;
170 }
171 if (ok1 != 200)
172 {
173 printf ("Got %d elements out of 200 "
174 "expected after reloading.\n",
175 ok1);
176 GNUNET_CONTAINER_bloomfilter_free (bf);
177 GNUNET_CONTAINER_bloomfilter_free (bfi);
178 return -1;
179 }
180
181 if (ok2 != 200)
182 {
183 printf ("Got %d elements out of 200 "
184 "expected after initialization.\n",
185 ok2);
186 GNUNET_CONTAINER_bloomfilter_free (bf);
187 GNUNET_CONTAINER_bloomfilter_free (bfi);
188 return -1;
189 }
190
191 GNUNET_CRYPTO_seed_weak_random (1);
192 for (i = 0; i < 100; i++)
193 {
194 nextHC (&tmp);
195 GNUNET_CONTAINER_bloomfilter_remove (bf, &tmp);
196 GNUNET_CONTAINER_bloomfilter_remove (bfi, &tmp);
197 }
198
199 GNUNET_CRYPTO_seed_weak_random (1);
200
201 ok1 = 0;
202 ok2 = 0;
203 for (i = 0; i < 200; i++)
204 {
205 nextHC (&tmp);
206 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
207 ok1++;
208 if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES)
209 ok2++;
210 }
211
212 if (ok1 != 100)
213 {
214 printf ("Expected 100 elements in loaded filter"
215 " after adding 200 and deleting 100, got %d\n",
216 ok1);
217 GNUNET_CONTAINER_bloomfilter_free (bf);
218 GNUNET_CONTAINER_bloomfilter_free (bfi);
219 return -1;
220 }
221 if (ok2 != 200)
222 {
223 printf ("Expected 200 elements in initialized filter"
224 " after adding 200 and deleting 100 "
225 "(which should do nothing for a filter not backed by a file), got %d\n",
226 ok2);
227 GNUNET_CONTAINER_bloomfilter_free (bf);
228 GNUNET_CONTAINER_bloomfilter_free (bfi);
229 return -1;
230 }
231
232 GNUNET_CRYPTO_seed_weak_random (3);
233
234 GNUNET_CONTAINER_bloomfilter_clear (bf);
235 falseok = 0;
236 for (i = 0; i < 1000; i++)
237 {
238 nextHC (&tmp);
239 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
240 falseok++;
241 }
242 if (falseok > 0)
243 {
244 GNUNET_CONTAINER_bloomfilter_free (bf);
245 GNUNET_CONTAINER_bloomfilter_free (bfi);
246 return -1;
247 }
248
249 if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_or (bf, buf, SIZE))
250 {
251 GNUNET_CONTAINER_bloomfilter_free (bf);
252 GNUNET_CONTAINER_bloomfilter_free (bfi);
253 return -1;
254 }
255
256 GNUNET_CRYPTO_seed_weak_random (2);
257 i = 20;
258 GNUNET_CONTAINER_bloomfilter_resize (bfi, &add_iterator, &i, SIZE * 2, K);
259
260 GNUNET_CRYPTO_seed_weak_random (2);
261 i = 20;
262 GNUNET_CONTAINER_bloomfilter_resize (bf, &add_iterator, &i, SIZE * 2, K);
263 GNUNET_CRYPTO_seed_weak_random (2);
264
265 ok1 = 0;
266 ok2 = 0;
267 for (i = 0; i < 20; i++)
268 {
269 nextHC (&tmp);
270 if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES)
271 ok1++;
272 if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES)
273 ok2++;
274 }
275
276 if (ok1 != 20)
277 {
278 printf ("Expected 20 elements in resized file-backed filter"
279 " after adding 20, got %d\n",
280 ok1);
281 GNUNET_CONTAINER_bloomfilter_free (bf);
282 GNUNET_CONTAINER_bloomfilter_free (bfi);
283 return -1;
284 }
285 if (ok2 != 20)
286 {
287 printf ("Expected 20 elements in resized filter"
288 " after adding 20, got %d\n",
289 ok2);
290 GNUNET_CONTAINER_bloomfilter_free (bf);
291 GNUNET_CONTAINER_bloomfilter_free (bfi);
292 return -1;
293 }
294
295
296 GNUNET_CONTAINER_bloomfilter_free (bf);
297 GNUNET_CONTAINER_bloomfilter_free (bfi);
298
299 GNUNET_break (0 == unlink (TESTFILE));
300 return 0;
301}
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_cs.c b/src/util/test_crypto_cs.c
deleted file mode 100644
index a56ff7421..000000000
--- a/src/util/test_crypto_cs.c
+++ /dev/null
@@ -1,609 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021,2022 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_cs.c
23 * @brief testcase for utility functions for clause blind schnorr signature scheme cryptography
24 * @author Lucien Heuzeveldt <lucienclaude.heuzeveldt@students.bfh.ch>
25 * @author Gian Demarmels <gian@demarmels.org>
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include <sodium.h>
30
31#define ITER 25
32
33static void
34test_create_priv (struct GNUNET_CRYPTO_CsPrivateKey *priv)
35{
36 /* TEST 1
37 * Check that privkey is set
38 */
39 struct GNUNET_CRYPTO_CsPrivateKey other_priv;
40
41 other_priv = *priv;
42 GNUNET_CRYPTO_cs_private_key_generate (priv);
43 GNUNET_assert (0 !=
44 GNUNET_memcmp (&other_priv.scalar,
45 &priv->scalar));
46}
47
48
49static void
50test_generate_pub (const struct GNUNET_CRYPTO_CsPrivateKey *priv,
51 struct GNUNET_CRYPTO_CsPublicKey *pub)
52{
53 /* TEST 1
54 * Check that pubkey is set
55 */
56 struct GNUNET_CRYPTO_CsPublicKey other_pub;
57
58 other_pub = *pub;
59 GNUNET_CRYPTO_cs_private_key_get_public (priv,
60 pub);
61 GNUNET_assert (0 !=
62 GNUNET_memcmp (&other_pub.point,
63 &pub->point));
64
65 /* TEST 2
66 * Check that pubkey is a valid point
67 */
68 GNUNET_assert (1 ==
69 crypto_core_ed25519_is_valid_point (pub->point.y));
70
71 /* TEST 3
72 * Check if function gives the same result for the same output
73 */
74 other_pub = *pub;
75 for (unsigned int i = 0; i<ITER; i++)
76 {
77 GNUNET_CRYPTO_cs_private_key_get_public (priv,
78 pub);
79 GNUNET_assert (0 ==
80 GNUNET_memcmp (&other_pub.point,
81 &pub->point));
82 }
83}
84
85
86static void
87test_derive_rsecret (const struct GNUNET_CRYPTO_CsNonce *nonce,
88 const struct GNUNET_CRYPTO_CsPrivateKey *priv,
89 struct GNUNET_CRYPTO_CsRSecret r[2])
90{
91 /* TEST 1
92 * Check that r are set
93 */
94 struct GNUNET_CRYPTO_CsPrivateKey other_r[2];
95
96 memcpy (other_r,
97 r,
98 sizeof(struct GNUNET_CRYPTO_CsPrivateKey) * 2);
99 GNUNET_CRYPTO_cs_r_derive (nonce,
100 "nw",
101 priv,
102 r);
103 GNUNET_assert (0 !=
104 memcmp (&other_r[0],
105 &r[0],
106 sizeof(struct GNUNET_CRYPTO_CsPrivateKey) * 2));
107
108 /* TEST 2
109 * Check if function gives the same result for the same input.
110 * This test ensures that the derivation is deterministic.
111 */
112 memcpy (other_r,
113 r,
114 sizeof(struct GNUNET_CRYPTO_CsPrivateKey) * 2);
115 for (unsigned int i = 0; i<ITER; i++)
116 {
117 GNUNET_CRYPTO_cs_r_derive (nonce,
118 "nw",
119 priv,
120 r);
121 GNUNET_assert (0 ==
122 memcmp (other_r,
123 r,
124 sizeof(struct GNUNET_CRYPTO_CsPrivateKey) * 2));
125 }
126}
127
128
129static void
130test_generate_rpublic (const struct GNUNET_CRYPTO_CsRSecret *r_priv,
131 struct GNUNET_CRYPTO_CsRPublic *r_pub)
132{
133 /* TEST 1
134 * Check that r_pub is set
135 */
136 struct GNUNET_CRYPTO_CsRPublic other_r_pub;
137
138 other_r_pub = *r_pub;
139 GNUNET_CRYPTO_cs_r_get_public (r_priv,
140 r_pub);
141 GNUNET_assert (0 !=
142 GNUNET_memcmp (&other_r_pub.point,
143 &r_pub->point));
144 /* TEST 2
145 * Check that r_pub is a valid point
146 */
147 GNUNET_assert (1 ==
148 crypto_core_ed25519_is_valid_point (r_pub->point.y));
149
150 /* TEST 3
151 * Check if function gives the same result for the same output
152 */
153 other_r_pub.point = r_pub->point;
154 for (int i = 0; i<ITER; i++)
155 {
156 GNUNET_CRYPTO_cs_r_get_public (r_priv,
157 r_pub);
158 GNUNET_assert (0 ==
159 GNUNET_memcmp (&other_r_pub.point,
160 &r_pub->point));
161 }
162}
163
164
165static void
166test_derive_blindingsecrets (const struct GNUNET_CRYPTO_CsNonce *blind_seed,
167 struct GNUNET_CRYPTO_CsBlindingSecret bs[2])
168{
169 /* TEST 1
170 * Check that blinding secrets are set
171 */
172 struct GNUNET_CRYPTO_CsBlindingSecret other_bs[2];
173
174 memcpy (other_bs,
175 bs,
176 sizeof(struct GNUNET_CRYPTO_CsBlindingSecret) * 2);
177
178 GNUNET_CRYPTO_cs_blinding_secrets_derive (blind_seed, bs);
179
180 GNUNET_assert (0 !=
181 memcmp (other_bs,
182 bs,
183 sizeof(struct GNUNET_CRYPTO_CsBlindingSecret)
184 * 2));
185
186 /* TEST 2
187 * Check if function gives the same result for the same input.
188 * This test ensures that the derivation is deterministic.
189 */
190 memcpy (other_bs,
191 bs,
192 sizeof(struct GNUNET_CRYPTO_CsBlindingSecret) * 2);
193 for (unsigned int i = 0; i<ITER; i++)
194 {
195 GNUNET_CRYPTO_cs_blinding_secrets_derive (blind_seed, bs);
196 GNUNET_assert (0 == memcmp (&other_bs[0],
197 &bs[0],
198 sizeof(struct GNUNET_CRYPTO_CsBlindingSecret)
199 * 2));
200 }
201}
202
203
204static void
205test_calc_blindedc (const struct GNUNET_CRYPTO_CsBlindingSecret bs[2],
206 const struct GNUNET_CRYPTO_CsRPublic r_pub[2],
207 const struct GNUNET_CRYPTO_CsPublicKey *pub,
208 const void *msg,
209 size_t msg_len,
210 struct GNUNET_CRYPTO_CsC blinded_cs[2],
211 struct GNUNET_CRYPTO_CsRPublic blinded_r_pub[2])
212{
213 /* TEST 1
214 * Check that the blinded c's and blinded r's
215 */
216 struct GNUNET_CRYPTO_CsC other_blinded_c[2];
217
218 memcpy (&other_blinded_c[0],
219 &blinded_cs[0],
220 sizeof(struct GNUNET_CRYPTO_CsC) * 2);
221
222 struct GNUNET_CRYPTO_CsRPublic other_blinded_r_pub[2];
223 memcpy (&other_blinded_r_pub[0],
224 &blinded_r_pub[0],
225 sizeof(struct GNUNET_CRYPTO_CsRPublic) * 2);
226
227 GNUNET_CRYPTO_cs_calc_blinded_c (bs,
228 r_pub,
229 pub,
230 msg,
231 msg_len,
232 blinded_cs,
233 blinded_r_pub);
234
235 GNUNET_assert (0 != memcmp (&other_blinded_c[0],
236 &blinded_cs[0],
237 sizeof(struct GNUNET_CRYPTO_CsC) * 2));
238 GNUNET_assert (0 != memcmp (&other_blinded_r_pub[0],
239 &blinded_r_pub[0],
240 sizeof(struct GNUNET_CRYPTO_CsRPublic) * 2));
241
242 /* TEST 2
243 * Check if R' - aG -bX = R for b = 0
244 * This test does the opposite operations and checks whether the equation is still correct.
245 */
246 for (unsigned int b = 0; b <= 1; b++)
247 {
248 struct GNUNET_CRYPTO_Cs25519Point aG;
249 struct GNUNET_CRYPTO_Cs25519Point bX;
250 struct GNUNET_CRYPTO_Cs25519Point r_min_aG;
251 struct GNUNET_CRYPTO_CsRPublic res;
252
253 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (
254 aG.y,
255 bs[b].alpha.d));
256
257 GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (
258 bX.y,
259 bs[b].beta.d,
260 pub->point.y));
261
262 GNUNET_assert (0 == crypto_core_ed25519_sub (
263 r_min_aG.y,
264 blinded_r_pub[b].point.y,
265 aG.y));
266
267 GNUNET_assert (0 == crypto_core_ed25519_sub (
268 res.point.y,
269 r_min_aG.y,
270 bX.y));
271
272 GNUNET_assert (0 == memcmp (&res, &r_pub[b], sizeof(struct
273 GNUNET_CRYPTO_CsRPublic)));
274 }
275
276
277 /* TEST 3
278 * Check that the blinded r_pubs' are valid points
279 */
280 GNUNET_assert (1 == crypto_core_ed25519_is_valid_point (
281 blinded_r_pub[0].point.y));
282 GNUNET_assert (1 == crypto_core_ed25519_is_valid_point (
283 blinded_r_pub[1].point.y));
284
285 /* TEST 4
286 * Check if function gives the same result for the same input.
287 */
288 memcpy (&other_blinded_c[0],
289 &blinded_cs[0],
290 sizeof(struct GNUNET_CRYPTO_CsC) * 2);
291 memcpy (&other_blinded_r_pub[0],
292 &blinded_r_pub[0],
293 sizeof(struct GNUNET_CRYPTO_CsRPublic) * 2);
294
295 for (unsigned int i = 0; i<ITER; i++)
296 {
297 GNUNET_CRYPTO_cs_calc_blinded_c (bs,
298 r_pub,
299 pub,
300 msg,
301 msg_len,
302 blinded_cs,
303 blinded_r_pub);
304 GNUNET_assert (0 == memcmp (&other_blinded_c[0],
305 &blinded_cs[0],
306 sizeof(struct GNUNET_CRYPTO_CsC) * 2));
307 GNUNET_assert (0 == memcmp (&other_blinded_r_pub[0],
308 &blinded_r_pub[0],
309 sizeof(struct GNUNET_CRYPTO_CsRPublic) * 2));
310 }
311}
312
313
314static void
315test_blind_sign (unsigned int *b,
316 const struct GNUNET_CRYPTO_CsPrivateKey *priv,
317 const struct GNUNET_CRYPTO_CsRSecret r[2],
318 const struct GNUNET_CRYPTO_CsC c[2],
319 const struct GNUNET_CRYPTO_CsNonce *nonce,
320 struct GNUNET_CRYPTO_CsBlindS *blinded_s)
321{
322 /* TEST 1
323 * Check that blinded_s is set
324 */
325 struct GNUNET_CRYPTO_CsC other_blinded_s;
326 memcpy (&other_blinded_s, blinded_s, sizeof(struct GNUNET_CRYPTO_CsBlindS));
327
328 *b = GNUNET_CRYPTO_cs_sign_derive (priv,
329 r,
330 c,
331 nonce,
332 blinded_s);
333
334 GNUNET_assert (0 == *b || 1 == *b);
335 GNUNET_assert (0 != memcmp (&other_blinded_s,
336 blinded_s,
337 sizeof(struct GNUNET_CRYPTO_CsBlindS)));
338
339 /* TEST 2
340 * Check if s := rb + cbX
341 * This test does the opposite operations and checks whether the equation is still correct.
342 */
343 struct GNUNET_CRYPTO_Cs25519Scalar cb_mul_x;
344 struct GNUNET_CRYPTO_Cs25519Scalar s_min_rb;
345
346 crypto_core_ed25519_scalar_mul (cb_mul_x.d,
347 c[*b].scalar.d,
348 priv->scalar.d);
349
350 crypto_core_ed25519_scalar_sub (s_min_rb.d,
351 blinded_s->scalar.d,
352 r[*b].scalar.d);
353
354 GNUNET_assert (0 == memcmp (&s_min_rb, &cb_mul_x, sizeof(struct
355 GNUNET_CRYPTO_Cs25519Scalar)));
356
357 /* TEST 3
358 * Check if function gives the same result for the same input.
359 */
360 memcpy (&other_blinded_s, blinded_s, sizeof(struct GNUNET_CRYPTO_CsBlindS));
361 for (unsigned int i = 0; i<ITER; i++)
362 {
363 unsigned int other_b;
364
365 other_b = GNUNET_CRYPTO_cs_sign_derive (priv, r, c, nonce, blinded_s);
366
367 GNUNET_assert (other_b == *b);
368 GNUNET_assert (0 == memcmp (&other_blinded_s,
369 blinded_s,
370 sizeof(struct GNUNET_CRYPTO_CsBlindS)));
371 }
372}
373
374
375static void
376test_unblinds (const struct GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar,
377 const struct GNUNET_CRYPTO_CsBlindingSecret *bs,
378 struct GNUNET_CRYPTO_CsS *signature_scalar)
379{
380 /* TEST 1
381 * Check that signature_scalar is set
382 */
383 struct GNUNET_CRYPTO_CsS other_signature_scalar;
384 memcpy (&other_signature_scalar,
385 signature_scalar,
386 sizeof(struct GNUNET_CRYPTO_CsS));
387
388 GNUNET_CRYPTO_cs_unblind (blinded_signature_scalar, bs, signature_scalar);
389
390 GNUNET_assert (0 != memcmp (&other_signature_scalar,
391 signature_scalar,
392 sizeof(struct GNUNET_CRYPTO_CsS)));
393
394 /* TEST 2
395 * Check if s' := s + a mod p
396 * This test does the opposite operations and checks whether the equation is still correct.
397 */
398 struct GNUNET_CRYPTO_Cs25519Scalar s_min_a;
399
400 crypto_core_ed25519_scalar_sub (s_min_a.d,
401 signature_scalar->scalar.d,
402 bs->alpha.d);
403
404 GNUNET_assert (0 == memcmp (&s_min_a, &blinded_signature_scalar->scalar,
405 sizeof(struct
406 GNUNET_CRYPTO_Cs25519Scalar)));
407
408 /* TEST 3
409 * Check if function gives the same result for the same input.
410 */
411 memcpy (&other_signature_scalar, signature_scalar,
412 sizeof(struct GNUNET_CRYPTO_CsS));
413
414 for (unsigned int i = 0; i<ITER; i++)
415 {
416 GNUNET_CRYPTO_cs_unblind (blinded_signature_scalar, bs, signature_scalar);
417 GNUNET_assert (0 == memcmp (&other_signature_scalar,
418 signature_scalar,
419 sizeof(struct GNUNET_CRYPTO_CsS)));
420 }
421}
422
423
424static void
425test_blind_verify (const struct GNUNET_CRYPTO_CsSignature *sig,
426 const struct GNUNET_CRYPTO_CsPublicKey *pub,
427 const struct GNUNET_CRYPTO_CsC *c)
428{
429 /* TEST 1
430 * Test verifies the blinded signature sG == Rb + cbX
431 */
432 struct GNUNET_CRYPTO_Cs25519Point sig_scal_mul_base;
433 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (
434 sig_scal_mul_base.y,
435 sig->s_scalar.scalar.d));
436
437 struct GNUNET_CRYPTO_Cs25519Point c_mul_pub;
438 GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (c_mul_pub.y,
439 c->scalar.d,
440 pub->point.y));
441
442 struct GNUNET_CRYPTO_Cs25519Point r_add_c_mul_pub;
443 GNUNET_assert (0 == crypto_core_ed25519_add (r_add_c_mul_pub.y,
444 sig->r_point.point.y,
445 c_mul_pub.y));
446
447 GNUNET_assert (0 == memcmp (sig_scal_mul_base.y,
448 r_add_c_mul_pub.y,
449 sizeof(struct GNUNET_CRYPTO_Cs25519Point)));
450}
451
452
453static void
454test_verify (const struct GNUNET_CRYPTO_CsSignature *sig,
455 const struct GNUNET_CRYPTO_CsPublicKey *pub,
456 const void *msg,
457 size_t msg_len)
458{
459 /* TEST 1
460 * Test simple verification
461 */
462 GNUNET_assert (GNUNET_YES ==
463 GNUNET_CRYPTO_cs_verify (sig,
464 pub,
465 msg,
466 msg_len));
467 /* TEST 2
468 * Test verification of "wrong" message
469 */
470 char other_msg[] = "test massege";
471 size_t other_msg_len = strlen ("test massege");
472 GNUNET_assert (GNUNET_SYSERR ==
473 GNUNET_CRYPTO_cs_verify (sig,
474 pub,
475 other_msg,
476 other_msg_len));
477}
478
479
480int
481main (int argc,
482 char *argv[])
483{
484 printf ("Test started\n");
485
486 // ---------- actions performed by signer
487 char message[] = "test message";
488 size_t message_len = strlen ("test message");
489
490 struct GNUNET_CRYPTO_CsPrivateKey priv;
491
492 memset (&priv,
493 42,
494 sizeof (priv));
495 test_create_priv (&priv);
496
497 struct GNUNET_CRYPTO_CsPublicKey pub;
498
499 memset (&pub,
500 42,
501 sizeof (pub));
502 test_generate_pub (&priv,
503 &pub);
504
505 // derive nonce
506 struct GNUNET_CRYPTO_CsNonce nonce;
507 GNUNET_assert (GNUNET_YES ==
508 GNUNET_CRYPTO_kdf (nonce.nonce,
509 sizeof(nonce.nonce),
510 "nonce",
511 strlen ("nonce"),
512 "nonce_secret",
513 strlen ("nonce_secret"),
514 NULL,
515 0));
516
517 // generate r, R
518 struct GNUNET_CRYPTO_CsRSecret r_secrets[2];
519
520 memset (r_secrets,
521 42,
522 sizeof (r_secrets));
523 test_derive_rsecret (&nonce,
524 &priv,
525 r_secrets);
526
527 struct GNUNET_CRYPTO_CsRPublic r_publics[2];
528
529 memset (r_publics,
530 42,
531 sizeof (r_publics));
532 test_generate_rpublic (&r_secrets[0],
533 &r_publics[0]);
534 test_generate_rpublic (&r_secrets[1],
535 &r_publics[1]);
536
537 // ---------- actions performed by user
538
539 // generate blinding secrets
540 struct GNUNET_CRYPTO_CsBlindingSecret blindingsecrets[2];
541
542 memset (blindingsecrets,
543 42,
544 sizeof (blindingsecrets));
545 test_derive_blindingsecrets (&nonce,
546 blindingsecrets);
547
548 // calculate blinded c's
549 struct GNUNET_CRYPTO_CsC blinded_cs[2];
550 struct GNUNET_CRYPTO_CsRPublic blinded_r_pubs[2];
551
552 memset (blinded_cs,
553 42,
554 sizeof (blinded_cs));
555 memset (blinded_r_pubs,
556 42,
557 sizeof (blinded_r_pubs));
558 test_calc_blindedc (blindingsecrets,
559 r_publics,
560 &pub,
561 message,
562 message_len,
563 blinded_cs,
564 blinded_r_pubs);
565
566 // ---------- actions performed by signer
567 // sign blinded c's and get b and s in return
568 unsigned int b;
569 struct GNUNET_CRYPTO_CsBlindS blinded_s;
570
571 memset (&blinded_s,
572 42,
573 sizeof (blinded_s));
574 test_blind_sign (&b,
575 &priv,
576 r_secrets,
577 blinded_cs,
578 &nonce,
579 &blinded_s);
580
581 // verify blinded signature
582 struct GNUNET_CRYPTO_CsSignature blinded_signature;
583
584 blinded_signature.r_point = r_publics[b];
585 blinded_signature.s_scalar.scalar = blinded_s.scalar;
586 test_blind_verify (&blinded_signature,
587 &pub,
588 &blinded_cs[b]);
589
590 // ---------- actions performed by user
591 struct GNUNET_CRYPTO_CsS sig_scalar;
592
593 memset (&sig_scalar,
594 42,
595 sizeof (sig_scalar));
596 test_unblinds (&blinded_s,
597 &blindingsecrets[b],
598 &sig_scalar);
599
600 // verify unblinded signature
601 struct GNUNET_CRYPTO_CsSignature signature;
602 signature.r_point = blinded_r_pubs[b];
603 signature.s_scalar = sig_scalar;
604 test_verify (&signature,
605 &pub,
606 message,
607 message_len);
608 return 0;
609}
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 e9573a307..000000000
--- a/src/util/test_crypto_eddsa.c
+++ /dev/null
@@ -1,318 +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_derived (&key,
134 "test-derive",
135 "test-CTX",
136 &purp,
137 &sig);
138 if (GNUNET_SYSERR ==
139 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
140 &purp,
141 &sig,
142 &dpub))
143 {
144 fprintf (stderr,
145 "GNUNET_CRYPTO_eddsa_verify failed!\n");
146 return GNUNET_SYSERR;
147 }
148 if (GNUNET_SYSERR !=
149 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
150 &purp,
151 &sig,
152 &pkey))
153 {
154 fprintf (stderr,
155 "GNUNET_CRYPTO_eddsa_verify failed to fail!\n");
156 return GNUNET_SYSERR;
157 }
158 if (GNUNET_SYSERR !=
159 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
160 &purp,
161 &sig,
162 &dpub))
163 {
164 fprintf (stderr,
165 "GNUNET_CRYPTO_eddsa_verify failed to fail!\n");
166 return GNUNET_SYSERR;
167 }
168 return GNUNET_OK;
169}
170
171
172#if PERF
173static int
174testSignPerformance ()
175{
176 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
177 struct GNUNET_CRYPTO_EddsaSignature sig;
178 struct GNUNET_CRYPTO_EddsaPublicKey pkey;
179 struct GNUNET_TIME_Absolute start;
180 int ok = GNUNET_OK;
181
182 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
183 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
184 fprintf (stderr, "%s", "W");
185 GNUNET_CRYPTO_eddsa_key_get_public (&key,
186 &pkey);
187 start = GNUNET_TIME_absolute_get ();
188 for (unsigned int i = 0; i < ITER; i++)
189 {
190 fprintf (stderr, "%s", ".");
191 fflush (stderr);
192 if (GNUNET_SYSERR ==
193 GNUNET_CRYPTO_eddsa_sign_ (&key,
194 &purp,
195 &sig))
196 {
197 fprintf (stderr, "%s", "GNUNET_CRYPTO_eddsa_sign returned SYSERR\n");
198 ok = GNUNET_SYSERR;
199 continue;
200 }
201 }
202 fprintf (stderr, "\n");
203 printf ("%d EdDSA sign operations %s\n",
204 ITER,
205 GNUNET_STRINGS_relative_time_to_string (
206 GNUNET_TIME_absolute_get_duration (start),
207 GNUNET_YES));
208 return ok;
209}
210
211
212#endif
213
214
215static int
216testCreateFromFile (void)
217{
218 struct GNUNET_CRYPTO_EddsaPublicKey p1;
219 struct GNUNET_CRYPTO_EddsaPublicKey p2;
220
221 /* do_create == GNUNET_YES and non-existing file MUST return GNUNET_YES */
222 GNUNET_assert (0 == unlink (KEYFILE) || ENOENT == errno);
223 GNUNET_assert (GNUNET_YES ==
224 GNUNET_CRYPTO_eddsa_key_from_file (KEYFILE,
225 GNUNET_YES,
226 &key));
227 GNUNET_CRYPTO_eddsa_key_get_public (&key,
228 &p1);
229
230 /* do_create == GNUNET_YES and _existing_ file MUST return GNUNET_NO */
231 GNUNET_assert (GNUNET_NO ==
232 GNUNET_CRYPTO_eddsa_key_from_file (KEYFILE,
233 GNUNET_YES,
234 &key));
235 GNUNET_CRYPTO_eddsa_key_get_public (&key,
236 &p2);
237 GNUNET_assert (0 ==
238 GNUNET_memcmp (&p1,
239 &p2));
240
241 /* do_create == GNUNET_NO and non-existing file MUST return GNUNET_SYSERR */
242 GNUNET_assert (0 == unlink (KEYFILE));
243 GNUNET_assert (GNUNET_SYSERR ==
244 GNUNET_CRYPTO_eddsa_key_from_file (KEYFILE,
245 GNUNET_NO,
246 &key));
247 return GNUNET_OK;
248}
249
250
251static void
252perf_keygen (void)
253{
254 struct GNUNET_TIME_Absolute start;
255 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
256
257 fprintf (stderr, "%s", "W");
258 start = GNUNET_TIME_absolute_get ();
259 for (unsigned int i = 0; i < 10; i++)
260 {
261 fprintf (stderr, ".");
262 fflush (stderr);
263 GNUNET_CRYPTO_eddsa_key_create (&pk);
264 }
265 fprintf (stderr, "\n");
266 printf ("10 EdDSA keys created in %s\n",
267 GNUNET_STRINGS_relative_time_to_string (
268 GNUNET_TIME_absolute_get_duration (start), GNUNET_YES));
269}
270
271
272int
273main (int argc, char *argv[])
274{
275 int failure_count = 0;
276
277 if (! gcry_check_version ("1.6.0"))
278 {
279 fprintf (stderr,
280 "libgcrypt has not the expected version (version %s is required).\n",
281 "1.6.0");
282 return 0;
283 }
284 if (getenv ("GNUNET_GCRYPT_DEBUG"))
285 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
286 GNUNET_log_setup ("test-crypto-eddsa",
287 "WARNING",
288 NULL);
289 GNUNET_CRYPTO_eddsa_key_create (&key);
290 if (GNUNET_OK != testDeriveSignVerify ())
291 {
292 failure_count++;
293 fprintf (stderr,
294 "\n\n%d TESTS FAILED!\n\n", failure_count);
295 return -1;
296 }
297#if PERF
298 if (GNUNET_OK != testSignPerformance ())
299 failure_count++;
300#endif
301 if (GNUNET_OK != testSignVerify ())
302 failure_count++;
303 if (GNUNET_OK != testCreateFromFile ())
304 failure_count++;
305 perf_keygen ();
306
307 if (0 != failure_count)
308 {
309 fprintf (stderr,
310 "\n\n%d TESTS FAILED!\n\n",
311 failure_count);
312 return -1;
313 }
314 return 0;
315}
316
317
318/* end of test_crypto_eddsa.c */
diff --git a/src/util/test_crypto_edx25519.c b/src/util/test_crypto_edx25519.c
deleted file mode 100644
index ead6f0bb9..000000000
--- a/src/util/test_crypto_edx25519.c
+++ /dev/null
@@ -1,326 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 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_edx25519.c
23 * @brief testcase for ECC public key crypto for edx25519
24 * @author Özgür Kesim
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-edx25519.key"
34
35#define PERF GNUNET_YES
36
37
38static struct GNUNET_CRYPTO_Edx25519PrivateKey key;
39
40
41static int
42testSignVerify (void)
43{
44 struct GNUNET_CRYPTO_Edx25519Signature sig;
45 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
46 struct GNUNET_CRYPTO_Edx25519PublicKey pkey;
47 struct GNUNET_TIME_Absolute start;
48 int ok = GNUNET_OK;
49
50 fprintf (stderr, "%s", "W");
51 GNUNET_CRYPTO_edx25519_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_edx25519_sign_ (&key,
61 &purp,
62 &sig))
63 {
64 fprintf (stderr,
65 "GNUNET_CRYPTO_edx25519_sign returned SYSERR\n");
66 ok = GNUNET_SYSERR;
67 continue;
68 }
69 if (GNUNET_SYSERR ==
70 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
71 &purp,
72 &sig,
73 &pkey))
74 {
75 fprintf (stderr,
76 "GNUNET_CRYPTO_edx25519_verify failed!\n");
77 ok = GNUNET_SYSERR;
78 continue;
79 }
80 if (GNUNET_SYSERR !=
81 GNUNET_CRYPTO_edx25519_verify_ (
82 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
83 &purp,
84 &sig,
85 &pkey))
86 {
87 fprintf (stderr,
88 "GNUNET_CRYPTO_edx25519_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_EccSignaturePurpose purp;
107 struct GNUNET_CRYPTO_Edx25519Signature sig;
108 struct GNUNET_CRYPTO_Edx25519PrivateKey dkey;
109 struct GNUNET_CRYPTO_Edx25519PublicKey pub;
110 struct GNUNET_CRYPTO_Edx25519PublicKey dpub;
111 struct GNUNET_CRYPTO_Edx25519PublicKey dpub2;
112
113 GNUNET_CRYPTO_edx25519_key_get_public (&key, &pub);
114 GNUNET_CRYPTO_edx25519_private_key_derive (&key,
115 "test-derive",
116 sizeof("test-derive"),
117 &dkey);
118 GNUNET_CRYPTO_edx25519_public_key_derive (&pub,
119 "test-derive",
120 sizeof("test-derive"),
121 &dpub);
122 GNUNET_CRYPTO_edx25519_key_get_public (&dkey, &dpub2);
123
124 if (0 != GNUNET_memcmp (&dpub.q_y, &dpub2.q_y))
125 {
126 fprintf (stderr, "key deriviation failed\n");
127 return GNUNET_SYSERR;
128 }
129
130 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
131 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
132
133 GNUNET_CRYPTO_edx25519_sign_ (&dkey,
134 &purp,
135 &sig);
136
137 if (GNUNET_SYSERR ==
138 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
139 &purp,
140 &sig,
141 &dpub))
142 {
143 fprintf (stderr,
144 "GNUNET_CRYPTO_edx25519_verify failed after derivation!\n");
145 return GNUNET_SYSERR;
146 }
147
148 if (GNUNET_SYSERR !=
149 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
150 &purp,
151 &sig,
152 &pub))
153 {
154 fprintf (stderr,
155 "GNUNET_CRYPTO_edx25519_verify failed to fail after derivation!\n");
156 return GNUNET_SYSERR;
157 }
158
159 if (GNUNET_SYSERR !=
160 GNUNET_CRYPTO_edx25519_verify_ (
161 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
162 &purp,
163 &sig,
164 &dpub))
165 {
166 fprintf (stderr,
167 "GNUNET_CRYPTO_edx25519_verify failed to fail after derivation!\n");
168 return GNUNET_SYSERR;
169 }
170 return GNUNET_OK;
171}
172
173
174#if PERF
175static int
176testSignPerformance ()
177{
178 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
179 struct GNUNET_CRYPTO_Edx25519Signature sig;
180 struct GNUNET_CRYPTO_Edx25519PublicKey pkey;
181 struct GNUNET_TIME_Absolute start;
182 int ok = GNUNET_OK;
183
184 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
185 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
186 fprintf (stderr, "%s", "W");
187 GNUNET_CRYPTO_edx25519_key_get_public (&key,
188 &pkey);
189 start = GNUNET_TIME_absolute_get ();
190 for (unsigned int i = 0; i < ITER; i++)
191 {
192 fprintf (stderr, "%s", ".");
193 fflush (stderr);
194 if (GNUNET_SYSERR ==
195 GNUNET_CRYPTO_edx25519_sign_ (&key,
196 &purp,
197 &sig))
198 {
199 fprintf (stderr, "%s", "GNUNET_CRYPTO_edx25519_sign returned SYSERR\n");
200 ok = GNUNET_SYSERR;
201 continue;
202 }
203 }
204 fprintf (stderr, "\n");
205 printf ("%d EdDSA sign operations %s\n",
206 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
217#if 0 /* not implemented */
218static int
219testCreateFromFile (void)
220{
221 struct GNUNET_CRYPTO_Edx25519PublicKey p1;
222 struct GNUNET_CRYPTO_Edx25519PublicKey p2;
223
224 /* do_create == GNUNET_YES and non-existing file MUST return GNUNET_YES */
225 GNUNET_assert (0 == unlink (KEYFILE) || ENOENT == errno);
226 GNUNET_assert (GNUNET_YES ==
227 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
228 GNUNET_YES,
229 &key));
230 GNUNET_CRYPTO_edx25519_key_get_public (&key,
231 &p1);
232
233 /* do_create == GNUNET_YES and _existing_ file MUST return GNUNET_NO */
234 GNUNET_assert (GNUNET_NO ==
235 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
236 GNUNET_YES,
237 &key));
238 GNUNET_CRYPTO_edx25519_key_get_public (&key,
239 &p2);
240 GNUNET_assert (0 ==
241 GNUNET_memcmp (&p1,
242 &p2));
243
244 /* do_create == GNUNET_NO and non-existing file MUST return GNUNET_SYSERR */
245 GNUNET_assert (0 == unlink (KEYFILE));
246 GNUNET_assert (GNUNET_SYSERR ==
247 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
248 GNUNET_NO,
249 &key));
250 return GNUNET_OK;
251}
252
253
254#endif
255
256
257static void
258perf_keygen (void)
259{
260 struct GNUNET_TIME_Absolute start;
261 struct GNUNET_CRYPTO_Edx25519PrivateKey pk;
262
263 fprintf (stderr, "%s", "W");
264 start = GNUNET_TIME_absolute_get ();
265 for (unsigned int i = 0; i < 10; i++)
266 {
267 fprintf (stderr, ".");
268 fflush (stderr);
269 GNUNET_CRYPTO_edx25519_key_create (&pk);
270 }
271 fprintf (stderr, "\n");
272 printf ("10 EdDSA keys created in %s\n",
273 GNUNET_STRINGS_relative_time_to_string (
274 GNUNET_TIME_absolute_get_duration (start), GNUNET_YES));
275}
276
277
278int
279main (int argc, char *argv[])
280{
281 int failure_count = 0;
282
283 if (! gcry_check_version ("1.6.0"))
284 {
285 fprintf (stderr,
286 "libgcrypt has not the expected version (version %s is required).\n",
287 "1.6.0");
288 return 0;
289 }
290 if (getenv ("GNUNET_GCRYPT_DEBUG"))
291 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
292 GNUNET_log_setup ("test-crypto-edx25519",
293 "WARNING",
294 NULL);
295 GNUNET_CRYPTO_edx25519_key_create (&key);
296 if (GNUNET_OK != testDeriveSignVerify ())
297 {
298 failure_count++;
299 fprintf (stderr,
300 "\n\n%d TESTS FAILED!\n\n", failure_count);
301 return -1;
302 }
303#if PERF
304 if (GNUNET_OK != testSignPerformance ())
305 failure_count++;
306#endif
307 if (GNUNET_OK != testSignVerify ())
308 failure_count++;
309#if 0 /* not implemented */
310 if (GNUNET_OK != testCreateFromFile ())
311 failure_count++;
312#endif
313 perf_keygen ();
314
315 if (0 != failure_count)
316 {
317 fprintf (stderr,
318 "\n\n%d TESTS FAILED!\n\n",
319 failure_count);
320 return -1;
321 }
322 return 0;
323}
324
325
326/* end of test_crypto_edx25519.c */
diff --git a/src/util/test_crypto_hash.c b/src/util/test_crypto_hash.c
deleted file mode 100644
index 8241676da..000000000
--- a/src/util/test_crypto_hash.c
+++ /dev/null
@@ -1,217 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2002, 2003, 2004, 2006, 2009, 2022 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,
41 number,
42 sizeof(struct GNUNET_HashCode));
43 GNUNET_CRYPTO_hash_to_enc (&h1,
44 &enc);
45 if (GNUNET_OK !=
46 GNUNET_CRYPTO_hash_from_string ((char *) &enc,
47 &h2))
48 {
49 printf ("enc2hash failed!\n");
50 return 1;
51 }
52 if (0 != GNUNET_memcmp (&h1,
53 &h2))
54 return 1;
55 return 0;
56}
57
58
59static int
60test_encoding (void)
61{
62 for (int i = 0; i < 255; i++)
63 if (0 != test (i))
64 return 1;
65 return 0;
66}
67
68
69static int
70test_arithmetic (void)
71{
72 struct GNUNET_HashCode h1;
73 struct GNUNET_HashCode h2;
74 struct GNUNET_HashCode d;
75 struct GNUNET_HashCode s;
76 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
77 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
78
79 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
80 &h1);
81 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
82 &h2);
83 if (GNUNET_CRYPTO_hash_distance_u32 (&h1,
84 &h2) !=
85 GNUNET_CRYPTO_hash_distance_u32 (&h2,
86 &h1))
87 return 1;
88 GNUNET_CRYPTO_hash_difference (&h1,
89 &h2,
90 &d);
91 GNUNET_CRYPTO_hash_sum (&h1,
92 &d,
93 &s);
94 if (0 !=
95 GNUNET_CRYPTO_hash_cmp (&s,
96 &h2))
97 return 1;
98 GNUNET_CRYPTO_hash_xor (&h1,
99 &h2,
100 &d);
101 GNUNET_CRYPTO_hash_xor (&h1,
102 &d,
103 &s);
104 if (0 !=
105 GNUNET_CRYPTO_hash_cmp (&s,
106 &h2))
107 return 1;
108 if (0 !=
109 GNUNET_CRYPTO_hash_xorcmp (&s,
110 &h2,
111 &h1))
112 return 1;
113 if (-1 !=
114 GNUNET_CRYPTO_hash_xorcmp (&h1,
115 &h2,
116 &h1))
117 return 1;
118 if (1 !=
119 GNUNET_CRYPTO_hash_xorcmp (&h1,
120 &h2,
121 &h2))
122 return 1;
123 memset (&d,
124 0,
125 sizeof(d));
126 GNUNET_CRYPTO_hash_to_aes_key (&d,
127 &skey,
128 &iv);
129 memset (&h1,
130 0,
131 sizeof (h1));
132 h1.bits[1] = htonl (0x00200000); /* 32 + 8 + 2 = 42 MSB bits cleared */
133 GNUNET_assert (42 ==
134 GNUNET_CRYPTO_hash_count_leading_zeros (&h1));
135 GNUNET_assert (512 - 42 - 1 ==
136 GNUNET_CRYPTO_hash_count_tailing_zeros (&h1));
137 return 0;
138}
139
140
141static void
142finished_task (void *cls,
143 const struct GNUNET_HashCode *res)
144{
145 int *ret = cls;
146 struct GNUNET_HashCode want;
147
148 GNUNET_CRYPTO_hash (block,
149 sizeof(block),
150 &want);
151 if (0 != GNUNET_memcmp (res,
152 &want))
153 *ret = 2;
154 else
155 *ret = 0;
156}
157
158
159static void
160file_hasher (void *cls)
161{
162 GNUNET_assert (NULL !=
163 GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
164 FILENAME,
165 1024,
166 &finished_task,
167 cls));
168}
169
170
171static int
172test_file_hash (void)
173{
174 int ret;
175 FILE *f;
176
177 memset (block,
178 42,
179 sizeof(block) / 2);
180 memset (&block[sizeof(block) / 2],
181 43,
182 sizeof(block) / 2);
183 GNUNET_assert (NULL != (f = fopen (FILENAME, "w+")));
184 GNUNET_break (sizeof(block) ==
185 fwrite (block,
186 1,
187 sizeof(block),
188 f));
189 GNUNET_break (0 == fclose (f));
190 ret = 1;
191 GNUNET_SCHEDULER_run (&file_hasher,
192 &ret);
193 GNUNET_break (0 == unlink (FILENAME));
194 return ret;
195}
196
197
198int
199main (int argc,
200 char *argv[])
201{
202 int failureCount = 0;
203
204 GNUNET_log_setup ("test-crypto-hash",
205 "WARNING",
206 NULL);
207 for (int i = 0; i < 10; i++)
208 failureCount += test_encoding ();
209 failureCount += test_arithmetic ();
210 failureCount += test_file_hash ();
211 if (0 != failureCount)
212 return 1;
213 return 0;
214}
215
216
217/* end of test_crypto_hash.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 cccffcaf5..000000000
--- a/src/util/test_strings.c
+++ /dev/null
@@ -1,168 +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 /* Normalization */
115 r = "q\u0307\u0323"; /* Non-canonical order */
116
117 b = GNUNET_STRINGS_utf8_normalize (r);
118 GNUNET_assert (0 == strcmp ("q\u0323\u0307", b));
119 GNUNET_free (b);
120 b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "ASCII");
121 WANT ("TEST", b);
122
123 at = GNUNET_TIME_UNIT_FOREVER_ABS;
124 bc = GNUNET_STRINGS_absolute_time_to_string (at);
125 GNUNET_assert (GNUNET_OK ==
126 GNUNET_STRINGS_fancy_time_to_absolute (bc, &atx));
127 GNUNET_assert (atx.abs_value_us == at.abs_value_us);
128
129 at.abs_value_us = 50000000000;
130 bc = GNUNET_STRINGS_absolute_time_to_string (at);
131
132 GNUNET_assert (GNUNET_OK ==
133 GNUNET_STRINGS_fancy_time_to_absolute (bc, &atx));
134
135 if (atx.abs_value_us != at.abs_value_us)
136 {
137 GNUNET_assert (0);
138 }
139
140 GNUNET_log_skip (2, GNUNET_NO);
141 b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "unknown");
142 GNUNET_log_skip (0, GNUNET_YES);
143 WANT ("TEST", b);
144
145 GNUNET_assert (GNUNET_OK ==
146 GNUNET_STRINGS_fancy_time_to_relative ("15m", &rt));
147 GNUNET_assert (GNUNET_OK ==
148 GNUNET_STRINGS_fancy_time_to_relative ("15 m", &rtx));
149 GNUNET_assert (rt.rel_value_us == rtx.rel_value_us);
150
151 GNUNET_assert (0 != GNUNET_STRINGS_urlencode (URLENCODE_TEST_VECTOR_PLAIN,
152 strlen (
153 URLENCODE_TEST_VECTOR_PLAIN),
154 &b));
155 WANT (URLENCODE_TEST_VECTOR_ENCODED, b);
156 GNUNET_free (b);
157 GNUNET_assert (0 !=
158 GNUNET_STRINGS_urldecode (URLENCODE_TEST_VECTOR_ENCODED,
159 strlen (
160 URLENCODE_TEST_VECTOR_ENCODED),
161 &b));
162 WANT (URLENCODE_TEST_VECTOR_PLAIN, b);
163 GNUNET_free (b);
164 return 0;
165}
166
167
168/* 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 cf072aebf..000000000
--- a/src/util/time.c
+++ /dev/null
@@ -1,990 +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
61bool
62GNUNET_TIME_absolute_approx_eq (struct GNUNET_TIME_Absolute a1,
63 struct GNUNET_TIME_Absolute a2,
64 struct GNUNET_TIME_Relative t)
65{
66 struct GNUNET_TIME_Relative delta;
67
68 delta = GNUNET_TIME_relative_min (
69 GNUNET_TIME_absolute_get_difference (a1, a2),
70 GNUNET_TIME_absolute_get_difference (a2, a1));
71 return GNUNET_TIME_relative_cmp (delta,
72 <=,
73 t);
74}
75
76
77struct GNUNET_TIME_Timestamp
78GNUNET_TIME_absolute_to_timestamp (struct GNUNET_TIME_Absolute at)
79{
80 struct GNUNET_TIME_Timestamp ts;
81
82 if (GNUNET_TIME_absolute_is_never (at))
83 return GNUNET_TIME_UNIT_FOREVER_TS;
84 ts.abs_time.abs_value_us = at.abs_value_us - at.abs_value_us % 1000000;
85 return ts;
86}
87
88
89struct GNUNET_TIME_TimestampNBO
90GNUNET_TIME_timestamp_hton (struct GNUNET_TIME_Timestamp t)
91{
92 struct GNUNET_TIME_TimestampNBO tn;
93
94 tn.abs_time_nbo = GNUNET_TIME_absolute_hton (t.abs_time);
95 return tn;
96}
97
98
99struct GNUNET_TIME_Timestamp
100GNUNET_TIME_timestamp_ntoh (struct GNUNET_TIME_TimestampNBO tn)
101{
102 struct GNUNET_TIME_Timestamp t;
103
104 t.abs_time = GNUNET_TIME_absolute_ntoh (tn.abs_time_nbo);
105 return t;
106}
107
108
109struct GNUNET_TIME_Absolute
110GNUNET_TIME_absolute_get ()
111{
112 struct GNUNET_TIME_Absolute ret;
113 struct timeval tv;
114
115 gettimeofday (&tv, NULL);
116 ret.abs_value_us = (uint64_t) (((uint64_t) tv.tv_sec * 1000LL * 1000LL)
117 + ((uint64_t) tv.tv_usec))
118 + timestamp_offset;
119 return ret;
120}
121
122
123struct GNUNET_TIME_Timestamp
124GNUNET_TIME_timestamp_get ()
125{
126 return GNUNET_TIME_absolute_to_timestamp (
127 GNUNET_TIME_absolute_get ());
128}
129
130
131struct GNUNET_TIME_Relative
132GNUNET_TIME_relative_get_zero_ ()
133{
134 static struct GNUNET_TIME_Relative zero;
135
136 return zero;
137}
138
139
140struct GNUNET_TIME_Absolute
141GNUNET_TIME_absolute_get_zero_ ()
142{
143 static struct GNUNET_TIME_Absolute zero;
144
145 return zero;
146}
147
148
149struct GNUNET_TIME_Relative
150GNUNET_TIME_relative_get_unit_ ()
151{
152 static struct GNUNET_TIME_Relative one = { 1 };
153
154 return one;
155}
156
157
158struct GNUNET_TIME_Relative
159GNUNET_TIME_relative_get_millisecond_ ()
160{
161 static struct GNUNET_TIME_Relative one = { 1000 };
162
163 return one;
164}
165
166
167struct GNUNET_TIME_Relative
168GNUNET_TIME_relative_get_second_ ()
169{
170 static struct GNUNET_TIME_Relative one = { 1000 * 1000LL };
171
172 return one;
173}
174
175
176struct GNUNET_TIME_Relative
177GNUNET_TIME_relative_get_minute_ ()
178{
179 static struct GNUNET_TIME_Relative one = { 60 * 1000 * 1000LL };
180
181 return one;
182}
183
184
185struct GNUNET_TIME_Relative
186GNUNET_TIME_relative_get_hour_ ()
187{
188 static struct GNUNET_TIME_Relative one = { 60 * 60 * 1000 * 1000LL };
189
190 return one;
191}
192
193
194struct GNUNET_TIME_Relative
195GNUNET_TIME_relative_get_forever_ ()
196{
197 static struct GNUNET_TIME_Relative forever = { UINT64_MAX };
198
199 return forever;
200}
201
202
203struct GNUNET_TIME_Absolute
204GNUNET_TIME_absolute_get_forever_ ()
205{
206 static struct GNUNET_TIME_Absolute forever = { UINT64_MAX };
207
208 return forever;
209}
210
211
212const char *
213GNUNET_TIME_timestamp2s (struct GNUNET_TIME_Timestamp ts)
214{
215 static GNUNET_THREAD_LOCAL char buf[255];
216 time_t tt;
217 struct tm *tp;
218
219 if (GNUNET_TIME_absolute_is_never (ts.abs_time))
220 return "end of time";
221 tt = ts.abs_time.abs_value_us / 1000LL / 1000LL;
222 tp = localtime (&tt);
223 /* This is hacky, but i don't know a way to detect libc character encoding.
224 * Just expect utf8 from glibc these days.
225 * As for msvcrt, use the wide variant, which always returns utf16
226 * (otherwise we'd have to detect current codepage or use W32API character
227 * set conversion routines to convert to UTF8).
228 */
229 strftime (buf,
230 sizeof(buf),
231 "%a %b %d %H:%M:%S %Y",
232 tp);
233 return buf;
234}
235
236
237const char *
238GNUNET_TIME_absolute2s (struct GNUNET_TIME_Absolute t)
239{
240 static GNUNET_THREAD_LOCAL char buf[255];
241 time_t tt;
242 struct tm *tp;
243
244 if (GNUNET_TIME_absolute_is_never (t))
245 return "end of time";
246 tt = t.abs_value_us / 1000LL / 1000LL;
247 tp = localtime (&tt);
248 /* This is hacky, but i don't know a way to detect libc character encoding.
249 * Just expect utf8 from glibc these days.
250 * As for msvcrt, use the wide variant, which always returns utf16
251 * (otherwise we'd have to detect current codepage or use W32API character
252 * set conversion routines to convert to UTF8).
253 */
254 strftime (buf,
255 sizeof(buf),
256 "%a %b %d %H:%M:%S %Y",
257 tp);
258 return buf;
259}
260
261
262const char *
263GNUNET_TIME_relative2s (struct GNUNET_TIME_Relative delta,
264 bool do_round)
265{
266 static GNUNET_THREAD_LOCAL char buf[128];
267 const char *unit = /* time unit */ "µs";
268 uint64_t dval = delta.rel_value_us;
269
270 if (GNUNET_TIME_relative_is_forever (delta))
271 return "forever";
272 if (0 == delta.rel_value_us)
273 return "0 ms";
274 if ( ((GNUNET_YES == do_round) &&
275 (dval > 5 * 1000)) ||
276 (0 == (dval % 1000)))
277 {
278 dval = dval / 1000;
279 unit = /* time unit */ "ms";
280 if (((GNUNET_YES == do_round) && (dval > 5 * 1000)) || (0 == (dval % 1000)))
281 {
282 dval = dval / 1000;
283 unit = /* time unit */ "s";
284 if (((GNUNET_YES == do_round) && (dval > 5 * 60)) || (0 == (dval % 60)))
285 {
286 dval = dval / 60;
287 unit = /* time unit */ "m";
288 if (((GNUNET_YES == do_round) && (dval > 5 * 60)) || (0 == (dval % 60)))
289 {
290 dval = dval / 60;
291 unit = /* time unit */ "h";
292 if (((GNUNET_YES == do_round) && (dval > 5 * 24)) ||
293 (0 == (dval % 24)))
294 {
295 dval = dval / 24;
296 if (1 == dval)
297 unit = /* time unit */ "day";
298 else
299 unit = /* time unit */ "days";
300 }
301 }
302 }
303 }
304 }
305 GNUNET_snprintf (buf,
306 sizeof(buf),
307 "%llu %s",
308 (unsigned long long) dval,
309 unit);
310 return buf;
311}
312
313
314struct GNUNET_TIME_Absolute
315GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel)
316{
317 struct GNUNET_TIME_Absolute ret;
318
319 if (GNUNET_TIME_relative_is_forever (rel))
320 return GNUNET_TIME_UNIT_FOREVER_ABS;
321 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
322
323 if (rel.rel_value_us + now.abs_value_us < rel.rel_value_us)
324 {
325 GNUNET_break (0); /* overflow... */
326 return GNUNET_TIME_UNIT_FOREVER_ABS;
327 }
328 ret.abs_value_us = rel.rel_value_us + now.abs_value_us;
329 return ret;
330}
331
332
333struct GNUNET_TIME_Timestamp
334GNUNET_TIME_relative_to_timestamp (struct GNUNET_TIME_Relative rel)
335{
336 return GNUNET_TIME_absolute_to_timestamp (
337 GNUNET_TIME_relative_to_absolute (rel));
338}
339
340
341struct GNUNET_TIME_Relative
342GNUNET_TIME_relative_min (struct GNUNET_TIME_Relative t1,
343 struct GNUNET_TIME_Relative t2)
344{
345 return (t1.rel_value_us < t2.rel_value_us) ? t1 : t2;
346}
347
348
349struct GNUNET_TIME_Relative
350GNUNET_TIME_relative_max (struct GNUNET_TIME_Relative t1,
351 struct GNUNET_TIME_Relative t2)
352{
353 return (t1.rel_value_us > t2.rel_value_us) ? t1 : t2;
354}
355
356
357struct GNUNET_TIME_Absolute
358GNUNET_TIME_absolute_min (struct GNUNET_TIME_Absolute t1,
359 struct GNUNET_TIME_Absolute t2)
360{
361 return (t1.abs_value_us < t2.abs_value_us) ? t1 : t2;
362}
363
364
365struct GNUNET_TIME_Absolute
366GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1,
367 struct GNUNET_TIME_Absolute t2)
368{
369 return (t1.abs_value_us > t2.abs_value_us) ? t1 : t2;
370}
371
372
373struct GNUNET_TIME_Timestamp
374GNUNET_TIME_timestamp_max (struct GNUNET_TIME_Timestamp t1,
375 struct GNUNET_TIME_Timestamp t2)
376{
377 return (t1.abs_time.abs_value_us > t2.abs_time.abs_value_us) ? t1 : t2;
378}
379
380
381struct GNUNET_TIME_Timestamp
382GNUNET_TIME_timestamp_min (struct GNUNET_TIME_Timestamp t1,
383 struct GNUNET_TIME_Timestamp t2)
384{
385 return (t1.abs_time.abs_value_us < t2.abs_time.abs_value_us) ? t1 : t2;
386}
387
388
389struct GNUNET_TIME_Absolute
390GNUNET_TIME_absolute_round_down (struct GNUNET_TIME_Absolute at,
391 struct GNUNET_TIME_Relative rt)
392{
393 struct GNUNET_TIME_Absolute ret;
394
395 GNUNET_assert (! GNUNET_TIME_relative_is_zero (rt));
396 ret.abs_value_us
397 = at.abs_value_us
398 - at.abs_value_us % rt.rel_value_us;
399 return ret;
400}
401
402
403struct GNUNET_TIME_Relative
404GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future)
405{
406 struct GNUNET_TIME_Relative ret;
407
408 if (GNUNET_TIME_absolute_is_never (future))
409 return GNUNET_TIME_UNIT_FOREVER_REL;
410 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
411
412 if (now.abs_value_us > future.abs_value_us)
413 return GNUNET_TIME_UNIT_ZERO;
414 ret.rel_value_us = future.abs_value_us - now.abs_value_us;
415 return ret;
416}
417
418
419struct GNUNET_TIME_Relative
420GNUNET_TIME_absolute_get_difference (struct GNUNET_TIME_Absolute start,
421 struct GNUNET_TIME_Absolute end)
422{
423 struct GNUNET_TIME_Relative ret;
424
425 if (GNUNET_TIME_absolute_is_never (end))
426 return GNUNET_TIME_UNIT_FOREVER_REL;
427 if (end.abs_value_us < start.abs_value_us)
428 return GNUNET_TIME_UNIT_ZERO;
429 ret.rel_value_us = end.abs_value_us - start.abs_value_us;
430 return ret;
431}
432
433
434struct GNUNET_TIME_Relative
435GNUNET_TIME_absolute_get_duration (struct GNUNET_TIME_Absolute whence)
436{
437 struct GNUNET_TIME_Absolute now;
438 struct GNUNET_TIME_Relative ret;
439
440 now = GNUNET_TIME_absolute_get ();
441 if (whence.abs_value_us > now.abs_value_us)
442 return GNUNET_TIME_UNIT_ZERO;
443 ret.rel_value_us = now.abs_value_us - whence.abs_value_us;
444 return ret;
445}
446
447
448struct GNUNET_TIME_Absolute
449GNUNET_TIME_absolute_add (struct GNUNET_TIME_Absolute start,
450 struct GNUNET_TIME_Relative duration)
451{
452 struct GNUNET_TIME_Absolute ret;
453
454 if (GNUNET_TIME_absolute_is_never (start) ||
455 GNUNET_TIME_relative_is_forever (duration))
456 return GNUNET_TIME_UNIT_FOREVER_ABS;
457 if (start.abs_value_us + duration.rel_value_us < start.abs_value_us)
458 {
459 GNUNET_break (0);
460 return GNUNET_TIME_UNIT_FOREVER_ABS;
461 }
462 ret.abs_value_us = start.abs_value_us + duration.rel_value_us;
463 return ret;
464}
465
466
467struct GNUNET_TIME_Absolute
468GNUNET_TIME_absolute_subtract (struct GNUNET_TIME_Absolute start,
469 struct GNUNET_TIME_Relative duration)
470{
471 struct GNUNET_TIME_Absolute ret;
472
473 if (start.abs_value_us <= duration.rel_value_us)
474 return GNUNET_TIME_UNIT_ZERO_ABS;
475 if (GNUNET_TIME_absolute_is_never (start))
476 return GNUNET_TIME_UNIT_FOREVER_ABS;
477 ret.abs_value_us = start.abs_value_us - duration.rel_value_us;
478 return ret;
479}
480
481
482struct GNUNET_TIME_Relative
483GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel,
484 unsigned long long factor)
485{
486 struct GNUNET_TIME_Relative ret;
487
488 if (0 == factor)
489 return GNUNET_TIME_UNIT_ZERO;
490 if (GNUNET_TIME_relative_is_forever (rel))
491 return GNUNET_TIME_UNIT_FOREVER_REL;
492 ret.rel_value_us = rel.rel_value_us * factor;
493 if (ret.rel_value_us / factor != rel.rel_value_us)
494 {
495 GNUNET_break (0);
496 return GNUNET_TIME_UNIT_FOREVER_REL;
497 }
498 return ret;
499}
500
501
502struct GNUNET_TIME_Relative
503relative_multiply_double (struct GNUNET_TIME_Relative rel,
504 double factor)
505{
506 struct GNUNET_TIME_Relative out;
507 double m;
508
509 GNUNET_assert (0 <= factor);
510
511 if (0 == factor)
512 return GNUNET_TIME_UNIT_ZERO;
513 if (GNUNET_TIME_relative_is_forever (rel))
514 return GNUNET_TIME_UNIT_FOREVER_REL;
515
516 m = ((double) rel.rel_value_us) * factor;
517
518 if (m >= (double) (GNUNET_TIME_UNIT_FOREVER_REL).rel_value_us)
519 {
520 GNUNET_break (0);
521 return GNUNET_TIME_UNIT_FOREVER_REL;
522 }
523
524 out.rel_value_us = (uint64_t) m;
525 return out;
526}
527
528
529struct GNUNET_TIME_Relative
530GNUNET_TIME_relative_saturating_multiply (struct GNUNET_TIME_Relative rel,
531 unsigned long long factor)
532{
533 struct GNUNET_TIME_Relative ret;
534
535 if (0 == factor)
536 return GNUNET_TIME_UNIT_ZERO;
537 if (GNUNET_TIME_relative_is_forever (rel))
538 return GNUNET_TIME_UNIT_FOREVER_REL;
539 ret.rel_value_us = rel.rel_value_us * factor;
540 if (ret.rel_value_us / factor != rel.rel_value_us)
541 {
542 return GNUNET_TIME_UNIT_FOREVER_REL;
543 }
544 return ret;
545}
546
547
548struct GNUNET_TIME_Relative
549GNUNET_TIME_relative_divide (struct GNUNET_TIME_Relative rel,
550 unsigned long long factor)
551{
552 struct GNUNET_TIME_Relative ret;
553
554 if ((0 == factor) ||
555 (GNUNET_TIME_relative_is_forever (rel)))
556 return GNUNET_TIME_UNIT_FOREVER_REL;
557 ret.rel_value_us = rel.rel_value_us / factor;
558 return ret;
559}
560
561
562struct GNUNET_TIME_Relative
563GNUNET_TIME_calculate_eta (struct GNUNET_TIME_Absolute start,
564 uint64_t finished,
565 uint64_t total)
566{
567 struct GNUNET_TIME_Relative due;
568 double exp;
569 struct GNUNET_TIME_Relative ret;
570
571 GNUNET_break (finished <= total);
572 if (finished >= total)
573 return GNUNET_TIME_UNIT_ZERO;
574 if (0 == finished)
575 return GNUNET_TIME_UNIT_FOREVER_REL;
576 due = GNUNET_TIME_absolute_get_duration (start);
577 exp = ((double) due.rel_value_us) * ((double) total) / ((double) finished);
578 ret.rel_value_us = ((uint64_t) exp) - due.rel_value_us;
579 return ret;
580}
581
582
583struct GNUNET_TIME_Relative
584GNUNET_TIME_relative_add (struct GNUNET_TIME_Relative a1,
585 struct GNUNET_TIME_Relative a2)
586{
587 struct GNUNET_TIME_Relative ret;
588
589 if ((a1.rel_value_us == UINT64_MAX) || (a2.rel_value_us == UINT64_MAX))
590 return GNUNET_TIME_UNIT_FOREVER_REL;
591 if (a1.rel_value_us + a2.rel_value_us < a1.rel_value_us)
592 {
593 GNUNET_break (0);
594 return GNUNET_TIME_UNIT_FOREVER_REL;
595 }
596 ret.rel_value_us = a1.rel_value_us + a2.rel_value_us;
597 return ret;
598}
599
600
601struct GNUNET_TIME_Relative
602GNUNET_TIME_relative_subtract (struct GNUNET_TIME_Relative a1,
603 struct GNUNET_TIME_Relative a2)
604{
605 struct GNUNET_TIME_Relative ret;
606
607 if (a2.rel_value_us >= a1.rel_value_us)
608 return GNUNET_TIME_UNIT_ZERO;
609 if (a1.rel_value_us == UINT64_MAX)
610 return GNUNET_TIME_UNIT_FOREVER_REL;
611 ret.rel_value_us = a1.rel_value_us - a2.rel_value_us;
612 return ret;
613}
614
615
616struct GNUNET_TIME_RelativeNBO
617GNUNET_TIME_relative_hton (struct GNUNET_TIME_Relative a)
618{
619 struct GNUNET_TIME_RelativeNBO ret;
620
621 ret.rel_value_us__ = GNUNET_htonll (a.rel_value_us);
622 return ret;
623}
624
625
626struct GNUNET_TIME_Relative
627GNUNET_TIME_relative_ntoh (struct GNUNET_TIME_RelativeNBO a)
628{
629 struct GNUNET_TIME_Relative ret;
630
631 ret.rel_value_us = GNUNET_ntohll (a.rel_value_us__);
632 return ret;
633}
634
635
636struct GNUNET_TIME_AbsoluteNBO
637GNUNET_TIME_absolute_hton (struct GNUNET_TIME_Absolute a)
638{
639 struct GNUNET_TIME_AbsoluteNBO ret;
640
641 ret.abs_value_us__ = GNUNET_htonll (a.abs_value_us);
642 return ret;
643}
644
645
646bool
647GNUNET_TIME_absolute_is_never (struct GNUNET_TIME_Absolute abs)
648{
649 return GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == abs.abs_value_us;
650}
651
652
653bool
654GNUNET_TIME_relative_is_forever (struct GNUNET_TIME_Relative rel)
655{
656 return GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rel.rel_value_us;
657}
658
659
660bool
661GNUNET_TIME_relative_is_zero (struct GNUNET_TIME_Relative rel)
662{
663 return 0 == rel.rel_value_us;
664}
665
666
667bool
668GNUNET_TIME_absolute_is_past (struct GNUNET_TIME_Absolute abs)
669{
670 struct GNUNET_TIME_Absolute now;
671
672 now = GNUNET_TIME_absolute_get ();
673 return abs.abs_value_us < now.abs_value_us;
674}
675
676
677bool
678GNUNET_TIME_absolute_is_future (struct GNUNET_TIME_Absolute abs)
679{
680 struct GNUNET_TIME_Absolute now;
681
682 now = GNUNET_TIME_absolute_get ();
683 return abs.abs_value_us > now.abs_value_us;
684}
685
686
687struct GNUNET_TIME_Absolute
688GNUNET_TIME_absolute_from_ms (uint64_t ms_after_epoch)
689{
690 struct GNUNET_TIME_Absolute ret;
691
692 ret.abs_value_us = GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us
693 * ms_after_epoch;
694 if (ret.abs_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us !=
695 ms_after_epoch)
696 ret = GNUNET_TIME_UNIT_FOREVER_ABS;
697 return ret;
698}
699
700
701struct GNUNET_TIME_Absolute
702GNUNET_TIME_absolute_from_s (uint64_t s_after_epoch)
703{
704 struct GNUNET_TIME_Absolute ret;
705
706 ret.abs_value_us = GNUNET_TIME_UNIT_SECONDS.rel_value_us * s_after_epoch;
707 if (ret.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us !=
708 s_after_epoch)
709 ret = GNUNET_TIME_UNIT_FOREVER_ABS;
710 return ret;
711}
712
713
714struct GNUNET_TIME_Timestamp
715GNUNET_TIME_timestamp_from_s (uint64_t s_after_epoch)
716{
717 struct GNUNET_TIME_Timestamp ret;
718
719 ret.abs_time.abs_value_us
720 = GNUNET_TIME_UNIT_SECONDS.rel_value_us * s_after_epoch;
721 if (ret.abs_time.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us
722 != s_after_epoch)
723 ret = GNUNET_TIME_UNIT_FOREVER_TS;
724 return ret;
725}
726
727
728uint64_t
729GNUNET_TIME_timestamp_to_s (struct GNUNET_TIME_Timestamp ts)
730{
731 return ts.abs_time.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
732}
733
734
735struct GNUNET_TIME_Absolute
736GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a)
737{
738 struct GNUNET_TIME_Absolute ret;
739
740 ret.abs_value_us = GNUNET_ntohll (a.abs_value_us__);
741 return ret;
742}
743
744
745unsigned int
746GNUNET_TIME_get_current_year ()
747{
748 time_t tp;
749 struct tm *t;
750
751 tp = time (NULL);
752 t = gmtime (&tp);
753 if (t == NULL)
754 return 0;
755 return t->tm_year + 1900;
756}
757
758
759unsigned int
760GNUNET_TIME_time_to_year (struct GNUNET_TIME_Absolute at)
761{
762 struct tm *t;
763 time_t tp;
764
765 tp = at.abs_value_us / 1000LL / 1000LL; /* microseconds to seconds */
766 t = gmtime (&tp);
767 if (t == NULL)
768 return 0;
769 return t->tm_year + 1900;
770}
771
772
773#ifndef HAVE_TIMEGM
774/**
775 * As suggested in the timegm() man page.
776 */
777static time_t
778my_timegm (struct tm *tm)
779{
780 time_t ret;
781 char *tz;
782
783 tz = getenv ("TZ");
784 setenv ("TZ", "", 1);
785 tzset ();
786 ret = mktime (tm);
787 if (tz)
788 setenv ("TZ", tz, 1);
789 else
790 unsetenv ("TZ");
791 tzset ();
792 return ret;
793}
794
795
796#endif
797
798
799struct GNUNET_TIME_Absolute
800GNUNET_TIME_year_to_time (unsigned int year)
801{
802 struct GNUNET_TIME_Absolute ret;
803 time_t tp;
804 struct tm t;
805
806 memset (&t, 0, sizeof(t));
807 if (year < 1900)
808 {
809 GNUNET_break (0);
810 return GNUNET_TIME_absolute_get (); /* now */
811 }
812 t.tm_year = year - 1900;
813 t.tm_mday = 1;
814 t.tm_mon = 0;
815 t.tm_wday = 1;
816 t.tm_yday = 1;
817#ifndef HAVE_TIMEGM
818 tp = my_timegm (&t);
819#else
820 tp = timegm (&t);
821#endif
822 GNUNET_break (tp != (time_t) -1);
823 ret.abs_value_us = tp * 1000LL * 1000LL; /* seconds to microseconds */
824 return ret;
825}
826
827
828struct GNUNET_TIME_Relative
829GNUNET_TIME_randomized_backoff (struct GNUNET_TIME_Relative rt,
830 struct GNUNET_TIME_Relative threshold)
831{
832 double r = (rand () % 500) / 1000.0;
833 struct GNUNET_TIME_Relative t;
834
835 t = relative_multiply_double (
836 GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, rt),
837 2 + r);
838 return GNUNET_TIME_relative_min (threshold, t);
839}
840
841
842bool
843GNUNET_TIME_absolute_is_zero (struct GNUNET_TIME_Absolute abs)
844{
845 return 0 == abs.abs_value_us;
846}
847
848
849struct GNUNET_TIME_Relative
850GNUNET_TIME_randomize (struct GNUNET_TIME_Relative r)
851{
852 double d = ((rand () % 1001) + 500) / 1000.0;
853
854 return relative_multiply_double (r, d);
855}
856
857
858struct GNUNET_TIME_Absolute
859GNUNET_TIME_absolute_get_monotonic (
860 const struct GNUNET_CONFIGURATION_Handle *cfg)
861{
862 static const struct GNUNET_CONFIGURATION_Handle *last_cfg;
863 static struct GNUNET_TIME_Absolute last_time;
864 static struct GNUNET_DISK_MapHandle *map_handle;
865 static ATOMIC volatile uint64_t *map;
866 struct GNUNET_TIME_Absolute now;
867
868 now = GNUNET_TIME_absolute_get ();
869 if (last_cfg != cfg)
870 {
871 char *filename;
872
873 if (NULL != map_handle)
874 {
875 GNUNET_DISK_file_unmap (map_handle);
876 map_handle = NULL;
877 }
878 map = NULL;
879
880 last_cfg = cfg;
881 if ((NULL != cfg) &&
882 (GNUNET_OK ==
883 GNUNET_CONFIGURATION_get_value_filename (cfg,
884 "util",
885 "MONOTONIC_TIME_FILENAME",
886 &filename)))
887 {
888 struct GNUNET_DISK_FileHandle *fh;
889
890 fh = GNUNET_DISK_file_open (filename,
891 GNUNET_DISK_OPEN_READWRITE
892 | GNUNET_DISK_OPEN_CREATE,
893 GNUNET_DISK_PERM_USER_WRITE
894 | GNUNET_DISK_PERM_GROUP_WRITE
895 | GNUNET_DISK_PERM_USER_READ
896 | GNUNET_DISK_PERM_GROUP_READ);
897 if (NULL == fh)
898 {
899 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
900 _ ("Failed to map `%s', cannot assure monotonic time!\n"),
901 filename);
902 }
903 else
904 {
905 off_t size;
906
907 size = 0;
908 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &size));
909 if (size < (off_t) sizeof(*map))
910 {
911 struct GNUNET_TIME_AbsoluteNBO o;
912
913 o = GNUNET_TIME_absolute_hton (now);
914 if (sizeof(o) != GNUNET_DISK_file_write (fh, &o, sizeof(o)))
915 size = 0;
916 else
917 size = sizeof(o);
918 }
919 if (size == sizeof(*map))
920 {
921 map = GNUNET_DISK_file_map (fh,
922 &map_handle,
923 GNUNET_DISK_MAP_TYPE_READWRITE,
924 sizeof(*map));
925 if (NULL == map)
926 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
927 _ (
928 "Failed to map `%s', cannot assure monotonic time!\n"),
929 filename);
930 }
931 else
932 {
933 GNUNET_log (
934 GNUNET_ERROR_TYPE_WARNING,
935 _ (
936 "Failed to setup monotonic time file `%s', cannot assure monotonic time!\n"),
937 filename);
938 }
939 }
940 GNUNET_DISK_file_close (fh);
941 GNUNET_free (filename);
942 }
943 }
944 if (NULL != map)
945 {
946 struct GNUNET_TIME_AbsoluteNBO mt;
947
948#if __STDC_NO_ATOMICS__
949#if __GNUC__
950 mt.abs_value_us__ = __sync_fetch_and_or (map, 0);
951#else
952 mt.abs_value_us__ = *map; /* godspeed, pray this is atomic */
953#endif
954#else
955 mt.abs_value_us__ = atomic_load (map);
956#endif
957 last_time =
958 GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_ntoh (mt), last_time);
959 }
960 if (now.abs_value_us <= last_time.abs_value_us)
961 now.abs_value_us = last_time.abs_value_us + 1;
962 last_time = now;
963 if (NULL != map)
964 {
965 uint64_t val = GNUNET_TIME_absolute_hton (now).abs_value_us__;
966#if __STDC_NO_ATOMICS__
967#if __GNUC__
968 (void) __sync_lock_test_and_set (map, val);
969#else
970 *map = val; /* godspeed, pray this is atomic */
971#endif
972#else
973 atomic_store (map, val);
974#endif
975 }
976 return now;
977}
978
979
980/**
981 * Destructor
982 */
983void __attribute__ ((destructor))
984GNUNET_util_time_fini ()
985{
986 (void) GNUNET_TIME_absolute_get_monotonic (NULL);
987}
988
989
990/* 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