aboutsummaryrefslogtreecommitdiff
path: root/src/namestore
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore')
-rw-r--r--src/namestore/.gitignore61
-rw-r--r--src/namestore/Makefile.am543
-rw-r--r--src/namestore/example_zonefile27
-rw-r--r--src/namestore/gnunet-namestore-dbtool.c199
-rw-r--r--src/namestore/gnunet-namestore-fcfsd.c1160
-rw-r--r--src/namestore/gnunet-namestore-zonefile.c763
-rw-r--r--src/namestore/gnunet-namestore.c2120
-rw-r--r--src/namestore/gnunet-service-namestore.c2752
-rw-r--r--src/namestore/gnunet-zoneimport.c1872
-rw-r--r--src/namestore/meson.build139
-rw-r--r--src/namestore/namestore-0001.sql48
-rw-r--r--src/namestore/namestore-drop.sql25
-rw-r--r--src/namestore/namestore.conf.in47
-rw-r--r--src/namestore/namestore.h491
-rw-r--r--src/namestore/namestore_api.c1563
-rw-r--r--src/namestore/namestore_api_monitor.c443
-rw-r--r--src/namestore/perf_namestore_api_import.c406
-rw-r--r--src/namestore/perf_namestore_api_postgres.conf12
-rw-r--r--src/namestore/perf_namestore_api_sqlite.conf8
-rw-r--r--src/namestore/perf_namestore_api_zone_iteration.c378
-rw-r--r--src/namestore/plugin_namestore_flat.c818
-rw-r--r--src/namestore/plugin_namestore_postgres.c796
-rw-r--r--src/namestore/plugin_namestore_sqlite.c983
-rw-r--r--src/namestore/plugin_rest_namestore.c1364
-rw-r--r--src/namestore/test_common.c128
-rw-r--r--src/namestore/test_hostkey0
-rw-r--r--src/namestore/test_namestore_api.conf43
-rw-r--r--src/namestore/test_namestore_api_edit_records.c399
-rw-r--r--src/namestore/test_namestore_api_lookup_nick.c347
-rw-r--r--src/namestore/test_namestore_api_monitoring.c378
-rw-r--r--src/namestore/test_namestore_api_monitoring_existing.c393
-rw-r--r--src/namestore/test_namestore_api_postgres.conf10
-rw-r--r--src/namestore/test_namestore_api_remove.c219
-rw-r--r--src/namestore/test_namestore_api_remove_not_existing_record.c179
-rw-r--r--src/namestore/test_namestore_api_sqlite.conf9
-rw-r--r--src/namestore/test_namestore_api_store.c172
-rw-r--r--src/namestore/test_namestore_api_store_update.c269
-rw-r--r--src/namestore/test_namestore_api_tx_rollback.c264
-rw-r--r--src/namestore/test_namestore_api_zone_iteration.c464
-rw-r--r--src/namestore/test_namestore_api_zone_iteration_nick.c460
-rw-r--r--src/namestore/test_namestore_api_zone_iteration_specific_zone.c447
-rw-r--r--src/namestore/test_namestore_api_zone_iteration_stop.c449
-rw-r--r--src/namestore/test_namestore_api_zone_to_name.c266
-rwxr-xr-xsrc/namestore/test_namestore_delete.sh68
-rwxr-xr-xsrc/namestore/test_namestore_lookup.sh63
-rwxr-xr-xsrc/namestore/test_namestore_put.sh55
-rwxr-xr-xsrc/namestore/test_namestore_put_multiple.sh112
-rwxr-xr-xsrc/namestore/test_namestore_put_stdin.sh68
-rwxr-xr-xsrc/namestore/test_namestore_zonefile_import.sh33
-rw-r--r--src/namestore/test_plugin_namestore.c218
-rw-r--r--src/namestore/test_plugin_namestore_postgres.conf4
-rw-r--r--src/namestore/test_plugin_namestore_sqlite.conf3
-rwxr-xr-xsrc/namestore/test_plugin_rest_namestore.sh131
53 files changed, 0 insertions, 22669 deletions
diff --git a/src/namestore/.gitignore b/src/namestore/.gitignore
deleted file mode 100644
index 2265f9815..000000000
--- a/src/namestore/.gitignore
+++ /dev/null
@@ -1,61 +0,0 @@
1gnunet-service-namestore
2gnunet-namestore
3gnunet-namestore-dbtool
4gnunet-namestore-zonefile
5gnunet-namestore-fcfsd
6test_namestore_api_lookup_nick.nc
7test_namestore_api_lookup_private.nc
8test_namestore_api_lookup_public.nc
9test_namestore_api_lookup_shadow.nc
10test_namestore_api_lookup_shadow_filter.nc
11test_namestore_api_monitoring.nc
12test_namestore_api_monitoring_existing.nc
13test_namestore_api_remove.nc
14test_namestore_api_remove_not_existing_record.nc
15test_namestore_api_store.nc
16test_namestore_api_store_update.nc
17test_namestore_api_zone_iteration.nc
18test_namestore_api_zone_iteration_nick.nc
19test_namestore_api_zone_iteration_specific_zone.nc
20test_namestore_api_zone_iteration_stop.nc
21test_plugin_namestore_postgres
22test_plugin_namestore_sqlite
23gnunet-zoneimport
24test_namestore_api_lookup_nick_postgres
25test_namestore_api_lookup_nick_sqlite
26test_namestore_api_lookup_private_postgres
27test_namestore_api_lookup_private_sqlite
28test_namestore_api_lookup_public_postgres
29test_namestore_api_lookup_public_sqlite
30test_namestore_api_lookup_shadow_filter_postgres
31test_namestore_api_lookup_shadow_filter_sqlite
32test_namestore_api_lookup_shadow_postgres
33test_namestore_api_lookup_shadow_sqlite
34test_namestore_api_monitoring_existing_postgres
35test_namestore_api_monitoring_existing_sqlite
36test_namestore_api_monitoring_postgres
37test_namestore_api_monitoring_sqlite
38test_namestore_api_remove_not_existing_record_postgres
39test_namestore_api_remove_not_existing_record_sqlite
40test_namestore_api_remove_postgres
41test_namestore_api_remove_sqlite
42test_namestore_api_store_postgres
43test_namestore_api_store_sqlite
44test_namestore_api_store_update_postgres
45test_namestore_api_store_update_sqlite
46test_namestore_api_zone_iteration_nick_postgres
47test_namestore_api_zone_iteration_nick_sqlite
48test_namestore_api_zone_iteration_postgres
49test_namestore_api_zone_iteration_specific_zone_postgres
50test_namestore_api_zone_iteration_specific_zone_sqlite
51test_namestore_api_zone_iteration_sqlite
52test_namestore_api_zone_iteration_stop_postgres
53test_namestore_api_zone_iteration_stop_sqlite
54test_namestore_api_zone_to_name_postgres
55test_namestore_api_zone_to_name_sqlite
56test_namestore_api_tx_rollback_postgres
57test_namestore_api_tx_rollback_sqlite
58test_namestore_api_edit_records_postgres
59perf_namestore_api_import_sqlite
60perf_namestore_api_import_postgres
61test_namestore_api_store_locking_sqlite
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
deleted file mode 100644
index 685829cc2..000000000
--- a/src/namestore/Makefile.am
+++ /dev/null
@@ -1,543 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS)
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10sqldir = $(prefix)/share/gnunet/sql/
11
12sql_DATA = \
13 namestore-0001.sql \
14 namestore-drop.sql
15
16pkgcfg_DATA = \
17 namestore.conf
18
19if USE_COVERAGE
20 AM_CFLAGS = --coverage -O0
21 XLIBS = -lgcov
22endif
23
24
25if HAVE_SQLITE
26SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la
27SQLITE_TESTS = test_plugin_namestore_sqlite \
28 test_namestore_api_store_sqlite \
29 test_namestore_api_store_update_sqlite \
30 test_namestore_api_zone_iteration_sqlite \
31 test_namestore_api_remove_sqlite \
32 test_namestore_api_lookup_nick_sqlite \
33 test_namestore_api_monitoring_sqlite \
34 test_namestore_api_remove_not_existing_record_sqlite \
35 test_namestore_api_zone_iteration_nick_sqlite \
36 test_namestore_api_zone_iteration_specific_zone_sqlite \
37 test_namestore_api_zone_iteration_stop_sqlite \
38 test_namestore_api_monitoring_existing_sqlite \
39 test_namestore_api_zone_to_name_sqlite \
40 perf_namestore_api_zone_iteration_sqlite \
41 perf_namestore_api_import_sqlite \
42 perf_namestore_api_import_postgres \
43 test_namestore_api_tx_rollback_sqlite
44endif
45
46
47if HAVE_POSTGRESQL
48POSTGRES_PLUGIN = libgnunet_plugin_namestore_postgres.la
49POSTGRES_TESTS = test_plugin_namestore_postgres \
50 test_namestore_api_store_postgres \
51 test_namestore_api_store_update_postgres \
52 test_namestore_api_remove_postgres \
53 test_namestore_api_zone_iteration_postgres \
54 test_namestore_api_lookup_nick_postgres \
55 test_namestore_api_monitoring_postgres \
56 test_namestore_api_remove_not_existing_record_postgres \
57 test_namestore_api_zone_iteration_nick_postgres \
58 test_namestore_api_zone_iteration_specific_zone_postgres \
59 test_namestore_api_zone_iteration_stop_postgres \
60 test_namestore_api_monitoring_existing_postgres \
61 test_namestore_api_zone_to_name_postgres \
62 perf_namestore_api_zone_iteration_postgres \
63 test_namestore_api_tx_rollback_postgres
64if HAVE_EXPERIMENTAL
65POSTGRES_TESTS += test_namestore_api_edit_records_postgres
66endif
67endif
68
69if HAVE_SQLITE
70check_PROGRAMS = \
71 $(SQLITE_TESTS) \
72 $(POSTGRES_TESTS)
73endif
74
75if ENABLE_TEST_RUN
76AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
77TESTS = \
78 $(check_PROGRAMS) \
79 $(check_SCRIPTS)
80endif
81
82REST_PLUGIN = libgnunet_plugin_rest_namestore.la
83
84lib_LTLIBRARIES = \
85 libgnunetnamestore.la
86
87
88libexec_PROGRAMS = \
89 gnunet-service-namestore
90
91bin_PROGRAMS = \
92 gnunet-namestore \
93 gnunet-namestore-dbtool \
94 gnunet-namestore-zonefile \
95 gnunet-zoneimport
96
97libexec_PROGRAMS += \
98 gnunet-namestore-fcfsd
99
100
101plugin_LTLIBRARIES = \
102 $(SQLITE_PLUGIN) \
103 $(POSTGRES_PLUGIN) \
104 $(REST_PLUGIN)
105
106
107libgnunet_plugin_rest_namestore_la_SOURCES = \
108 plugin_rest_namestore.c
109libgnunet_plugin_rest_namestore_la_LIBADD = \
110 libgnunetnamestore.la \
111 $(top_builddir)/src/service/rest/libgnunetrest.la \
112 $(top_builddir)/src/service/identity/libgnunetidentity.la \
113 $(top_builddir)/src/lib/json/libgnunetjson.la \
114 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
115 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecordjson.la \
116 $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \
117 $(LTLIBINTL) -ljansson $(MHD_LIBS)
118libgnunet_plugin_rest_namestore_la_LDFLAGS = \
119 $(GN_PLUGIN_LDFLAGS)
120libgnunet_plugin_rest_namestore_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
121
122
123libgnunetnamestore_la_SOURCES = \
124 namestore_api.c \
125 namestore_api_monitor.c \
126 namestore.h
127libgnunetnamestore_la_LIBADD = \
128 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
129 $(top_builddir)/src/service/identity/libgnunetidentity.la \
130 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
131 $(top_builddir)/src/lib/util/libgnunetutil.la \
132 $(GN_LIBINTL)
133libgnunetnamestore_la_LDFLAGS = \
134 $(GN_LIB_LDFLAGS) \
135 -version-info 0:1:0
136
137gnunet_namestore_zonefile_SOURCES = \
138 gnunet-namestore-zonefile.c
139gnunet_namestore_zonefile_LDADD = \
140 libgnunetnamestore.la \
141 $(top_builddir)/src/service/identity/libgnunetidentity.la \
142 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
143 $(top_builddir)/src/lib/util/libgnunetutil.la \
144 $(GN_LIBINTL)
145
146gnunet_zoneimport_SOURCES = \
147 gnunet-zoneimport.c
148gnunet_zoneimport_LDADD = \
149 libgnunetnamestore.la \
150 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
151 $(top_builddir)/src/service/identity/libgnunetidentity.la \
152 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
153 $(top_builddir)/src/lib/util/libgnunetutil.la \
154 $(GN_LIBINTL)
155
156gnunet_namestore_SOURCES = \
157 gnunet-namestore.c
158gnunet_namestore_LDADD = \
159 $(top_builddir)/src/service/identity/libgnunetidentity.la \
160 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
161 $(top_builddir)/src/lib/util/libgnunetutil.la \
162 libgnunetnamestore.la \
163 $(GN_LIBINTL)
164
165gnunet_namestore_dbtool_SOURCES = \
166 gnunet-namestore-dbtool.c
167gnunet_namestore_dbtool_LDADD = \
168 $(top_builddir)/src/lib/util/libgnunetutil.la \
169 libgnunetnamestore.la \
170 $(GN_LIBINTL)
171
172
173
174gnunet_namestore_fcfsd_SOURCES = \
175 gnunet-namestore-fcfsd.c
176gnunet_namestore_fcfsd_LDADD = $(MHD_LIBS) \
177 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
178 $(top_builddir)/src/service/identity/libgnunetidentity.la \
179 libgnunetnamestore.la \
180 $(top_builddir)/src/lib/util/libgnunetutil.la \
181 $(top_builddir)/src/lib/json/libgnunetjson.la \
182 $(GN_LIBINTL) -ljansson
183gnunet_namestore_fcfsd_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
184
185
186gnunet_service_namestore_SOURCES = \
187 gnunet-service-namestore.c
188gnunet_service_namestore_LDADD = \
189 $(top_builddir)/src/service/namecache/libgnunetnamecache.la \
190 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
191 $(top_builddir)/src/service/identity/libgnunetidentity.la \
192 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
193 $(top_builddir)/src/lib/util/libgnunetutil.la \
194 libgnunetnamestore.la \
195 $(GN_LIBINTL)
196
197
198
199libgnunet_plugin_namestore_sqlite_la_SOURCES = \
200 plugin_namestore_sqlite.c
201libgnunet_plugin_namestore_sqlite_la_LIBADD = \
202 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
203 $(top_builddir)/src/service/identity/libgnunetidentity.la \
204 $(top_builddir)/src/lib/sq/libgnunetsq.la \
205 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
206 $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
207 $(LTLIBINTL)
208libgnunet_plugin_namestore_sqlite_la_LDFLAGS = \
209 $(GN_PLUGIN_LDFLAGS)
210
211libgnunet_plugin_namestore_postgres_la_SOURCES = \
212 plugin_namestore_postgres.c
213libgnunet_plugin_namestore_postgres_la_LIBADD = \
214 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
215 $(top_builddir)/src/service/identity/libgnunetidentity.la \
216 $(top_builddir)/src/lib/pq/libgnunetpq.la \
217 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
218 $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) -lpq \
219 $(LTLIBINTL)
220libgnunet_plugin_namestore_postgres_la_LDFLAGS = \
221 $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS)
222
223test_namestore_api_store_sqlite_SOURCES = \
224 test_namestore_api_store.c
225test_namestore_api_store_sqlite_LDADD = \
226 $(top_builddir)/src/service/testing/libgnunettesting.la \
227 $(top_builddir)/src/lib/util/libgnunetutil.la \
228 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
229 $(top_builddir)/src/service/identity/libgnunetidentity.la \
230 libgnunetnamestore.la
231
232test_namestore_api_store_postgres_SOURCES = \
233 test_namestore_api_store.c
234test_namestore_api_store_postgres_LDADD = \
235 $(top_builddir)/src/service/testing/libgnunettesting.la \
236 $(top_builddir)/src/lib/util/libgnunetutil.la \
237 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
238 $(top_builddir)/src/service/identity/libgnunetidentity.la \
239 libgnunetnamestore.la
240
241test_namestore_api_store_update_sqlite_SOURCES = \
242 test_namestore_api_store_update.c
243test_namestore_api_store_update_sqlite_LDADD = \
244 $(top_builddir)/src/service/testing/libgnunettesting.la \
245 $(top_builddir)/src/lib/util/libgnunetutil.la \
246 $(top_builddir)/src/service/identity/libgnunetidentity.la \
247 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
248 $(top_builddir)/src/service/namecache/libgnunetnamecache.la \
249 libgnunetnamestore.la
250
251test_namestore_api_store_update_postgres_SOURCES = \
252 test_namestore_api_store_update.c
253test_namestore_api_store_update_postgres_LDADD = \
254 $(top_builddir)/src/service/testing/libgnunettesting.la \
255 $(top_builddir)/src/lib/util/libgnunetutil.la \
256 $(top_builddir)/src/service/identity/libgnunetidentity.la \
257 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
258 $(top_builddir)/src/service/namecache/libgnunetnamecache.la \
259 libgnunetnamestore.la
260
261test_namestore_api_lookup_nick_sqlite_SOURCES = \
262 test_namestore_api_lookup_nick.c
263test_namestore_api_lookup_nick_sqlite_LDADD = \
264 $(top_builddir)/src/service/testing/libgnunettesting.la \
265 $(top_builddir)/src/lib/util/libgnunetutil.la \
266 $(top_builddir)/src/service/identity/libgnunetidentity.la \
267 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
268 $(top_builddir)/src/service/namecache/libgnunetnamecache.la \
269 libgnunetnamestore.la
270
271test_namestore_api_lookup_nick_postgres_SOURCES = \
272 test_namestore_api_lookup_nick.c
273test_namestore_api_lookup_nick_postgres_LDADD = \
274 $(top_builddir)/src/service/testing/libgnunettesting.la \
275 $(top_builddir)/src/lib/util/libgnunetutil.la \
276 $(top_builddir)/src/service/identity/libgnunetidentity.la \
277 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
278 $(top_builddir)/src/service/namecache/libgnunetnamecache.la \
279 libgnunetnamestore.la
280
281test_namestore_api_remove_sqlite_SOURCES = \
282 test_namestore_api_remove.c
283test_namestore_api_remove_sqlite_LDADD = \
284 $(top_builddir)/src/service/identity/libgnunetidentity.la \
285 $(top_builddir)/src/service/testing/libgnunettesting.la \
286 $(top_builddir)/src/lib/util/libgnunetutil.la \
287 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
288 libgnunetnamestore.la
289
290test_namestore_api_remove_postgres_SOURCES = \
291 test_namestore_api_remove.c
292test_namestore_api_remove_postgres_LDADD = \
293 $(top_builddir)/src/service/identity/libgnunetidentity.la \
294 $(top_builddir)/src/service/testing/libgnunettesting.la \
295 $(top_builddir)/src/lib/util/libgnunetutil.la \
296 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
297 libgnunetnamestore.la
298
299test_namestore_api_remove_not_existing_record_sqlite_SOURCES = \
300 test_namestore_api_remove_not_existing_record.c
301test_namestore_api_remove_not_existing_record_sqlite_LDADD = \
302 $(top_builddir)/src/service/testing/libgnunettesting.la \
303 $(top_builddir)/src/lib/util/libgnunetutil.la \
304 $(top_builddir)/src/service/identity/libgnunetidentity.la \
305 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
306 libgnunetnamestore.la
307
308test_namestore_api_remove_not_existing_record_postgres_SOURCES = \
309 test_namestore_api_remove_not_existing_record.c
310test_namestore_api_remove_not_existing_record_postgres_LDADD = \
311 $(top_builddir)/src/service/testing/libgnunettesting.la \
312 $(top_builddir)/src/service/identity/libgnunetidentity.la \
313 $(top_builddir)/src/lib/util/libgnunetutil.la \
314 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
315 libgnunetnamestore.la
316
317test_namestore_api_zone_to_name_sqlite_SOURCES = \
318 test_namestore_api_zone_to_name.c
319test_namestore_api_zone_to_name_sqlite_LDADD = \
320 $(top_builddir)/src/service/identity/libgnunetidentity.la \
321 $(top_builddir)/src/service/testing/libgnunettesting.la \
322 $(top_builddir)/src/lib/util/libgnunetutil.la \
323 libgnunetnamestore.la
324
325test_namestore_api_zone_to_name_postgres_SOURCES = \
326 test_namestore_api_zone_to_name.c
327test_namestore_api_zone_to_name_postgres_LDADD = \
328 $(top_builddir)/src/service/identity/libgnunetidentity.la \
329 $(top_builddir)/src/service/testing/libgnunettesting.la \
330 $(top_builddir)/src/lib/util/libgnunetutil.la \
331 libgnunetnamestore.la
332
333test_namestore_api_monitoring_sqlite_SOURCES = \
334 test_namestore_api_monitoring.c
335test_namestore_api_monitoring_sqlite_LDADD = \
336 $(top_builddir)/src/service/identity/libgnunetidentity.la \
337 $(top_builddir)/src/service/testing/libgnunettesting.la \
338 libgnunetnamestore.la \
339 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
340 $(top_builddir)/src/lib/util/libgnunetutil.la
341
342test_namestore_api_monitoring_postgres_SOURCES = \
343 test_namestore_api_monitoring.c
344test_namestore_api_monitoring_postgres_LDADD = \
345 $(top_builddir)/src/service/testing/libgnunettesting.la \
346 $(top_builddir)/src/service/identity/libgnunetidentity.la \
347 libgnunetnamestore.la \
348 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
349 $(top_builddir)/src/lib/util/libgnunetutil.la
350
351test_namestore_api_monitoring_existing_sqlite_SOURCES = \
352 test_namestore_api_monitoring_existing.c
353test_namestore_api_monitoring_existing_sqlite_LDADD = \
354 $(top_builddir)/src/service/testing/libgnunettesting.la \
355 $(top_builddir)/src/service/identity/libgnunetidentity.la \
356 libgnunetnamestore.la \
357 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
358 $(top_builddir)/src/lib/util/libgnunetutil.la
359
360test_namestore_api_monitoring_existing_postgres_SOURCES = \
361 test_namestore_api_monitoring_existing.c
362test_namestore_api_monitoring_existing_postgres_LDADD = \
363 $(top_builddir)/src/service/testing/libgnunettesting.la \
364 libgnunetnamestore.la \
365 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
366 $(top_builddir)/src/service/identity/libgnunetidentity.la \
367 $(top_builddir)/src/lib/util/libgnunetutil.la
368
369test_namestore_api_tx_rollback_sqlite_SOURCES = \
370 test_namestore_api_tx_rollback.c
371test_namestore_api_tx_rollback_sqlite_LDADD = \
372 $(top_builddir)/src/service/testing/libgnunettesting.la \
373 $(top_builddir)/src/service/identity/libgnunetidentity.la \
374 libgnunetnamestore.la \
375 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
376 $(top_builddir)/src/lib/util/libgnunetutil.la
377
378test_namestore_api_tx_rollback_postgres_SOURCES = \
379 test_namestore_api_tx_rollback.c
380test_namestore_api_tx_rollback_postgres_LDADD = \
381 $(top_builddir)/src/service/testing/libgnunettesting.la \
382 $(top_builddir)/src/service/identity/libgnunetidentity.la \
383 libgnunetnamestore.la \
384 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
385 $(top_builddir)/src/lib/util/libgnunetutil.la
386
387if HAVE_EXPERIMENTAL
388test_namestore_api_edit_records_postgres_SOURCES = \
389 test_namestore_api_edit_records.c
390test_namestore_api_edit_records_postgres_LDADD = \
391 $(top_builddir)/src/service/testing/libgnunettesting.la \
392 $(top_builddir)/src/service/identity/libgnunetidentity.la \
393 libgnunetnamestore.la \
394 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
395 $(top_builddir)/src/lib/util/libgnunetutil.la
396endif
397
398test_namestore_api_zone_iteration_sqlite_SOURCES = \
399 test_namestore_api_zone_iteration.c
400test_namestore_api_zone_iteration_sqlite_LDADD = \
401 $(top_builddir)/src/service/testing/libgnunettesting.la \
402 $(top_builddir)/src/service/identity/libgnunetidentity.la \
403 $(top_builddir)/src/lib/util/libgnunetutil.la \
404 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
405 libgnunetnamestore.la
406
407test_namestore_api_zone_iteration_postgres_SOURCES = \
408 test_namestore_api_zone_iteration.c
409test_namestore_api_zone_iteration_postgres_LDADD = \
410 $(top_builddir)/src/service/testing/libgnunettesting.la \
411 $(top_builddir)/src/service/identity/libgnunetidentity.la \
412 $(top_builddir)/src/lib/util/libgnunetutil.la \
413 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
414 libgnunetnamestore.la
415
416perf_namestore_api_zone_iteration_postgres_SOURCES = \
417 perf_namestore_api_zone_iteration.c
418perf_namestore_api_zone_iteration_postgres_LDADD = \
419 $(top_builddir)/src/service/testing/libgnunettesting.la \
420 $(top_builddir)/src/lib/util/libgnunetutil.la \
421 $(top_builddir)/src/service/identity/libgnunetidentity.la \
422 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
423 libgnunetnamestore.la
424
425perf_namestore_api_import_sqlite_SOURCES = \
426 perf_namestore_api_import.c
427perf_namestore_api_import_sqlite_LDADD = \
428 $(top_builddir)/src/service/testing/libgnunettesting.la \
429 $(top_builddir)/src/lib/util/libgnunetutil.la \
430 $(top_builddir)/src/service/identity/libgnunetidentity.la \
431 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
432 libgnunetnamestore.la
433
434perf_namestore_api_import_postgres_SOURCES = \
435 perf_namestore_api_import.c
436perf_namestore_api_import_postgres_LDADD = \
437 $(top_builddir)/src/service/testing/libgnunettesting.la \
438 $(top_builddir)/src/lib/util/libgnunetutil.la \
439 $(top_builddir)/src/service/identity/libgnunetidentity.la \
440 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
441 libgnunetnamestore.la
442
443
444perf_namestore_api_zone_iteration_sqlite_SOURCES = \
445 perf_namestore_api_zone_iteration.c
446perf_namestore_api_zone_iteration_sqlite_LDADD = \
447 $(top_builddir)/src/service/testing/libgnunettesting.la \
448 $(top_builddir)/src/service/identity/libgnunetidentity.la \
449 $(top_builddir)/src/lib/util/libgnunetutil.la \
450 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
451 libgnunetnamestore.la
452
453test_namestore_api_zone_iteration_nick_sqlite_SOURCES = \
454 test_namestore_api_zone_iteration_nick.c
455test_namestore_api_zone_iteration_nick_sqlite_LDADD = \
456 $(top_builddir)/src/service/testing/libgnunettesting.la \
457 $(top_builddir)/src/service/identity/libgnunetidentity.la \
458 $(top_builddir)/src/lib/util/libgnunetutil.la \
459 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
460 libgnunetnamestore.la
461
462test_namestore_api_zone_iteration_nick_postgres_SOURCES = \
463 test_namestore_api_zone_iteration_nick.c
464test_namestore_api_zone_iteration_nick_postgres_LDADD = \
465 $(top_builddir)/src/service/testing/libgnunettesting.la \
466 $(top_builddir)/src/service/identity/libgnunetidentity.la \
467 $(top_builddir)/src/lib/util/libgnunetutil.la \
468 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
469 libgnunetnamestore.la
470
471test_namestore_api_zone_iteration_specific_zone_sqlite_SOURCES = \
472 test_namestore_api_zone_iteration_specific_zone.c
473test_namestore_api_zone_iteration_specific_zone_sqlite_LDADD = \
474 $(top_builddir)/src/service/testing/libgnunettesting.la \
475 $(top_builddir)/src/service/identity/libgnunetidentity.la \
476 $(top_builddir)/src/lib/util/libgnunetutil.la \
477 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
478 libgnunetnamestore.la
479
480test_namestore_api_zone_iteration_specific_zone_postgres_SOURCES = \
481 test_namestore_api_zone_iteration_specific_zone.c
482test_namestore_api_zone_iteration_specific_zone_postgres_LDADD = \
483 $(top_builddir)/src/service/testing/libgnunettesting.la \
484 $(top_builddir)/src/service/identity/libgnunetidentity.la \
485 $(top_builddir)/src/lib/util/libgnunetutil.la \
486 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
487 libgnunetnamestore.la
488
489test_namestore_api_zone_iteration_stop_sqlite_SOURCES = \
490 test_namestore_api_zone_iteration_stop.c
491test_namestore_api_zone_iteration_stop_sqlite_LDADD = \
492 $(top_builddir)/src/service/testing/libgnunettesting.la \
493 $(top_builddir)/src/service/identity/libgnunetidentity.la \
494 $(top_builddir)/src/lib/util/libgnunetutil.la \
495 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
496 libgnunetnamestore.la
497
498test_namestore_api_zone_iteration_stop_postgres_SOURCES = \
499 test_namestore_api_zone_iteration_stop.c
500test_namestore_api_zone_iteration_stop_postgres_LDADD = \
501 $(top_builddir)/src/service/testing/libgnunettesting.la \
502 $(top_builddir)/src/service/identity/libgnunetidentity.la \
503 $(top_builddir)/src/lib/util/libgnunetutil.la \
504 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
505 libgnunetnamestore.la
506
507test_plugin_namestore_sqlite_SOURCES = \
508 test_plugin_namestore.c
509test_plugin_namestore_sqlite_LDADD = \
510 $(top_builddir)/src/service/testing/libgnunettesting.la \
511 $(top_builddir)/src/service/identity/libgnunetidentity.la \
512 $(top_builddir)/src/lib/util/libgnunetutil.la
513
514test_plugin_namestore_postgres_SOURCES = \
515 test_plugin_namestore.c
516test_plugin_namestore_postgres_LDADD = \
517 $(top_builddir)/src/service/identity/libgnunetidentity.la \
518 $(top_builddir)/src/service/testing/libgnunettesting.la \
519 $(top_builddir)/src/lib/util/libgnunetutil.la
520
521check_SCRIPTS = \
522 test_namestore_put.sh \
523 test_namestore_put_stdin.sh \
524 test_namestore_lookup.sh \
525 test_namestore_delete.sh \
526 test_namestore_zonefile_import.sh
527
528check_SCRIPTS += \
529 test_plugin_rest_namestore.sh
530
531EXTRA_DIST = \
532 test_common.c \
533 test_namestore_api.conf \
534 test_namestore_api_postgres.conf \
535 test_namestore_api_sqlite.conf \
536 perf_namestore_api_postgres.conf \
537 perf_namestore_api_sqlite.conf \
538 test_plugin_namestore_sqlite.conf \
539 test_plugin_namestore_postgres.conf \
540 test_hostkey \
541 example_zonefile \
542 $(check_SCRIPTS) \
543 $(sql_DATA)
diff --git a/src/namestore/example_zonefile b/src/namestore/example_zonefile
deleted file mode 100644
index 5e380ff90..000000000
--- a/src/namestore/example_zonefile
+++ /dev/null
@@ -1,27 +0,0 @@
1$ORIGIN example.com. ; designates the start of this zone file in the namespace
2$TTL 3600 ; default expiration time (in seconds) of all RRs without their own TTL value
3example.com. IN SOA ns.example.com. username.example.com. ( 2020091025 ; A comment
4 7200 ; Comment
5 ; empty line on purpose
6 3600
7 1209600
8 3600 )
9example.com. IN NS ns ; ns.example.com is a nameserver for example.com
10example.com. IN NS ns.somewhere.example. ; ns.somewhere.example is a backup nameserver for example.com
11example.com. IN MX 10 mail.example.com. ; mail.example.com is the mailserver for example.com
12@ IN MX 20 mail2.example.com. ; equivalent to above line, "@" represents zone origin
13@ IN MX 50 mail3 ; equivalent to above line, but using a relative host name
14b.example.com. IN A 192.0.2.1 ; IPv4 address for example.com
15 IN AAAA 2001:db8:10::1 ; IPv6 address for example.com
16ns IN A 192.0.2.2 ; IPv4 address for ns.example.com
17 IN AAAA 2001:db8:10::2 ; IPv6 address for ns.example.com
18www IN CNAME example.com. ; www.example.com is an alias for example.com
19wwwtest IN CNAME www ; wwwtest.example.com is another alias for www.example.com
20mail IN A 192.0.2.3 ; IPv4 address for mail.example.com
21mail2 IN A 192.0.2.4 ; IPv4 address for mail2.example.com
22mail3 IN A 192.0.2.5 ; IPv4 address for mail3.example.com
23
24mail3 IN TXT "This is ; quoted" ; A quoted comment separator
25$ORIGIN example.de.
26www2 IN A 192.0.2.7 ; IPv4 address for www2.example.de
27
diff --git a/src/namestore/gnunet-namestore-dbtool.c b/src/namestore/gnunet-namestore-dbtool.c
deleted file mode 100644
index 835d7a228..000000000
--- a/src/namestore/gnunet-namestore-dbtool.c
+++ /dev/null
@@ -1,199 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 2019, 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 gnunet-namestore-dbtool.c
22 * @brief command line tool to manipulate the database backends for the namestore
23 * @author Martin Schanzenbach
24 *
25 */
26#include "platform.h"
27#include <gnunet_util_lib.h>
28#include <gnunet_namestore_plugin.h>
29
30/**
31 * Name of the plugin argument
32 */
33static char *pluginname;
34
35/**
36 * Reset argument
37 */
38static int reset;
39
40/**
41 * Initialize argument
42 */
43static int init;
44
45/**
46 * Return code
47 */
48static int ret = 0;
49
50/**
51 * Task run on shutdown. Cleans up everything.
52 *
53 * @param cls unused
54 */
55static void
56do_shutdown (void *cls)
57{
58 (void) cls;
59 if (NULL != pluginname)
60 GNUNET_free (pluginname);
61}
62
63
64/**
65 * Main function that will be run.
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 char *db_lib_name;
79 struct GNUNET_NAMESTORE_PluginFunctions *plugin;
80
81 (void) cls;
82 (void) args;
83 (void) cfgfile;
84 if (NULL != args[0])
85 GNUNET_log (
86 GNUNET_ERROR_TYPE_WARNING,
87 _ ("Superfluous command line arguments (starting with `%s') ignored\n"),
88 args[0]);
89
90 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
91 (void *) cfg);
92 if (NULL == pluginname)
93 {
94 fprintf (stderr, "No plugin given!\n");
95 ret = 1;
96 GNUNET_SCHEDULER_shutdown ();
97 return;
98 }
99 GNUNET_asprintf (&db_lib_name,
100 "libgnunet_plugin_namestore_%s",
101 pluginname);
102 plugin = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
103 if (NULL == plugin)
104 {
105 fprintf (stderr,
106 "Failed to load %s!\n",
107 db_lib_name);
108 ret = 1;
109 GNUNET_SCHEDULER_shutdown ();
110 GNUNET_free (db_lib_name);
111 return;
112 }
113 if (reset)
114 {
115 if (GNUNET_OK !=
116 plugin->drop_tables (plugin->cls))
117 {
118 fprintf (stderr,
119 "Failed to reset database\n");
120 ret = 1;
121 GNUNET_free (db_lib_name);
122 GNUNET_SCHEDULER_shutdown ();
123 return;
124 }
125 }
126 if (init || reset)
127 {
128 if (GNUNET_OK !=
129 plugin->create_tables (plugin->cls))
130 {
131 fprintf (stderr,
132 "Failed to initialize database\n");
133 ret = 1;
134 GNUNET_free (db_lib_name);
135 GNUNET_SCHEDULER_shutdown ();
136 return;
137 }
138 }
139 GNUNET_SCHEDULER_shutdown ();
140 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name,
141 plugin));
142 GNUNET_free (db_lib_name);
143}
144
145
146/**
147 * The main function for gnunet-namestore-dbtool.
148 *
149 * @param argc number of arguments from the command line
150 * @param argv command line arguments
151 * @return 0 ok, 1 on error
152 */
153int
154main (int argc, char *const *argv)
155{
156 struct GNUNET_GETOPT_CommandLineOption options[] = {
157 GNUNET_GETOPT_option_flag ('i', "init",
158 gettext_noop ("initialize database"),
159 &init),
160 GNUNET_GETOPT_option_flag ('r',
161 "reset",
162 gettext_noop (
163 "reset database (DANGEROUS: All existing data is lost!"),
164 &reset),
165 GNUNET_GETOPT_option_string (
166 'p',
167 "plugin",
168 "PLUGIN",
169 gettext_noop (
170 "the namestore plugin to work with, e.g. 'sqlite'"),
171 &pluginname),
172 GNUNET_GETOPT_OPTION_END
173 };
174 int lret;
175
176 if (GNUNET_OK !=
177 GNUNET_STRINGS_get_utf8_args (argc, argv,
178 &argc, &argv))
179 return 2;
180
181 GNUNET_log_setup ("gnunet-namestore-dbtool",
182 "WARNING",
183 NULL);
184 if (GNUNET_OK !=
185 (lret = GNUNET_PROGRAM_run (argc,
186 argv,
187 "gnunet-namestore-dbtool",
188 _ (
189 "GNUnet namestore database manipulation tool"),
190 options,
191 &run,
192 NULL)))
193 {
194 GNUNET_free_nz ((void *) argv);
195 return lret;
196 }
197 GNUNET_free_nz ((void *) argv);
198 return ret;
199}
diff --git a/src/namestore/gnunet-namestore-fcfsd.c b/src/namestore/gnunet-namestore-fcfsd.c
deleted file mode 100644
index 4948ae441..000000000
--- a/src/namestore/gnunet-namestore-fcfsd.c
+++ /dev/null
@@ -1,1160 +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 gnunet-namestore-fcfsd.c
23 * @brief HTTP daemon that offers first-come-first-serve GNS domain registration
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include <microhttpd.h>
29#include "gnunet_util_lib.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_namestore_service.h"
33#include "gnunet_mhd_compat.h"
34#include "gnunet_json_lib.h"
35
36/**
37 * Structure representing a static page.
38 * "Static" means that the server does not process the page before sending it
39 * to the client. Clients can still process the received data, for example
40 * because there are scripting elements within.
41 */
42struct StaticPage
43{
44 /**
45 * Handle to file on disk.
46 */
47 struct GNUNET_DISK_FileHandle *handle;
48
49 /**
50 * Size in bytes of the file.
51 */
52 uint64_t size;
53
54 /**
55 * Cached response object to send to clients.
56 */
57 struct MHD_Response *response;
58};
59
60/**
61 * Structure containing some request-specific data.
62 */
63struct RequestData
64{
65 /**
66 * The connection this request was sent in.
67 */
68 struct MHD_Connection *c;
69
70 /**
71 * Body of the response object.
72 */
73 char *body;
74
75 /**
76 * Length in bytes of the body.
77 */
78 size_t body_length;
79
80 /**
81 * Response code.
82 */
83 int code;
84
85 /**
86 * Task started to search for an entry in the namestore.
87 */
88 struct GNUNET_NAMESTORE_QueueEntry *searching;
89
90 /**
91 * Task started to iterate over the namestore.
92 */
93 struct GNUNET_NAMESTORE_ZoneIterator *iterating;
94
95 /**
96 * Pointer used while processing POST data.
97 */
98 void *ptr;
99
100 /**
101 * Name requested to be registered.
102 */
103 char *register_name;
104
105 /**
106 * Key (encoded as a string) to be associated with the requested name.
107 */
108 char *register_key;
109
110 /**
111 * Key to be associated with the requested name.
112 */
113 struct GNUNET_CRYPTO_PublicKey key;
114};
115
116/**
117 * Name of the zone being managed.
118 */
119static char *zone = NULL;
120
121/**
122 * The port the daemon is listening to for HTTP requests.
123 */
124static unsigned long long port = 18080;
125
126/**
127 * Connection with the namestore service.
128 */
129static struct GNUNET_NAMESTORE_Handle *namestore = NULL;
130
131/**
132 * Connection with the identity service.
133 */
134static struct GNUNET_IDENTITY_Handle *identity = NULL;
135
136/**
137 * Private key of the zone.
138 */
139static const struct GNUNET_CRYPTO_PrivateKey *zone_key = NULL;
140
141/**
142 * The HTTP daemon.
143 */
144static struct MHD_Daemon *httpd = NULL;
145
146/**
147 * Task executing the HTTP daemon.
148 */
149static struct GNUNET_SCHEDULER_Task *httpd_task = NULL;
150
151/**
152 * The main page, a.k.a. "index.html"
153 */
154static struct StaticPage *main_page = NULL;
155
156/**
157 * Page indicating the requested resource could not be found.
158 */
159static struct StaticPage *notfound_page = NULL;
160
161/**
162 * Page indicating the requested resource could not be accessed, and other
163 * errors.
164 */
165static struct StaticPage *forbidden_page = NULL;
166
167/**
168 * The relative expiration time for added records
169 */
170static struct GNUNET_TIME_Relative record_exp;
171
172/**
173 * Task ran at shutdown to clean up everything.
174 *
175 * @param cls unused
176 */
177static void
178do_shutdown (void *cls)
179{
180 /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so
181 calling `GNUNET_DISK_file_close' would generate a spurious warning message
182 in the log. Since that function does nothing but close the descriptor and
183 free the allocated memory, After destroying the response all that's left to
184 do is call `GNUNET_free'. */
185 if (NULL != main_page)
186 {
187 MHD_destroy_response (main_page->response);
188 GNUNET_free (main_page->handle);
189 GNUNET_free (main_page);
190 }
191 if (NULL != notfound_page)
192 {
193 MHD_destroy_response (notfound_page->response);
194 GNUNET_free (notfound_page->handle);
195 GNUNET_free (notfound_page);
196 }
197 if (NULL != forbidden_page)
198 {
199 MHD_destroy_response (forbidden_page->response);
200 GNUNET_free (forbidden_page->handle);
201 GNUNET_free (forbidden_page);
202 }
203
204 if (NULL != namestore)
205 {
206 GNUNET_NAMESTORE_disconnect (namestore);
207 }
208
209 if (NULL != identity)
210 {
211 GNUNET_IDENTITY_disconnect (identity);
212 }
213
214 if (NULL != httpd_task)
215 {
216 GNUNET_SCHEDULER_cancel (httpd_task);
217 }
218 if (NULL != httpd)
219 {
220 MHD_stop_daemon (httpd);
221 }
222}
223
224
225/**
226 * Called when the HTTP server has some pending operations.
227 *
228 * @param cls unused
229 */
230static void
231do_httpd (void *cls);
232
233/**
234 * Schedule a task to run MHD.
235 */
236static void
237run_httpd (void)
238{
239 fd_set rs;
240 fd_set ws;
241 fd_set es;
242
243 struct GNUNET_NETWORK_FDSet *grs = GNUNET_NETWORK_fdset_create ();
244 struct GNUNET_NETWORK_FDSet *gws = GNUNET_NETWORK_fdset_create ();
245 struct GNUNET_NETWORK_FDSet *ges = GNUNET_NETWORK_fdset_create ();
246
247 FD_ZERO (&rs);
248 FD_ZERO (&ws);
249 FD_ZERO (&es);
250
251 int max = -1;
252 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
253
254 unsigned MHD_LONG_LONG timeout = 0;
255 struct GNUNET_TIME_Relative gtime = GNUNET_TIME_UNIT_FOREVER_REL;
256 if (MHD_YES == MHD_get_timeout (httpd, &timeout))
257 {
258 gtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
259 timeout);
260 }
261
262 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
263 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
264 GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1);
265
266 httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
267 gtime,
268 grs,
269 gws,
270 &do_httpd,
271 NULL);
272 GNUNET_NETWORK_fdset_destroy (grs);
273 GNUNET_NETWORK_fdset_destroy (gws);
274 GNUNET_NETWORK_fdset_destroy (ges);
275}
276
277
278/**
279 * Called when the HTTP server has some pending operations.
280 *
281 * @param cls unused
282 */
283static void
284do_httpd (void *cls)
285{
286 httpd_task = NULL;
287 MHD_run (httpd);
288 run_httpd ();
289}
290
291
292static void
293run_httpd_now (void)
294{
295 if (NULL != httpd_task)
296 {
297 GNUNET_SCHEDULER_cancel (httpd_task);
298 httpd_task = NULL;
299 }
300 httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
301}
302
303
304/**
305 * Generate a JSON object.
306 *
307 * @param key the key for the first element
308 * @param value the value for the first element
309 * @param ... key-value pairs of the object, terminated by NULL
310 * @return a JSON string (allocated)
311 */
312static char *
313make_json (const char *key, const char *value, ...)
314{
315 va_list args;
316 va_start (args, value);
317
318 json_t *obj = NULL;
319
320 obj = json_object ();
321 if ((NULL == key) || (NULL == value))
322 {
323 va_end (args);
324 return json_dumps (obj, JSON_COMPACT);
325 }
326
327 json_object_set (obj, key, json_string (value));
328
329 char *k = va_arg (args, char *);
330 if (NULL == k)
331 {
332 va_end (args);
333 return json_dumps (obj, JSON_COMPACT);
334 }
335 char *v = va_arg (args, char *);
336 if (NULL == v)
337 {
338 va_end (args);
339 return json_dumps (obj, JSON_COMPACT);
340 }
341
342 while (NULL != k && NULL != v)
343 {
344 json_object_set (obj, k, json_string (v));
345 k = va_arg (args, char *);
346 if (NULL != k)
347 {
348 v = va_arg (args, char *);
349 }
350 }
351
352 va_end (args);
353
354 char *json = json_dumps (obj, JSON_COMPACT);
355 json_decref (obj);
356
357 return json;
358}
359
360
361/**
362 * The namestore search task failed.
363 *
364 * @param cls the request data
365 */
366static void
367search_error_cb (void *cls)
368{
369 struct RequestData *rd = cls;
370 MHD_resume_connection (rd->c);
371 rd->searching = NULL;
372 rd->body = make_json ("error", "true",
373 "message", _ ("can not search the namestore"),
374 NULL);
375 rd->body_length = strlen (rd->body);
376 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
377 run_httpd_now ();
378}
379
380
381/**
382 * The lookup terminated with some results.
383 *
384 * @param cls closure
385 * @param zone the private key of the zone
386 * @param label the result label
387 * @param count number of records found
388 * @param d records found
389 */
390static void
391search_done_cb (void *cls,
392 const struct GNUNET_CRYPTO_PrivateKey *zone,
393 const char *label,
394 unsigned int count,
395 const struct GNUNET_GNSRECORD_Data *d)
396{
397 (void) zone;
398 (void) d;
399
400 struct RequestData *rd = cls;
401 MHD_resume_connection (rd->c);
402
403 rd->searching = NULL;
404 rd->body = make_json ("error", "false",
405 "free", (0 == count) ? "true" : "false",
406 NULL);
407 rd->body_length = strlen (rd->body);
408 rd->code = MHD_HTTP_OK;
409
410 run_httpd_now ();
411}
412
413
414/**
415 * An error occurred while registering a name.
416 *
417 * @param cls the connection
418 */
419static void
420register_error_cb (void *cls)
421{
422 struct RequestData *rd = cls;
423
424 MHD_resume_connection (rd->c);
425 rd->searching = NULL;
426 rd->body = make_json ("error", "true",
427 "message", _ ("unable to scan namestore"),
428 NULL);
429 rd->body_length = strlen (rd->body);
430 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
431 run_httpd_now ();
432}
433
434
435static void
436register_done_cb (void *cls,
437 enum GNUNET_ErrorCode ec)
438{
439 struct RequestData *rd = cls;
440
441 MHD_resume_connection (rd->c);
442 rd->searching = NULL;
443
444 if (GNUNET_EC_NONE != ec)
445 {
446 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
447 _ ("Failed to create record for `%s': %s\n"),
448 rd->register_name,
449 GNUNET_ErrorCode_get_hint (ec));
450 rd->body = make_json ("error", "true",
451 "message",
452 GNUNET_ErrorCode_get_hint (ec),
453 NULL);
454 rd->body_length = strlen (rd->body);
455 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
456 }
457 else
458 {
459 rd->body = make_json ("error", "false",
460 "message", _ ("no errors"),
461 NULL);
462 rd->body_length = strlen (rd->body);
463 rd->code = MHD_HTTP_OK;
464 }
465
466 run_httpd_now ();
467}
468
469
470/**
471 * Attempt to register the requested name.
472 *
473 * @param cls the connection
474 * @param key the zone key
475 * @param label name of the record
476 * @param count number of records found
477 * @param d records
478 */
479static void
480register_do_cb (void *cls,
481 const struct GNUNET_CRYPTO_PrivateKey *key,
482 const char *label,
483 unsigned int count,
484 const struct GNUNET_GNSRECORD_Data *d)
485{
486 (void) key;
487 (void) d;
488
489 struct RequestData *rd = cls;
490
491 rd->searching = NULL;
492
493 if (0 != count)
494 {
495 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
496 _ ("The requested key `%s' exists as `%s'\n"),
497 rd->register_key,
498 label);
499
500 MHD_resume_connection (rd->c);
501 rd->searching = NULL;
502 rd->body = make_json ("error", "true",
503 "message", _ ("key exists"),
504 NULL);
505 rd->body_length = strlen (rd->body);
506 rd->code = MHD_HTTP_FORBIDDEN;
507 run_httpd_now ();
508 return;
509 }
510
511 struct GNUNET_GNSRECORD_Data gd;
512 char *gdraw = NULL;
513
514 if (GNUNET_OK != GNUNET_GNSRECORD_data_from_identity (&(rd->key),
515 &gdraw,
516 &(gd.data_size),
517 &(gd.record_type)))
518 {
519 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
520 _ ("Error creating record data\n"));
521 MHD_resume_connection (rd->c);
522 rd->searching = NULL;
523 rd->body = make_json ("error", "true",
524 "message", _ ("unable to store record"),
525 NULL);
526 rd->body_length = strlen (rd->body);
527 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
528 run_httpd_now ();
529 return;
530 }
531
532 gd.data = gdraw;
533 gd.expiration_time = record_exp.rel_value_us;
534 gd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
535
536 rd->searching = GNUNET_NAMESTORE_records_store (namestore,
537 zone_key,
538 rd->register_name,
539 1,
540 &gd,
541 &register_done_cb,
542 rd);
543
544 GNUNET_free (gdraw);
545}
546
547
548/**
549 * An error occurred while iterating the namestore.
550 *
551 * @param cls the connection
552 */
553static void
554iterate_error_cb (void *cls)
555{
556 struct RequestData *rd = cls;
557
558 MHD_resume_connection (rd->c);
559 rd->iterating = NULL;
560 rd->body = make_json ("error", "true",
561 "message", _ ("unable to scan namestore"),
562 NULL);
563 rd->body_length = strlen (rd->body);
564 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
565 run_httpd_now ();
566}
567
568
569/**
570 * A block was received from the namestore.
571 *
572 * @param cls the connection
573 * @param key the zone key
574 * @param label the records' label
575 * @param count number of records found
576 * @param d the found records
577 */
578static void
579iterate_do_cb (void *cls,
580 const struct GNUNET_CRYPTO_PrivateKey *key,
581 const char *label,
582 unsigned int count,
583 const struct GNUNET_GNSRECORD_Data *d)
584{
585 (void) key;
586 (void) label;
587 (void) d;
588
589 struct RequestData *rd = cls;
590
591 if (0 == strcmp (label, rd->register_name))
592 {
593 GNUNET_break (0 != count);
594 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
595 _ ("Requested name `%s' exists with `%u' records\n"),
596 rd->register_name,
597 count);
598
599 MHD_resume_connection (rd->c);
600 rd->body = make_json ("error", "true",
601 "message", _ ("name exists\n"),
602 NULL);
603 rd->body_length = strlen (rd->body);
604 rd->code = MHD_HTTP_FORBIDDEN;
605 GNUNET_NAMESTORE_zone_iteration_stop (rd->iterating);
606 run_httpd_now ();
607 return;
608 }
609
610 GNUNET_NAMESTORE_zone_iterator_next (rd->iterating, 1);
611}
612
613
614/**
615 * All entries in the namestore have been iterated over.
616 *
617 * @param cls the connection
618 */
619static void
620iterate_done_cb (void *cls)
621{
622 struct RequestData *rd = cls;
623
624 rd->iterating = NULL;
625
626 /* See if the key was not registered already */
627 rd->searching = GNUNET_NAMESTORE_zone_to_name (namestore,
628 zone_key,
629 &(rd->key),
630 &register_error_cb,
631 rd,
632 &register_do_cb,
633 rd);
634}
635
636
637/**
638 * Generate a response containing JSON and send it to the client.
639 *
640 * @param c the connection
641 * @param body the response body
642 * @param length the body length in bytes
643 * @param code the response code
644 * @return MHD_NO on error
645 */
646static MHD_RESULT
647serve_json (struct MHD_Connection *c,
648 char *body,
649 size_t length,
650 int code)
651{
652 struct MHD_Response *response =
653 MHD_create_response_from_buffer (length,
654 body,
655 MHD_RESPMEM_PERSISTENT);
656 MHD_RESULT r = MHD_queue_response (c, code, response);
657 MHD_destroy_response (response);
658 return r;
659}
660
661
662/**
663 * Send a response back to a connected client.
664 *
665 * @param cls unused
666 * @param connection the connection with the client
667 * @param url the requested address
668 * @param method the HTTP method used
669 * @param version the protocol version (including the "HTTP/" part)
670 * @param upload_data data sent with a POST request
671 * @param upload_data_size length in bytes of the POST data
672 * @param ptr used to pass data between request handling phases
673 * @return MHD_NO on error
674 */
675static MHD_RESULT
676create_response (void *cls,
677 struct MHD_Connection *connection,
678 const char *url,
679 const char *method,
680 const char *version,
681 const char *upload_data,
682 size_t *upload_data_size,
683 void **ptr)
684{
685 (void) cls;
686 (void) version;
687
688 struct RequestData *rd = *ptr;
689
690 if (0 == strcmp (method, MHD_HTTP_METHOD_GET))
691 {
692 /* Handle a previously suspended request */
693 if (NULL != rd)
694 {
695 return serve_json (rd->c, rd->body, rd->body_length, rd->code);
696 }
697
698 if (0 == strcmp ("/", url))
699 {
700 return MHD_queue_response (connection,
701 MHD_HTTP_OK,
702 main_page->response);
703 }
704
705 if (0 == strcmp ("/search", url))
706 {
707 const char *name = MHD_lookup_connection_value (connection,
708 MHD_GET_ARGUMENT_KIND,
709 "name");
710 if (NULL == name)
711 {
712 return MHD_queue_response (connection,
713 MHD_HTTP_BAD_REQUEST,
714 forbidden_page->response);
715 }
716
717 MHD_suspend_connection (connection);
718 rd = GNUNET_new (struct RequestData);
719 rd->c = connection;
720 rd->searching = GNUNET_NAMESTORE_records_lookup (namestore,
721 zone_key,
722 name,
723 &search_error_cb,
724 rd,
725 &search_done_cb,
726 rd);
727 *ptr = rd;
728 return MHD_YES;
729 }
730
731 return MHD_queue_response (connection,
732 MHD_HTTP_NOT_FOUND,
733 notfound_page->response);
734 }
735
736 if (0 == strcmp (method, MHD_HTTP_METHOD_HEAD))
737 {
738 /* We take a shortcut here by always serving the main page: starting a
739 namestore lookup, allocating the necessary resources, waiting for the
740 lookup to complete and then discard everything just because it was a HEAD
741 and thus only the headers are significative, is an unnecessary waste of
742 resources. The handling of this method could be smarter, for example by
743 sending a proper content type header based on the endpoint, but this is
744 not a service in which HEAD requests are significant, so there's no need
745 to spend too much time here. */
746 return MHD_queue_response (connection,
747 MHD_HTTP_OK,
748 main_page->response);
749 }
750
751 if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
752 {
753 if (0 == strcmp ("/register", url))
754 {
755 /* Handle a previously suspended request */
756 if ((NULL != rd) && (NULL != rd->body))
757 {
758 return serve_json (rd->c, rd->body, rd->body_length, rd->code);
759 }
760
761 if (NULL == rd)
762 {
763 rd = GNUNET_new (struct RequestData);
764 rd->c = connection;
765 rd->body = NULL;
766 rd->ptr = NULL;
767 *ptr = rd;
768 }
769
770 json_t *json = NULL;
771 enum GNUNET_JSON_PostResult result =
772 GNUNET_JSON_post_parser (32 * 1024,
773 connection,
774 &(rd->ptr),
775 upload_data,
776 upload_data_size,
777 &json);
778
779 switch (result)
780 {
781 case GNUNET_JSON_PR_CONTINUE:
782 /* Keep processing POST data */
783 return MHD_YES;
784 case GNUNET_JSON_PR_OUT_OF_MEMORY:
785 case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
786 rd->body = make_json ("error", "true",
787 "message", _ ("unable to process submitted data"),
788 NULL);
789 rd->body_length = strlen (rd->body);
790#ifdef MHD_HTTP_CONTENT_TOO_LARGE
791 rd->code = MHD_HTTP_CONTENT_TOO_LARGE;
792#else
793 rd->code = MHD_HTTP_PAYLOAD_TOO_LARGE;
794#endif
795 return MHD_YES;
796 case GNUNET_JSON_PR_JSON_INVALID:
797 rd->body = make_json ("error", "true",
798 "message", _ ("the submitted data is invalid"),
799 NULL);
800 rd->body_length = strlen (rd->body);
801 rd->code = MHD_HTTP_BAD_REQUEST;
802 return MHD_YES;
803 default:
804 break;
805 }
806
807 /* POST data has been read in its entirety */
808
809 const char *name = json_string_value (json_object_get (json, "name"));
810 const char *key = json_string_value (json_object_get (json, "key"));
811 if ((NULL == name) || (NULL == key) || (0 == strlen (name)) || (0 ==
812 strlen (
813 key)))
814 {
815 json_decref (json);
816 rd->body = make_json ("error", "true",
817 "message", _ ("invalid parameters"),
818 NULL);
819 rd->body_length = strlen (rd->body);
820 rd->code = MHD_HTTP_BAD_REQUEST;
821 return MHD_YES;
822 }
823
824 rd->register_name = strdup (name);
825 rd->register_key = strdup (key);
826
827 json_decref (json);
828 GNUNET_JSON_post_parser_cleanup (rd->ptr);
829
830 if ((NULL != strchr (rd->register_name, '.')) ||
831 (NULL != strchr (rd->register_name, '+')))
832 {
833 rd->body = make_json ("error", "true",
834 "message", _ ("invalid name"),
835 NULL);
836 rd->body_length = strlen (rd->body);
837 rd->code = MHD_HTTP_BAD_REQUEST;
838 return MHD_YES;
839 }
840
841 if (GNUNET_OK != GNUNET_CRYPTO_public_key_from_string (rd->register_key,
842 &(rd->key)))
843 {
844 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
845 _ ("Unable to parse key %s\n"),
846 rd->register_key);
847
848 rd->body = make_json ("error", "true",
849 "message", _ ("unable to parse key"),
850 NULL);
851 rd->body_length = strlen (rd->body);
852 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
853 return MHD_YES;
854 }
855
856 MHD_suspend_connection (connection);
857 /* See if the requested name is free */
858 rd->iterating =
859 GNUNET_NAMESTORE_zone_iteration_start (namestore,
860 zone_key,
861 &iterate_error_cb,
862 rd,
863 &iterate_do_cb,
864 rd,
865 &iterate_done_cb,
866 rd);
867 return MHD_YES;
868 }
869
870 return MHD_queue_response (connection,
871 MHD_HTTP_FORBIDDEN,
872 forbidden_page->response);
873 }
874
875 return MHD_queue_response (connection,
876 MHD_HTTP_NOT_IMPLEMENTED,
877 forbidden_page->response);
878}
879
880
881/**
882 * Called when a request is completed.
883 *
884 * @param cls unused
885 * @param connection the connection
886 * @param ptr connection-specific data
887 * @param status status code
888 */
889static void
890completed_cb (void *cls,
891 struct MHD_Connection *connection,
892 void **ptr,
893 enum MHD_RequestTerminationCode status)
894{
895 (void) cls;
896 (void) connection;
897 (void) status;
898
899 struct RequestData *rd = *ptr;
900
901 if (NULL == rd)
902 {
903 return;
904 }
905
906 if (NULL == rd->body)
907 {
908 GNUNET_free (rd->body);
909 }
910
911 if (NULL != rd->searching)
912 {
913 GNUNET_NAMESTORE_cancel (rd->searching);
914 }
915
916 if (NULL != rd->register_name)
917 {
918 GNUNET_free (rd->register_name);
919 }
920
921 if (NULL != rd->register_key)
922 {
923 GNUNET_free (rd->register_key);
924 }
925
926 if (NULL != rd->iterating)
927 {
928 GNUNET_NAMESTORE_zone_iteration_stop (rd->iterating);
929 }
930
931 GNUNET_free (rd);
932}
933
934
935/**
936 * Called for each ego provided by the identity service.
937 *
938 * @param cls closure
939 * @param ego the ego
940 * @param ctx application-provided data for the ego
941 * @param name the ego name
942 */
943static void
944identity_cb (void *cls,
945 struct GNUNET_IDENTITY_Ego *ego,
946 void **ctx,
947 const char *name)
948{
949 (void) cls;
950 (void) ctx;
951
952 if ((NULL == name) || (0 != strcmp (name, zone)))
953 {
954 return;
955 }
956
957 if (NULL == ego)
958 {
959 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
960 _ ("No ego configured for `fcfsd` subsystem\n"));
961 GNUNET_SCHEDULER_shutdown ();
962 return;
963 }
964
965 zone_key = GNUNET_IDENTITY_ego_get_private_key (ego);
966
967 int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME;
968 do
969 {
970 httpd = MHD_start_daemon (flags,
971 (uint16_t) port,
972 NULL, NULL,
973 &create_response, NULL,
974 MHD_OPTION_CONNECTION_LIMIT, 128,
975 MHD_OPTION_PER_IP_CONNECTION_LIMIT, 1,
976 MHD_OPTION_CONNECTION_TIMEOUT, 4 * 1024,
977 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
978 MHD_OPTION_END);
979 flags = MHD_USE_DEBUG;
980 } while (NULL == httpd && flags != MHD_USE_DEBUG);
981
982 if (NULL == httpd)
983 {
984 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
985 _ ("Failed to start HTTP server\n"));
986 GNUNET_SCHEDULER_shutdown ();
987 return;
988 }
989
990 run_httpd ();
991}
992
993
994/**
995 * Open a file on disk and generate a response object for it.
996 *
997 * @param name name of the file to open
998 * @param basedir directory where the file is located
999 * @return NULL on error
1000 */
1001static struct StaticPage *
1002open_static_page (const char *name, const char *basedir)
1003{
1004 char *fullname = NULL;
1005 GNUNET_asprintf (&fullname, "%s/fcfsd-%s", basedir, name);
1006
1007 struct GNUNET_DISK_FileHandle *f =
1008 GNUNET_DISK_file_open (fullname,
1009 GNUNET_DISK_OPEN_READ,
1010 GNUNET_DISK_PERM_NONE);
1011 GNUNET_free (fullname);
1012
1013 if (NULL == f)
1014 {
1015 return NULL;
1016 }
1017
1018 off_t size = 0;
1019 if (GNUNET_SYSERR == GNUNET_DISK_file_handle_size (f, &size))
1020 {
1021 GNUNET_DISK_file_close (f);
1022 return NULL;
1023 }
1024
1025 struct MHD_Response *response =
1026 MHD_create_response_from_fd64 (size,
1027 f->fd);
1028
1029 if (NULL == response)
1030 {
1031 GNUNET_DISK_file_close (f);
1032 return NULL;
1033 }
1034
1035 struct StaticPage *page = GNUNET_new (struct StaticPage);
1036 page->handle = f;
1037 page->size = (uint64_t) size;
1038 page->response = response;
1039 return page;
1040}
1041
1042
1043/**
1044 * Called after the service is up.
1045 *
1046 * @param cls closure
1047 * @param args remaining command line arguments
1048 * @param cfgfile name of the configuration file
1049 * @param cfg the service configuration
1050 */
1051static void
1052run_service (void *cls,
1053 char *const *args,
1054 const char *cfgfile,
1055 const struct GNUNET_CONFIGURATION_Handle *cfg)
1056{
1057 (void) cls;
1058 (void) args;
1059 (void) cfgfile;
1060
1061 GNUNET_log_setup ("fcfsd", "WARNING", NULL);
1062
1063 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
1064 "fcfsd",
1065 "RELATIVE_RECORD_EXPIRATION",
1066 &record_exp))
1067 {
1068 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1069 _("No expiration specified for records.\n"));
1070 GNUNET_SCHEDULER_shutdown ();
1071 return;
1072 }
1073
1074 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1075 "fcfsd",
1076 "HTTPPORT",
1077 &port))
1078 {
1079 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1080 _ ("No port specified, using default value\n"));
1081 }
1082
1083 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1084
1085 namestore = GNUNET_NAMESTORE_connect (cfg);
1086 if (NULL == namestore)
1087 {
1088 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1089 _ ("Failed to connect to namestore\n"));
1090 GNUNET_SCHEDULER_shutdown ();
1091 return;
1092 }
1093
1094 identity = GNUNET_IDENTITY_connect (cfg, &identity_cb, NULL);
1095 if (NULL == identity)
1096 {
1097 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1098 _ ("Failed to connect to identity\n"));
1099 GNUNET_SCHEDULER_shutdown ();
1100 return;
1101 }
1102
1103 char *basedir = NULL;
1104 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
1105 "fcfsd",
1106 "HTMLDIR",
1107 &basedir))
1108 {
1109 basedir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1110 }
1111
1112 main_page = open_static_page ("index.html", basedir);
1113 notfound_page = open_static_page ("notfound.html", basedir);
1114 forbidden_page = open_static_page ("forbidden.html", basedir);
1115
1116 GNUNET_free (basedir);
1117
1118 if ((NULL == main_page) || (NULL == notfound_page) || (NULL ==
1119 forbidden_page) )
1120 {
1121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1122 _ ("Unable to set up the daemon\n"));
1123 GNUNET_SCHEDULER_shutdown ();
1124 return;
1125 }
1126}
1127
1128
1129/**
1130 * The main function of the fcfs daemon.
1131 *
1132 * @param argc number of arguments from the command line
1133 * @param argv the command line arguments
1134 * @return 0 successful exit, a different value otherwise
1135 */
1136int
1137main (int argc, char *const *argv)
1138{
1139 struct GNUNET_GETOPT_CommandLineOption options[] = {
1140 GNUNET_GETOPT_option_mandatory
1141 (GNUNET_GETOPT_option_string ('z',
1142 "zone",
1143 "EGO",
1144 gettext_noop (
1145 "name of the zone managed by FCFSD"),
1146 &zone)),
1147 GNUNET_GETOPT_OPTION_END
1148 };
1149
1150 return ((GNUNET_OK == GNUNET_PROGRAM_run (argc,
1151 argv,
1152 "gnunet-namestore-fcfsd",
1153 _ (
1154 "GNU Name System First-Come-First-Served name registration service"),
1155 options,
1156 &run_service,
1157 NULL)) ?
1158 0 :
1159 1);
1160}
diff --git a/src/namestore/gnunet-namestore-zonefile.c b/src/namestore/gnunet-namestore-zonefile.c
deleted file mode 100644
index dfd438e94..000000000
--- a/src/namestore/gnunet-namestore-zonefile.c
+++ /dev/null
@@ -1,763 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 2019, 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 gnunet-namestore-dbtool.c
22 * @brief command line tool to manipulate the database backends for the namestore
23 * @author Martin Schanzenbach
24 *
25 */
26#include "platform.h"
27#include <gnunet_util_lib.h>
28#include <gnunet_namestore_plugin.h>
29
30#define MAX_RECORDS_PER_NAME 50
31
32/**
33 * Maximum length of a zonefile line
34 */
35#define MAX_ZONEFILE_LINE_LEN 4096
36
37/**
38 * FIXME: Soft limit this?
39 */
40#define MAX_ZONEFILE_RECORD_DATA_LEN 2048
41
42/**
43 * The record data under a single label. Reused.
44 * Hard limit.
45 */
46static struct GNUNET_GNSRECORD_Data rd[MAX_RECORDS_PER_NAME];
47
48/**
49 * Current record $TTL to use
50 */
51static struct GNUNET_TIME_Relative ttl;
52
53/**
54 * Current origin
55 */
56static char origin[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
57
58/**
59 * Number of records for currently parsed set
60 */
61static unsigned int rd_count = 0;
62
63/**
64 * Return code
65 */
66static int ret = 0;
67
68/**
69 * Name of the ego
70 */
71static char *ego_name = NULL;
72
73/**
74 * Currently read line or NULL on EOF
75 */
76static char *res;
77
78/**
79 * Statistics, how many published record sets
80 */
81static unsigned int published_sets = 0;
82
83/**
84 * Statistics, how many records published in aggregate
85 */
86static unsigned int published_records = 0;
87
88
89/**
90 * Handle to identity lookup.
91 */
92static struct GNUNET_IDENTITY_EgoLookup *el;
93
94/**
95 * Private key for the our zone.
96 */
97static struct GNUNET_CRYPTO_PrivateKey zone_pkey;
98
99/**
100 * Queue entry for the 'add' operation.
101 */
102static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
103
104/**
105 * Handle to the namestore.
106 */
107static struct GNUNET_NAMESTORE_Handle *ns;
108
109/**
110 * Origin create operations
111 */
112static struct GNUNET_IDENTITY_Operation *id_op;
113
114/**
115 * Handle to IDENTITY
116 */
117static struct GNUNET_IDENTITY_Handle *id;
118
119/**
120 * Current configurataion
121 */
122static const struct GNUNET_CONFIGURATION_Handle *cfg;
123
124/**
125 * Scheduled parse task
126 */
127static struct GNUNET_SCHEDULER_Task *parse_task;
128
129/**
130 * The current state of the parser
131 */
132static int state;
133
134enum ZonefileImportState
135{
136
137 /* Uninitialized */
138 ZS_READY,
139
140 /* The initial state */
141 ZS_ORIGIN_SET,
142
143 /* The $ORIGIN has changed */
144 ZS_ORIGIN_CHANGED,
145
146 /* The record name/label has changed */
147 ZS_NAME_CHANGED
148
149};
150
151
152
153/**
154 * Task run on shutdown. Cleans up everything.
155 *
156 * @param cls unused
157 */
158static void
159do_shutdown (void *cls)
160{
161 (void) cls;
162 if (NULL != ego_name)
163 GNUNET_free (ego_name);
164 if (NULL != el)
165 {
166 GNUNET_IDENTITY_ego_lookup_cancel (el);
167 el = NULL;
168 }
169 if (NULL != ns_qe)
170 GNUNET_NAMESTORE_cancel (ns_qe);
171 if (NULL != id_op)
172 GNUNET_IDENTITY_cancel (id_op);
173 if (NULL != ns)
174 GNUNET_NAMESTORE_disconnect (ns);
175 if (NULL != id)
176 GNUNET_IDENTITY_disconnect (id);
177 for (int i = 0; i < rd_count; i++)
178 {
179 void *rd_ptr = (void*) rd[i].data;
180 GNUNET_free (rd_ptr);
181 }
182 if (NULL != parse_task)
183 GNUNET_SCHEDULER_cancel (parse_task);
184}
185
186static void
187tx_end (void *cls, enum GNUNET_ErrorCode ec)
188{
189 ns_qe = NULL;
190 if (GNUNET_EC_NONE != ec)
191 {
192 fprintf (stderr,
193 _ ("Ego `%s' not known to identity service\n"),
194 ego_name);
195 GNUNET_SCHEDULER_shutdown ();
196 ret = -1;
197 }
198 GNUNET_SCHEDULER_shutdown ();
199}
200
201static void
202parse (void *cls);
203
204static char*
205trim (char *line)
206{
207 char *ltrimmed = line;
208 int ltrimmed_len;
209 int quoted = 0;
210
211 // Trim all whitespace to the left
212 while (*ltrimmed == ' ')
213 ltrimmed++;
214 ltrimmed_len = strlen (ltrimmed);
215 // Find the first occurence of an unqoted ';', which is our comment
216 for (int i = 0; i < ltrimmed_len; i++)
217 {
218 if (ltrimmed[i] == '"')
219 quoted = ! quoted;
220 if ((ltrimmed[i] != ';') || quoted)
221 continue;
222 ltrimmed[i] = '\0';
223 }
224 ltrimmed_len = strlen (ltrimmed);
225 // Remove trailing whitespace
226 for (int i = ltrimmed_len; i > 0; i--)
227 {
228 if (ltrimmed[i - 1] != ' ')
229 break;
230 ltrimmed[i - 1] = '\0';
231 }
232 ltrimmed_len = strlen (ltrimmed);
233 if (ltrimmed[ltrimmed_len - 1] == '\n')
234 ltrimmed[ltrimmed_len - 1] = ' ';
235 return ltrimmed;
236}
237
238static char*
239next_token (char *token)
240{
241 char *next = token;
242 while (*next == ' ')
243 next++;
244 return next;
245}
246
247static int
248parse_ttl (char *token, struct GNUNET_TIME_Relative *ttl)
249{
250 char *next;
251 unsigned int ttl_tmp;
252
253 next = strchr (token, ';');
254 if (NULL != next)
255 next[0] = '\0';
256 next = strchr (token, ' ');
257 if (NULL != next)
258 next[0] = '\0';
259 if (1 != sscanf (token, "%u", &ttl_tmp))
260 {
261 fprintf (stderr, "Unable to parse TTL `%s'\n", token);
262 return GNUNET_SYSERR;
263 }
264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TTL is: %u\n", ttl_tmp);
265 ttl->rel_value_us = ttl_tmp * 1000 * 1000;
266 return GNUNET_OK;
267}
268
269static int
270parse_origin (char *token, char *origin)
271{
272 char *next;
273 next = strchr (token, ';');
274 if (NULL != next)
275 next[0] = '\0';
276 next = strchr (token, ' ');
277 if (NULL != next)
278 next[0] = '\0';
279 strcpy (origin, token);
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Origin is: %s\n", origin);
281 return GNUNET_OK;
282}
283
284static void
285origin_create_cb (void *cls, const struct GNUNET_CRYPTO_PrivateKey *pk,
286 enum GNUNET_ErrorCode ec)
287{
288 id_op = NULL;
289 if (GNUNET_EC_NONE != ec)
290 {
291 fprintf (stderr, "Error: %s\n", GNUNET_ErrorCode_get_hint (ec));
292 ret = 1;
293 GNUNET_SCHEDULER_shutdown ();
294 return;
295 }
296 state = ZS_ORIGIN_SET;
297 zone_pkey = *pk;
298 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
299}
300
301static void
302origin_lookup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
303{
304
305 el = NULL;
306
307 if (NULL == ego)
308 {
309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310 "$ORIGIN %s does not exist, creating...\n", ego_name);
311 id_op = GNUNET_IDENTITY_create (id, ego_name, NULL,
312 GNUNET_PUBLIC_KEY_TYPE_ECDSA, // FIXME make configurable
313 origin_create_cb,
314 NULL);
315 return;
316 }
317 state = ZS_ORIGIN_SET;
318 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
319 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
320}
321
322static void
323add_continuation (void *cls, enum GNUNET_ErrorCode ec)
324{
325 ns_qe = NULL;
326 if (GNUNET_EC_NONE != ec)
327 {
328 fprintf (stderr,
329 _ ("Failed to store records...\n"));
330 GNUNET_SCHEDULER_shutdown ();
331 ret = -1;
332 }
333 if (ZS_ORIGIN_CHANGED == state)
334 {
335 if (NULL != ego_name)
336 GNUNET_free (ego_name);
337 ego_name = GNUNET_strdup (origin);
338 if (ego_name[strlen (ego_name) - 1] == '.')
339 ego_name[strlen (ego_name) - 1] = '\0';
340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341 "Changing origin to %s\n", ego_name);
342 el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name,
343 &origin_lookup_cb, NULL);
344 return;
345 }
346 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
347}
348
349
350
351/**
352 * Main function that will be run.
353 *
354 * TODO:
355 * - We must assume that names are not repeated later in the zonefile because
356 * our _store APIs are replacing. No sure if that is common in zonefiles.
357 * - We must only actually store a record set when the name to store changes or
358 * the end of the file is reached.
359 * that way we can group them and add (see above).
360 * - We need to hope our string formats are compatible, but seems ok.
361 *
362 * @param cls closure
363 * @param args remaining command-line arguments
364 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
365 * @param cfg configuration
366 */
367static void
368parse (void *cls)
369{
370 char buf[MAX_ZONEFILE_LINE_LEN];
371 char payload[MAX_ZONEFILE_RECORD_DATA_LEN];
372 char *next;
373 char *token;
374 char *payload_pos;
375 static char lastname[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
376 char newname[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
377 void *data;
378 size_t data_size;
379 int ttl_line = 0;
380 int type;
381 int bracket_unclosed = 0;
382 int quoted = 0;
383
384 parse_task = NULL;
385 /* use filename provided as 1st argument (stdin by default) */
386 int ln = 0;
387 while ((res = fgets (buf, sizeof(buf), stdin))) /* read each line of input */
388 {
389 ln++;
390 ttl_line = 0;
391 token = trim (buf);
392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393 "Trimmed line (bracket %s): `%s'\n",
394 (bracket_unclosed > 0) ? "unclosed" : "closed",
395 token);
396 if ((0 == strlen (token)) ||
397 ((1 == strlen (token)) && (' ' == *token)))
398 continue; // I guess we can safely ignore blank lines
399 if (bracket_unclosed == 0)
400 {
401 /* Payload is already parsed */
402 payload_pos = payload;
403 /* Find space */
404 next = strchr (token, ' ');
405 if (NULL == next)
406 {
407 fprintf (stderr, "Error at line %u: %s\n", ln, token);
408 ret = 1;
409 GNUNET_SCHEDULER_shutdown ();
410 return;
411 }
412 next[0] = '\0';
413 next++;
414 if (0 == (strcmp (token, "$ORIGIN")))
415 {
416 state = ZS_ORIGIN_CHANGED;
417 token = next_token (next);
418 }
419 else if (0 == (strcmp (token, "$TTL")))
420 {
421 ttl_line = 1;
422 token = next_token (next);
423 }
424 else
425 {
426 if (0 == strcmp (token, "IN")) // Inherit name from before
427 {
428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429 "Old name: %s\n", lastname);
430 strcpy (newname, lastname);
431 token[strlen (token)] = ' ';
432 }
433 else if (token[strlen (token) - 1] != '.') // no fqdn
434 {
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: %s\n", token);
436 if (GNUNET_DNSPARSER_MAX_LABEL_LENGTH < strlen (token))
437 {
438 fprintf (stderr,
439 _ ("Name `%s' is too long\n"),
440 token);
441 ret = 1;
442 GNUNET_SCHEDULER_shutdown ();
443 return;
444 }
445 strcpy (newname, token);
446 token = next_token (next);
447 }
448 else if (0 == strcmp (token, origin))
449 {
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: @\n");
451 strcpy (newname, "@");
452 token = next_token (next);
453 }
454 else
455 {
456 if (strlen (token) < strlen (origin))
457 {
458 fprintf (stderr, "Wrong origin: %s (expected %s)\n", token, origin);
459 break; // FIXME error?
460 }
461 if (0 != strcmp (token + (strlen (token) - strlen (origin)), origin))
462 {
463 fprintf (stderr, "Wrong origin: %s (expected %s)\n", token, origin);
464 break;
465 }
466 token[strlen (token) - strlen (origin) - 1] = '\0';
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: %s\n", token);
468 if (GNUNET_DNSPARSER_MAX_LABEL_LENGTH < strlen (token))
469 {
470 fprintf (stderr,
471 _ ("Name `%s' is too long\n"),
472 token);
473 ret = 1;
474 GNUNET_SCHEDULER_shutdown ();
475 return;
476 }
477 strcpy (newname, token);
478 token = next_token (next);
479 }
480 if (0 != strcmp (newname, lastname) &&
481 (0 < rd_count))
482 {
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484 "Name changed %s->%s, storing record set of %u elements\n",
485 lastname, newname,
486 rd_count);
487 state = ZS_NAME_CHANGED;
488 }
489 else {
490 strcpy (lastname, newname);
491 }
492 }
493
494 if (ttl_line)
495 {
496 if (GNUNET_SYSERR == parse_ttl (token, &ttl))
497 {
498 fprintf (stderr, _ ("Failed to parse $TTL\n"));
499 ret = 1;
500 GNUNET_SCHEDULER_shutdown ();
501 return;
502 }
503 continue;
504 }
505 if (ZS_ORIGIN_CHANGED == state)
506 {
507 if (GNUNET_SYSERR == parse_origin (token, origin))
508 {
509 fprintf (stderr, _ ("Failed to parse $ORIGIN from %s\n"), token);
510 ret = 1;
511 GNUNET_SCHEDULER_shutdown ();
512 return;
513 }
514 break;
515 }
516 if (ZS_READY == state)
517 {
518 fprintf (stderr,
519 _ (
520 "You must provide $ORIGIN in your zonefile or via arguments (--zone)!\n"));
521 ret = 1;
522 GNUNET_SCHEDULER_shutdown ();
523 return;
524 }
525 // This is a record, let's go
526 if (MAX_RECORDS_PER_NAME == rd_count)
527 {
528 fprintf (stderr,
529 _ ("Only %u records per unique name supported.\n"),
530 MAX_RECORDS_PER_NAME);
531 ret = 1;
532 GNUNET_SCHEDULER_shutdown ();
533 return;
534 }
535 rd[rd_count].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
536 rd[rd_count].expiration_time = ttl.rel_value_us;
537 next = strchr (token, ' ');
538 if (NULL == next)
539 {
540 fprintf (stderr, "Error, last token: %s\n", token);
541 ret = 1;
542 GNUNET_SCHEDULER_shutdown ();
543 break;
544 }
545 next[0] = '\0';
546 next++;
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "class is: %s\n", token);
548 while (*next == ' ')
549 next++;
550 token = next;
551 next = strchr (token, ' ');
552 if (NULL == next)
553 {
554 fprintf (stderr, "Error\n");
555 break;
556 }
557 next[0] = '\0';
558 next++;
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "type is: %s\n", token);
560 type = GNUNET_GNSRECORD_typename_to_number (token);
561 rd[rd_count].record_type = type;
562 while (*next == ' ')
563 next++;
564 token = next;
565 }
566 for (int i = 0; i < strlen (token); i++)
567 {
568 if (token[i] == '"')
569 quoted = ! quoted;
570 if ((token[i] == '(') && ! quoted)
571 bracket_unclosed++;
572 if ((token[i] == ')') && ! quoted)
573 bracket_unclosed--;
574 }
575 memcpy (payload_pos, token, strlen (token));
576 payload_pos += strlen (token);
577 if (bracket_unclosed > 0)
578 {
579 *payload_pos = ' ';
580 payload_pos++;
581 continue;
582 }
583 *payload_pos = '\0';
584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "data is: %s\n\n", payload);
585 if (GNUNET_OK !=
586 GNUNET_GNSRECORD_string_to_value (type, payload,
587 &data,
588 &data_size))
589 {
590 fprintf (stderr,
591 _ ("Data `%s' invalid\n"),
592 payload);
593 ret = 1;
594 GNUNET_SCHEDULER_shutdown ();
595 return;
596 }
597 rd[rd_count].data = data;
598 rd[rd_count].data_size = data_size;
599 if (ZS_NAME_CHANGED == state)
600 break;
601 rd_count++;
602 }
603 if (rd_count > 0)
604 {
605 ns_qe = GNUNET_NAMESTORE_records_store (ns,
606 &zone_pkey,
607 lastname,
608 rd_count,
609 rd,
610 &add_continuation,
611 NULL);
612 published_sets++;
613 published_records += rd_count;
614 for (int i = 0; i < rd_count; i++)
615 {
616 data = (void*) rd[i].data;
617 GNUNET_free (data);
618 }
619 if (ZS_NAME_CHANGED == state)
620 {
621 rd[0] = rd[rd_count]; // recover last rd parsed.
622 rd_count = 1;
623 strcpy (lastname, newname);
624 state = ZS_ORIGIN_SET;
625 }
626 else
627 rd_count = 0;
628 return;
629 }
630 if (ZS_ORIGIN_CHANGED == state)
631 {
632 if (NULL != ego_name)
633 GNUNET_free (ego_name);
634 ego_name = GNUNET_strdup (origin);
635 if (ego_name[strlen (ego_name) - 1] == '.')
636 ego_name[strlen (ego_name) - 1] = '\0';
637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
638 "Changing origin to %s\n", ego_name);
639 el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name,
640 &origin_lookup_cb, NULL);
641 return;
642 }
643 printf ("Published %u records sets with total %u records\n",
644 published_sets, published_records);
645 ns_qe = GNUNET_NAMESTORE_transaction_commit (ns,
646 &tx_end,
647 NULL);
648}
649
650static void
651tx_start (void *cls, enum GNUNET_ErrorCode ec)
652{
653 ns_qe = NULL;
654 if (GNUNET_EC_NONE != ec)
655 {
656 fprintf (stderr,
657 _ ("Ego `%s' not known to identity service\n"),
658 ego_name);
659 GNUNET_SCHEDULER_shutdown ();
660 ret = -1;
661 return;
662 }
663 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
664}
665
666static void
667identity_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
668{
669
670 el = NULL;
671 if (NULL == ego)
672 {
673 if (NULL != ego_name)
674 {
675 fprintf (stderr,
676 _ ("Ego `%s' not known to identity service\n"),
677 ego_name);
678
679 }
680 GNUNET_SCHEDULER_shutdown ();
681 ret = -1;
682 return;
683 }
684 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
685 sprintf (origin, "%s.", ego_name);
686 state = ZS_ORIGIN_SET;
687 ns_qe = GNUNET_NAMESTORE_transaction_begin (ns,
688 &tx_start,
689 NULL);
690}
691
692
693static void
694run (void *cls,
695 char *const *args,
696 const char *cfgfile,
697 const struct GNUNET_CONFIGURATION_Handle *_cfg)
698{
699 cfg = _cfg;
700 ns = GNUNET_NAMESTORE_connect (cfg);
701 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, (void *) cfg);
702 if (NULL == ns)
703 {
704 fprintf (stderr,
705 _ ("Failed to connect to NAMESTORE\n"));
706 return;
707 }
708 id = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
709 if (NULL == id)
710 {
711 fprintf (stderr,
712 _ ("Failed to connect to IDENTITY\n"));
713 return;
714 }
715 if (NULL != ego_name)
716 el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name, &identity_cb, (void *) cfg);
717 else
718 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
719 state = ZS_READY;
720}
721
722
723/**
724 * The main function for gnunet-namestore-dbtool.
725 *
726 * @param argc number of arguments from the command line
727 * @param argv command line arguments
728 * @return 0 ok, 1 on error
729 */
730int
731main (int argc, char *const *argv)
732{
733 struct GNUNET_GETOPT_CommandLineOption options[] = {
734 GNUNET_GETOPT_option_string ('z',
735 "zone",
736 "EGO",
737 gettext_noop (
738 "name of the ego controlling the zone"),
739 &ego_name),
740 GNUNET_GETOPT_OPTION_END
741 };
742 int lret;
743
744 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
745 return 2;
746
747 GNUNET_log_setup ("gnunet-namestore-dbtool", "WARNING", NULL);
748 if (GNUNET_OK !=
749 (lret = GNUNET_PROGRAM_run (argc,
750 argv,
751 "gnunet-namestore-zonefile",
752 _ (
753 "GNUnet namestore database manipulation tool"),
754 options,
755 &run,
756 NULL)))
757 {
758 GNUNET_free_nz ((void *) argv);
759 return lret;
760 }
761 GNUNET_free_nz ((void *) argv);
762 return ret;
763}
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c
deleted file mode 100644
index baa036ac7..000000000
--- a/src/namestore/gnunet-namestore.c
+++ /dev/null
@@ -1,2120 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 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 gnunet-namestore.c
22 * @brief command line tool to manipulate the local zone
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * - test
27 */
28#include "platform.h"
29#include <gnunet_util_lib.h>
30#include <gnunet_identity_service.h>
31#include <gnunet_gnsrecord_lib.h>
32#include <gnunet_gns_service.h>
33#include <gnunet_namestore_service.h>
34#include <inttypes.h>
35
36/**
37 * The upper bound for the zone iteration interval
38 * (per record).
39 */
40#define WARN_RELATIVE_EXPIRATION_LIMIT GNUNET_TIME_relative_multiply ( \
41 GNUNET_TIME_UNIT_MINUTES, 15)
42
43/**
44 * Entry in record set for bulk processing.
45 */
46struct RecordSetEntry
47{
48 /**
49 * Kept in a linked list.
50 */
51 struct RecordSetEntry *next;
52
53 /**
54 * The record to add/remove.
55 */
56 struct GNUNET_GNSRECORD_Data record;
57};
58
59/**
60 * The record marked for deletion
61 */
62struct MarkedRecord
63{
64 /**
65 * DLL
66 */
67 struct MarkedRecord *next;
68
69 /**
70 * DLL
71 */
72 struct MarkedRecord *prev;
73
74 /**
75 * Ego Identifier
76 */
77 char *name;
78
79 /**
80 * The zone key
81 */
82 struct GNUNET_CRYPTO_PrivateKey key;
83};
84
85/**
86 * The default namestore ego
87 */
88struct EgoEntry
89{
90 /**
91 * DLL
92 */
93 struct EgoEntry *next;
94
95 /**
96 * DLL
97 */
98 struct EgoEntry *prev;
99
100 /**
101 * Ego Identifier
102 */
103 char *identifier;
104
105 /**
106 * The Ego
107 */
108 struct GNUNET_IDENTITY_Ego *ego;
109};
110
111/**
112 * Handle to the namestore.
113 */
114static struct GNUNET_NAMESTORE_Handle *ns;
115
116/**
117 * Private key for the our zone.
118 */
119static struct GNUNET_CRYPTO_PrivateKey zone_pkey;
120
121/**
122 * Identity service handle
123 */
124static struct GNUNET_IDENTITY_Handle *idh;
125
126/**
127 * Name of the ego controlling the zone.
128 */
129static char *ego_name;
130
131/**
132 * Queue entry for the 'add-uri' operation.
133 */
134static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
135
136/**
137 * Queue entry for the 'add' operation.
138 */
139static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
140
141/**
142 * Queue entry for the 'lookup' operation.
143 */
144static struct GNUNET_NAMESTORE_QueueEntry *get_qe;
145
146/**
147 * Queue entry for the 'reverse lookup' operation (in combination with a name).
148 */
149static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
150
151/**
152 * Marked record list
153 */
154static struct MarkedRecord *marked_head;
155
156/**
157 * Marked record list
158 */
159static struct MarkedRecord *marked_tail;
160
161/**
162 * Configuration handle
163 */
164const struct GNUNET_CONFIGURATION_Handle *cfg;
165
166/**
167 * Ego list
168 */
169static struct EgoEntry *ego_head;
170
171/**
172 * Ego list
173 */
174static struct EgoEntry *ego_tail;
175
176/**
177 * List iterator for the 'list' operation.
178 */
179static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
180
181/**
182 * Run in read from stdin mode.
183 */
184static int read_from_stdin;
185
186/**
187 * Desired action is to list records.
188 */
189static int list;
190
191/**
192 * Desired action is to add a record.
193 */
194static int add;
195
196/**
197 * Desired action is to remove a record.
198 */
199static int del;
200
201/**
202 * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
203 */
204static int is_public;
205
206/**
207 * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW)
208 */
209static int is_shadow;
210
211/**
212 * Filter private records
213 */
214static int omit_private;
215
216/**
217 * Output in recordline format
218 */
219static int output_recordline;
220
221
222/**
223 * Purge zone contents
224 */
225static int purge_zone;
226
227/**
228 * Do not filter maintenance records
229 */
230static int include_maintenance;
231
232/**
233 * Purge orphaned records
234 */
235static int purge_orphaned;
236
237/**
238 * List records and zone keys of orphaned records
239 */
240static int list_orphaned;
241
242/**
243 * Queue entry for the 'del' operation.
244 */
245static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
246
247/**
248 * Queue entry for the 'set/replace' operation.
249 */
250static struct GNUNET_NAMESTORE_QueueEntry *set_qe;
251
252/**
253 * Queue entry for begin/commit
254 */
255static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
256
257/**
258 * Name of the records to add/list/remove.
259 */
260static char *name;
261
262/**
263 * Value of the record to add/remove.
264 */
265static char *value;
266
267/**
268 * URI to import.
269 */
270static char *uri;
271
272/**
273 * Reverse lookup to perform.
274 */
275static char *reverse_pkey;
276
277/**
278 * Type of the record to add/remove, NULL to remove all.
279 */
280static char *typestring;
281
282/**
283 * Desired expiration time.
284 */
285static char *expirationstring;
286
287/**
288 * Desired nick name.
289 */
290static char *nickstring;
291
292/**
293 * Global return value
294 */
295static int ret;
296
297/**
298 * Type string converted to DNS type value.
299 */
300static uint32_t type;
301
302/**
303 * Value in binary format.
304 */
305static void *data;
306
307/**
308 * Number of bytes in #data.
309 */
310static size_t data_size;
311
312/**
313 * Expiration string converted to numeric value.
314 */
315static uint64_t etime;
316
317/**
318 * Is expiration time relative or absolute time?
319 */
320static int etime_is_rel = GNUNET_SYSERR;
321
322/**
323 * Monitor handle.
324 */
325static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
326
327/**
328 * Enables monitor mode.
329 */
330static int monitor;
331
332/**
333 * Entry in record set for processing records in bulk.
334 */
335static struct RecordSetEntry *recordset;
336
337/**
338 * Purge task
339 */
340static struct GNUNET_SCHEDULER_Task *purge_task;
341
342/**
343 * Parse expiration time.
344 *
345 * @param expirationstring text to parse
346 * @param[out] etime_is_rel set to #GNUNET_YES if time is relative
347 * @param[out] etime set to expiration time (abs or rel)
348 * @return #GNUNET_OK on success
349 */
350static int
351parse_expiration (const char *expirationstring,
352 int *etime_is_rel,
353 uint64_t *etime)
354{
355 struct GNUNET_TIME_Relative etime_rel;
356 struct GNUNET_TIME_Absolute etime_abs;
357
358 if (0 == strcmp (expirationstring, "never"))
359 {
360 *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
361 *etime_is_rel = GNUNET_NO;
362 return GNUNET_OK;
363 }
364 if (GNUNET_OK ==
365 GNUNET_STRINGS_fancy_time_to_relative (expirationstring, &etime_rel))
366 {
367 *etime_is_rel = GNUNET_YES;
368 *etime = etime_rel.rel_value_us;
369 if (GNUNET_TIME_relative_cmp (etime_rel, <, WARN_RELATIVE_EXPIRATION_LIMIT))
370 {
371 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
372 "Relative expiration times of less than %s are not recommended. To improve availability, consider increasing this value.\n",
373 GNUNET_STRINGS_relative_time_to_string (
374 WARN_RELATIVE_EXPIRATION_LIMIT, GNUNET_NO));
375 }
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "Storing record with relative expiration time of %s\n",
378 GNUNET_STRINGS_relative_time_to_string (etime_rel, GNUNET_NO));
379 return GNUNET_OK;
380 }
381 if (GNUNET_OK ==
382 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring, &etime_abs))
383 {
384 *etime_is_rel = GNUNET_NO;
385 *etime = etime_abs.abs_value_us;
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387 "Storing record with absolute expiration time of %s\n",
388 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
389 return GNUNET_OK;
390 }
391 return GNUNET_SYSERR;
392}
393
394
395static int
396parse_recordline (const char *line)
397{
398 struct RecordSetEntry **head = &recordset;
399 struct RecordSetEntry *r;
400 struct GNUNET_GNSRECORD_Data record;
401 char *cp;
402 char *tok;
403 char *saveptr;
404 void *raw_data;
405
406 cp = GNUNET_strdup (line);
407 tok = strtok_r (cp, " ", &saveptr);
408 if (NULL == tok)
409 {
410 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
411 _ ("Missing entries in record line `%s'.\n"),
412 line);
413 GNUNET_free (cp);
414 return GNUNET_SYSERR;
415 }
416 record.record_type = GNUNET_GNSRECORD_typename_to_number (tok);
417 if (UINT32_MAX == record.record_type)
418 {
419 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Unknown record type `%s'\n"), tok);
420 GNUNET_free (cp);
421 return GNUNET_SYSERR;
422 }
423 tok = strtok_r (NULL, " ", &saveptr);
424 if (NULL == tok)
425 {
426 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
427 _ ("Empty record line argument is not allowed.\n"));
428 GNUNET_free (cp);
429 return GNUNET_SYSERR;
430 }
431 if (1 != sscanf (tok, "%" SCNu64, &record.expiration_time))
432 {
433 fprintf (stderr,
434 _ ("Error parsing expiration time %s.\n"), tok);
435 GNUNET_free (cp);
436 return GNUNET_SYSERR;
437 }
438 tok = strtok_r (NULL, " ", &saveptr);
439 if (NULL == tok)
440 {
441 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
442 _ ("Empty record line argument is not allowed.\n"));
443 GNUNET_free (cp);
444 return GNUNET_SYSERR;
445 }
446 record.flags = GNUNET_GNSRECORD_RF_NONE;
447 if (NULL != strchr (tok, (unsigned char) 'r'))
448 record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
449 if (NULL == strchr (tok, (unsigned char) 'p')) /* p = public */
450 record.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
451 if (NULL != strchr (tok, (unsigned char) 'S'))
452 record.flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
453 if (NULL != strchr (tok, (unsigned char) 's'))
454 record.flags |= GNUNET_GNSRECORD_RF_SHADOW;
455 if (NULL != strchr (tok, (unsigned char) 'C'))
456 record.flags |= GNUNET_GNSRECORD_RF_CRITICAL;
457 tok += strlen (tok) + 1;
458 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (record.record_type,
459 tok,
460 &raw_data,
461 &record.data_size))
462 {
463 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
464 _ ("Invalid record data for type %s: `%s'.\n"),
465 GNUNET_GNSRECORD_number_to_typename (record.record_type),
466 tok);
467 GNUNET_free (cp);
468 return GNUNET_SYSERR;
469 }
470 GNUNET_free (cp);
471
472 r = GNUNET_malloc (sizeof(struct RecordSetEntry) + record.data_size);
473 r->next = *head;
474 record.data = &r[1];
475 memcpy (&r[1], raw_data, record.data_size);
476 GNUNET_free (raw_data);
477 r->record = record;
478 *head = r;
479 return GNUNET_OK;
480}
481
482static void
483reset_handles (void)
484{
485 struct MarkedRecord *mrec;
486 struct MarkedRecord *mrec_tmp;
487 struct RecordSetEntry *rs_entry;
488
489 rs_entry = recordset;
490 while (NULL != (rs_entry = recordset))
491 {
492 recordset = recordset->next;
493 GNUNET_free (rs_entry);
494 }
495 recordset = NULL;
496 if (NULL != ego_name)
497 {
498 GNUNET_free (ego_name);
499 ego_name = NULL;
500 }
501 if (NULL != name)
502 {
503 GNUNET_free (name);
504 name = NULL;
505 }
506 if (NULL != value)
507 {
508 GNUNET_free (value);
509 value = NULL;
510 }
511 if (NULL != uri)
512 {
513 GNUNET_free (uri);
514 uri = NULL;
515 }
516 if (NULL != expirationstring)
517 {
518 GNUNET_free (expirationstring);
519 expirationstring = NULL;
520 }
521 if (NULL != purge_task)
522 {
523 GNUNET_SCHEDULER_cancel (purge_task);
524 purge_task = NULL;
525 }
526 for (mrec = marked_head; NULL != mrec;)
527 {
528 mrec_tmp = mrec;
529 mrec = mrec->next;
530 GNUNET_free (mrec_tmp->name);
531 GNUNET_free (mrec_tmp);
532 }
533 if (NULL != list_it)
534 {
535 GNUNET_NAMESTORE_zone_iteration_stop (list_it);
536 list_it = NULL;
537 }
538 if (NULL != add_qe)
539 {
540 GNUNET_NAMESTORE_cancel (add_qe);
541 add_qe = NULL;
542 }
543 if (NULL != set_qe)
544 {
545 GNUNET_NAMESTORE_cancel (set_qe);
546 set_qe = NULL;
547 }
548 if (NULL != add_qe_uri)
549 {
550 GNUNET_NAMESTORE_cancel (add_qe_uri);
551 add_qe_uri = NULL;
552 }
553 if (NULL != get_qe)
554 {
555 GNUNET_NAMESTORE_cancel (get_qe);
556 get_qe = NULL;
557 }
558 if (NULL != del_qe)
559 {
560 GNUNET_NAMESTORE_cancel (del_qe);
561 del_qe = NULL;
562 }
563 if (NULL != reverse_qe)
564 {
565 GNUNET_NAMESTORE_cancel (reverse_qe);
566 reverse_qe = NULL;
567 }
568 memset (&zone_pkey, 0, sizeof(zone_pkey));
569 if (NULL != zm)
570 {
571 GNUNET_NAMESTORE_zone_monitor_stop (zm);
572 zm = NULL;
573 }
574 if (NULL != data)
575 {
576 GNUNET_free (data);
577 data = NULL;
578 }
579 if (NULL != typestring)
580 {
581 GNUNET_free (typestring);
582 typestring = NULL;
583 }
584 list = 0;
585 is_public = 0;
586 is_shadow = 0;
587 purge_zone = 0;
588}
589
590
591
592/**
593 * Task run on shutdown. Cleans up everything.
594 *
595 * @param cls unused
596 */
597static void
598do_shutdown (void *cls)
599{
600 struct EgoEntry *ego_entry;
601 struct EgoEntry *ego_tmp;
602 (void) cls;
603
604 reset_handles ();
605 if (NULL != ns_qe)
606 {
607 GNUNET_NAMESTORE_cancel (ns_qe);
608 ns_qe = NULL;
609 }
610 if (NULL != ns)
611 {
612 GNUNET_NAMESTORE_disconnect (ns);
613 ns = NULL;
614 }
615 if (NULL != idh)
616 {
617 GNUNET_IDENTITY_disconnect (idh);
618 idh = NULL;
619 }
620 for (ego_entry = ego_head; NULL != ego_entry;)
621 {
622 ego_tmp = ego_entry;
623 ego_entry = ego_entry->next;
624 GNUNET_free (ego_tmp->identifier);
625 GNUNET_free (ego_tmp);
626 }
627}
628
629static void
630commit_cb (void *cls, enum GNUNET_ErrorCode ec)
631{
632 ns_qe = NULL;
633 if (GNUNET_EC_NONE != ec)
634 {
635 fprintf (stderr, "Failed to commit to namestore: `%s'\n",
636 GNUNET_ErrorCode_get_hint (ec));
637 ret = 1;
638 }
639 GNUNET_SCHEDULER_shutdown ();
640}
641
642static void
643process_command_stdin ();
644
645
646static void
647finish_command (void)
648{
649 reset_handles ();
650 if (read_from_stdin)
651 {
652 process_command_stdin ();
653 return;
654 }
655 ns_qe = GNUNET_NAMESTORE_transaction_commit (ns, &commit_cb, NULL);
656}
657
658
659static void
660add_continuation (void *cls, enum GNUNET_ErrorCode ec)
661{
662 struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
663
664 *qe = NULL;
665 if (GNUNET_EC_NONE != ec)
666 {
667 fprintf (stderr,
668 _ ("Adding record failed: %s\n"),
669 GNUNET_ErrorCode_get_hint (ec));
670 if (GNUNET_EC_NAMESTORE_RECORD_EXISTS != ec)
671 ret = 1;
672 }
673 ret = 0;
674 finish_command ();
675}
676
677
678static void
679del_continuation (void *cls, enum GNUNET_ErrorCode ec)
680{
681 (void) cls;
682 del_qe = NULL;
683 if (GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND == ec)
684 {
685 fprintf (stderr,
686 _ ("Deleting record failed: %s\n"), GNUNET_ErrorCode_get_hint (
687 ec));
688 }
689 finish_command ();
690}
691
692static void
693purge_next_record (void *cls);
694
695static void
696marked_deleted (void *cls, enum GNUNET_ErrorCode ec)
697{
698 del_qe = NULL;
699 if (GNUNET_EC_NONE != ec)
700 {
701 fprintf (stderr,
702 _ ("Deleting record failed: %s\n"),
703 GNUNET_ErrorCode_get_hint (ec));
704 }
705 purge_task = GNUNET_SCHEDULER_add_now (&purge_next_record, NULL);
706}
707
708
709static void
710purge_next_record (void *cls)
711{
712 struct MarkedRecord *mrec;
713 purge_task = NULL;
714
715 if (NULL == marked_head)
716 {
717 ret = 0;
718 finish_command ();
719 return;
720 }
721 mrec = marked_head;
722 GNUNET_CONTAINER_DLL_remove (marked_head,
723 marked_tail,
724 mrec);
725 del_qe = GNUNET_NAMESTORE_records_store (ns,
726 &mrec->key,
727 mrec->name,
728 0, NULL,
729 &marked_deleted,
730 NULL);
731 GNUNET_free (mrec->name);
732 GNUNET_free (mrec);
733}
734
735/**
736 * Function called when we are done with a zone iteration.
737 */
738static void
739zone_iteration_finished (void *cls)
740{
741 (void) cls;
742 list_it = NULL;
743 if (purge_orphaned || purge_zone)
744 {
745 purge_task = GNUNET_SCHEDULER_add_now (&purge_next_record, NULL);
746 return;
747 }
748 ret = 0;
749 finish_command ();
750}
751
752
753/**
754 * Function called when we encountered an error in a zone iteration.
755 */
756static void
757zone_iteration_error_cb (void *cls)
758{
759 (void) cls;
760 list_it = NULL;
761 fprintf (stderr, "Error iterating over zone\n");
762 ret = 1;
763 finish_command ();
764}
765
766static void
767collect_zone_records_to_purge (const struct
768 GNUNET_CRYPTO_PrivateKey *zone_key,
769 const char *rname,
770 unsigned int rd_len,
771 const struct GNUNET_GNSRECORD_Data *rd)
772{
773 struct MarkedRecord *mrec;
774
775 mrec = GNUNET_new (struct MarkedRecord);
776 mrec->key = *zone_key;
777 mrec->name = GNUNET_strdup (rname);
778 GNUNET_CONTAINER_DLL_insert (marked_head,
779 marked_tail,
780 mrec);
781}
782
783
784static void
785collect_orphans (const struct GNUNET_CRYPTO_PrivateKey *zone_key,
786 const char *rname,
787 unsigned int rd_len,
788 const struct GNUNET_GNSRECORD_Data *rd)
789{
790 struct EgoEntry *ego;
791 struct MarkedRecord *orphan;
792 int is_orphaned = 1;
793
794 for (ego = ego_head; NULL != ego; ego = ego->next)
795 {
796 if (0 == memcmp (GNUNET_IDENTITY_ego_get_private_key (ego->ego),
797 zone_key,
798 sizeof (*zone_key)))
799 {
800 is_orphaned = 0;
801 break;
802 }
803 }
804 if (is_orphaned)
805 {
806 orphan = GNUNET_new (struct MarkedRecord);
807 orphan->key = *zone_key;
808 orphan->name = GNUNET_strdup (rname);
809 GNUNET_CONTAINER_DLL_insert (marked_head,
810 marked_tail,
811 orphan);
812 }
813}
814
815/**
816 * Process a record that was stored in the namestore.
817 *
818 * @param rname name that is being mapped (at most 255 characters long)
819 * @param rd_len number of entries in @a rd array
820 * @param rd array of records with data to store
821 */
822static void
823display_record (const struct GNUNET_CRYPTO_PrivateKey *zone_key,
824 const char *rname,
825 unsigned int rd_len,
826 const struct GNUNET_GNSRECORD_Data *rd)
827{
828 const char *typestr;
829 char *s;
830 const char *ets;
831 struct GNUNET_TIME_Absolute at;
832 struct GNUNET_TIME_Relative rt;
833 struct EgoEntry *ego;
834 int have_record;
835 int is_orphaned = 1;
836 char *orphaned_str;
837
838 if ((NULL != name) && (0 != strcmp (name, rname)))
839 return;
840 have_record = GNUNET_NO;
841 for (unsigned int i = 0; i < rd_len; i++)
842 {
843 if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
844 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)))
845 continue;
846 if ((type != rd[i].record_type) && (GNUNET_GNSRECORD_TYPE_ANY != type))
847 continue;
848 have_record = GNUNET_YES;
849 break;
850 }
851 if (GNUNET_NO == have_record)
852 return;
853 for (ego = ego_head; NULL != ego; ego = ego->next)
854 {
855 if (0 == memcmp (GNUNET_IDENTITY_ego_get_private_key (ego->ego),
856 zone_key,
857 sizeof (*zone_key)))
858 {
859 is_orphaned = 0;
860 break;
861 }
862 }
863 if (list_orphaned && ! is_orphaned)
864 return;
865 if (! list_orphaned && is_orphaned)
866 return;
867 orphaned_str = GNUNET_CRYPTO_private_key_to_string (zone_key);
868 fprintf (stdout, "%s.%s:\n", rname, is_orphaned ? orphaned_str :
869 ego->identifier);
870 GNUNET_free (orphaned_str);
871 if (NULL != typestring)
872 type = GNUNET_GNSRECORD_typename_to_number (typestring);
873 else
874 type = GNUNET_GNSRECORD_TYPE_ANY;
875 for (unsigned int i = 0; i < rd_len; i++)
876 {
877 if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
878 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)))
879 continue;
880 if ((type != rd[i].record_type) && (GNUNET_GNSRECORD_TYPE_ANY != type))
881 continue;
882 typestr = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
883 s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
884 rd[i].data,
885 rd[i].data_size);
886 if (NULL == s)
887 {
888 fprintf (stdout,
889 _ ("\tCorrupt or unsupported record of type %u\n"),
890 (unsigned int) rd[i].record_type);
891 continue;
892 }
893 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
894 {
895 rt.rel_value_us = rd[i].expiration_time;
896 ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
897 }
898 else
899 {
900 at.abs_value_us = rd[i].expiration_time;
901 ets = GNUNET_STRINGS_absolute_time_to_string (at);
902 }
903 char flgstr[16];
904 sprintf (flgstr, "[%s%s%s%s%s]",
905 (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE) ? "" : "p",
906 (rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL) ? "S" : "",
907 (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION) ? "r" : "",
908 (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW) ? "S" : "",
909 (rd[i].flags & GNUNET_GNSRECORD_RF_CRITICAL) ? "C" : "");
910 if (output_recordline)
911 fprintf (stdout,
912 " %s %" PRIu64 " %s %s\n",
913 typestr,
914 rd[i].expiration_time,
915 flgstr,
916 s);
917 else
918 fprintf (stdout,
919 "\t%s: %s (%s)\t%s\t%s\n",
920 typestr,
921 s,
922 ets,
923 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE"
924 : "PUBLIC",
925 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW)) ? "SHADOW"
926 : "");
927 GNUNET_free (s);
928 }
929 // fprintf (stdout, "%s", "\n");
930}
931
932static void
933purge_zone_iterator (void *cls,
934 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
935 const char *rname,
936 unsigned int rd_len,
937 const struct GNUNET_GNSRECORD_Data *rd,
938 struct GNUNET_TIME_Absolute expiry)
939{
940 (void) cls;
941 (void) zone_key;
942 (void) expiry;
943 collect_zone_records_to_purge (zone_key, rname, rd_len, rd);
944 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
945}
946
947
948static void
949purge_orphans_iterator (void *cls,
950 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
951 const char *rname,
952 unsigned int rd_len,
953 const struct GNUNET_GNSRECORD_Data *rd,
954 struct GNUNET_TIME_Absolute expiry)
955{
956 (void) cls;
957 (void) zone_key;
958 (void) expiry;
959 collect_orphans (zone_key, rname, rd_len, rd);
960 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
961}
962
963
964/**
965 * Process a record that was stored in the namestore.
966 *
967 * @param cls closure
968 * @param zone_key private key of the zone
969 * @param rname name that is being mapped (at most 255 characters long)
970 * @param rd_len number of entries in @a rd array
971 * @param rd array of records with data to store
972 */
973static void
974display_record_iterator (void *cls,
975 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
976 const char *rname,
977 unsigned int rd_len,
978 const struct GNUNET_GNSRECORD_Data *rd,
979 struct GNUNET_TIME_Absolute expiry)
980{
981 (void) cls;
982 (void) zone_key;
983 (void) expiry;
984 display_record (zone_key, rname, rd_len, rd);
985 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
986}
987
988
989/**
990 * Process a record that was stored in the namestore.
991 *
992 * @param cls closure
993 * @param zone_key private key of the zone
994 * @param rname name that is being mapped (at most 255 characters long)
995 * @param rd_len number of entries in @a rd array
996 * @param rd array of records with data to store
997 */
998static void
999display_record_monitor (void *cls,
1000 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
1001 const char *rname,
1002 unsigned int rd_len,
1003 const struct GNUNET_GNSRECORD_Data *rd,
1004 struct GNUNET_TIME_Absolute expiry)
1005{
1006 (void) cls;
1007 (void) zone_key;
1008 (void) expiry;
1009 display_record (zone_key, rname, rd_len, rd);
1010 GNUNET_NAMESTORE_zone_monitor_next (zm, 1);
1011}
1012
1013
1014/**
1015 * Process a record that was stored in the namestore.
1016 *
1017 * @param cls closure
1018 * @param zone_key private key of the zone
1019 * @param rname name that is being mapped (at most 255 characters long)
1020 * @param rd_len number of entries in @a rd array
1021 * @param rd array of records with data to store
1022 */
1023static void
1024display_record_lookup (void *cls,
1025 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
1026 const char *rname,
1027 unsigned int rd_len,
1028 const struct GNUNET_GNSRECORD_Data *rd)
1029{
1030 (void) cls;
1031 (void) zone_key;
1032 get_qe = NULL;
1033 display_record (zone_key, rname, rd_len, rd);
1034 finish_command ();
1035}
1036
1037
1038/**
1039 * Function called once we are in sync in monitor mode.
1040 *
1041 * @param cls NULL
1042 */
1043static void
1044sync_cb (void *cls)
1045{
1046 (void) cls;
1047 fprintf (stdout, "%s", "Monitor is now in sync.\n");
1048}
1049
1050
1051/**
1052 * Function called on errors while monitoring.
1053 *
1054 * @param cls NULL
1055 */
1056static void
1057monitor_error_cb (void *cls)
1058{
1059 (void) cls;
1060 fprintf (stderr, "%s", "Monitor disconnected and out of sync.\n");
1061}
1062
1063
1064/**
1065 * Function called on errors while monitoring.
1066 *
1067 * @param cls NULL
1068 */
1069static void
1070lookup_error_cb (void *cls)
1071{
1072 (void) cls;
1073 get_qe = NULL;
1074 fprintf (stderr, "%s", "Failed to lookup record.\n");
1075 finish_command ();
1076}
1077
1078
1079/**
1080 * Function called if lookup fails.
1081 */
1082static void
1083add_error_cb (void *cls)
1084{
1085 (void) cls;
1086 add_qe = NULL;
1087 GNUNET_break (0);
1088 ret = 1;
1089 finish_command ();
1090}
1091
1092
1093/**
1094 * We're storing a record; this function is given the existing record
1095 * so that we can merge the information.
1096 *
1097 * @param cls closure, unused
1098 * @param zone_key private key of the zone
1099 * @param rec_name name that is being mapped (at most 255 characters long)
1100 * @param rd_count number of entries in @a rd array
1101 * @param rd array of records with data to store
1102 */
1103static void
1104get_existing_record (void *cls,
1105 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
1106 const char *rec_name,
1107 unsigned int rd_count,
1108 const struct GNUNET_GNSRECORD_Data *rd)
1109{
1110 struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
1111 struct GNUNET_GNSRECORD_Data *rde;
1112
1113 (void) cls;
1114 (void) zone_key;
1115 add_qe = NULL;
1116 if (0 != strcmp (rec_name, name))
1117 {
1118 GNUNET_break (0);
1119 ret = 1;
1120 finish_command ();
1121 return;
1122 }
1123
1124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125 "Received %u records for name `%s'\n",
1126 rd_count,
1127 rec_name);
1128 for (unsigned int i = 0; i < rd_count; i++)
1129 {
1130 switch (rd[i].record_type)
1131 {
1132 case GNUNET_DNSPARSER_TYPE_SOA:
1133 if (GNUNET_DNSPARSER_TYPE_SOA == type)
1134 {
1135 fprintf (
1136 stderr,
1137 _ (
1138 "A SOA record exists already under `%s', cannot add a second SOA to the same zone.\n"),
1139 rec_name);
1140 ret = 1;
1141 finish_command ();
1142 return;
1143 }
1144 break;
1145 }
1146 }
1147 memset (rdn, 0, sizeof(struct GNUNET_GNSRECORD_Data));
1148 GNUNET_memcpy (&rdn[1], rd, rd_count * sizeof(struct GNUNET_GNSRECORD_Data));
1149 rde = &rdn[0];
1150 rde->data = data;
1151 rde->data_size = data_size;
1152 rde->record_type = type;
1153 if (1 == is_shadow)
1154 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW;
1155 if (1 != is_public)
1156 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1157 rde->expiration_time = etime;
1158 if (GNUNET_YES == etime_is_rel)
1159 rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1160 else if (GNUNET_NO != etime_is_rel)
1161 rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
1162 GNUNET_assert (NULL != name);
1163 add_qe = GNUNET_NAMESTORE_records_store (ns,
1164 &zone_pkey,
1165 name,
1166 rd_count + 1,
1167 rde,
1168 &add_continuation,
1169 &add_qe);
1170}
1171
1172
1173/**
1174 * Function called if we encountered an error in zone-to-name.
1175 */
1176static void
1177reverse_error_cb (void *cls)
1178{
1179 (void) cls;
1180 reverse_qe = NULL;
1181 fprintf (stdout, "%s.zkey\n", reverse_pkey);
1182}
1183
1184
1185/**
1186 * Function called with the result of our attempt to obtain a name for a given
1187 * public key.
1188 *
1189 * @param cls NULL
1190 * @param zone private key of the zone; NULL on disconnect
1191 * @param label label of the records; NULL on disconnect
1192 * @param rd_count number of entries in @a rd array, 0 if label was deleted
1193 * @param rd array of records with data to store
1194 */
1195static void
1196handle_reverse_lookup (void *cls,
1197 const struct GNUNET_CRYPTO_PrivateKey *zone,
1198 const char *label,
1199 unsigned int rd_count,
1200 const struct GNUNET_GNSRECORD_Data *rd)
1201{
1202 (void) cls;
1203 (void) zone;
1204 (void) rd_count;
1205 (void) rd;
1206 reverse_qe = NULL;
1207 if (NULL == label)
1208 fprintf (stdout, "%s\n", reverse_pkey);
1209 else
1210 fprintf (stdout, "%s.%s\n", label, ego_name);
1211 finish_command ();
1212}
1213
1214
1215/**
1216 * Function called if lookup for deletion fails.
1217 */
1218static void
1219del_lookup_error_cb (void *cls)
1220{
1221 (void) cls;
1222 del_qe = NULL;
1223 GNUNET_break (0);
1224 ret = 1;
1225 finish_command ();
1226}
1227
1228
1229/**
1230 * We were asked to delete something; this function is called with
1231 * the existing records. Now we should determine what should be
1232 * deleted and then issue the deletion operation.
1233 *
1234 * @param cls NULL
1235 * @param zone private key of the zone we are deleting from
1236 * @param label name of the records we are editing
1237 * @param rd_count size of the @a rd array
1238 * @param rd existing records
1239 */
1240static void
1241del_monitor (void *cls,
1242 const struct GNUNET_CRYPTO_PrivateKey *zone,
1243 const char *label,
1244 unsigned int rd_count,
1245 const struct GNUNET_GNSRECORD_Data *rd)
1246{
1247 struct GNUNET_GNSRECORD_Data rdx[rd_count];
1248 unsigned int rd_left;
1249 uint32_t type;
1250 char *vs;
1251
1252 (void) cls;
1253 (void) zone;
1254 del_qe = NULL;
1255 if (0 == rd_count)
1256 {
1257 fprintf (stderr,
1258 _ (
1259 "There are no records under label `%s' that could be deleted.\n"),
1260 label);
1261 ret = 1;
1262 finish_command ();
1263 return;
1264 }
1265 if ((NULL == value) && (NULL == typestring))
1266 {
1267 /* delete everything */
1268 del_qe = GNUNET_NAMESTORE_records_store (ns,
1269 &zone_pkey,
1270 name,
1271 0,
1272 NULL,
1273 &del_continuation,
1274 NULL);
1275 return;
1276 }
1277 rd_left = 0;
1278 if (NULL != typestring)
1279 type = GNUNET_GNSRECORD_typename_to_number (typestring);
1280 else
1281 type = GNUNET_GNSRECORD_TYPE_ANY;
1282 for (unsigned int i = 0; i < rd_count; i++)
1283 {
1284 vs = NULL;
1285 if (! (((GNUNET_GNSRECORD_TYPE_ANY == type) ||
1286 (rd[i].record_type == type)) &&
1287 ((NULL == value) ||
1288 (NULL ==
1289 (vs = (GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1290 rd[i].data,
1291 rd[i].data_size)))) ||
1292 (0 == strcmp (vs, value)))))
1293 rdx[rd_left++] = rd[i];
1294 GNUNET_free (vs);
1295 }
1296 if (rd_count == rd_left)
1297 {
1298 /* nothing got deleted */
1299 fprintf (
1300 stderr,
1301 _ (
1302 "There are no records under label `%s' that match the request for deletion.\n"),
1303 label);
1304 finish_command ();
1305 return;
1306 }
1307 /* delete everything but what we copied to 'rdx' */
1308 del_qe = GNUNET_NAMESTORE_records_store (ns,
1309 &zone_pkey,
1310 name,
1311 rd_left,
1312 rdx,
1313 &del_continuation,
1314 NULL);
1315}
1316
1317
1318static void
1319replace_cont (void *cls, enum GNUNET_ErrorCode ec)
1320{
1321 (void) cls;
1322
1323 set_qe = NULL;
1324 if (GNUNET_EC_NONE != ec)
1325 {
1326 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1327 _ ("%s\n"),
1328 GNUNET_ErrorCode_get_hint (ec));
1329 ret = 1; /* fail from 'main' */
1330 }
1331 finish_command ();
1332}
1333
1334
1335/**
1336 * We have obtained the zone's private key, so now process
1337 * the main commands using it.
1338 *
1339 * @param cfg configuration to use
1340 */
1341static void
1342run_with_zone_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg)
1343{
1344 struct GNUNET_GNSRECORD_Data rd;
1345 enum GNUNET_GNSRECORD_Filter filter_flags = GNUNET_GNSRECORD_FILTER_NONE;
1346
1347 if (omit_private)
1348 filter_flags |= GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE;
1349 if (include_maintenance)
1350 filter_flags |= GNUNET_GNSRECORD_FILTER_INCLUDE_MAINTENANCE;
1351 if (! (add | del | list | (NULL != nickstring) | (NULL != uri)
1352 | (NULL != reverse_pkey) | (NULL != recordset) | (monitor)
1353 | (purge_orphaned) | (list_orphaned) | (purge_zone)) )
1354 {
1355 /* nothing more to be done */
1356 fprintf (stderr, _ ("No options given\n"));
1357 finish_command ();
1358 return;
1359 }
1360
1361 if (NULL != recordset)
1362 {
1363 /* replace entire record set */
1364 unsigned int rd_count;
1365 struct GNUNET_GNSRECORD_Data *rd;
1366
1367 /* FIXME: We could easily support append and delete with this as well */
1368 if (! add)
1369 {
1370 fprintf (stderr, _ ("Recordlines only work with option `%s'\n"),
1371 "-a");
1372 ret = 1;
1373 finish_command ();
1374 return;
1375 }
1376 if (NULL == name)
1377 {
1378 fprintf (stderr,
1379 _ ("Missing option `%s' for operation `%s'\n"),
1380 "-n",
1381 _ ("name"));
1382 ret = 1;
1383 finish_command ();
1384 return;
1385 }
1386 rd_count = 0;
1387 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1388 rd_count++;
1389 rd = GNUNET_new_array (rd_count, struct GNUNET_GNSRECORD_Data);
1390 rd_count = 0;
1391 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1392 {
1393 rd[rd_count] = e->record;
1394 rd_count++;
1395 }
1396 set_qe = GNUNET_NAMESTORE_records_store (ns,
1397 &zone_pkey,
1398 name,
1399 rd_count,
1400 rd,
1401 &replace_cont,
1402 NULL);
1403 GNUNET_free (rd);
1404 return;
1405 }
1406 if (NULL != nickstring)
1407 {
1408 if (0 == strlen (nickstring))
1409 {
1410 fprintf (stderr, _ ("Invalid nick `%s'\n"), nickstring);
1411 ret = 1;
1412 finish_command ();
1413 return;
1414 }
1415 add = 1;
1416 typestring = GNUNET_strdup (GNUNET_GNSRECORD_number_to_typename (
1417 GNUNET_GNSRECORD_TYPE_NICK));
1418 name = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
1419 value = GNUNET_strdup (nickstring);
1420 is_public = 0;
1421 expirationstring = GNUNET_strdup ("never");
1422 GNUNET_free (nickstring);
1423 nickstring = NULL;
1424 }
1425
1426 if (add)
1427 {
1428 if (NULL == ego_name)
1429 {
1430 fprintf (stderr,
1431 _ ("Missing option `%s' for operation `%s'\n"),
1432 "-z",
1433 _ ("add"));
1434 ret = 1;
1435 finish_command ();
1436 return;
1437 }
1438 if (NULL == name)
1439 {
1440 fprintf (stderr,
1441 _ ("Missing option `%s' for operation `%s'\n"),
1442 "-n",
1443 _ ("add"));
1444 ret = 1;
1445 finish_command ();
1446 return;
1447 }
1448 if (NULL == typestring)
1449 {
1450 fprintf (stderr,
1451 _ ("Missing option `%s' for operation `%s'\n"),
1452 "-t",
1453 _ ("add"));
1454 ret = 1;
1455 finish_command ();
1456 return;
1457 }
1458 type = GNUNET_GNSRECORD_typename_to_number (typestring);
1459 if (UINT32_MAX == type)
1460 {
1461 fprintf (stderr, _ ("Unsupported type `%s'\n"), typestring);
1462 ret = 1;
1463 finish_command ();
1464 return;
1465 }
1466 if ((GNUNET_DNSPARSER_TYPE_SRV == type) ||
1467 (GNUNET_DNSPARSER_TYPE_TLSA == type) ||
1468 (GNUNET_DNSPARSER_TYPE_OPENPGPKEY == type))
1469 {
1470 fprintf (stderr,
1471 _ ("For DNS record types `SRV', `TLSA' and `OPENPGPKEY'"));
1472 fprintf (stderr, ", please use a `BOX' record instead\n");
1473 ret = 1;
1474 finish_command ();
1475 return;
1476 }
1477 if (NULL == value)
1478 {
1479 fprintf (stderr,
1480 _ ("Missing option `%s' for operation `%s'\n"),
1481 "-V",
1482 _ ("add"));
1483 ret = 1;
1484 finish_command ();
1485 return;
1486 }
1487 if (GNUNET_OK !=
1488 GNUNET_GNSRECORD_string_to_value (type, value, &data, &data_size))
1489 {
1490 fprintf (stderr,
1491 _ ("Value `%s' invalid for record type `%s'\n"),
1492 value,
1493 typestring);
1494 ret = 1;
1495 finish_command ();
1496 return;
1497 }
1498 if (NULL == expirationstring)
1499 {
1500 fprintf (stderr,
1501 _ ("Missing option `%s' for operation `%s'\n"),
1502 "-e",
1503 _ ("add"));
1504 ret = 1;
1505 finish_command ();
1506 return;
1507 }
1508 if (GNUNET_OK != parse_expiration (expirationstring, &etime_is_rel, &etime))
1509 {
1510 fprintf (stderr, _ ("Invalid time format `%s'\n"), expirationstring);
1511 ret = 1;
1512 finish_command ();
1513 return;
1514 }
1515 add_qe = GNUNET_NAMESTORE_records_lookup (ns,
1516 &zone_pkey,
1517 name,
1518 &add_error_cb,
1519 NULL,
1520 &get_existing_record,
1521 NULL);
1522 }
1523 if (del)
1524 {
1525 if (NULL == ego_name)
1526 {
1527 fprintf (stderr,
1528 _ ("Missing option `%s' for operation `%s'\n"),
1529 "-z",
1530 _ ("del"));
1531 ret = 1;
1532 finish_command ();
1533 return;
1534 }
1535 if (NULL == name)
1536 {
1537 fprintf (stderr,
1538 _ ("Missing option `%s' for operation `%s'\n"),
1539 "-n",
1540 _ ("del"));
1541 ret = 1;
1542 finish_command ();
1543 return;
1544 }
1545 del_qe = GNUNET_NAMESTORE_records_lookup (ns,
1546 &zone_pkey,
1547 name,
1548 &del_lookup_error_cb,
1549 NULL,
1550 &del_monitor,
1551 NULL);
1552 }
1553 if (purge_orphaned)
1554 {
1555 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1556 NULL,
1557 &zone_iteration_error_cb,
1558 NULL,
1559 &purge_orphans_iterator,
1560 NULL,
1561 &zone_iteration_finished,
1562 NULL,
1563 filter_flags);
1564
1565 }
1566 else if (purge_zone)
1567 {
1568 if (NULL == ego_name)
1569 {
1570 fprintf (stderr,
1571 _ ("Missing option `%s' for operation `%s'\n"),
1572 "-z",
1573 _ ("purge-zone"));
1574 ret = 1;
1575 finish_command ();
1576 return;
1577 }
1578 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1579 &zone_pkey,
1580 &zone_iteration_error_cb,
1581 NULL,
1582 &purge_zone_iterator,
1583 NULL,
1584 &zone_iteration_finished,
1585 NULL,
1586 filter_flags);
1587
1588 }
1589 else if (list || list_orphaned)
1590 {
1591 if (NULL != name)
1592 {
1593 if (NULL == ego_name)
1594 {
1595 fprintf (stderr,
1596 _ ("Missing option `%s' for operation `%s'\n"),
1597 "-z",
1598 _ ("list"));
1599 ret = 1;
1600 finish_command ();
1601 return;
1602 }
1603 get_qe = GNUNET_NAMESTORE_records_lookup (ns,
1604 &zone_pkey,
1605 name,
1606 &lookup_error_cb,
1607 NULL,
1608 &display_record_lookup,
1609 NULL);
1610 }
1611 else
1612 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1613 (NULL == ego_name) ?
1614 NULL : &zone_pkey,
1615 &zone_iteration_error_cb,
1616 NULL,
1617 &display_record_iterator,
1618 NULL,
1619 &zone_iteration_finished,
1620 NULL,
1621 filter_flags);
1622 }
1623 if (NULL != reverse_pkey)
1624 {
1625 struct GNUNET_CRYPTO_PublicKey pubkey;
1626
1627 if (NULL == ego_name)
1628 {
1629 fprintf (stderr,
1630 _ ("Missing option `%s' for operation `%s'\n"),
1631 "-z",
1632 _ ("reverse-pkey"));
1633 ret = 1;
1634 finish_command ();
1635 return;
1636 }
1637 if (GNUNET_OK !=
1638 GNUNET_CRYPTO_public_key_from_string (reverse_pkey,
1639 &pubkey))
1640 {
1641 fprintf (stderr,
1642 _ ("Invalid public key for reverse lookup `%s'\n"),
1643 reverse_pkey);
1644 ret = 1;
1645 finish_command ();
1646 return;
1647 }
1648 reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
1649 &zone_pkey,
1650 &pubkey,
1651 &reverse_error_cb,
1652 NULL,
1653 &handle_reverse_lookup,
1654 NULL);
1655 }
1656 if (NULL != uri)
1657 {
1658 char sh[105];
1659 char sname[64];
1660 struct GNUNET_CRYPTO_PublicKey pkey;
1661 if (NULL == ego_name)
1662 {
1663 fprintf (stderr,
1664 _ ("Missing option `%s' for operation `%s'\n"),
1665 "-z",
1666 _ ("uri"));
1667 ret = 1;
1668 finish_command ();
1669 return;
1670 }
1671
1672 memset (sh, 0, 105);
1673 memset (sname, 0, 64);
1674
1675 if ((2 != (sscanf (uri, "gnunet://gns/%58s/%63s", sh, sname))) ||
1676 (GNUNET_OK !=
1677 GNUNET_CRYPTO_public_key_from_string (sh, &pkey)))
1678 {
1679 fprintf (stderr, _ ("Invalid URI `%s'\n"), uri);
1680 ret = 1;
1681 finish_command ();
1682 return;
1683 }
1684 if (NULL == expirationstring)
1685 {
1686 fprintf (stderr,
1687 _ ("Missing option `%s' for operation `%s'\n"),
1688 "-e",
1689 _ ("add"));
1690 ret = 1;
1691 finish_command ();
1692 return;
1693 }
1694 if (GNUNET_OK != parse_expiration (expirationstring, &etime_is_rel, &etime))
1695 {
1696 fprintf (stderr, _ ("Invalid time format `%s'\n"), expirationstring);
1697 ret = 1;
1698 finish_command ();
1699 return;
1700 }
1701 memset (&rd, 0, sizeof(rd));
1702 rd.data = &pkey;
1703 rd.data_size = GNUNET_CRYPTO_public_key_get_length (&pkey);
1704 rd.record_type = ntohl (pkey.type);
1705 rd.expiration_time = etime;
1706 if (GNUNET_YES == etime_is_rel)
1707 rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1708 if (1 == is_shadow)
1709 rd.flags |= GNUNET_GNSRECORD_RF_SHADOW;
1710 add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
1711 &zone_pkey,
1712 sname,
1713 1,
1714 &rd,
1715 &add_continuation,
1716 &add_qe_uri);
1717 }
1718 if (monitor)
1719 {
1720 zm = GNUNET_NAMESTORE_zone_monitor_start2 (cfg,
1721 (NULL != ego_name) ?
1722 &zone_pkey : NULL,
1723 GNUNET_YES,
1724 &monitor_error_cb,
1725 NULL,
1726 &display_record_monitor,
1727 NULL,
1728 &sync_cb,
1729 NULL,
1730 filter_flags);
1731 }
1732}
1733
1734#define MAX_LINE_LEN 4086
1735
1736#define MAX_ARGS 20
1737
1738static int
1739get_identity_for_string (const char *str,
1740 struct GNUNET_CRYPTO_PrivateKey *zk)
1741{
1742 const struct GNUNET_CRYPTO_PrivateKey *privkey;
1743 struct GNUNET_CRYPTO_PublicKey pubkey;
1744 struct GNUNET_CRYPTO_PublicKey ego_pubkey;
1745 struct EgoEntry *ego_entry;
1746
1747 if (GNUNET_OK == GNUNET_CRYPTO_public_key_from_string (str,
1748 &pubkey))
1749 {
1750 for (ego_entry = ego_head;
1751 NULL != ego_entry; ego_entry = ego_entry->next)
1752 {
1753 privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1754 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &ego_pubkey);
1755 if (0 == memcmp (&ego_pubkey, &pubkey, sizeof (pubkey)))
1756 {
1757 *zk = *privkey;
1758 return GNUNET_OK;
1759 }
1760 }
1761 }
1762 else
1763 {
1764 for (ego_entry = ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
1765 {
1766 /** FIXME: Check for zTLD? **/
1767 if (0 != strcmp (str, ego_entry->identifier))
1768 continue;
1769 *zk = *GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1770 return GNUNET_OK;
1771 }
1772 }
1773 return GNUNET_NO;
1774}
1775
1776static void
1777process_command_stdin ()
1778{
1779 char buf[MAX_LINE_LEN];
1780 static struct GNUNET_CRYPTO_PrivateKey next_zone_key;
1781 static char next_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1782 static int finished = GNUNET_NO;
1783 static int have_next_zonekey = GNUNET_NO;
1784 int zonekey_set = GNUNET_NO;
1785 char *tmp;
1786
1787
1788 if (GNUNET_YES == have_next_zonekey)
1789 {
1790 zone_pkey = next_zone_key;
1791 if (NULL != name)
1792 GNUNET_free (name);
1793 name = GNUNET_strdup (next_name);
1794 zonekey_set = GNUNET_YES;
1795 }
1796 while (NULL != fgets (buf, sizeof (buf), stdin))
1797 {
1798 if (1 >= strlen (buf))
1799 continue;
1800 if (buf[strlen (buf) - 1] == '\n')
1801 buf[strlen (buf) - 1] = '\0';
1802 /**
1803 * Check if this is a new name. If yes, and we have records, store them.
1804 */
1805 if (buf[strlen (buf) - 1] == ':')
1806 {
1807 memset (next_name, 0, sizeof (next_name));
1808 strncpy (next_name, buf, strlen (buf) - 1);
1809 tmp = strchr (next_name, '.');
1810 if (NULL == tmp)
1811 {
1812 fprintf (stderr, "Error parsing name `%s'\n", next_name);
1813 ns_qe = GNUNET_NAMESTORE_transaction_commit (ns, &commit_cb, NULL);
1814 ret = 1;
1815 return;
1816 }
1817 if (GNUNET_OK != get_identity_for_string (tmp + 1, &next_zone_key))
1818 {
1819 fprintf (stderr, "Error parsing zone name `%s'\n", tmp + 1);
1820 ret = 1;
1821 GNUNET_SCHEDULER_shutdown ();
1822 return;
1823 }
1824 *tmp = '\0';
1825 have_next_zonekey = GNUNET_YES;
1826 /* Run a command for the previous record set */
1827 if (NULL != recordset)
1828 {
1829 run_with_zone_pkey (cfg);
1830 return;
1831 }
1832 zone_pkey = next_zone_key;
1833 if (NULL != name)
1834 GNUNET_free (name);
1835 name = GNUNET_strdup (next_name);
1836 zonekey_set = GNUNET_YES;
1837 continue;
1838 }
1839 if (GNUNET_NO == zonekey_set)
1840 {
1841 fprintf (stderr, "Warning, encountered recordline without zone\n");
1842 continue;
1843 }
1844 parse_recordline (buf);
1845 }
1846 if (GNUNET_NO == finished)
1847 {
1848 if (NULL != recordset)
1849 {
1850 if (GNUNET_YES == zonekey_set)
1851 {
1852 run_with_zone_pkey (cfg); /** one last time **/
1853 finished = GNUNET_YES;
1854 return;
1855 }
1856 fprintf (stderr, "Warning, encountered recordline without zone\n");
1857 }
1858 }
1859 ns_qe = GNUNET_NAMESTORE_transaction_commit (ns, &commit_cb, NULL);
1860 return;
1861}
1862
1863
1864static void
1865begin_cb (void *cls, enum GNUNET_ErrorCode ec)
1866{
1867 ns_qe = NULL;
1868 if (GNUNET_EC_NONE != ec)
1869 {
1870 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1871 "Failed to start transaction: %s\n",
1872 GNUNET_ErrorCode_get_hint (ec));
1873 GNUNET_SCHEDULER_shutdown ();
1874 return;
1875 }
1876 if (read_from_stdin)
1877 {
1878 process_command_stdin ();
1879 return;
1880 }
1881 run_with_zone_pkey (cfg);
1882}
1883
1884
1885/**
1886 * Function called with ALL of the egos known to the
1887 * identity service, used on startup if the user did
1888 * not specify a zone on the command-line.
1889 * Once the iteration is done (@a ego is NULL), we
1890 * ask for the default ego for "namestore".
1891 *
1892 * @param cls a `struct GNUNET_CONFIGURATION_Handle`
1893 * @param ego an ego, NULL for end of iteration
1894 * @param ctx NULL
1895 * @param name name associated with @a ego
1896 */
1897static void
1898id_connect_cb (void *cls,
1899 struct GNUNET_IDENTITY_Ego *ego,
1900 void **ctx,
1901 const char *name)
1902{
1903 struct GNUNET_CRYPTO_PublicKey pk;
1904 struct EgoEntry *ego_entry;
1905
1906 (void) ctx;
1907 (void) name;
1908 if ((NULL != name) && (NULL != ego))
1909 {
1910 ego_entry = GNUNET_new (struct EgoEntry);
1911 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1912 ego_entry->ego = ego;
1913 ego_entry->identifier = GNUNET_strdup (name);
1914 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1915 ego_tail,
1916 ego_entry);
1917 if ((NULL != ego_name) &&
1918 (0 == strcmp (name, ego_name)))
1919 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1920 return;
1921 }
1922 if (NULL != ego)
1923 return;
1924 ns_qe = GNUNET_NAMESTORE_transaction_begin (ns, &begin_cb, (void *) cfg);
1925}
1926
1927
1928
1929
1930
1931/**
1932 * Main function that will be run.
1933 *
1934 * @param cls closure
1935 * @param args remaining command-line arguments
1936 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1937 * @param cfg configuration
1938 */
1939static void
1940run (void *cls,
1941 char *const *args,
1942 const char *cfgfile,
1943 const struct GNUNET_CONFIGURATION_Handle *_cfg)
1944{
1945 (void) cls;
1946 (void) args;
1947 (void) cfgfile;
1948 cfg = _cfg;
1949 if (NULL != args[0])
1950 GNUNET_log (
1951 GNUNET_ERROR_TYPE_WARNING,
1952 _ ("Superfluous command line arguments (starting with `%s') ignored\n"),
1953 args[0]);
1954
1955 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, (void *) cfg);
1956 ns = GNUNET_NAMESTORE_connect (cfg);
1957 if (NULL == ns)
1958 {
1959 fprintf (stderr, _ ("Failed to connect to namestore\n"));
1960 GNUNET_SCHEDULER_shutdown ();
1961 return;
1962 }
1963 idh = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, (void *) cfg);
1964 if (NULL == idh)
1965 {
1966 ret = -1;
1967 fprintf (stderr, _ ("Cannot connect to identity service\n"));
1968 GNUNET_SCHEDULER_shutdown ();
1969 }
1970}
1971
1972
1973
1974/**
1975 * The main function for gnunet-namestore.
1976 *
1977 * @param argc number of arguments from the command line
1978 * @param argv command line arguments
1979 * @return 0 ok, 1 on error
1980 */
1981int
1982main (int argc, char *const *argv)
1983{
1984 int lret;
1985 struct GNUNET_GETOPT_CommandLineOption options[] =
1986 { GNUNET_GETOPT_option_flag ('a', "add", gettext_noop ("add record"), &add),
1987 GNUNET_GETOPT_option_flag ('d',
1988 "delete",
1989 gettext_noop ("delete record"),
1990 &del),
1991 GNUNET_GETOPT_option_flag ('D',
1992 "display",
1993 gettext_noop ("display records"),
1994 &list),
1995 GNUNET_GETOPT_option_flag ('S',
1996 "from-stdin",
1997 gettext_noop ("read commands from stdin"),
1998 &read_from_stdin),
1999 GNUNET_GETOPT_option_string (
2000 'e',
2001 "expiration",
2002 "TIME",
2003 gettext_noop (
2004 "expiration time for record to use (for adding only), \"never\" is possible"),
2005 &expirationstring),
2006 GNUNET_GETOPT_option_string ('i',
2007 "nick",
2008 "NICKNAME",
2009 gettext_noop (
2010 "set the desired nick name for the zone"),
2011 &nickstring),
2012 GNUNET_GETOPT_option_flag ('m',
2013 "monitor",
2014 gettext_noop (
2015 "monitor changes in the namestore"),
2016 &monitor),
2017 GNUNET_GETOPT_option_string ('n',
2018 "name",
2019 "NAME",
2020 gettext_noop (
2021 "name of the record to add/delete/display"),
2022 &name),
2023 GNUNET_GETOPT_option_flag ('r',
2024 "recordline",
2025 gettext_noop ("Output in recordline format"),
2026 &output_recordline),
2027 GNUNET_GETOPT_option_string ('Z',
2028 "zone-to-name",
2029 "KEY",
2030 gettext_noop (
2031 "determine our name for the given KEY"),
2032 &reverse_pkey),
2033 GNUNET_GETOPT_option_string ('t',
2034 "type",
2035 "TYPE",
2036 gettext_noop (
2037 "type of the record to add/delete/display"),
2038 &typestring),
2039 GNUNET_GETOPT_option_string ('u',
2040 "uri",
2041 "URI",
2042 gettext_noop ("URI to import into our zone"),
2043 &uri),
2044 GNUNET_GETOPT_option_string ('V',
2045 "value",
2046 "VALUE",
2047 gettext_noop (
2048 "value of the record to add/delete"),
2049 &value),
2050 GNUNET_GETOPT_option_flag ('p',
2051 "public",
2052 gettext_noop ("create or list public record"),
2053 &is_public),
2054 GNUNET_GETOPT_option_flag ('o',
2055 "omit-private",
2056 gettext_noop ("omit private records"),
2057 &omit_private),
2058 GNUNET_GETOPT_option_flag ('T',
2059 "include-maintenance",
2060 gettext_noop (
2061 "do not filter maintenance records"),
2062 &include_maintenance),
2063 GNUNET_GETOPT_option_flag ('P',
2064 "purge-orphans",
2065 gettext_noop (
2066 "purge namestore of all orphans"),
2067 &purge_orphaned),
2068 GNUNET_GETOPT_option_flag ('O',
2069 "list-orphans",
2070 gettext_noop (
2071 "show private key for orphaned records for recovery using `gnunet-identity -C -P <key>'. Use in combination with --display"),
2072 &list_orphaned),
2073 GNUNET_GETOPT_option_flag ('X',
2074 "purge-zone-records",
2075 gettext_noop (
2076 "delete all records in specified zone"),
2077 &purge_zone),
2078 GNUNET_GETOPT_option_flag (
2079 's',
2080 "shadow",
2081 gettext_noop (
2082 "create shadow record (only valid if all other records of the same type have expired"),
2083 &is_shadow),
2084 GNUNET_GETOPT_option_string ('z',
2085 "zone",
2086 "EGO",
2087 gettext_noop (
2088 "name of the ego controlling the zone"),
2089 &ego_name),
2090 GNUNET_GETOPT_OPTION_END };
2091
2092
2093 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
2094 return 2;
2095
2096 is_public = -1;
2097 is_shadow = -1;
2098 GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
2099 if (GNUNET_OK !=
2100 (lret = GNUNET_PROGRAM_run (argc,
2101 argv,
2102 "gnunet-namestore",
2103 _ ("GNUnet zone manipulation tool"),
2104 options,
2105 &run,
2106 NULL)))
2107 {
2108 GNUNET_free_nz ((void *) argv);
2109 // FIXME
2110 // GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
2111 return lret;
2112 }
2113 GNUNET_free_nz ((void *) argv);
2114 // FIXME
2115 // GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
2116 return ret;
2117}
2118
2119
2120/* end of gnunet-namestore.c */
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c
deleted file mode 100644
index 26de295bf..000000000
--- a/src/namestore/gnunet-service-namestore.c
+++ /dev/null
@@ -1,2752 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 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 namestore/gnunet-service-namestore.c
23 * @brief namestore for the GNUnet naming system
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_gns_service.h"
30#include "gnunet_namestore_service.h"
31#include "gnunet_namestore_plugin.h"
32#include "gnunet_statistics_service.h"
33#include "gnunet_signatures.h"
34#include "namestore.h"
35
36#define LOG_STRERROR_FILE(kind, syscall, filename) \
37 GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
38
39/**
40 * If a monitor takes more than 1 minute to process an event, print a warning.
41 */
42#define MONITOR_STALL_WARN_DELAY GNUNET_TIME_UNIT_MINUTES
43
44/**
45 * Size of the cache used by #get_nick_record()
46 */
47#define NC_SIZE 16
48
49/**
50 * A namestore client
51 */
52struct NamestoreClient;
53
54
55/**
56 * A namestore iteration operation.
57 */
58struct ZoneIteration
59{
60 /**
61 * Next element in the DLL
62 */
63 struct ZoneIteration *next;
64
65 /**
66 * Previous element in the DLL
67 */
68 struct ZoneIteration *prev;
69
70 /**
71 * Namestore client which intiated this zone iteration
72 */
73 struct NamestoreClient *nc;
74
75 /**
76 * The nick to add to the records
77 */
78 struct GNUNET_GNSRECORD_Data *nick;
79
80 /**
81 * Key of the zone we are iterating over.
82 */
83 struct GNUNET_CRYPTO_PrivateKey zone;
84
85 /**
86 * The record set filter
87 */
88 enum GNUNET_GNSRECORD_Filter filter;
89
90 /**
91 * Last sequence number in the zone iteration used to address next
92 * result of the zone iteration in the store
93 *
94 * Initially set to 0.
95 * Updated in #zone_iterate_proc()
96 */
97 uint64_t seq;
98
99 /**
100 * The operation id for the zone iteration in the response for the client
101 */
102 uint32_t request_id;
103
104 /**
105 * Offset of the zone iteration used to address next result of the zone
106 * iteration in the store
107 *
108 * Initially set to 0 in #handle_iteration_start
109 * Incremented with by every call to #handle_iteration_next
110 */
111 uint32_t offset;
112
113 /**
114 * Number of pending cache operations triggered by this zone iteration which we
115 * need to wait for before allowing the client to continue.
116 */
117 unsigned int cache_ops;
118
119 /**
120 * Set to #GNUNET_YES if the last iteration exhausted the limit set by the
121 * client and we should send the #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END
122 * message and free the data structure once @e cache_ops is zero.
123 */
124 int send_end;
125};
126
127/**
128 * A namestore client
129 */
130struct NamestoreClient
131{
132 /**
133 * The client
134 */
135 struct GNUNET_SERVICE_Client *client;
136
137 /**
138 * Database handle for client
139 */
140 struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
141
142 /**
143 * Name of loaded plugin (neeed for cleanup)
144 */
145 char *db_lib_name;
146
147 /**
148 * GNUNET_YES if this nc has begun a transaction which is uncommited.
149 */
150 int in_transaction;
151
152 /**
153 * Message queue for transmission to @e client
154 */
155 struct GNUNET_MQ_Handle *mq;
156
157 /**
158 * Head of the DLL of
159 * Zone iteration operations in progress initiated by this client
160 */
161 struct ZoneIteration *op_head;
162
163 /**
164 * Tail of the DLL of
165 * Zone iteration operations in progress initiated by this client
166 */
167 struct ZoneIteration *op_tail;
168};
169
170
171/**
172 * A namestore monitor.
173 */
174struct ZoneMonitor
175{
176 /**
177 * Next element in the DLL
178 */
179 struct ZoneMonitor *next;
180
181 /**
182 * Previous element in the DLL
183 */
184 struct ZoneMonitor *prev;
185
186 /**
187 * Namestore client which intiated this zone monitor
188 */
189 struct NamestoreClient *nc;
190
191 /**
192 * Private key of the zone.
193 */
194 struct GNUNET_CRYPTO_PrivateKey zone;
195
196 /**
197 * The record set filter
198 */
199 enum GNUNET_GNSRECORD_Filter filter;
200
201 /**
202 * Task active during initial iteration.
203 */
204 struct GNUNET_SCHEDULER_Task *task;
205
206 /**
207 * Task to warn about slow monitors.
208 */
209 struct GNUNET_SCHEDULER_Task *sa_wait_warning;
210
211 /**
212 * Since when are we blocked on this monitor?
213 */
214 struct GNUNET_TIME_Absolute sa_waiting_start;
215
216 /**
217 * Last sequence number in the zone iteration used to address next
218 * result of the zone iteration in the store
219 *
220 * Initially set to 0.
221 * Updated in #monitor_iterate_cb()
222 */
223 uint64_t seq;
224
225 /**
226 * Current limit of how many more messages we are allowed
227 * to queue to this monitor.
228 */
229 uint64_t limit;
230
231 /**
232 * How many more requests may we receive from the iterator
233 * before it is at the limit we gave it? Will be below or
234 * equal to @e limit. The effective limit for monitor
235 * events is thus @e iteration_cnt - @e limit!
236 */
237 uint64_t iteration_cnt;
238
239 /**
240 * Are we (still) in the initial iteration pass?
241 */
242 int in_first_iteration;
243
244 /**
245 * Run again because we skipped an orphan
246 */
247 int run_again;
248
249 /**
250 * Is there a store activity waiting for this monitor? We only raise the
251 * flag when it happens and search the DLL for the store activity when we
252 * had a limit increase. If we cannot find any waiting store activity at
253 * that time, we clear the flag again.
254 */
255 int sa_waiting;
256};
257
258
259
260/**
261 * Information for an ongoing #handle_record_store() operation.
262 * Needed as we may wait for monitors to be ready for the notification.
263 */
264struct StoreActivity
265{
266 /**
267 * Kept in a DLL.
268 */
269 struct StoreActivity *next;
270
271 /**
272 * Kept in a DLL.
273 */
274 struct StoreActivity *prev;
275
276 /**
277 * Which client triggered the store activity?
278 */
279 struct NamestoreClient *nc;
280
281 /**
282 * The request ID
283 */
284 uint32_t rid;
285
286 /**
287 * The currently processed record
288 */
289 uint16_t rd_set_pos;
290
291 /**
292 * The number of records in this activity
293 */
294 uint16_t rd_set_count;
295
296 /**
297 * Wheather or not this store action is already commited.
298 * The store activity will not be processed unless this field is GNUNET_YES
299 */
300 int uncommited;
301
302 /**
303 * The zone private key
304 */
305 struct GNUNET_CRYPTO_PrivateKey private_key;
306
307 /**
308 * Copy of the original record set (as data fields in @e rd will
309 * point into it!).
310 */
311 const struct RecordSet *rs;
312
313 /**
314 * Next zone monitor that still needs to be notified about this PUT.
315 */
316 struct ZoneMonitor *zm_pos;
317
318};
319
320
321/**
322 * Entry in list of cached nick resolutions.
323 */
324struct NickCache
325{
326 /**
327 * Zone the cache entry is for.
328 */
329 struct GNUNET_CRYPTO_PrivateKey zone;
330
331 /**
332 * Cached record data.
333 */
334 struct GNUNET_GNSRECORD_Data *rd;
335
336 /**
337 * Timestamp when this cache entry was used last.
338 */
339 struct GNUNET_TIME_Absolute last_used;
340};
341
342/**
343 * We cache nick records to reduce DB load.
344 */
345static struct NickCache nick_cache[NC_SIZE];
346
347/**
348 * Public key of all zeros.
349 */
350static const struct GNUNET_CRYPTO_PrivateKey zero;
351
352/**
353 * Configuration handle.
354 */
355static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
356
357/**
358 * Handle to the statistics service
359 */
360static struct GNUNET_STATISTICS_Handle *statistics;
361
362/**
363 * Name of the database plugin
364 */
365static char *db_lib_name;
366
367/**
368 * Database handle for service
369 */
370struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
371
372
373/**
374 * First active zone monitor.
375 */
376static struct ZoneMonitor *monitor_head;
377
378/**
379 * Last active zone monitor.
380 */
381static struct ZoneMonitor *monitor_tail;
382
383/**
384 * Head of DLL of monitor-blocked store activities.
385 */
386static struct StoreActivity *sa_head;
387
388/**
389 * Tail of DLL of monitor-blocked store activities.
390 */
391static struct StoreActivity *sa_tail;
392
393/**
394 * Notification context shared by all monitors.
395 */
396static struct GNUNET_NotificationContext *monitor_nc;
397
398/**
399 * Returned orphaned records?
400 */
401static int return_orphaned;
402
403/**
404 * Task run during shutdown.
405 *
406 * @param cls unused
407 */
408static void
409cleanup_task (void *cls)
410{
411 (void) cls;
412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
413 if (NULL != monitor_nc)
414 {
415 GNUNET_notification_context_destroy (monitor_nc);
416 monitor_nc = NULL;
417 }
418 if (NULL != statistics)
419 {
420 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
421 statistics = NULL;
422 }
423 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
424 GNUNET_free (db_lib_name);
425 db_lib_name = NULL;
426}
427
428
429/**
430 * Release memory used by @a sa.
431 *
432 * @param sa activity to free
433 */
434static void
435free_store_activity (struct StoreActivity *sa)
436{
437 GNUNET_CONTAINER_DLL_remove (sa_head, sa_tail, sa);
438 GNUNET_free (sa);
439}
440
441/**
442 * Function called with the records for the #GNUNET_GNS_EMPTY_LABEL_AT
443 * label in the zone. Used to locate the #GNUNET_GNSRECORD_TYPE_NICK
444 * record, which (if found) is then copied to @a cls for future use.
445 *
446 * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found)
447 * @param seq sequence number of the record, MUST NOT BE ZERO
448 * @param private_key the private key of the zone (unused)
449 * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT
450 * @param rd_count number of records in @a rd
451 * @param rd records stored under @a label in the zone
452 */
453static void
454lookup_nick_it (void *cls,
455 uint64_t seq,
456 const struct GNUNET_CRYPTO_PrivateKey *private_key,
457 const char *label,
458 unsigned int rd_count,
459 const struct GNUNET_GNSRECORD_Data *rd)
460{
461 struct GNUNET_GNSRECORD_Data **res = cls;
462
463 (void) private_key;
464 GNUNET_assert (0 != seq);
465 if (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT))
466 {
467 GNUNET_break (0);
468 return;
469 }
470 for (unsigned int c = 0; c < rd_count; c++)
471 {
472 if (GNUNET_GNSRECORD_TYPE_NICK == rd[c].record_type)
473 {
474 (*res) =
475 GNUNET_malloc (rd[c].data_size + sizeof(struct GNUNET_GNSRECORD_Data));
476 (*res)->data = &(*res)[1];
477 GNUNET_memcpy ((void *) (*res)->data, rd[c].data, rd[c].data_size);
478 (*res)->data_size = rd[c].data_size;
479 (*res)->expiration_time = rd[c].expiration_time;
480 (*res)->flags = rd[c].flags;
481 (*res)->record_type = GNUNET_GNSRECORD_TYPE_NICK;
482 return;
483 }
484 }
485 (*res) = NULL;
486}
487
488
489/**
490 * Add entry to the cache for @a zone and @a nick
491 *
492 * @param zone zone key to cache under
493 * @param nick nick entry to cache
494 */
495static void
496cache_nick (const struct GNUNET_CRYPTO_PrivateKey *zone,
497 const struct GNUNET_GNSRECORD_Data *nick)
498{
499 struct NickCache *oldest;
500
501 oldest = NULL;
502 for (unsigned int i = 0; i < NC_SIZE; i++)
503 {
504 struct NickCache *pos = &nick_cache[i];
505
506 if ((NULL == oldest) ||
507 (oldest->last_used.abs_value_us > pos->last_used.abs_value_us))
508 oldest = pos;
509 if (0 == GNUNET_memcmp (zone, &pos->zone))
510 {
511 oldest = pos;
512 break;
513 }
514 }
515 GNUNET_free (oldest->rd);
516 oldest->zone = *zone;
517 if (NULL != nick)
518 {
519 oldest->rd = GNUNET_malloc (sizeof(*nick) + nick->data_size);
520 *oldest->rd = *nick;
521 oldest->rd->data = &oldest->rd[1];
522 memcpy (&oldest->rd[1], nick->data, nick->data_size);
523 }
524 else
525 {
526 oldest->rd = NULL;
527 }
528 oldest->last_used = GNUNET_TIME_absolute_get ();
529}
530
531
532/**
533 * Return the NICK record for the zone (if it exists).
534 *
535 * @param nc the namestore client
536 * @param zone private key for the zone to look for nick
537 * @return NULL if no NICK record was found
538 */
539static struct GNUNET_GNSRECORD_Data *
540get_nick_record (const struct GNUNET_CRYPTO_PrivateKey *zone)
541{
542 struct GNUNET_CRYPTO_PublicKey pub;
543 struct GNUNET_GNSRECORD_Data *nick;
544 int res;
545
546 /* check cache first */
547 for (unsigned int i = 0; i < NC_SIZE; i++)
548 {
549 struct NickCache *pos = &nick_cache[i];
550 if ((NULL != pos->rd) && (0 == GNUNET_memcmp (zone, &pos->zone)))
551 {
552 if (NULL == pos->rd)
553 return NULL;
554 nick = GNUNET_malloc (sizeof(*nick) + pos->rd->data_size);
555 *nick = *pos->rd;
556 nick->data = &nick[1];
557 memcpy (&nick[1], pos->rd->data, pos->rd->data_size);
558 pos->last_used = GNUNET_TIME_absolute_get ();
559 return nick;
560 }
561 }
562
563 nick = NULL;
564 res = GSN_database->lookup_records (GSN_database->cls,
565 zone,
566 GNUNET_GNS_EMPTY_LABEL_AT,
567 &lookup_nick_it,
568 &nick);
569 if ((GNUNET_OK != res) || (NULL == nick))
570 {
571#if ! defined(GNUNET_CULL_LOGGING)
572 static int do_log = GNUNET_LOG_CALL_STATUS;
573
574 if (0 == do_log)
575 do_log = GNUNET_get_log_call_status (GNUNET_ERROR_TYPE_DEBUG,
576 "namestore",
577 __FILE__,
578 __FUNCTION__,
579 __LINE__);
580 if (1 == do_log)
581 {
582 GNUNET_CRYPTO_key_get_public (zone, &pub);
583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
584 "No nick name set for zone `%s'\n",
585 GNUNET_GNSRECORD_z2s (&pub));
586 }
587#endif
588 /* update cache */
589 cache_nick (zone, NULL);
590 return NULL;
591 }
592
593 /* update cache */
594 cache_nick (zone, nick);
595 return nick;
596}
597
598
599/**
600 * Merge the nick record @a nick_rd with the rest of the
601 * record set given in @a rd2. Store the result in @a rdc_res
602 * and @a rd_res. The @a nick_rd's expiration time is set to
603 * the maximum expiration time of all of the records in @a rd2.
604 *
605 * @param nick_rd the nick record to integrate
606 * @param rd2_length length of the @a rd2 array
607 * @param rd2 array of records
608 * @param[out] rdc_res length of the resulting @a rd_res array
609 * @param[out] rd_res set to an array of records,
610 * including @a nick_rd and @a rd2;
611 * all of the variable-size 'data' fields in @a rd2 are
612 * allocated in the same chunk of memory!
613 */
614static void
615merge_with_nick_records (const struct GNUNET_GNSRECORD_Data *nick_rd,
616 unsigned int rd2_length,
617 const struct GNUNET_GNSRECORD_Data *rd2,
618 unsigned int *rdc_res,
619 struct GNUNET_GNSRECORD_Data **rd_res)
620{
621 uint64_t latest_expiration;
622 size_t req;
623 char *data;
624 size_t data_offset;
625 struct GNUNET_GNSRECORD_Data *target;
626
627 (*rdc_res) = 1 + rd2_length;
628 if (0 == 1 + rd2_length)
629 {
630 GNUNET_break (0);
631 (*rd_res) = NULL;
632 return;
633 }
634 req = sizeof(struct GNUNET_GNSRECORD_Data) + nick_rd->data_size;
635 for (unsigned int i = 0; i < rd2_length; i++)
636 {
637 const struct GNUNET_GNSRECORD_Data *orig = &rd2[i];
638
639 if (req + sizeof(struct GNUNET_GNSRECORD_Data) + orig->data_size < req)
640 {
641 GNUNET_break (0);
642 (*rd_res) = NULL;
643 return;
644 }
645 req += sizeof(struct GNUNET_GNSRECORD_Data) + orig->data_size;
646 }
647 target = GNUNET_malloc (req);
648 (*rd_res) = target;
649 data = (char *) &target[1 + rd2_length];
650 data_offset = 0;
651 latest_expiration = 0;
652 for (unsigned int i = 0; i < rd2_length; i++)
653 {
654 const struct GNUNET_GNSRECORD_Data *orig = &rd2[i];
655
656 if (0 != (orig->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
657 {
658 if ((GNUNET_TIME_absolute_get ().abs_value_us + orig->expiration_time) >
659 latest_expiration)
660 latest_expiration = orig->expiration_time;
661 }
662 else if (orig->expiration_time > latest_expiration)
663 latest_expiration = orig->expiration_time;
664 target[i] = *orig;
665 target[i].data = (void *) &data[data_offset];
666 GNUNET_memcpy (&data[data_offset], orig->data, orig->data_size);
667 data_offset += orig->data_size;
668 }
669 /* append nick */
670 target[rd2_length] = *nick_rd;
671 /* Mark as supplemental */
672 target[rd2_length].flags = nick_rd->flags | GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
673 target[rd2_length].expiration_time = latest_expiration;
674 target[rd2_length].data = (void *) &data[data_offset];
675 GNUNET_memcpy (&data[data_offset], nick_rd->data, nick_rd->data_size);
676 data_offset += nick_rd->data_size;
677 GNUNET_assert (req == (sizeof(struct GNUNET_GNSRECORD_Data)) * (*rdc_res)
678 + data_offset);
679}
680
681
682/**
683 * Generate a `struct LookupNameResponseMessage` and send it to the
684 * given client using the given notification context.
685 *
686 * @param nc client to unicast to
687 * @param request_id request ID to use
688 * @param zone_key zone key of the zone
689 * @param name name
690 * @param rd_count number of records in @a rd
691 * @param rd array of records
692 * @param filter record set filter
693 */
694static int
695send_lookup_response_with_filter (struct NamestoreClient *nc,
696 uint32_t request_id,
697 const struct
698 GNUNET_CRYPTO_PrivateKey *zone_key,
699 const char *name,
700 unsigned int rd_count,
701 const struct GNUNET_GNSRECORD_Data *rd,
702 enum GNUNET_GNSRECORD_Filter filter)
703{
704 struct GNUNET_MQ_Envelope *env;
705 struct RecordResultMessage *zir_msg;
706 struct GNUNET_GNSRECORD_Data *nick;
707 struct GNUNET_GNSRECORD_Data *res;
708 struct GNUNET_GNSRECORD_Data rd_nf[rd_count];
709 struct GNUNET_TIME_Absolute block_exp = GNUNET_TIME_UNIT_ZERO_ABS;;
710 unsigned int res_count;
711 unsigned int rd_nf_count;
712 size_t name_len;
713 size_t key_len;
714 ssize_t rd_ser_len;
715 char *name_tmp;
716 char *rd_ser;
717 char *emsg;
718
719 nick = get_nick_record (zone_key);
720 GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (rd_count, rd));
721
722 if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (name,
723 rd,
724 rd_count,
725 rd_nf,
726 &rd_nf_count,
727 &block_exp,
728 filter,
729 &emsg))
730 {
731 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
732 GNUNET_free (emsg);
733 GNUNET_assert (0);
734 }
735
736 /**
737 * FIXME if we ever support GNUNET_NAMESTORE_OMIT_PUBLIC,
738 * we need to omit adding this public record here
739 */
740 if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT)))
741 {
742 nick->flags =
743 (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
744 merge_with_nick_records (nick, rd_nf_count, rd_nf, &res_count, &res);
745 }
746 else
747 {
748 res_count = rd_nf_count;
749 res = (struct GNUNET_GNSRECORD_Data *) rd_nf;
750 }
751 if (NULL != nick)
752 GNUNET_free (nick);
753
754 if (0 == res_count)
755 {
756 if (rd_nf != res)
757 GNUNET_free (res);
758 return 0;
759 }
760 GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (res_count, res));
761
762
763 name_len = strlen (name) + 1;
764 rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res);
765 if (rd_ser_len < 0)
766 {
767 if (rd_nf != res)
768 GNUNET_free (res);
769 GNUNET_break (0);
770 GNUNET_SERVICE_client_drop (nc->client);
771 return 0;
772 }
773 if (((size_t) rd_ser_len) >= UINT16_MAX - name_len - sizeof(*zir_msg))
774 {
775 if (rd_nf != res)
776 GNUNET_free (res);
777 GNUNET_break (0);
778 GNUNET_SERVICE_client_drop (nc->client);
779 return 0;
780 }
781 key_len = GNUNET_CRYPTO_private_key_get_length (zone_key);
782 env = GNUNET_MQ_msg_extra (zir_msg,
783 name_len + rd_ser_len + key_len,
784 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
785 zir_msg->gns_header.r_id = htonl (request_id);
786 zir_msg->name_len = htons (name_len);
787 zir_msg->rd_count = htons (res_count);
788 zir_msg->rd_len = htons ((uint16_t) rd_ser_len);
789 zir_msg->key_len = htons (key_len);
790 GNUNET_CRYPTO_write_private_key_to_buffer (zone_key,
791 &zir_msg[1],
792 key_len);
793 zir_msg->expire = GNUNET_TIME_absolute_hton (block_exp);
794 name_tmp = (char *) &zir_msg[1] + key_len;
795 GNUNET_memcpy (name_tmp, name, name_len);
796 rd_ser = &name_tmp[name_len];
797 GNUNET_assert (
798 rd_ser_len ==
799 GNUNET_GNSRECORD_records_serialize (res_count, res, rd_ser_len, rd_ser));
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801 "Sending RECORD_RESULT message with %u records\n",
802 res_count);
803 GNUNET_STATISTICS_update (statistics,
804 "Record sets sent to clients",
805 1,
806 GNUNET_NO);
807 GNUNET_MQ_send (nc->mq, env);
808 if (rd_nf != res)
809 GNUNET_free (res);
810 return res_count;
811}
812
813/**
814 * Send response to the store request to the client.
815 *
816 * @param nc client to talk to
817 * @param ec status of the operation
818 * @param rid client's request ID
819 */
820static void
821send_store_response (struct NamestoreClient *nc,
822 enum GNUNET_ErrorCode ec,
823 uint32_t rid)
824{
825 struct GNUNET_MQ_Envelope *env;
826 struct RecordStoreResponseMessage *rcr_msg;
827
828 GNUNET_assert (NULL != nc);
829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
830 "Sending RECORD_STORE_RESPONSE message\n");
831 GNUNET_STATISTICS_update (statistics,
832 "Store requests completed",
833 1,
834 GNUNET_NO);
835 env = GNUNET_MQ_msg (rcr_msg,
836 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE);
837 rcr_msg->gns_header.r_id = htonl (rid);
838 rcr_msg->ec = htonl (ec);
839 GNUNET_MQ_send (nc->mq, env);
840}
841
842
843/**
844 * Function called once we are done with the zone iteration and
845 * allow the zone iteration client to send us more messages.
846 *
847 * @param zi zone iteration we are processing
848 */
849static void
850zone_iteration_done_client_continue (struct ZoneIteration *zi)
851{
852 struct GNUNET_MQ_Envelope *env;
853 struct GNUNET_NAMESTORE_Header *em;
854
855 GNUNET_SERVICE_client_continue (zi->nc->client);
856 if (! zi->send_end)
857 return;
858 /* send empty response to indicate end of list */
859 env = GNUNET_MQ_msg (em, GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END);
860 em->r_id = htonl (zi->request_id);
861 GNUNET_MQ_send (zi->nc->mq, env);
862
863 GNUNET_CONTAINER_DLL_remove (zi->nc->op_head, zi->nc->op_tail, zi);
864 GNUNET_free (zi);
865}
866
867
868
869
870/**
871 * Print a warning that one of our monitors is no longer reacting.
872 *
873 * @param cls a `struct ZoneMonitor` to warn about
874 */
875static void
876warn_monitor_slow (void *cls)
877{
878 struct ZoneMonitor *zm = cls;
879
880 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
881 "No response from monitor since %s\n",
882 GNUNET_STRINGS_absolute_time_to_string (zm->sa_waiting_start));
883 zm->sa_wait_warning = GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
884 &warn_monitor_slow,
885 zm);
886}
887
888
889/**
890 * Continue processing the @a sa.
891 *
892 * @param sa store activity to process
893 */
894static int
895continue_store_activity (struct StoreActivity *sa,
896 int call_continue)
897{
898 const struct RecordSet *rd_set = sa->rs;
899 unsigned int rd_count;
900 size_t name_len;
901 size_t rd_ser_len;
902 const char *name_tmp;
903 const char *rd_ser;
904 const char *buf;
905 char *conv_name;
906
907 // If we are in a transaction, do not notify monitors or update
908 // cached. This will be done when we are commiting.
909 if (GNUNET_YES == sa->uncommited)
910 {
911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
912 "Transaction not yet committed, delaying monitor and cache updates\n");
913 send_store_response (sa->nc, GNUNET_EC_NONE, sa->rid);
914 if (GNUNET_YES == call_continue)
915 GNUNET_SERVICE_client_continue (sa->nc->client);
916 return GNUNET_OK;
917 }
918 buf = (const char *) &sa[1];
919 for (int i = sa->rd_set_pos; i < sa->rd_set_count; i++)
920 {
921 rd_set = (struct RecordSet *) buf;
922 name_len = ntohs (rd_set->name_len);
923 rd_count = ntohs (rd_set->rd_count);
924 rd_ser_len = ntohs (rd_set->rd_len);
925 name_tmp = (const char *) &rd_set[1];
926 rd_ser = &name_tmp[name_len];
927 conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
928 GNUNET_assert (NULL != conv_name);
929 {
930 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
931
932 /* We did this before, must succeed again */
933 GNUNET_assert (
934 GNUNET_OK ==
935 GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count,
936 rd));
937
938 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
939 "Checking monitors watching for `%s'\n",
940 conv_name);
941 for (struct ZoneMonitor *zm = sa->zm_pos; NULL != zm; zm = sa->zm_pos)
942 {
943 if ((0 != GNUNET_memcmp (&sa->private_key, &zm->zone)) &&
944 (0 != GNUNET_memcmp (&zm->zone, &zero)))
945 {
946 sa->zm_pos = zm->next; /* not interesting to this monitor */
947 continue;
948 }
949 if (zm->limit == zm->iteration_cnt)
950 {
951 zm->sa_waiting = GNUNET_YES;
952 zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
953 if (NULL != zm->sa_wait_warning)
954 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
955 zm->sa_wait_warning =
956 GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
957 &warn_monitor_slow,
958 zm);
959 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
960 "Monitor is blocking client for `%s'\n",
961 conv_name);
962 GNUNET_free (conv_name);
963 return GNUNET_NO; /* blocked on zone monitor */
964 }
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966 "Notifying monitor about changes under label `%s'\n",
967 conv_name);
968 if (0 < send_lookup_response_with_filter (zm->nc,
969 0,
970 &sa->private_key,
971 conv_name,
972 rd_count,
973 rd,
974 zm->filter))
975 zm->limit--;
976 sa->zm_pos = zm->next;
977 }
978 sa->rd_set_pos++;
979 GNUNET_free (conv_name);
980 }
981 }
982 if (GNUNET_YES == call_continue)
983 GNUNET_SERVICE_client_continue (sa->nc->client);
984 send_store_response (sa->nc, GNUNET_EC_NONE, sa->rid);
985 free_store_activity (sa);
986 return GNUNET_OK;
987}
988
989
990/**
991 * Called whenever a client is disconnected.
992 * Frees our resources associated with that client.
993 *
994 * @param cls closure
995 * @param client identification of the client
996 * @param app_ctx the `struct NamestoreClient` of @a client
997 */
998static void
999client_disconnect_cb (void *cls,
1000 struct GNUNET_SERVICE_Client *client,
1001 void *app_ctx)
1002{
1003 struct NamestoreClient *nc = app_ctx;
1004 struct ZoneIteration *no;
1005 struct StoreActivity *sa = sa_head;
1006 struct StoreActivity *sn;
1007 char *emsg;
1008
1009 (void) cls;
1010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
1011 if (GNUNET_YES == nc->in_transaction)
1012 {
1013 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1014 "Client in transaction, rolling back...\n");
1015 if (GNUNET_SYSERR == nc->GSN_database->transaction_rollback (
1016 nc->GSN_database->cls,
1017 &emsg))
1018 {
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020 "Unable to roll back: %s\n", emsg);
1021 GNUNET_free (emsg);
1022 }
1023 else
1024 {
1025 nc->in_transaction = GNUNET_NO;
1026 while (NULL != sa)
1027 {
1028 if ((nc != sa->nc) ||
1029 (GNUNET_NO == sa->uncommited))
1030 {
1031 sa = sa->next;
1032 continue;
1033 }
1034 sn = sa->next;
1035 free_store_activity (sa);
1036 sa = sn;
1037 }
1038 }
1039 }
1040 for (struct ZoneMonitor *zm = monitor_head; NULL != zm; zm = zm->next)
1041 {
1042 if (nc != zm->nc)
1043 continue;
1044 GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, zm);
1045 if (NULL != zm->task)
1046 {
1047 GNUNET_SCHEDULER_cancel (zm->task);
1048 zm->task = NULL;
1049 }
1050 if (NULL != zm->sa_wait_warning)
1051 {
1052 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
1053 zm->sa_wait_warning = NULL;
1054 }
1055 for (sa = sa_head; NULL != sa; sa = sn)
1056 {
1057 sn = sa->next;
1058 if (zm == sa->zm_pos)
1059 {
1060 sa->zm_pos = zm->next;
1061 /* this may free sa */
1062 continue_store_activity (sa, GNUNET_YES);
1063 }
1064 }
1065 GNUNET_free (zm);
1066 break;
1067 }
1068 sa = sa_head;
1069 while (NULL != sa)
1070 {
1071 if (nc != sa->nc)
1072 {
1073 sa = sa->next;
1074 continue;
1075 }
1076 sn = sa->next;
1077 free_store_activity (sa);
1078 sa = sn;
1079 }
1080 while (NULL != (no = nc->op_head))
1081 {
1082 GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
1083 GNUNET_free (no);
1084 }
1085 GNUNET_break (NULL == GNUNET_PLUGIN_unload (nc->db_lib_name,
1086 nc->GSN_database));
1087 GNUNET_free (nc->db_lib_name);
1088 GNUNET_free (nc);
1089}
1090
1091
1092/**
1093 * Add a client to our list of active clients.
1094 *
1095 * @param cls NULL
1096 * @param client client to add
1097 * @param mq message queue for @a client
1098 * @return internal namestore client structure for this client
1099 */
1100static void *
1101client_connect_cb (void *cls,
1102 struct GNUNET_SERVICE_Client *client,
1103 struct GNUNET_MQ_Handle *mq)
1104{
1105 struct NamestoreClient *nc;
1106 char *database;
1107
1108 (void) cls;
1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
1110 nc = GNUNET_new (struct NamestoreClient);
1111 nc->client = client;
1112 nc->mq = mq;
1113 /* Loading database plugin */
1114 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (GSN_cfg,
1115 "namestore",
1116 "database",
1117 &database))
1118 {
1119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
1120 GNUNET_free (nc);
1121 return NULL;
1122 }
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading %s\n", db_lib_name);
1124 nc->GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
1125 GNUNET_free (database);
1126 if (NULL == nc->GSN_database)
1127 {
1128 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1129 "Could not load database backend `%s'\n",
1130 db_lib_name);
1131 GNUNET_free (nc);
1132 return NULL;
1133 }
1134 nc->db_lib_name = GNUNET_strdup (db_lib_name);
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded %s\n", db_lib_name);
1136 return nc;
1137}
1138
1139
1140/**
1141 * Closure for #lookup_it().
1142 */
1143struct RecordLookupContext
1144{
1145 /**
1146 * The label to look up.
1147 */
1148 const char *label;
1149
1150 /**
1151 * The record result.
1152 */
1153 char *res_rd;
1154
1155 /**
1156 * The nick for the zone.
1157 */
1158 struct GNUNET_GNSRECORD_Data *nick;
1159
1160 /**
1161 * If a record set was found or not.
1162 */
1163 int found;
1164
1165 /**
1166 * The record filter
1167 */
1168 enum GNUNET_GNSRECORD_Filter filter;
1169
1170 /**
1171 * The number of found records.
1172 */
1173 unsigned int res_rd_count;
1174
1175 /**
1176 * The length of the serialized records.
1177 */
1178 ssize_t rd_ser_len;
1179};
1180
1181
1182/**
1183 * Function called by the namestore plugin when we are trying to lookup
1184 * a record as part of #handle_record_lookup(). Merges all results into
1185 * the context.
1186 *
1187 * @param cls closure with a `struct RecordLookupContext`
1188 * @param seq unique serial number of the record, MUST NOT BE ZERO
1189 * @param private_key private key of the zone
1190 * @param label name that is being mapped (at most 255 characters long)
1191 * @param rd_count number of entries in @a rd array
1192 * @param rd array of records with data to store
1193 */
1194static void
1195lookup_it (void *cls,
1196 uint64_t seq,
1197 const struct GNUNET_CRYPTO_PrivateKey *private_key,
1198 const char *label,
1199 unsigned int rd_count_nf,
1200 const struct GNUNET_GNSRECORD_Data *rd_nf)
1201{
1202 struct RecordLookupContext *rlc = cls;
1203 struct GNUNET_GNSRECORD_Data rd[rd_count_nf];
1204 struct GNUNET_TIME_Absolute block_exp;
1205 unsigned int rd_count = 0;
1206 char *emsg;
1207
1208 (void) private_key;
1209 GNUNET_assert (0 != seq);
1210 if (0 != strcmp (label, rlc->label))
1211 return;
1212 rlc->found = GNUNET_YES;
1213
1214 if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (rlc->label,
1215 rd_nf,
1216 rd_count_nf,
1217 rd,
1218 &rd_count,
1219 &block_exp,
1220 rlc->filter,
1221 &emsg))
1222 {
1223 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1224 GNUNET_free (emsg);
1225 GNUNET_assert (0);
1226 }
1227
1228 if (0 == rd_count)
1229 {
1230 rlc->rd_ser_len = 0;
1231 rlc->res_rd_count = 0;
1232 rlc->res_rd = NULL;
1233 return;
1234 }
1235 if ((NULL != rlc->nick) && (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT)))
1236 {
1237 /* Merge */
1238 struct GNUNET_GNSRECORD_Data *rd_res;
1239 unsigned int rdc_res;
1240
1241 rd_res = NULL;
1242 rdc_res = 0;
1243 rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE)
1244 ^ GNUNET_GNSRECORD_RF_PRIVATE;
1245 merge_with_nick_records (rlc->nick, rd_count, rd, &rdc_res, &rd_res);
1246 rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res, rd_res);
1247 if (rlc->rd_ser_len < 0)
1248 {
1249 GNUNET_break (0);
1250 GNUNET_free (rd_res);
1251 rlc->found = GNUNET_NO;
1252 rlc->rd_ser_len = 0;
1253 return;
1254 }
1255 rlc->res_rd_count = rdc_res;
1256 rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
1257 if (rlc->rd_ser_len != GNUNET_GNSRECORD_records_serialize (rdc_res,
1258 rd_res,
1259 rlc->rd_ser_len,
1260 rlc->res_rd))
1261 {
1262 GNUNET_break (0);
1263 GNUNET_free (rlc->res_rd);
1264 rlc->res_rd = NULL;
1265 rlc->res_rd_count = 0;
1266 rlc->rd_ser_len = 0;
1267 GNUNET_free (rd_res);
1268 rlc->found = GNUNET_NO;
1269 return;
1270 }
1271 GNUNET_free (rd_res);
1272 GNUNET_free (rlc->nick);
1273 rlc->nick = NULL;
1274 }
1275 else
1276 {
1277 rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1278 if (rlc->rd_ser_len < 0)
1279 {
1280 GNUNET_break (0);
1281 rlc->found = GNUNET_NO;
1282 rlc->rd_ser_len = 0;
1283 return;
1284 }
1285 rlc->res_rd_count = rd_count;
1286 rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
1287 if (rlc->rd_ser_len != GNUNET_GNSRECORD_records_serialize (rd_count,
1288 rd,
1289 rlc->rd_ser_len,
1290 rlc->res_rd))
1291 {
1292 GNUNET_break (0);
1293 GNUNET_free (rlc->res_rd);
1294 rlc->res_rd = NULL;
1295 rlc->res_rd_count = 0;
1296 rlc->rd_ser_len = 0;
1297 rlc->found = GNUNET_NO;
1298 return;
1299 }
1300 }
1301}
1302
1303
1304/**
1305 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
1306 *
1307 * @param cls client sending the message
1308 * @param ll_msg message of type `struct LabelLookupMessage`
1309 * @return #GNUNET_OK if @a ll_msg is well-formed
1310 */
1311static int
1312check_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg)
1313{
1314 uint32_t name_len;
1315 size_t src_size;
1316 size_t key_len;
1317
1318 (void) cls;
1319 name_len = ntohs (ll_msg->label_len);
1320 key_len = ntohs (ll_msg->key_len);
1321 src_size = ntohs (ll_msg->gns_header.header.size);
1322 if (name_len + key_len != src_size - sizeof(struct LabelLookupMessage))
1323 {
1324 GNUNET_break (0);
1325 return GNUNET_SYSERR;
1326 }
1327 return GNUNET_OK;
1328}
1329
1330
1331/**
1332 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
1333 *
1334 * @param cls client sending the message
1335 * @param ll_msg message of type `struct LabelLookupMessage`
1336 */
1337static void
1338handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg)
1339{
1340 struct GNUNET_CRYPTO_PrivateKey zone;
1341 struct NamestoreClient *nc = cls;
1342 struct GNUNET_MQ_Envelope *env;
1343 struct LabelLookupResponseMessage *llr_msg;
1344 struct RecordLookupContext rlc;
1345 const char *name_tmp;
1346 char *res_name;
1347 char *conv_name;
1348 uint32_t name_len;
1349 int res;
1350 size_t key_len;
1351 size_t kb_read;
1352
1353 key_len = ntohs (ll_msg->key_len);
1354 if ((GNUNET_SYSERR ==
1355 GNUNET_CRYPTO_read_private_key_from_buffer (&ll_msg[1],
1356 key_len,
1357 &zone,
1358 &kb_read)) ||
1359 (kb_read != key_len))
1360 {
1361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1362 "Error reading private key\n");
1363 GNUNET_SERVICE_client_drop (nc->client);
1364 return;
1365 }
1366 name_tmp = (const char *) &ll_msg[1] + key_len;
1367 GNUNET_SERVICE_client_continue (nc->client);
1368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1369 "Received NAMESTORE_RECORD_LOOKUP message for name `%s'\n",
1370 name_tmp);
1371
1372 conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
1373 if (NULL == conv_name)
1374 {
1375 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1376 "Error converting name `%s'\n",
1377 name_tmp);
1378 GNUNET_SERVICE_client_drop (nc->client);
1379 return;
1380 }
1381 name_len = strlen (conv_name) + 1;
1382 rlc.label = conv_name;
1383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1384 "Looking up with filter %u\n", ntohs (ll_msg->filter));
1385 rlc.filter = ntohs (ll_msg->filter);
1386 rlc.found = GNUNET_NO;
1387 rlc.res_rd_count = 0;
1388 rlc.res_rd = NULL;
1389 rlc.rd_ser_len = 0;
1390 rlc.nick = get_nick_record (&zone);
1391 if (GNUNET_YES != ntohs (ll_msg->is_edit_request))
1392 res = nc->GSN_database->lookup_records (nc->GSN_database->cls,
1393 &zone,
1394 conv_name,
1395 &lookup_it,
1396 &rlc);
1397 else
1398 res = nc->GSN_database->edit_records (nc->GSN_database->cls,
1399 &zone,
1400 conv_name,
1401 &lookup_it,
1402 &rlc);
1403
1404 env =
1405 GNUNET_MQ_msg_extra (llr_msg,
1406 key_len + name_len + rlc.rd_ser_len,
1407 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE);
1408 llr_msg->gns_header.r_id = ll_msg->gns_header.r_id;
1409 GNUNET_memcpy (&llr_msg[1], &ll_msg[1], key_len);
1410 llr_msg->key_len = ll_msg->key_len;
1411 llr_msg->name_len = htons (name_len);
1412 llr_msg->rd_count = htons (rlc.res_rd_count);
1413 llr_msg->rd_len = htons (rlc.rd_ser_len);
1414 llr_msg->reserved = htons (0);
1415 res_name = ((char *) &llr_msg[1]) + key_len;
1416 if (GNUNET_YES == rlc.found)
1417 llr_msg->found = htons (GNUNET_YES);
1418 else if (GNUNET_SYSERR == res)
1419 llr_msg->found = htons (GNUNET_SYSERR);
1420 else
1421 llr_msg->found = htons (GNUNET_NO);
1422 GNUNET_memcpy (res_name, conv_name, name_len);
1423 GNUNET_memcpy (&res_name[name_len], rlc.res_rd, rlc.rd_ser_len);
1424 GNUNET_MQ_send (nc->mq, env);
1425 GNUNET_free (rlc.res_rd);
1426 GNUNET_free (conv_name);
1427}
1428
1429
1430
1431/**
1432 * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
1433 *
1434 * @param cls client sending the message
1435 * @param rp_msg message of type `struct RecordStoreMessage`
1436 * @return #GNUNET_OK if @a rp_msg is well-formed
1437 */
1438static int
1439check_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1440{
1441 size_t msg_size;
1442 size_t min_size_exp;
1443 size_t rd_set_count;
1444 size_t key_len;
1445
1446 (void) cls;
1447 msg_size = ntohs (rp_msg->gns_header.header.size);
1448 rd_set_count = ntohs (rp_msg->rd_set_count);
1449 key_len = ntohs (rp_msg->key_len);
1450
1451 min_size_exp = sizeof(*rp_msg) + key_len + sizeof (struct RecordSet)
1452 * rd_set_count;
1453 if (msg_size < min_size_exp)
1454 {
1455 GNUNET_break (0);
1456 return GNUNET_SYSERR;
1457 }
1458 return GNUNET_OK;
1459}
1460
1461struct LookupExistingRecordsContext
1462{
1463
1464 /**
1465 * The expiration of the existing records or tombstone
1466 */
1467 struct GNUNET_TIME_Absolute exp;
1468
1469 /**
1470 * Whether the existing record set consists only of a tombstone
1471 * (e.g. is "empty")
1472 */
1473 int only_tombstone;
1474
1475};
1476
1477
1478/**
1479 * Check if set contains a tombstone, store if necessary
1480 *
1481 * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found)
1482 * @param seq sequence number of the record, MUST NOT BE ZERO
1483 * @param private_key the private key of the zone (unused)
1484 * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT
1485 * @param rd_count number of records in @a rd
1486 * @param rd records stored under @a label in the zone
1487 */
1488static void
1489get_existing_rd_exp (void *cls,
1490 uint64_t seq,
1491 const struct
1492 GNUNET_CRYPTO_PrivateKey *private_key,
1493 const char *label,
1494 unsigned int rd_count,
1495 const struct GNUNET_GNSRECORD_Data *rd)
1496{
1497 struct LookupExistingRecordsContext *lctx = cls;
1498 struct GNUNET_GNSRECORD_Data rd_pub[rd_count];
1499 unsigned int rd_pub_count;
1500 char *emsg;
1501
1502 if ((1 == rd_count) &&
1503 (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[0].record_type))
1504 {
1505 /* This record set contains only a tombstone! */
1506 lctx->only_tombstone = GNUNET_YES;
1507 }
1508 if (GNUNET_OK !=
1509 GNUNET_GNSRECORD_normalize_record_set (label,
1510 rd,
1511 rd_count,
1512 rd_pub,
1513 &rd_pub_count,
1514 &lctx->exp,
1515 GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE,
1516 &emsg))
1517 {
1518 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1519 "%s\n", emsg);
1520 GNUNET_free (emsg);
1521 }
1522}
1523
1524static enum GNUNET_ErrorCode
1525store_record_set (struct NamestoreClient *nc,
1526 const struct GNUNET_CRYPTO_PrivateKey *private_key,
1527 const struct RecordSet *rd_set,
1528 ssize_t *len)
1529{
1530 size_t name_len;
1531 size_t rd_ser_len;
1532 const char *name_tmp;
1533 const char *rd_ser;
1534 char *conv_name;
1535 char *emsg;
1536 unsigned int rd_count;
1537 int res;
1538 enum GNUNET_ErrorCode ec;
1539 struct GNUNET_TIME_Absolute new_block_exp;
1540 struct LookupExistingRecordsContext lctx;
1541 *len = sizeof (struct RecordSet);
1542
1543 ec = GNUNET_EC_NONE;
1544 lctx.only_tombstone = GNUNET_NO;
1545 lctx.exp = GNUNET_TIME_UNIT_ZERO_ABS;
1546 new_block_exp = GNUNET_TIME_UNIT_ZERO_ABS;
1547 name_len = ntohs (rd_set->name_len);
1548 *len += name_len;
1549 rd_count = ntohs (rd_set->rd_count);
1550 rd_ser_len = ntohs (rd_set->rd_len);
1551 *len += rd_ser_len;
1552 name_tmp = (const char *) &rd_set[1];
1553 rd_ser = &name_tmp[name_len];
1554 {
1555 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
1556
1557 /* Extracting and converting private key */
1558 conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
1559 if (NULL == conv_name)
1560 {
1561 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1562 "Error normalizing name `%s'\n",
1563 name_tmp);
1564 return GNUNET_EC_NAMESTORE_LABEL_INVALID;
1565 }
1566
1567 /* Check name for validity */
1568 if (GNUNET_OK != GNUNET_GNSRECORD_label_check (conv_name, &emsg))
1569 {
1570 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1571 "Label invalid: `%s'\n",
1572 emsg);
1573 GNUNET_free (emsg);
1574 GNUNET_free (conv_name);
1575 return GNUNET_EC_NAMESTORE_LABEL_INVALID;
1576 }
1577
1578 if (GNUNET_OK !=
1579 GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count,
1580 rd))
1581 {
1582 GNUNET_free (conv_name);
1583 return GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
1584 }
1585
1586 GNUNET_STATISTICS_update (statistics,
1587 "Well-formed store requests received",
1588 1,
1589 GNUNET_NO);
1590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1591 "Creating %u records for name `%s'\n",
1592 (unsigned int) rd_count,
1593 conv_name);
1594 if ((GNUNET_NO == nc->GSN_database->lookup_records (nc->GSN_database->cls,
1595 private_key,
1596 conv_name,
1597 &get_existing_rd_exp,
1598 &lctx))
1599 &&
1600 (rd_count == 0))
1601 {
1602 /* This name does not exist, so cannot be removed */
1603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604 "Name `%s' does not exist, no deletion required\n",
1605 conv_name);
1606 res = GNUNET_NO;
1607 ec = GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND;
1608 }
1609 else
1610 {
1611 /* remove "NICK" records, unless this is for the
1612 #GNUNET_GNS_EMPTY_LABEL_AT label
1613 We may need one additional record later for tombstone.
1614 FIXME: Since we must normalize the record set (check for
1615 consistency etc) we have to iterate the set twice.
1616 May be inefficient.
1617 We cannot really move the nick caching into GNSRECORD.
1618 */
1619 struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL (rd_count)];
1620 struct GNUNET_GNSRECORD_Data rd_nf[GNUNET_NZL (rd_count) + 1];
1621 unsigned int rd_clean_off;
1622 unsigned int rd_nf_count;
1623 int have_nick;
1624
1625 rd_clean_off = 0;
1626 have_nick = GNUNET_NO;
1627 for (unsigned int i = 0; i < rd_count; i++)
1628 {
1629 rd_clean[rd_clean_off] = rd[i];
1630
1631 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) ||
1632 (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type))
1633 rd_clean_off++;
1634
1635 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) &&
1636 (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type))
1637 {
1638 // FIXME: In case this is an uncommited transaction,
1639 // we should not do this here. Can we do this in the store activity?
1640 cache_nick (private_key, &rd[i]);
1641 have_nick = GNUNET_YES;
1642 }
1643 }
1644 if (GNUNET_OK !=
1645 GNUNET_GNSRECORD_normalize_record_set (conv_name,
1646 rd_clean,
1647 rd_clean_off,
1648 rd_nf,
1649 &rd_nf_count,
1650 &new_block_exp,
1651 GNUNET_GNSRECORD_FILTER_NONE,
1652 &emsg))
1653 {
1654 GNUNET_free (conv_name);
1655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1656 "Error normalizing record set: `%s'\n",
1657 emsg);
1658 GNUNET_free (emsg);
1659 return GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
1660 }
1661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1662 "%u/%u records before tombstone\n", rd_nf_count,
1663 rd_clean_off);
1664 /*
1665 * If existing_block_exp is 0, then there was no record set
1666 * and no tombstone.
1667 * Otherwise, if the existing block expiration is after the
1668 * new block expiration would be, we need to add a tombstone
1669 * or update it.
1670 */
1671 if (GNUNET_TIME_absolute_cmp (new_block_exp, <=, lctx.exp))
1672 {
1673 rd_nf[rd_nf_count].record_type = GNUNET_GNSRECORD_TYPE_TOMBSTONE;
1674 rd_nf[rd_nf_count].expiration_time =
1675 lctx.exp.abs_value_us;
1676 rd_nf[rd_nf_count].data = NULL;
1677 rd_nf[rd_nf_count].data_size = 0;
1678 rd_nf[rd_nf_count].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1679 rd_nf_count++;
1680 }
1681 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) &&
1682 (GNUNET_NO == have_nick))
1683 {
1684 /* remove nick record from cache, in case we have one there */
1685 // FIXME: In case this is an uncommited transaction,
1686 // we should not do this here. Can we do this in the store activity?
1687 cache_nick (private_key, NULL);
1688 }
1689 res = nc->GSN_database->store_records (nc->GSN_database->cls,
1690 private_key,
1691 conv_name,
1692 rd_nf_count,
1693 rd_nf);
1694 /* If after a store there is only a TOMBSTONE left, and
1695 * there was >1 record under this label found (the tombstone; indicated
1696 * through res != GNUNET_NO) then we should return "NOT FOUND" == GNUNET_NO
1697 */
1698 if ((GNUNET_SYSERR != res) &&
1699 (0 == rd_count) &&
1700 (1 == rd_nf_count) &&
1701 (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd_nf[0].record_type) &&
1702 (GNUNET_YES == lctx.only_tombstone))
1703 {
1704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705 "Client tried to remove non-existant record\n");
1706 ec = GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND;
1707 }
1708 }
1709
1710 if (GNUNET_SYSERR == res)
1711 {
1712 /* store not successful, no need to tell monitors */
1713 GNUNET_free (conv_name);
1714 return GNUNET_EC_NAMESTORE_STORE_FAILED;
1715 }
1716 }
1717 GNUNET_free (conv_name);
1718 return ec;
1719}
1720
1721/**
1722 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
1723 *
1724 * @param cls client sending the message
1725 * @param rp_msg message of type `struct RecordStoreMessage`
1726 */
1727static void
1728handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1729{
1730 struct GNUNET_CRYPTO_PrivateKey zone;
1731 struct NamestoreClient *nc = cls;
1732 uint32_t rid;
1733 uint16_t rd_set_count;
1734 const char *buf;
1735 ssize_t read;
1736 size_t key_len;
1737 size_t kb_read;
1738 size_t rp_msg_len;
1739 size_t rs_len;
1740 size_t rs_off;
1741 struct StoreActivity *sa;
1742 struct RecordSet *rs;
1743 enum GNUNET_ErrorCode res;
1744
1745 key_len = ntohs (rp_msg->key_len);
1746 rp_msg_len = ntohs (rp_msg->gns_header.header.size);
1747 rs_off = sizeof (*rp_msg) + key_len;
1748 rs_len = rp_msg_len - rs_off;
1749 if ((GNUNET_SYSERR ==
1750 GNUNET_CRYPTO_read_private_key_from_buffer (&rp_msg[1],
1751 key_len,
1752 &zone,
1753 &kb_read)) ||
1754 (kb_read != key_len))
1755 {
1756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1757 "Error reading private key\n");
1758 GNUNET_SERVICE_client_drop (nc->client);
1759 return;
1760 }
1761 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1762 "Received NAMESTORE_RECORD_STORE message\n");
1763 rid = ntohl (rp_msg->gns_header.r_id);
1764 rd_set_count = ntohs (rp_msg->rd_set_count);
1765 buf = (const char *) rp_msg + rs_off;
1766 for (int i = 0; i < rd_set_count; i++)
1767 {
1768 rs = (struct RecordSet *) buf;
1769 res = store_record_set (nc, &zone,
1770 rs, &read);
1771 if (GNUNET_EC_NONE != res)
1772 {
1773 send_store_response (nc, res, rid);
1774 GNUNET_SERVICE_client_continue (nc->client);
1775 return;
1776 }
1777 buf += read;
1778 }
1779 sa = GNUNET_malloc (sizeof(struct StoreActivity) + rs_len);
1780 GNUNET_CONTAINER_DLL_insert (sa_head, sa_tail, sa);
1781 sa->nc = nc;
1782 sa->rs = (struct RecordSet *) &sa[1];
1783 sa->rd_set_count = rd_set_count;
1784 GNUNET_memcpy (&sa[1], (char *) rp_msg + rs_off, rs_len);
1785 sa->rid = rid;
1786 sa->rd_set_pos = 0;
1787 sa->private_key = zone;
1788 sa->zm_pos = monitor_head;
1789 sa->uncommited = nc->in_transaction;
1790 continue_store_activity (sa, GNUNET_YES);
1791}
1792
1793static void
1794send_tx_response (int rid, enum GNUNET_ErrorCode ec, struct NamestoreClient *nc)
1795{
1796 struct TxControlResultMessage *txr_msg;
1797 struct GNUNET_MQ_Envelope *env;
1798
1799 env =
1800 GNUNET_MQ_msg (txr_msg, GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL_RESULT);
1801 txr_msg->gns_header.r_id = rid;
1802 txr_msg->ec = htonl (ec);
1803 GNUNET_MQ_send (nc->mq, env);
1804}
1805
1806/**
1807 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL message
1808 *
1809 * @param cls client sending the message
1810 * @param tx_msg message of type `struct TxControlMessage`
1811 */
1812static void
1813handle_tx_control (void *cls, const struct TxControlMessage *tx_msg)
1814{
1815 struct NamestoreClient *nc = cls;
1816 struct StoreActivity *sa = sa_head;
1817 struct StoreActivity *sn;
1818 enum GNUNET_GenericReturnValue ret;
1819 char *emsg = NULL;
1820 int blocked = GNUNET_NO;
1821
1822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received TX_CONTROL message\n");
1823
1824 switch (ntohs (tx_msg->control))
1825 {
1826 case GNUNET_NAMESTORE_TX_BEGIN:
1827 ret = nc->GSN_database->transaction_begin (nc->GSN_database->cls,
1828 &emsg);
1829 send_tx_response (tx_msg->gns_header.r_id,
1830 (GNUNET_SYSERR == ret) ?
1831 GNUNET_EC_NAMESTORE_BACKEND_FAILED : GNUNET_EC_NONE, nc);
1832 if (GNUNET_SYSERR == ret)
1833 {
1834 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1835 "Databse backend error: `%s'", emsg);
1836 GNUNET_free (emsg);
1837 }
1838 GNUNET_SERVICE_client_continue (nc->client);
1839 nc->in_transaction = GNUNET_YES;
1840 break;
1841 case GNUNET_NAMESTORE_TX_COMMIT:
1842 ret = nc->GSN_database->transaction_commit (nc->GSN_database->cls,
1843 &emsg);
1844 send_tx_response (tx_msg->gns_header.r_id,
1845 (GNUNET_SYSERR == ret) ?
1846 GNUNET_EC_NAMESTORE_BACKEND_FAILED : GNUNET_EC_NONE,
1847 nc);
1848 if (GNUNET_SYSERR == ret)
1849 {
1850 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1851 "Databse backend error: `%s'", emsg);
1852 GNUNET_free (emsg);
1853 }
1854 if (GNUNET_SYSERR != ret)
1855 {
1856 nc->in_transaction = GNUNET_NO;
1857 while (NULL != sa)
1858 {
1859 if ((nc != sa->nc) ||
1860 (GNUNET_NO == sa->uncommited))
1861 {
1862 sa = sa->next;
1863 continue;
1864 }
1865 sa->uncommited = GNUNET_NO;
1866 sn = sa->next;
1867 if (GNUNET_OK != continue_store_activity (sa, GNUNET_NO))
1868 blocked = GNUNET_YES;
1869 sa = sn;
1870 }
1871 if (GNUNET_YES != blocked)
1872 GNUNET_SERVICE_client_continue (nc->client);
1873 }
1874 break;
1875 case GNUNET_NAMESTORE_TX_ROLLBACK:
1876 ret = nc->GSN_database->transaction_rollback (nc->GSN_database->cls,
1877 &emsg);
1878 send_tx_response (tx_msg->gns_header.r_id,
1879 (GNUNET_SYSERR == ret) ?
1880 GNUNET_EC_NAMESTORE_BACKEND_FAILED : GNUNET_EC_NONE, nc);
1881 GNUNET_SERVICE_client_continue (nc->client);
1882 if (GNUNET_SYSERR == ret)
1883 {
1884 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1885 "Databse backend error: `%s'", emsg);
1886 GNUNET_free (emsg);
1887 }
1888 if (GNUNET_SYSERR != ret)
1889 {
1890 nc->in_transaction = GNUNET_NO;
1891 while (NULL != sa)
1892 {
1893 if ((nc != sa->nc) ||
1894 (GNUNET_NO == sa->uncommited))
1895 {
1896 sa = sa->next;
1897 continue;
1898 }
1899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1900 "Discarding uncommited StoreActivity\n");
1901 sn = sa->next;
1902 free_store_activity (sa);
1903 sa = sn;
1904 }
1905 }
1906 break;
1907 default:
1908 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1909 "Unknown control type %u\n", ntohs (tx_msg->control));
1910 GNUNET_break (0);
1911 }
1912}
1913
1914/**
1915 * Context for record remove operations passed from #handle_zone_to_name to
1916 * #handle_zone_to_name_it as closure
1917 */
1918struct ZoneToNameCtx
1919{
1920 /**
1921 * Namestore client
1922 */
1923 struct NamestoreClient *nc;
1924
1925 /**
1926 * Request id (to be used in the response to the client).
1927 */
1928 uint32_t rid;
1929
1930 /**
1931 * Set to #GNUNET_OK on success, #GNUNET_SYSERR on error. Note that
1932 * not finding a name for the zone still counts as a 'success' here,
1933 * as this field is about the success of executing the IPC protocol.
1934 */
1935 enum GNUNET_ErrorCode ec;
1936};
1937
1938
1939/**
1940 * Zone to name iterator
1941 *
1942 * @param cls struct ZoneToNameCtx *
1943 * @param seq sequence number of the record, MUST NOT BE ZERO
1944 * @param zone_key the zone key
1945 * @param name name
1946 * @param rd_count number of records in @a rd
1947 * @param rd record data
1948 */
1949static void
1950handle_zone_to_name_it (void *cls,
1951 uint64_t seq,
1952 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
1953 const char *name,
1954 unsigned int rd_count,
1955 const struct GNUNET_GNSRECORD_Data *rd)
1956{
1957 struct ZoneToNameCtx *ztn_ctx = cls;
1958 struct GNUNET_MQ_Envelope *env;
1959 struct ZoneToNameResponseMessage *ztnr_msg;
1960 size_t name_len;
1961 size_t key_len;
1962 ssize_t rd_ser_len;
1963 size_t msg_size;
1964 char *name_tmp;
1965 char *rd_tmp;
1966
1967 GNUNET_assert (0 != seq);
1968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1969 "Found result for zone-to-name lookup: `%s'\n",
1970 name);
1971 ztn_ctx->ec = GNUNET_EC_NONE;
1972 name_len = (NULL == name) ? 0 : strlen (name) + 1;
1973 rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1974 if (rd_ser_len < 0)
1975 {
1976 GNUNET_break (0);
1977 ztn_ctx->ec = htonl (GNUNET_EC_NAMESTORE_UNKNOWN);
1978 return;
1979 }
1980 key_len = GNUNET_CRYPTO_private_key_get_length (zone_key);
1981 msg_size = sizeof(struct ZoneToNameResponseMessage)
1982 + name_len + rd_ser_len + key_len;
1983 if (msg_size >= GNUNET_MAX_MESSAGE_SIZE)
1984 {
1985 GNUNET_break (0);
1986 ztn_ctx->ec = GNUNET_EC_NAMESTORE_RECORD_TOO_BIG;
1987 return;
1988 }
1989 env =
1990 GNUNET_MQ_msg_extra (ztnr_msg,
1991 key_len + name_len + rd_ser_len,
1992 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1993 ztnr_msg->gns_header.header.size = htons (msg_size);
1994 ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1995 ztnr_msg->ec = htonl (ztn_ctx->ec);
1996 ztnr_msg->rd_len = htons (rd_ser_len);
1997 ztnr_msg->rd_count = htons (rd_count);
1998 ztnr_msg->name_len = htons (name_len);
1999 ztnr_msg->key_len = htons (key_len);
2000 GNUNET_CRYPTO_write_private_key_to_buffer (zone_key,
2001 &ztnr_msg[1],
2002 key_len);
2003 name_tmp = (char *) &ztnr_msg[1] + key_len;
2004 GNUNET_memcpy (name_tmp, name, name_len);
2005 rd_tmp = &name_tmp[name_len];
2006 GNUNET_assert (
2007 rd_ser_len ==
2008 GNUNET_GNSRECORD_records_serialize (rd_count, rd, rd_ser_len, rd_tmp));
2009 ztn_ctx->ec = GNUNET_EC_NONE;
2010 GNUNET_MQ_send (ztn_ctx->nc->mq, env);
2011}
2012
2013static enum GNUNET_GenericReturnValue
2014check_zone_to_name (void *cls,
2015 const struct ZoneToNameMessage *zis_msg)
2016{
2017 return GNUNET_OK;
2018}
2019
2020
2021/**
2022 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME message
2023 *
2024 * @param cls client client sending the message
2025 * @param ztn_msg message of type 'struct ZoneToNameMessage'
2026 */
2027static void
2028handle_zone_to_name (void *cls, const struct ZoneToNameMessage *ztn_msg)
2029{
2030 struct GNUNET_CRYPTO_PrivateKey zone;
2031 struct GNUNET_CRYPTO_PublicKey value_zone;
2032 struct NamestoreClient *nc = cls;
2033 struct ZoneToNameCtx ztn_ctx;
2034 struct GNUNET_MQ_Envelope *env;
2035 struct ZoneToNameResponseMessage *ztnr_msg;
2036 size_t key_len;
2037 size_t pkey_len;
2038 size_t kb_read;
2039
2040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ZONE_TO_NAME message\n");
2041 ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
2042 ztn_ctx.nc = nc;
2043 ztn_ctx.ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
2044 key_len = ntohs (ztn_msg->key_len);
2045 if ((GNUNET_SYSERR ==
2046 GNUNET_CRYPTO_read_private_key_from_buffer (&ztn_msg[1],
2047 key_len,
2048 &zone,
2049 &kb_read)) ||
2050 (kb_read != key_len))
2051 {
2052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2053 "Error parsing private key.\n");
2054 GNUNET_SERVICE_client_drop (nc->client);
2055 GNUNET_break (0);
2056 return;
2057 }
2058 pkey_len = ntohs (ztn_msg->pkey_len);
2059 if ((GNUNET_SYSERR ==
2060 GNUNET_CRYPTO_read_public_key_from_buffer ((char*) &ztn_msg[1]
2061 + key_len,
2062 pkey_len,
2063 &value_zone,
2064 &kb_read)) ||
2065 (kb_read != pkey_len))
2066 {
2067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2068 "Error parsing public key.\n");
2069 GNUNET_SERVICE_client_drop (nc->client);
2070 GNUNET_break (0);
2071 return;
2072 }
2073 if (GNUNET_SYSERR == nc->GSN_database->zone_to_name (nc->GSN_database->cls,
2074 &zone,
2075 &value_zone,
2076 &handle_zone_to_name_it,
2077 &ztn_ctx))
2078 {
2079 /* internal error, hang up instead of signalling something
2080 that might be wrong */
2081 GNUNET_break (0);
2082 GNUNET_SERVICE_client_drop (nc->client);
2083 return;
2084 }
2085 if (GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND == ztn_ctx.ec)
2086 {
2087 /* no result found, send empty response */
2088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2089 "Found no result for zone-to-name lookup.\n");
2090 env = GNUNET_MQ_msg (ztnr_msg,
2091 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
2092 ztnr_msg->gns_header.r_id = ztn_msg->gns_header.r_id;
2093 ztnr_msg->ec = htonl (GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND);
2094 GNUNET_MQ_send (nc->mq, env);
2095 }
2096 GNUNET_SERVICE_client_continue (nc->client);
2097}
2098
2099
2100/**
2101 * Context for record remove operations passed from
2102 * #run_zone_iteration_round to #zone_iterate_proc as closure
2103 */
2104struct ZoneIterationProcResult
2105{
2106 /**
2107 * The zone iteration handle
2108 */
2109 struct ZoneIteration *zi;
2110
2111 /**
2112 * Number of results left to be returned in this iteration.
2113 */
2114 uint64_t limit;
2115
2116 /**
2117 * Skip a result and run again unless GNUNET_NO
2118 */
2119 int run_again;
2120};
2121
2122
2123/**
2124 * Process results for zone iteration from database
2125 *
2126 * @param cls struct ZoneIterationProcResult
2127 * @param seq sequence number of the record, MUST NOT BE ZERO
2128 * @param zone_key the zone key
2129 * @param name name
2130 * @param rd_count number of records for this name
2131 * @param rd record data
2132 */
2133static void
2134zone_iterate_proc (void *cls,
2135 uint64_t seq,
2136 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
2137 const char *name,
2138 unsigned int rd_count,
2139 const struct GNUNET_GNSRECORD_Data *rd)
2140{
2141 struct ZoneIterationProcResult *proc = cls;
2142
2143 GNUNET_assert (0 != seq);
2144 if ((NULL == zone_key) && (NULL == name))
2145 {
2146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n");
2147 return;
2148 }
2149 if ((NULL == zone_key) || (NULL == name))
2150 {
2151 /* what is this!? should never happen */
2152 GNUNET_break (0);
2153 return;
2154 }
2155 if (0 == proc->limit)
2156 {
2157 /* what is this!? should never happen */
2158 GNUNET_break (0);
2159 return;
2160 }
2161 proc->zi->seq = seq;
2162 if (0 < send_lookup_response_with_filter (proc->zi->nc,
2163 proc->zi->request_id,
2164 zone_key,
2165 name,
2166 rd_count,
2167 rd,
2168 proc->zi->filter))
2169 proc->limit--;
2170 else
2171 proc->run_again = GNUNET_YES;
2172}
2173
2174
2175/**
2176 * Perform the next round of the zone iteration.
2177 *
2178 * @param zi zone iterator to process
2179 * @param limit number of results to return in one pass
2180 */
2181static void
2182run_zone_iteration_round (struct ZoneIteration *zi, uint64_t limit)
2183{
2184 struct ZoneIterationProcResult proc;
2185 struct GNUNET_TIME_Absolute start;
2186 struct GNUNET_TIME_Relative duration;
2187 struct NamestoreClient *nc = zi->nc;
2188
2189 memset (&proc, 0, sizeof(proc));
2190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2191 "Asked to return up to %llu records at position %llu\n",
2192 (unsigned long long) limit,
2193 (unsigned long long) zi->seq);
2194 proc.zi = zi;
2195 proc.limit = limit;
2196 proc.run_again = GNUNET_YES;
2197 start = GNUNET_TIME_absolute_get ();
2198 while (GNUNET_YES == proc.run_again)
2199 {
2200 proc.run_again = GNUNET_NO;
2201 GNUNET_break (GNUNET_SYSERR !=
2202 nc->GSN_database->iterate_records (nc->GSN_database->cls,
2203 (GNUNET_YES ==
2204 GNUNET_is_zero (
2205 &zi->zone))
2206 ? NULL
2207 : &zi->zone,
2208 zi->seq,
2209 proc.limit,
2210 &zone_iterate_proc,
2211 &proc));
2212 }
2213 duration = GNUNET_TIME_absolute_get_duration (start);
2214 duration = GNUNET_TIME_relative_divide (duration, limit - proc.limit);
2215 GNUNET_STATISTICS_set (statistics,
2216 "NAMESTORE iteration delay (μs/record)",
2217 duration.rel_value_us,
2218 GNUNET_NO);
2219 if (0 == proc.limit)
2220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2221 "Returned %llu results, more results available\n",
2222 (unsigned long long) limit);
2223 zi->send_end = (0 != proc.limit);
2224 if (0 == zi->cache_ops)
2225 zone_iteration_done_client_continue (zi);
2226}
2227
2228static enum GNUNET_GenericReturnValue
2229check_iteration_start (void *cls,
2230 const struct ZoneIterationStartMessage *zis_msg)
2231{
2232 uint16_t size;
2233 size_t key_len;
2234
2235 size = ntohs (zis_msg->gns_header.header.size);
2236 key_len = ntohs (zis_msg->key_len);
2237
2238 if (size < key_len + sizeof(*zis_msg))
2239 {
2240 GNUNET_break (0);
2241 return GNUNET_SYSERR;
2242 }
2243 return GNUNET_OK;
2244}
2245
2246
2247/**
2248 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START message
2249 *
2250 * @param cls the client sending the message
2251 * @param zis_msg message from the client
2252 */
2253static void
2254handle_iteration_start (void *cls,
2255 const struct ZoneIterationStartMessage *zis_msg)
2256{
2257 struct GNUNET_CRYPTO_PrivateKey zone;
2258 struct NamestoreClient *nc = cls;
2259 struct ZoneIteration *zi;
2260 size_t key_len;
2261 size_t kb_read;
2262
2263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2264 "Received ZONE_ITERATION_START message\n");
2265 key_len = ntohs (zis_msg->key_len);
2266 zi = GNUNET_new (struct ZoneIteration);
2267 if (0 < key_len)
2268 {
2269 if ((GNUNET_SYSERR ==
2270 GNUNET_CRYPTO_read_private_key_from_buffer (&zis_msg[1],
2271 key_len,
2272 &zone,
2273 &kb_read)) ||
2274 (kb_read != key_len))
2275 {
2276 GNUNET_SERVICE_client_drop (nc->client);
2277 GNUNET_free (zi);
2278 return;
2279 }
2280 zi->zone = zone;
2281 }
2282 zi->request_id = ntohl (zis_msg->gns_header.r_id);
2283 zi->filter = ntohs (zis_msg->filter);
2284 zi->offset = 0;
2285 zi->nc = nc;
2286 GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
2287 run_zone_iteration_round (zi, 1);
2288}
2289
2290
2291/**
2292 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP message
2293 *
2294 * @param cls the client sending the message
2295 * @param zis_msg message from the client
2296 */
2297static void
2298handle_iteration_stop (void *cls,
2299 const struct ZoneIterationStopMessage *zis_msg)
2300{
2301 struct NamestoreClient *nc = cls;
2302 struct ZoneIteration *zi;
2303 uint32_t rid;
2304
2305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2306 "Received ZONE_ITERATION_STOP message\n");
2307 rid = ntohl (zis_msg->gns_header.r_id);
2308 for (zi = nc->op_head; NULL != zi; zi = zi->next)
2309 if (zi->request_id == rid)
2310 break;
2311 if (NULL == zi)
2312 {
2313 GNUNET_break (0);
2314 GNUNET_SERVICE_client_drop (nc->client);
2315 return;
2316 }
2317 GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
2318 GNUNET_free (zi);
2319 GNUNET_SERVICE_client_continue (nc->client);
2320}
2321
2322
2323/**
2324 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message
2325 *
2326 * @param cls the client sending the message
2327 * @param zis_msg message from the client
2328 */
2329static void
2330handle_iteration_next (void *cls,
2331 const struct ZoneIterationNextMessage *zis_msg)
2332{
2333 struct NamestoreClient *nc = cls;
2334 struct ZoneIteration *zi;
2335 uint32_t rid;
2336 uint64_t limit;
2337
2338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2339 "Received ZONE_ITERATION_NEXT message\n");
2340 GNUNET_STATISTICS_update (statistics,
2341 "Iteration NEXT messages received",
2342 1,
2343 GNUNET_NO);
2344 rid = ntohl (zis_msg->gns_header.r_id);
2345 limit = GNUNET_ntohll (zis_msg->limit);
2346 for (zi = nc->op_head; NULL != zi; zi = zi->next)
2347 if (zi->request_id == rid)
2348 break;
2349 if (NULL == zi)
2350 {
2351 GNUNET_break (0);
2352 GNUNET_SERVICE_client_drop (nc->client);
2353 return;
2354 }
2355 run_zone_iteration_round (zi, limit);
2356}
2357
2358
2359/**
2360 * Function called when the monitor is ready for more data, and we
2361 * should thus unblock PUT operations that were blocked on the
2362 * monitor not being ready.
2363 */
2364static void
2365monitor_unblock (struct ZoneMonitor *zm)
2366{
2367 struct StoreActivity *sa = sa_head;
2368
2369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2370 "Unblocking zone monitor %p\n", zm);
2371 while ((NULL != sa) && (zm->limit > zm->iteration_cnt))
2372 {
2373 struct StoreActivity *sn = sa->next;
2374
2375 if (sa->zm_pos == zm)
2376 continue_store_activity (sa, GNUNET_YES);
2377 sa = sn;
2378 }
2379 if (zm->limit > zm->iteration_cnt)
2380 {
2381 zm->sa_waiting = GNUNET_NO;
2382 if (NULL != zm->sa_wait_warning)
2383 {
2384 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
2385 zm->sa_wait_warning = NULL;
2386 }
2387 }
2388 else if (GNUNET_YES == zm->sa_waiting)
2389 {
2390 zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
2391 if (NULL != zm->sa_wait_warning)
2392 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
2393 zm->sa_wait_warning =
2394 GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
2395 &warn_monitor_slow,
2396 zm);
2397 }
2398}
2399
2400
2401/**
2402 * Send 'sync' message to zone monitor, we're now in sync.
2403 *
2404 * @param zm monitor that is now in sync
2405 */
2406static void
2407monitor_sync (struct ZoneMonitor *zm)
2408{
2409 struct GNUNET_MQ_Envelope *env;
2410 struct GNUNET_MessageHeader *sync;
2411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2412 "Synching zone monitor %p\n", zm);
2413
2414 env = GNUNET_MQ_msg (sync, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
2415 GNUNET_MQ_send (zm->nc->mq, env);
2416 /* mark iteration done */
2417 zm->in_first_iteration = GNUNET_NO;
2418 zm->iteration_cnt = 0;
2419 if ((zm->limit > 0) && (zm->sa_waiting))
2420 monitor_unblock (zm);
2421}
2422
2423
2424/**
2425 * Obtain the next datum during the zone monitor's zone initial iteration.
2426 *
2427 * @param cls zone monitor that does its initial iteration
2428 */
2429static void
2430monitor_iteration_next (void *cls);
2431
2432
2433/**
2434 * A #GNUNET_NAMESTORE_RecordIterator for monitors.
2435 *
2436 * @param cls a 'struct ZoneMonitor *' with information about the monitor
2437 * @param seq sequence number of the record, MUST NOT BE ZERO
2438 * @param zone_key zone key of the zone
2439 * @param name name
2440 * @param rd_count number of records in @a rd
2441 * @param rd array of records
2442 */
2443static void
2444monitor_iterate_cb (void *cls,
2445 uint64_t seq,
2446 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
2447 const char *name,
2448 unsigned int rd_count,
2449 const struct GNUNET_GNSRECORD_Data *rd)
2450{
2451 struct ZoneMonitor *zm = cls;
2452
2453 GNUNET_assert (0 != seq);
2454 zm->seq = seq;
2455 GNUNET_assert (NULL != name);
2456 GNUNET_STATISTICS_update (statistics,
2457 "Monitor notifications sent",
2458 1,
2459 GNUNET_NO);
2460 if (0 < send_lookup_response_with_filter (zm->nc, 0, zone_key, name,
2461 rd_count, rd, zm->filter))
2462 {
2463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2464 "Sent records.\n");
2465 zm->limit--;
2466 zm->iteration_cnt--;
2467 }
2468 else
2469 zm->run_again = GNUNET_YES;
2470 if ((0 == zm->iteration_cnt) && (0 != zm->limit))
2471 {
2472 /* We are done with the current iteration batch, AND the
2473 client would right now accept more, so go again! */
2474 GNUNET_assert (NULL == zm->task);
2475 zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm);
2476 }
2477}
2478
2479static enum GNUNET_GenericReturnValue
2480check_monitor_start (void *cls,
2481 const struct ZoneMonitorStartMessage *zis_msg)
2482{
2483 uint16_t size;
2484 size_t key_len;
2485
2486 size = ntohs (zis_msg->header.size);
2487 key_len = ntohs (zis_msg->key_len);
2488
2489 if (size < key_len + sizeof(*zis_msg))
2490 {
2491 GNUNET_break (0);
2492 return GNUNET_SYSERR;
2493 }
2494 return GNUNET_OK;
2495}
2496
2497
2498/**
2499 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START message
2500 *
2501 * @param cls the client sending the message
2502 * @param zis_msg message from the client
2503 */
2504static void
2505handle_monitor_start (void *cls, const struct
2506 ZoneMonitorStartMessage *zis_msg)
2507{
2508 struct GNUNET_CRYPTO_PrivateKey zone;
2509 struct NamestoreClient *nc = cls;
2510 struct ZoneMonitor *zm;
2511 size_t key_len;
2512 size_t kb_read;
2513
2514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2515 "Received ZONE_MONITOR_START message\n");
2516 zm = GNUNET_new (struct ZoneMonitor);
2517 zm->nc = nc;
2518 key_len = ntohs (zis_msg->key_len);
2519 if (0 < key_len)
2520 {
2521 if ((GNUNET_SYSERR ==
2522 GNUNET_CRYPTO_read_private_key_from_buffer (&zis_msg[1],
2523 key_len,
2524 &zone,
2525 &kb_read)) ||
2526 (kb_read != key_len))
2527 {
2528 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2529 "Error reading private key\n");
2530 GNUNET_SERVICE_client_drop (nc->client);
2531 GNUNET_free (zm);
2532 return;
2533 }
2534 zm->zone = zone;
2535 }
2536 zm->limit = 1;
2537 zm->filter = ntohs (zis_msg->filter);
2538 zm->in_first_iteration = (GNUNET_YES == ntohl (zis_msg->iterate_first));
2539 GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm);
2540 GNUNET_SERVICE_client_mark_monitor (nc->client);
2541 GNUNET_SERVICE_client_continue (nc->client);
2542 GNUNET_notification_context_add (monitor_nc, nc->mq);
2543 if (zm->in_first_iteration)
2544 zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm);
2545 else
2546 monitor_sync (zm);
2547}
2548
2549
2550/**
2551 * Obtain the next datum during the zone monitor's zone initial iteration.
2552 *
2553 * @param cls zone monitor that does its initial iteration
2554 */
2555static void
2556monitor_iteration_next (void *cls)
2557{
2558 struct ZoneMonitor *zm = cls;
2559 struct NamestoreClient *nc = zm->nc;
2560 int ret;
2561
2562 zm->task = NULL;
2563 GNUNET_assert (0 == zm->iteration_cnt);
2564 if (zm->limit > 16)
2565 zm->iteration_cnt = zm->limit / 2; /* leave half for monitor events */
2566 else
2567 zm->iteration_cnt = zm->limit; /* use it all */
2568 zm->run_again = GNUNET_YES;
2569 while (GNUNET_YES == zm->run_again)
2570 {
2571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2572 "Running iteration\n");
2573 zm->run_again = GNUNET_NO;
2574 ret = nc->GSN_database->iterate_records (nc->GSN_database->cls,
2575 (GNUNET_YES == GNUNET_is_zero (
2576 &zm->zone)) ? NULL : &zm->zone,
2577 zm->seq,
2578 zm->iteration_cnt,
2579 &monitor_iterate_cb,
2580 zm);
2581 }
2582 if (GNUNET_SYSERR == ret)
2583 {
2584 GNUNET_SERVICE_client_drop (zm->nc->client);
2585 return;
2586 }
2587 if (GNUNET_NO == ret)
2588 {
2589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2590 "Zone empty... syncing\n");
2591 /* empty zone */
2592 monitor_sync (zm);
2593 return;
2594 }
2595}
2596
2597/**
2598 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT message
2599 *
2600 * @param cls the client sending the message
2601 * @param nm message from the client
2602 */
2603static void
2604handle_monitor_next (void *cls, const struct ZoneMonitorNextMessage *nm)
2605{
2606 struct NamestoreClient *nc = cls;
2607 struct ZoneMonitor *zm;
2608 uint64_t inc;
2609
2610 inc = GNUNET_ntohll (nm->limit);
2611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2612 "Received ZONE_MONITOR_NEXT message with limit %llu\n",
2613 (unsigned long long) inc);
2614 for (zm = monitor_head; NULL != zm; zm = zm->next)
2615 if (zm->nc == nc)
2616 break;
2617 if (NULL == zm)
2618 {
2619 GNUNET_break (0);
2620 GNUNET_SERVICE_client_drop (nc->client);
2621 return;
2622 }
2623 GNUNET_SERVICE_client_continue (nc->client);
2624 if (zm->limit + inc < zm->limit)
2625 {
2626 GNUNET_break (0);
2627 GNUNET_SERVICE_client_drop (nc->client);
2628 return;
2629 }
2630 zm->limit += inc;
2631 if ((zm->in_first_iteration) && (zm->limit == inc))
2632 {
2633 /* We are still iterating, and the previous iteration must
2634 have stopped due to the client's limit, so continue it! */
2635 GNUNET_assert (NULL == zm->task);
2636 zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm);
2637 }
2638 GNUNET_assert (zm->iteration_cnt <= zm->limit);
2639 if ((zm->limit > zm->iteration_cnt) && (zm->sa_waiting))
2640 {
2641 monitor_unblock (zm);
2642 }
2643 else if (GNUNET_YES == zm->sa_waiting)
2644 {
2645 if (NULL != zm->sa_wait_warning)
2646 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
2647 zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
2648 zm->sa_wait_warning =
2649 GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
2650 &warn_monitor_slow,
2651 zm);
2652 }
2653}
2654
2655/**
2656 * Process namestore requests.
2657 *
2658 * @param cls closure
2659 * @param cfg configuration to use
2660 * @param service the initialized service
2661 */
2662static void
2663run (void *cls,
2664 const struct GNUNET_CONFIGURATION_Handle *cfg,
2665 struct GNUNET_SERVICE_Handle *service)
2666{
2667 char *database;
2668 (void) cls;
2669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
2670 return_orphaned = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2671 "namestore",
2672 "RETURN_ORPHANED");
2673 GSN_cfg = cfg;
2674 monitor_nc = GNUNET_notification_context_create (1);
2675 statistics = GNUNET_STATISTICS_create ("namestore", cfg);
2676 /* Loading database plugin */
2677 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
2678 "namestore",
2679 "database",
2680 &database))
2681 {
2682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
2683 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2684 return;
2685 }
2686 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
2687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading %s\n", db_lib_name);
2688 GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
2689 GNUNET_free (database);
2690 if (NULL == GSN_database)
2691 {
2692 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2693 "Could not load database backend `%s'\n",
2694 db_lib_name);
2695 GNUNET_free (db_lib_name);
2696 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2697 return;
2698 }
2699 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
2700}
2701
2702
2703/**
2704 * Define "main" method using service macro.
2705 */
2706GNUNET_SERVICE_MAIN (
2707 "namestore",
2708 GNUNET_SERVICE_OPTION_NONE,
2709 &run,
2710 &client_connect_cb,
2711 &client_disconnect_cb,
2712 NULL,
2713 GNUNET_MQ_hd_fixed_size (tx_control,
2714 GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL,
2715 struct TxControlMessage,
2716 NULL),
2717 GNUNET_MQ_hd_var_size (record_store,
2718 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE,
2719 struct RecordStoreMessage,
2720 NULL),
2721 GNUNET_MQ_hd_var_size (record_lookup,
2722 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP,
2723 struct LabelLookupMessage,
2724 NULL),
2725 GNUNET_MQ_hd_var_size (zone_to_name,
2726 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME,
2727 struct ZoneToNameMessage,
2728 NULL),
2729 GNUNET_MQ_hd_var_size (iteration_start,
2730 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START,
2731 struct ZoneIterationStartMessage,
2732 NULL),
2733 GNUNET_MQ_hd_fixed_size (iteration_next,
2734 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT,
2735 struct ZoneIterationNextMessage,
2736 NULL),
2737 GNUNET_MQ_hd_fixed_size (iteration_stop,
2738 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP,
2739 struct ZoneIterationStopMessage,
2740 NULL),
2741 GNUNET_MQ_hd_var_size (monitor_start,
2742 GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START,
2743 struct ZoneMonitorStartMessage,
2744 NULL),
2745 GNUNET_MQ_hd_fixed_size (monitor_next,
2746 GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT,
2747 struct ZoneMonitorNextMessage,
2748 NULL),
2749 GNUNET_MQ_handler_end ());
2750
2751
2752/* end of gnunet-service-namestore.c */
diff --git a/src/namestore/gnunet-zoneimport.c b/src/namestore/gnunet-zoneimport.c
deleted file mode 100644
index c7e0cf65f..000000000
--- a/src/namestore/gnunet-zoneimport.c
+++ /dev/null
@@ -1,1872 +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 * @file src/namestore/gnunet-zoneimport.c
22 * @brief import a DNS zone for publication in GNS, incremental
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include <gnunet_util_lib.h>
27#include <gnunet_gnsrecord_lib.h>
28#include <gnunet_namestore_service.h>
29#include <gnunet_statistics_service.h>
30#include <gnunet_identity_service.h>
31
32
33/**
34 * Maximum number of queries pending at the same time.
35 */
36#define THRESH 100
37
38/**
39 * TIME_THRESH is in usecs. How quickly do we submit fresh queries.
40 * Used as an additional throttle.
41 */
42#define TIME_THRESH 10
43
44/**
45 * How often do we retry a query before giving up for good?
46 */
47#define MAX_RETRIES 5
48
49/**
50 * How many DNS requests do we at most issue in rapid series?
51 */
52#define MAX_SERIES 10
53
54/**
55 * How long do we wait at least between series of requests?
56 */
57#define SERIES_DELAY \
58 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS, 10)
59
60/**
61 * How long do DNS records have to last at least after being imported?
62 */
63static struct GNUNET_TIME_Relative minimum_expiration_time;
64
65/**
66 * How many requests do we request from NAMESTORE in one batch
67 * during our initial iteration?
68 */
69#define NS_BATCH_SIZE 1024
70
71/**
72 * Some zones may include authoritative records for other
73 * zones, such as foo.com.uk or bar.com.fr. As for GNS
74 * each dot represents a zone cut, we then need to create a
75 * zone on-the-fly to capture those records properly.
76 */
77struct Zone
78{
79 /**
80 * Kept in a DLL.
81 */
82 struct Zone *next;
83
84 /**
85 * Kept in a DLL.
86 */
87 struct Zone *prev;
88
89 /**
90 * Domain of the zone (i.e. "fr" or "com.fr")
91 */
92 char *domain;
93
94 /**
95 * Private key of the zone.
96 */
97 struct GNUNET_CRYPTO_PrivateKey key;
98};
99
100
101/**
102 * Record for the request to be stored by GNS.
103 */
104struct Record
105{
106 /**
107 * Kept in a DLL.
108 */
109 struct Record *next;
110
111 /**
112 * Kept in a DLL.
113 */
114 struct Record *prev;
115
116 /**
117 * GNS record.
118 */
119 struct GNUNET_GNSRECORD_Data grd;
120};
121
122
123/**
124 * Request we should make. We keep this struct in memory per request,
125 * thus optimizing it is crucial for the overall memory consumption of
126 * the zone importer.
127 */
128struct Request
129{
130 /**
131 * Requests are kept in a heap while waiting to be resolved.
132 */
133 struct GNUNET_CONTAINER_HeapNode *hn;
134
135 /**
136 * Active requests are kept in a DLL.
137 */
138 struct Request *next;
139
140 /**
141 * Active requests are kept in a DLL.
142 */
143 struct Request *prev;
144
145 /**
146 * Head of records that should be published in GNS for
147 * this hostname.
148 */
149 struct Record *rec_head;
150
151 /**
152 * Tail of records that should be published in GNS for
153 * this hostname.
154 */
155 struct Record *rec_tail;
156
157 /**
158 * Socket used to make the request, NULL if not active.
159 */
160 struct GNUNET_DNSSTUB_RequestSocket *rs;
161
162 /**
163 * Hostname we are resolving, allocated at the end of
164 * this struct (optimizing memory consumption by reducing
165 * total number of allocations).
166 */
167 char *hostname;
168
169 /**
170 * Namestore operation pending for this record.
171 */
172 struct GNUNET_NAMESTORE_QueueEntry *qe;
173
174 /**
175 * Zone responsible for this request.
176 */
177 const struct Zone *zone;
178
179 /**
180 * At what time does the (earliest) of the returned records
181 * for this name expire? At this point, we need to re-fetch
182 * the record.
183 */
184 struct GNUNET_TIME_Absolute expires;
185
186 /**
187 * While we are fetching the record, the value is set to the
188 * starting time of the DNS operation. While doing a
189 * NAMESTORE store, again set to the start time of the
190 * NAMESTORE operation.
191 */
192 struct GNUNET_TIME_Absolute op_start_time;
193
194 /**
195 * How often did we issue this query? (And failed, reset
196 * to zero once we were successful.)
197 */
198 unsigned int issue_num;
199
200 /**
201 * random 16-bit DNS query identifier.
202 */
203 uint16_t id;
204};
205
206
207/**
208 * Command-line argument specifying desired size of the hash map with
209 * all of our pending names. Usually, we use an automatically growing
210 * map, but this is only OK up to about a million entries. Above that
211 * number, the user must explicitly specify the size at startup.
212 */
213static unsigned int map_size = 1024;
214
215/**
216 * Handle to the identity service.
217 */
218static struct GNUNET_IDENTITY_Handle *id;
219
220/**
221 * Namestore handle.
222 */
223static struct GNUNET_NAMESTORE_Handle *ns;
224
225/**
226 * Handle to the statistics service.
227 */
228static struct GNUNET_STATISTICS_Handle *stats;
229
230/**
231 * Context for DNS resolution.
232 */
233static struct GNUNET_DNSSTUB_Context *ctx;
234
235/**
236 * The number of DNS queries that are outstanding
237 */
238static unsigned int pending;
239
240/**
241 * The number of NAMESTORE record store operations that are outstanding
242 */
243static unsigned int pending_rs;
244
245/**
246 * Number of lookups we performed overall.
247 */
248static unsigned int lookups;
249
250/**
251 * Number of records we had cached.
252 */
253static unsigned int cached;
254
255/**
256 * How many hostnames did we reject (malformed).
257 */
258static unsigned int rejects;
259
260/**
261 * Number of lookups that failed.
262 */
263static unsigned int failures;
264
265/**
266 * Number of records we found.
267 */
268static unsigned int records;
269
270/**
271 * Number of record sets given to namestore.
272 */
273static unsigned int record_sets;
274
275/**
276 * Heap of all requests to perform, sorted by
277 * the time we should next do the request (i.e. by expires).
278 */
279static struct GNUNET_CONTAINER_Heap *req_heap;
280
281/**
282 * Active requests are kept in a DLL.
283 */
284static struct Request *req_head;
285
286/**
287 * Active requests are kept in a DLL.
288 */
289static struct Request *req_tail;
290
291/**
292 * Main task.
293 */
294static struct GNUNET_SCHEDULER_Task *t;
295
296/**
297 * Hash map of requests for which we may still get a response from
298 * the namestore. Set to NULL once the initial namestore iteration
299 * is done.
300 */
301static struct GNUNET_CONTAINER_MultiHashMap *ns_pending;
302
303/**
304 * Current zone iteration handle.
305 */
306static struct GNUNET_NAMESTORE_ZoneIterator *zone_it;
307
308/**
309 * Head of list of zones we are managing.
310 */
311static struct Zone *zone_head;
312
313/**
314 * Tail of list of zones we are managing.
315 */
316static struct Zone *zone_tail;
317
318/**
319 * After how many more results must #ns_lookup_result_cb() ask
320 * the namestore for more?
321 */
322static uint64_t ns_iterator_trigger_next;
323
324/**
325 * Number of DNS requests counted in latency total.
326 */
327static uint64_t total_dns_latency_cnt;
328
329/**
330 * Sum of DNS latencies observed.
331 */
332static struct GNUNET_TIME_Relative total_dns_latency;
333
334/**
335 * Number of records processed (DNS lookup, no NAMESTORE) in total.
336 */
337static uint64_t total_reg_proc_dns;
338
339/**
340 * Number of records processed (DNS lookup, with NAMESTORE) in total.
341 */
342static uint64_t total_reg_proc_dns_ns;
343
344/**
345 * Start time of the regular processing.
346 */
347static struct GNUNET_TIME_Absolute start_time_reg_proc;
348
349/**
350 * Last time we worked before going idle.
351 */
352static struct GNUNET_TIME_Absolute sleep_time_reg_proc;
353
354/**
355 * Time we slept just waiting for work.
356 */
357static struct GNUNET_TIME_Relative idle_time;
358
359
360/**
361 * Callback for #for_all_records
362 *
363 * @param cls closure
364 * @param rec a DNS record
365 */
366typedef void (*RecordProcessor) (void *cls,
367 const struct GNUNET_DNSPARSER_Record *rec);
368
369
370/**
371 * Call @a rp for each record in @a p, regardless of
372 * what response section it is in.
373 *
374 * @param p packet from DNS
375 * @param rp function to call
376 * @param rp_cls closure for @a rp
377 */
378static void
379for_all_records (const struct GNUNET_DNSPARSER_Packet *p,
380 RecordProcessor rp,
381 void *rp_cls)
382{
383 for (unsigned int i = 0; i < p->num_answers; i++)
384 {
385 struct GNUNET_DNSPARSER_Record *rs = &p->answers[i];
386
387 rp (rp_cls, rs);
388 }
389 for (unsigned int i = 0; i < p->num_authority_records; i++)
390 {
391 struct GNUNET_DNSPARSER_Record *rs = &p->authority_records[i];
392
393 rp (rp_cls, rs);
394 }
395 for (unsigned int i = 0; i < p->num_additional_records; i++)
396 {
397 struct GNUNET_DNSPARSER_Record *rs = &p->additional_records[i];
398
399 rp (rp_cls, rs);
400 }
401}
402
403
404/**
405 * Return just the label of the hostname in @a req.
406 *
407 * @param req request to process hostname of
408 * @return statically allocated pointer to the label,
409 * overwritten upon the next request!
410 */
411static const char *
412get_label (struct Request *req)
413{
414 static char label[64];
415 const char *dot;
416
417 dot = strchr (req->hostname, (unsigned char) '.');
418 if (NULL == dot)
419 {
420 GNUNET_break (0);
421 return NULL;
422 }
423 if (((size_t) (dot - req->hostname)) >= sizeof(label))
424 {
425 GNUNET_break (0);
426 return NULL;
427 }
428 GNUNET_memcpy (label, req->hostname, dot - req->hostname);
429 label[dot - req->hostname] = '\0';
430 return label;
431}
432
433
434/**
435 * Build DNS query for @a hostname.
436 *
437 * @param hostname host to build query for
438 * @param[out] raw_size number of bytes in the query
439 * @return NULL on error, otherwise pointer to statically (!)
440 * allocated query buffer
441 */
442static void *
443build_dns_query (struct Request *req, size_t *raw_size)
444{
445 static char raw[512];
446 char *rawp;
447 struct GNUNET_DNSPARSER_Packet p;
448 struct GNUNET_DNSPARSER_Query q;
449 int ret;
450
451 q.name = (char *) req->hostname;
452 q.type = GNUNET_DNSPARSER_TYPE_NS;
453 q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
454
455 memset (&p, 0, sizeof(p));
456 p.num_queries = 1;
457 p.queries = &q;
458 p.id = req->id;
459 ret = GNUNET_DNSPARSER_pack (&p, UINT16_MAX, &rawp, raw_size);
460 if (GNUNET_OK != ret)
461 {
462 if (GNUNET_NO == ret)
463 GNUNET_free (rawp);
464 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
465 "Failed to pack query for hostname `%s'\n",
466 req->hostname);
467 rejects++;
468 return NULL;
469 }
470 if (*raw_size > sizeof(raw))
471 {
472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
473 "Failed to pack query for hostname `%s'\n",
474 req->hostname);
475 rejects++;
476 GNUNET_break (0);
477 GNUNET_free (rawp);
478 return NULL;
479 }
480 GNUNET_memcpy (raw, rawp, *raw_size);
481 GNUNET_free (rawp);
482 return raw;
483}
484
485
486/**
487 * Free records associated with @a req.
488 *
489 * @param req request to free records of
490 */
491static void
492free_records (struct Request *req)
493{
494 struct Record *rec;
495
496 /* Free records */
497 while (NULL != (rec = req->rec_head))
498 {
499 GNUNET_CONTAINER_DLL_remove (req->rec_head, req->rec_tail, rec);
500 GNUNET_free (rec);
501 }
502}
503
504
505/**
506 * Free @a req and data structures reachable from it.
507 *
508 * @param req request to free
509 */
510static void
511free_request (struct Request *req)
512{
513 free_records (req);
514 GNUNET_free (req);
515}
516
517
518/**
519 * Process as many requests as possible from the queue.
520 *
521 * @param cls NULL
522 */
523static void
524process_queue (void *cls);
525
526
527/**
528 * Insert @a req into DLL sorted by next fetch time.
529 *
530 * @param req request to insert into #req_heap
531 */
532static void
533insert_sorted (struct Request *req)
534{
535 req->hn =
536 GNUNET_CONTAINER_heap_insert (req_heap, req, req->expires.abs_value_us);
537 if (req == GNUNET_CONTAINER_heap_peek (req_heap))
538 {
539 if (NULL != t)
540 GNUNET_SCHEDULER_cancel (t);
541 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
542 t = GNUNET_SCHEDULER_add_at (req->expires, &process_queue, NULL);
543 }
544}
545
546
547/**
548 * Add record to the GNS record set for @a req.
549 *
550 * @param req the request to expand GNS record set for
551 * @param type type to use
552 * @param expiration_time when should @a rec expire
553 * @param data raw data to store
554 * @param data_len number of bytes in @a data
555 */
556static void
557add_record (struct Request *req,
558 uint32_t type,
559 struct GNUNET_TIME_Absolute expiration_time,
560 const void *data,
561 size_t data_len)
562{
563 struct Record *rec;
564
565 rec = GNUNET_malloc (sizeof(struct Record) + data_len);
566 rec->grd.data = &rec[1];
567 rec->grd.expiration_time = expiration_time.abs_value_us;
568 rec->grd.data_size = data_len;
569 rec->grd.record_type = type;
570 rec->grd.flags = GNUNET_GNSRECORD_RF_NONE;
571 GNUNET_memcpy (&rec[1], data, data_len);
572 GNUNET_CONTAINER_DLL_insert (req->rec_head, req->rec_tail, rec);
573}
574
575
576/**
577 * Closure for #check_for_glue.
578 */
579struct GlueClosure
580{
581 /**
582 * Overall request we are processing.
583 */
584 struct Request *req;
585
586 /**
587 * NS name we are looking for glue for.
588 */
589 const char *ns;
590
591 /**
592 * Set to #GNUNET_YES if glue was found.
593 */
594 int found;
595};
596
597
598/**
599 * Try to find glue records for a given NS record.
600 *
601 * @param cls a `struct GlueClosure *`
602 * @param rec record that may contain glue information
603 */
604static void
605check_for_glue (void *cls, const struct GNUNET_DNSPARSER_Record *rec)
606{
607 struct GlueClosure *gc = cls;
608 char dst[65536];
609 size_t dst_len;
610 size_t off;
611 char ip[INET6_ADDRSTRLEN + 1];
612 socklen_t ip_size = (socklen_t) sizeof(ip);
613 struct GNUNET_TIME_Absolute expiration_time;
614 struct GNUNET_TIME_Relative left;
615
616 if (0 != strcasecmp (rec->name, gc->ns))
617 return;
618 expiration_time = rec->expiration_time;
619 left = GNUNET_TIME_absolute_get_remaining (expiration_time);
620 if (0 == left.rel_value_us)
621 return; /* ignore expired glue records */
622 /* if expiration window is too short, bump it to configured minimum */
623 if (left.rel_value_us < minimum_expiration_time.rel_value_us)
624 expiration_time =
625 GNUNET_TIME_relative_to_absolute (minimum_expiration_time);
626 dst_len = sizeof(dst);
627 off = 0;
628 switch (rec->type)
629 {
630 case GNUNET_DNSPARSER_TYPE_A:
631 if (sizeof(struct in_addr) != rec->data.raw.data_len)
632 {
633 GNUNET_break (0);
634 return;
635 }
636 if (NULL == inet_ntop (AF_INET, rec->data.raw.data, ip, ip_size))
637 {
638 GNUNET_break (0);
639 return;
640 }
641 if ((GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
642 dst_len,
643 &off,
644 gc->req->hostname)) &&
645 (GNUNET_OK ==
646 GNUNET_DNSPARSER_builder_add_name (dst, dst_len, &off, ip)))
647 {
648 add_record (gc->req,
649 GNUNET_GNSRECORD_TYPE_GNS2DNS,
650 expiration_time,
651 dst,
652 off);
653 gc->found = GNUNET_YES;
654 }
655 break;
656
657 case GNUNET_DNSPARSER_TYPE_AAAA:
658 if (sizeof(struct in6_addr) != rec->data.raw.data_len)
659 {
660 GNUNET_break (0);
661 return;
662 }
663 if (NULL == inet_ntop (AF_INET6, rec->data.raw.data, ip, ip_size))
664 {
665 GNUNET_break (0);
666 return;
667 }
668 if ((GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
669 dst_len,
670 &off,
671 gc->req->hostname)) &&
672 (GNUNET_OK ==
673 GNUNET_DNSPARSER_builder_add_name (dst, dst_len, &off, ip)))
674 {
675 add_record (gc->req,
676 GNUNET_GNSRECORD_TYPE_GNS2DNS,
677 expiration_time,
678 dst,
679 off);
680 gc->found = GNUNET_YES;
681 }
682 break;
683
684 case GNUNET_DNSPARSER_TYPE_CNAME:
685 if ((GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
686 dst_len,
687 &off,
688 gc->req->hostname)) &&
689 (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
690 dst_len,
691 &off,
692 rec->data.hostname)))
693 {
694 add_record (gc->req,
695 GNUNET_GNSRECORD_TYPE_GNS2DNS,
696 expiration_time,
697 dst,
698 off);
699 gc->found = GNUNET_YES;
700 }
701 break;
702
703 default:
704 /* useless, do nothing */
705 break;
706 }
707}
708
709
710/**
711 * Closure for #process_record().
712 */
713struct ProcessRecordContext
714{
715 /**
716 * Answer we got back and are currently parsing, or NULL
717 * if not active.
718 */
719 struct GNUNET_DNSPARSER_Packet *p;
720
721 /**
722 * Request we are processing.
723 */
724 struct Request *req;
725};
726
727
728/**
729 * We received @a rec for @a req. Remember the answer.
730 *
731 * @param cls a `struct ProcessRecordContext`
732 * @param rec response
733 */
734static void
735process_record (void *cls, const struct GNUNET_DNSPARSER_Record *rec)
736{
737 struct ProcessRecordContext *prc = cls;
738 struct Request *req = prc->req;
739 char dst[65536];
740 size_t dst_len;
741 size_t off;
742 struct GNUNET_TIME_Absolute expiration_time;
743 struct GNUNET_TIME_Relative left;
744
745 dst_len = sizeof(dst);
746 off = 0;
747 records++;
748 if (0 != strcasecmp (rec->name, req->hostname))
749 {
750 GNUNET_log (
751 GNUNET_ERROR_TYPE_DEBUG,
752 "DNS returned record from zone `%s' of type %u while resolving `%s'\n",
753 rec->name,
754 (unsigned int) rec->type,
755 req->hostname);
756 return; /* does not match hostname, might be glue, but
757 not useful for this pass! */
758 }
759 expiration_time = rec->expiration_time;
760 left = GNUNET_TIME_absolute_get_remaining (expiration_time);
761 if (0 == left.rel_value_us)
762 {
763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764 "DNS returned expired record for `%s'\n",
765 req->hostname);
766 GNUNET_STATISTICS_update (stats,
767 "# expired records obtained from DNS",
768 1,
769 GNUNET_NO);
770 return; /* record expired */
771 }
772
773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
774 "DNS returned record that expires at %s for `%s'\n",
775 GNUNET_STRINGS_absolute_time_to_string (expiration_time),
776 req->hostname);
777 /* if expiration window is too short, bump it to configured minimum */
778 if (left.rel_value_us < minimum_expiration_time.rel_value_us)
779 expiration_time =
780 GNUNET_TIME_relative_to_absolute (minimum_expiration_time);
781 switch (rec->type)
782 {
783 case GNUNET_DNSPARSER_TYPE_NS: {
784 struct GlueClosure gc;
785
786 /* check for glue */
787 gc.req = req;
788 gc.ns = rec->data.hostname;
789 gc.found = GNUNET_NO;
790 for_all_records (prc->p, &check_for_glue, &gc);
791 if ((GNUNET_NO == gc.found) &&
792 (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
793 dst_len,
794 &off,
795 req->hostname)) &&
796 (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
797 dst_len,
798 &off,
799 rec->data.hostname)))
800 {
801 /* FIXME: actually check if this is out-of-bailiwick,
802 and if not request explicit resolution... */
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "Converted OOB (`%s') NS record for `%s'\n",
805 rec->data.hostname,
806 rec->name);
807 add_record (req,
808 GNUNET_GNSRECORD_TYPE_GNS2DNS,
809 expiration_time,
810 dst,
811 off);
812 }
813 else
814 {
815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
816 "Converted NS record for `%s' using glue\n",
817 rec->name);
818 }
819 break;
820 }
821
822 case GNUNET_DNSPARSER_TYPE_CNAME:
823 if (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
824 dst_len,
825 &off,
826 rec->data.hostname))
827 {
828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
829 "Converting CNAME (`%s') record for `%s'\n",
830 rec->data.hostname,
831 rec->name);
832 add_record (req, rec->type, expiration_time, dst, off);
833 }
834 break;
835
836 case GNUNET_DNSPARSER_TYPE_DNAME:
837 /* No support for DNAME in GNS yet! FIXME: support later! */
838 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
839 "FIXME: not supported: %s DNAME %s\n",
840 rec->name,
841 rec->data.hostname);
842 break;
843
844 case GNUNET_DNSPARSER_TYPE_MX:
845 if (GNUNET_OK ==
846 GNUNET_DNSPARSER_builder_add_mx (dst, dst_len, &off, rec->data.mx))
847 {
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 "Converting MX (`%s') record for `%s'\n",
850 rec->data.mx->mxhost,
851 rec->name);
852 add_record (req, rec->type, expiration_time, dst, off);
853 }
854 break;
855
856 case GNUNET_DNSPARSER_TYPE_SOA:
857 if (GNUNET_OK ==
858 GNUNET_DNSPARSER_builder_add_soa (dst, dst_len, &off, rec->data.soa))
859 {
860 /* NOTE: GNS does not really use SOAs */
861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
862 "Converting SOA record for `%s'\n",
863 rec->name);
864 add_record (req, rec->type, expiration_time, dst, off);
865 }
866 break;
867
868 case GNUNET_DNSPARSER_TYPE_SRV:
869 if (GNUNET_OK ==
870 GNUNET_DNSPARSER_builder_add_srv (dst, dst_len, &off, rec->data.srv))
871 {
872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
873 "Converting SRV record for `%s'\n",
874 rec->name);
875 add_record (req, rec->type, expiration_time, dst, off);
876 }
877 break;
878
879 case GNUNET_DNSPARSER_TYPE_PTR:
880 if (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
881 dst_len,
882 &off,
883 rec->data.hostname))
884 {
885 /* !?: what does a PTR record do in a regular TLD??? */
886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
887 "Converting PTR record for `%s' (weird)\n",
888 rec->name);
889 add_record (req, rec->type, expiration_time, dst, off);
890 }
891 break;
892
893 case GNUNET_DNSPARSER_TYPE_CERT:
894 if (GNUNET_OK ==
895 GNUNET_DNSPARSER_builder_add_cert (dst, dst_len, &off, rec->data.cert))
896 {
897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898 "Converting CERT record for `%s'\n",
899 rec->name);
900 add_record (req, rec->type, expiration_time, dst, off);
901 }
902 break;
903
904 /* Rest is 'raw' encoded and just needs to be copied IF
905 the hostname matches the requested name; otherwise we
906 simply cannot use it. */
907 case GNUNET_DNSPARSER_TYPE_A:
908 case GNUNET_DNSPARSER_TYPE_AAAA:
909 case GNUNET_DNSPARSER_TYPE_TXT:
910 default:
911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
912 "Converting record of type %u for `%s'\n",
913 (unsigned int) rec->type,
914 rec->name);
915 add_record (req,
916 rec->type,
917 expiration_time,
918 rec->data.raw.data,
919 rec->data.raw.data_len);
920 break;
921 }
922}
923
924
925static void
926store_completed_cb (void *cls, enum GNUNET_ErrorCode ec)
927{
928 static struct GNUNET_TIME_Absolute last;
929 struct Request *req = cls;
930
931 req->qe = NULL;
932 if (GNUNET_EC_NONE != ec)
933 {
934 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
935 "Failed to store zone data for `%s': %s\n",
936 req->hostname,
937 GNUNET_ErrorCode_get_hint (ec));
938 }
939 else
940 {
941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
942 "Stored records under `%s' (%d)\n",
943 req->hostname,
944 ec);
945 }
946 total_reg_proc_dns_ns++; /* finished regular processing */
947 pending_rs--;
948 free_records (req);
949 /* compute NAMESTORE statistics */
950 {
951 static uint64_t total_ns_latency_cnt;
952 static struct GNUNET_TIME_Relative total_ns_latency;
953 struct GNUNET_TIME_Relative ns_latency;
954
955 ns_latency = GNUNET_TIME_absolute_get_duration (req->op_start_time);
956 total_ns_latency = GNUNET_TIME_relative_add (total_ns_latency, ns_latency);
957 if (0 == total_ns_latency_cnt)
958 last = GNUNET_TIME_absolute_get ();
959 total_ns_latency_cnt++;
960 if (0 == (total_ns_latency_cnt % 1000))
961 {
962 struct GNUNET_TIME_Relative delta;
963
964 delta = GNUNET_TIME_absolute_get_duration (last);
965 last = GNUNET_TIME_absolute_get ();
966 fprintf (stderr,
967 "Processed 1000 records in %s\n",
968 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_YES));
969 GNUNET_STATISTICS_set (stats,
970 "# average NAMESTORE PUT latency (μs)",
971 total_ns_latency.rel_value_us
972 / total_ns_latency_cnt,
973 GNUNET_NO);
974 }
975 }
976 /* compute and publish overall velocity */
977 if (0 == (total_reg_proc_dns_ns % 100))
978 {
979 struct GNUNET_TIME_Relative runtime;
980
981 runtime = GNUNET_TIME_absolute_get_duration (start_time_reg_proc);
982 runtime = GNUNET_TIME_relative_subtract (runtime, idle_time);
983 runtime =
984 GNUNET_TIME_relative_divide (runtime,
985 total_reg_proc_dns + total_reg_proc_dns_ns);
986 GNUNET_STATISTICS_set (stats,
987 "# Regular processing completed without NAMESTORE",
988 total_reg_proc_dns,
989 GNUNET_NO);
990 GNUNET_STATISTICS_set (stats,
991 "# Regular processing completed with NAMESTORE PUT",
992 total_reg_proc_dns_ns,
993 GNUNET_NO);
994 GNUNET_STATISTICS_set (stats,
995 "# average request processing latency (μs)",
996 runtime.rel_value_us,
997 GNUNET_NO);
998 GNUNET_STATISTICS_set (stats,
999 "# total time spent idle (μs)",
1000 idle_time.rel_value_us,
1001 GNUNET_NO);
1002 }
1003
1004 if (NULL == t)
1005 {
1006 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1007 t = GNUNET_SCHEDULER_add_now (&process_queue, NULL);
1008 }
1009}
1010
1011
1012/**
1013 * Function called with the result of a DNS resolution.
1014 *
1015 * @param cls closure with the `struct Request`
1016 * @param dns dns response, never NULL
1017 * @param dns_len number of bytes in @a dns
1018 */
1019static void
1020process_result (void *cls,
1021 const struct GNUNET_TUN_DnsHeader *dns,
1022 size_t dns_len)
1023{
1024 struct Request *req = cls;
1025 struct Record *rec;
1026 struct GNUNET_DNSPARSER_Packet *p;
1027 unsigned int rd_count;
1028
1029 GNUNET_assert (NULL == req->hn);
1030 if (NULL == dns)
1031 {
1032 /* stub gave up */
1033 GNUNET_CONTAINER_DLL_remove (req_head, req_tail, req);
1034 pending--;
1035 if (NULL == t)
1036 {
1037 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1038 t = GNUNET_SCHEDULER_add_now (&process_queue, NULL);
1039 }
1040 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1041 "Stub gave up on DNS reply for `%s'\n",
1042 req->hostname);
1043 GNUNET_STATISTICS_update (stats, "# DNS lookups timed out", 1, GNUNET_NO);
1044 if (req->issue_num > MAX_RETRIES)
1045 {
1046 failures++;
1047 free_request (req);
1048 GNUNET_STATISTICS_update (stats, "# requests given up on", 1, GNUNET_NO);
1049 return;
1050 }
1051 total_reg_proc_dns++;
1052 req->rs = NULL;
1053 insert_sorted (req);
1054 return;
1055 }
1056 if (req->id != dns->id)
1057 {
1058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1059 "DNS ID did not match request, ignoring reply\n");
1060 GNUNET_STATISTICS_update (stats, "# DNS ID mismatches", 1, GNUNET_NO);
1061 return;
1062 }
1063 GNUNET_CONTAINER_DLL_remove (req_head, req_tail, req);
1064 GNUNET_DNSSTUB_resolve_cancel (req->rs);
1065 req->rs = NULL;
1066 pending--;
1067 p = GNUNET_DNSPARSER_parse ((const char *) dns, dns_len);
1068 if (NULL == p)
1069 {
1070 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1071 "Failed to parse DNS reply for `%s'\n",
1072 req->hostname);
1073 GNUNET_STATISTICS_update (stats, "# DNS parser errors", 1, GNUNET_NO);
1074 if (NULL == t)
1075 {
1076 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1077 t = GNUNET_SCHEDULER_add_now (&process_queue, NULL);
1078 }
1079 if (req->issue_num > MAX_RETRIES)
1080 {
1081 failures++;
1082 free_request (req);
1083 GNUNET_STATISTICS_update (stats, "# requests given up on", 1, GNUNET_NO);
1084 return;
1085 }
1086 insert_sorted (req);
1087 return;
1088 }
1089 /* import new records */
1090 req->issue_num = 0; /* success, reset counter! */
1091 {
1092 struct ProcessRecordContext prc = { .req = req, .p = p };
1093
1094 for_all_records (p, &process_record, &prc);
1095 }
1096 GNUNET_DNSPARSER_free_packet (p);
1097 /* count records found, determine minimum expiration time */
1098 req->expires = GNUNET_TIME_UNIT_FOREVER_ABS;
1099 {
1100 struct GNUNET_TIME_Relative dns_latency;
1101
1102 dns_latency = GNUNET_TIME_absolute_get_duration (req->op_start_time);
1103 total_dns_latency =
1104 GNUNET_TIME_relative_add (total_dns_latency, dns_latency);
1105 total_dns_latency_cnt++;
1106 if (0 == (total_dns_latency_cnt % 1000))
1107 {
1108 GNUNET_STATISTICS_set (stats,
1109 "# average DNS lookup latency (μs)",
1110 total_dns_latency.rel_value_us
1111 / total_dns_latency_cnt,
1112 GNUNET_NO);
1113 }
1114 }
1115 rd_count = 0;
1116 for (rec = req->rec_head; NULL != rec; rec = rec->next)
1117 {
1118 struct GNUNET_TIME_Absolute at;
1119
1120 at.abs_value_us = rec->grd.expiration_time;
1121 req->expires = GNUNET_TIME_absolute_min (req->expires, at);
1122 rd_count++;
1123 }
1124 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1125 "Obtained %u records for `%s'\n",
1126 rd_count,
1127 req->hostname);
1128 /* Instead of going for SOA, simplified for now to look each
1129 day in case we got an empty response */
1130 if (0 == rd_count)
1131 {
1132 req->expires = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS);
1133 GNUNET_STATISTICS_update (stats,
1134 "# empty DNS replies (usually NXDOMAIN)",
1135 1,
1136 GNUNET_NO);
1137 }
1138 else
1139 {
1140 record_sets++;
1141 }
1142 /* convert records to namestore import format */
1143 {
1144 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
1145 unsigned int off = 0;
1146
1147 /* convert linked list into array */
1148 for (rec = req->rec_head; NULL != rec; rec = rec->next)
1149 rd[off++] = rec->grd;
1150 pending_rs++;
1151 req->op_start_time = GNUNET_TIME_absolute_get ();
1152 req->qe = GNUNET_NAMESTORE_records_store (ns,
1153 &req->zone->key,
1154 get_label (req),
1155 rd_count,
1156 rd,
1157 &store_completed_cb,
1158 req);
1159 GNUNET_assert (NULL != req->qe);
1160 }
1161 insert_sorted (req);
1162}
1163
1164
1165/**
1166 * Process as many requests as possible from the queue.
1167 *
1168 * @param cls NULL
1169 */
1170static void
1171process_queue (void *cls)
1172{
1173 struct Request *req;
1174 unsigned int series;
1175 void *raw;
1176 size_t raw_size;
1177 struct GNUNET_TIME_Relative delay;
1178
1179 (void) cls;
1180 delay = GNUNET_TIME_absolute_get_duration (sleep_time_reg_proc);
1181 idle_time = GNUNET_TIME_relative_add (idle_time, delay);
1182 series = 0;
1183 t = NULL;
1184 while (pending + pending_rs < THRESH)
1185 {
1186 req = GNUNET_CONTAINER_heap_peek (req_heap);
1187 if (NULL == req)
1188 break;
1189 if (NULL != req->qe)
1190 return; /* namestore op still pending */
1191 if (NULL != req->rs)
1192 {
1193 GNUNET_break (0);
1194 return; /* already submitted */
1195 }
1196 if (GNUNET_TIME_absolute_get_remaining (req->expires).rel_value_us > 0)
1197 break;
1198 GNUNET_assert (req == GNUNET_CONTAINER_heap_remove_root (req_heap));
1199 req->hn = NULL;
1200 GNUNET_CONTAINER_DLL_insert (req_head, req_tail, req);
1201 GNUNET_assert (NULL == req->rs);
1202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1203 "Requesting resolution for `%s'\n",
1204 req->hostname);
1205 raw = build_dns_query (req, &raw_size);
1206 if (NULL == raw)
1207 {
1208 GNUNET_break (0);
1209 free_request (req);
1210 continue;
1211 }
1212 req->op_start_time = GNUNET_TIME_absolute_get ();
1213 req->rs = GNUNET_DNSSTUB_resolve (ctx, raw, raw_size, &process_result, req);
1214 GNUNET_assert (NULL != req->rs);
1215 req->issue_num++;
1216 lookups++;
1217 pending++;
1218 series++;
1219 if (series > MAX_SERIES)
1220 break;
1221 }
1222 if (pending + pending_rs >= THRESH)
1223 {
1224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225 "Stopped processing queue (%u+%u/%u)]\n",
1226 pending,
1227 pending_rs,
1228 THRESH);
1229 return; /* wait for replies */
1230 }
1231 req = GNUNET_CONTAINER_heap_peek (req_heap);
1232 if (NULL == req)
1233 {
1234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1235 "Stopped processing queue: empty queue\n");
1236 return;
1237 }
1238 if (GNUNET_TIME_absolute_get_remaining (req->expires).rel_value_us > 0)
1239 {
1240 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1241 "Waiting until %s for next record (`%s') to expire\n",
1242 GNUNET_STRINGS_absolute_time_to_string (req->expires),
1243 req->hostname);
1244 if (NULL != t)
1245 GNUNET_SCHEDULER_cancel (t);
1246 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1247 t = GNUNET_SCHEDULER_add_at (req->expires, &process_queue, NULL);
1248 return;
1249 }
1250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Throttling\n");
1251 if (NULL != t)
1252 GNUNET_SCHEDULER_cancel (t);
1253 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1254 t = GNUNET_SCHEDULER_add_delayed (SERIES_DELAY, &process_queue, NULL);
1255}
1256
1257
1258/**
1259 * Iterator called during #do_shutdown() to free requests in
1260 * the #ns_pending map.
1261 *
1262 * @param cls NULL
1263 * @param key unused
1264 * @param value the `struct Request` to free
1265 * @return #GNUNET_OK
1266 */
1267static int
1268free_request_it (void *cls, const struct GNUNET_HashCode *key, void *value)
1269{
1270 struct Request *req = value;
1271
1272 (void) cls;
1273 (void) key;
1274 free_request (req);
1275 return GNUNET_OK;
1276}
1277
1278
1279/**
1280 * Clean up and terminate the process.
1281 *
1282 * @param cls NULL
1283 */
1284static void
1285do_shutdown (void *cls)
1286{
1287 struct Request *req;
1288 struct Zone *zone;
1289
1290 (void) cls;
1291 if (NULL != id)
1292 {
1293 GNUNET_IDENTITY_disconnect (id);
1294 id = NULL;
1295 }
1296 if (NULL != t)
1297 {
1298 GNUNET_SCHEDULER_cancel (t);
1299 t = NULL;
1300 }
1301 while (NULL != (req = req_head))
1302 {
1303 GNUNET_CONTAINER_DLL_remove (req_head, req_tail, req);
1304 if (NULL != req->qe)
1305 GNUNET_NAMESTORE_cancel (req->qe);
1306 free_request (req);
1307 }
1308 while (NULL != (req = GNUNET_CONTAINER_heap_remove_root (req_heap)))
1309 {
1310 req->hn = NULL;
1311 if (NULL != req->qe)
1312 GNUNET_NAMESTORE_cancel (req->qe);
1313 free_request (req);
1314 }
1315 if (NULL != zone_it)
1316 {
1317 GNUNET_NAMESTORE_zone_iteration_stop (zone_it);
1318 zone_it = NULL;
1319 }
1320 if (NULL != ns)
1321 {
1322 GNUNET_NAMESTORE_disconnect (ns);
1323 ns = NULL;
1324 }
1325 if (NULL != ctx)
1326 {
1327 GNUNET_DNSSTUB_stop (ctx);
1328 ctx = NULL;
1329 }
1330 if (NULL != req_heap)
1331 {
1332 GNUNET_CONTAINER_heap_destroy (req_heap);
1333 req_heap = NULL;
1334 }
1335 if (NULL != ns_pending)
1336 {
1337 GNUNET_CONTAINER_multihashmap_iterate (ns_pending, &free_request_it, NULL);
1338 GNUNET_CONTAINER_multihashmap_destroy (ns_pending);
1339 ns_pending = NULL;
1340 }
1341 while (NULL != (zone = zone_head))
1342 {
1343 GNUNET_CONTAINER_DLL_remove (zone_head, zone_tail, zone);
1344 GNUNET_free (zone->domain);
1345 GNUNET_free (zone);
1346 }
1347 if (NULL != stats)
1348 {
1349 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1350 stats = NULL;
1351 }
1352}
1353
1354
1355/**
1356 * Iterate over all of the zones we care about and see which records
1357 * we may need to re-fetch when.
1358 *
1359 * @param cls NULL
1360 */
1361static void
1362iterate_zones (void *cls);
1363
1364
1365/**
1366 * Function called if #GNUNET_NAMESTORE_records_lookup() failed.
1367 * Just logs an error.
1368 *
1369 * @param cls a `struct Zone`
1370 */
1371static void
1372ns_lookup_error_cb (void *cls)
1373{
1374 struct Zone *zone = cls;
1375
1376 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1377 "Failed to load data from namestore for zone `%s'\n",
1378 zone->domain);
1379 zone_it = NULL;
1380 ns_iterator_trigger_next = 0;
1381 iterate_zones (NULL);
1382}
1383
1384
1385/**
1386 * Process a record that was stored in the namestore.
1387 *
1388 * @param cls a `struct Zone *`
1389 * @param key private key of the zone
1390 * @param label label of the records
1391 * @param rd_count number of entries in @a rd array, 0 if label was deleted
1392 * @param rd array of records with data to store
1393 */
1394static void
1395ns_lookup_result_cb (void *cls,
1396 const struct GNUNET_CRYPTO_PrivateKey *key,
1397 const char *label,
1398 unsigned int rd_count,
1399 const struct GNUNET_GNSRECORD_Data *rd)
1400{
1401 struct Zone *zone = cls;
1402 struct Request *req;
1403 struct GNUNET_HashCode hc;
1404 char *fqdn;
1405
1406 ns_iterator_trigger_next--;
1407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1408 "Obtained NAMESTORE reply, %llu left in round\n",
1409 (unsigned long long) ns_iterator_trigger_next);
1410 if (0 == ns_iterator_trigger_next)
1411 {
1412 ns_iterator_trigger_next = NS_BATCH_SIZE;
1413 GNUNET_STATISTICS_update (stats,
1414 "# NAMESTORE records requested from cache",
1415 ns_iterator_trigger_next,
1416 GNUNET_NO);
1417 GNUNET_NAMESTORE_zone_iterator_next (zone_it, ns_iterator_trigger_next);
1418 }
1419 GNUNET_asprintf (&fqdn, "%s.%s", label, zone->domain);
1420 GNUNET_CRYPTO_hash (fqdn, strlen (fqdn) + 1, &hc);
1421 GNUNET_free (fqdn);
1422 req = GNUNET_CONTAINER_multihashmap_get (ns_pending, &hc);
1423 if (NULL == req)
1424 {
1425 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1426 "Ignoring record `%s' in zone `%s': not on my list!\n",
1427 label,
1428 zone->domain);
1429 return;
1430 }
1431 GNUNET_assert (GNUNET_OK ==
1432 GNUNET_CONTAINER_multihashmap_remove (ns_pending, &hc, req));
1433 GNUNET_break (0 == GNUNET_memcmp (key, &req->zone->key));
1434 GNUNET_break (0 == strcasecmp (label, get_label (req)));
1435 for (unsigned int i = 0; i < rd_count; i++)
1436 {
1437 struct GNUNET_TIME_Absolute at;
1438
1439 if (0 != (rd->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
1440 {
1441 struct GNUNET_TIME_Relative rel;
1442
1443 rel.rel_value_us = rd->expiration_time;
1444 at = GNUNET_TIME_relative_to_absolute (rel);
1445 }
1446 else
1447 {
1448 at.abs_value_us = rd->expiration_time;
1449 }
1450 add_record (req, rd->record_type, at, rd->data, rd->data_size);
1451 }
1452 if (0 == rd_count)
1453 {
1454 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1455 "Empty record set in namestore for `%s'\n",
1456 req->hostname);
1457 }
1458 else
1459 {
1460 unsigned int pos = 0;
1461
1462 cached++;
1463 req->expires = GNUNET_TIME_UNIT_FOREVER_ABS;
1464 for (struct Record *rec = req->rec_head; NULL != rec; rec = rec->next)
1465 {
1466 struct GNUNET_TIME_Absolute at;
1467
1468 at.abs_value_us = rec->grd.expiration_time;
1469 req->expires = GNUNET_TIME_absolute_min (req->expires, at);
1470 pos++;
1471 }
1472 if (0 == pos)
1473 req->expires = GNUNET_TIME_UNIT_ZERO_ABS;
1474 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1475 "Hot-start with %u existing records for `%s'\n",
1476 pos,
1477 req->hostname);
1478 }
1479 free_records (req);
1480
1481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1482 "Adding `%s' to worklist to start at %s\n",
1483 req->hostname,
1484 GNUNET_STRINGS_absolute_time_to_string (req->expires));
1485 insert_sorted (req);
1486}
1487
1488
1489/**
1490 * Add @a hostname to the list of requests to be made.
1491 *
1492 * @param hostname name to resolve
1493 */
1494static void
1495queue (const char *hostname)
1496{
1497 struct Request *req;
1498 const char *dot;
1499 struct Zone *zone;
1500 size_t hlen;
1501 struct GNUNET_HashCode hc;
1502
1503 if (GNUNET_OK != GNUNET_DNSPARSER_check_name (hostname))
1504 {
1505 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1506 "Refusing invalid hostname `%s'\n",
1507 hostname);
1508 rejects++;
1509 return;
1510 }
1511 dot = strchr (hostname, (unsigned char) '.');
1512 if (NULL == dot)
1513 {
1514 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1515 "Refusing invalid hostname `%s' (lacks '.')\n",
1516 hostname);
1517 rejects++;
1518 return;
1519 }
1520 for (zone = zone_head; NULL != zone; zone = zone->next)
1521 if (0 == strcmp (zone->domain, dot + 1))
1522 break;
1523 if (NULL == zone)
1524 {
1525 rejects++;
1526 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1527 "Domain name `%s' not in ego list!\n",
1528 dot + 1);
1529 return;
1530 }
1531
1532 hlen = strlen (hostname) + 1;
1533 req = GNUNET_malloc (sizeof(struct Request) + hlen);
1534 req->zone = zone;
1535 req->hostname = (char *) &req[1];
1536 GNUNET_memcpy (req->hostname, hostname, hlen);
1537 req->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1538 UINT16_MAX);
1539 GNUNET_CRYPTO_hash (req->hostname, hlen, &hc);
1540 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
1541 ns_pending,
1542 &hc,
1543 req,
1544 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1545 {
1546 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1547 "Duplicate hostname `%s' ignored\n",
1548 hostname);
1549 GNUNET_free (req);
1550 return;
1551 }
1552}
1553
1554
1555/**
1556 * We have completed the initial iteration over the namestore's database.
1557 * This function is called on each of the remaining records in
1558 * #move_to_queue to #queue() them, as we will simply not find existing
1559 * records for them any longer.
1560 *
1561 * @param cls NULL
1562 * @param key unused
1563 * @param value a `struct Request`
1564 * @return #GNUNET_OK (continue to iterate)
1565 */
1566static int
1567move_to_queue (void *cls, const struct GNUNET_HashCode *key, void *value)
1568{
1569 struct Request *req = value;
1570
1571 (void) cls;
1572 (void) key;
1573 insert_sorted (req);
1574 return GNUNET_OK;
1575}
1576
1577
1578/**
1579 * Iterate over all of the zones we care about and see which records
1580 * we may need to re-fetch when.
1581 *
1582 * @param cls NULL
1583 */
1584static void
1585iterate_zones (void *cls)
1586{
1587 static struct Zone *last;
1588
1589 (void) cls;
1590 if (NULL != zone_it)
1591 {
1592 zone_it = NULL;
1593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1594 "Finished iteration over zone `%s'!\n",
1595 last->domain);
1596 /* subtract left-overs from previous iteration */
1597 GNUNET_STATISTICS_update (stats,
1598 "# NAMESTORE records requested from cache",
1599 (long long) (-ns_iterator_trigger_next),
1600 GNUNET_NO);
1601 ns_iterator_trigger_next = 0;
1602 }
1603 GNUNET_assert (NULL != zone_tail);
1604 if (zone_tail == last)
1605 {
1606 /* Done iterating over relevant zones in NAMESTORE, move
1607 rest of hash map to work queue as well. */
1608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1609 "Finished all NAMESTORE iterations!\n");
1610 GNUNET_STATISTICS_set (stats,
1611 "# Domain names without cached reply",
1612 GNUNET_CONTAINER_multihashmap_size (ns_pending),
1613 GNUNET_NO);
1614 GNUNET_CONTAINER_multihashmap_iterate (ns_pending, &move_to_queue, NULL);
1615 GNUNET_CONTAINER_multihashmap_destroy (ns_pending);
1616 ns_pending = NULL;
1617 start_time_reg_proc = GNUNET_TIME_absolute_get ();
1618 total_reg_proc_dns = 0;
1619 total_reg_proc_dns_ns = 0;
1620 return;
1621 }
1622 if (NULL == last)
1623 last = zone_head;
1624 else
1625 last = last->next;
1626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1627 "Starting iteration over zone `%s'!\n",
1628 last->domain);
1629 /* subtract left-overs from previous iteration */
1630 GNUNET_STATISTICS_update (stats,
1631 "# NAMESTORE records requested from cache",
1632 1,
1633 GNUNET_NO);
1634 ns_iterator_trigger_next = 1;
1635 GNUNET_STATISTICS_update (stats, "# zones iterated", 1, GNUNET_NO);
1636 zone_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
1637 &last->key,
1638 &ns_lookup_error_cb,
1639 NULL,
1640 &ns_lookup_result_cb,
1641 last,
1642 &iterate_zones,
1643 NULL);
1644}
1645
1646
1647/**
1648 * Begin processing hostnames from stdin.
1649 *
1650 * @param cls NULL
1651 */
1652static void
1653process_stdin (void *cls)
1654{
1655 static struct GNUNET_TIME_Absolute last;
1656 static uint64_t idot;
1657 char hn[256];
1658
1659 (void) cls;
1660 t = NULL;
1661 if (NULL != id)
1662 {
1663 GNUNET_IDENTITY_disconnect (id);
1664 id = NULL;
1665 }
1666 while (NULL != fgets (hn, sizeof(hn), stdin))
1667 {
1668 if (strlen (hn) > 0)
1669 hn[strlen (hn) - 1] = '\0'; /* eat newline */
1670 if (0 == idot)
1671 last = GNUNET_TIME_absolute_get ();
1672 idot++;
1673 if (0 == idot % 100000)
1674 {
1675 struct GNUNET_TIME_Relative delta;
1676
1677 delta = GNUNET_TIME_absolute_get_duration (last);
1678 last = GNUNET_TIME_absolute_get ();
1679 fprintf (stderr,
1680 "Read 100000 domain names in %s\n",
1681 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_YES));
1682 GNUNET_STATISTICS_set (stats, "# domain names provided", idot, GNUNET_NO);
1683 }
1684 queue (hn);
1685 }
1686 fprintf (stderr,
1687 "Done reading %llu domain names\n",
1688 (unsigned long long) idot);
1689 GNUNET_STATISTICS_set (stats, "# domain names provided", idot, GNUNET_NO);
1690 iterate_zones (NULL);
1691}
1692
1693
1694/**
1695 * Method called to inform about the egos of this peer.
1696 *
1697 * When used with #GNUNET_IDENTITY_connect, this function is
1698 * initially called for all egos and then again whenever a
1699 * ego's name changes or if it is deleted. At the end of
1700 * the initial pass over all egos, the function is once called
1701 * with 'NULL' for @a ego. That does NOT mean that the callback won't
1702 * be invoked in the future or that there was an error.
1703 *
1704 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get, this
1705 * function is only called ONCE, and 'NULL' being passed in @a ego does
1706 * indicate an error (for example because name is taken or no default value is
1707 * known). If @a ego is non-NULL and if '*ctx' is set in those callbacks, the
1708 * value WILL be passed to a subsequent call to the identity callback of
1709 * #GNUNET_IDENTITY_connect (if that one was not NULL).
1710 *
1711 * When an identity is renamed, this function is called with the
1712 * (known) @a ego but the NEW @a name.
1713 *
1714 * When an identity is deleted, this function is called with the
1715 * (known) ego and "NULL" for the @a name. In this case,
1716 * the @a ego is henceforth invalid (and the @a ctx should also be
1717 * cleaned up).
1718 *
1719 * @param cls closure
1720 * @param ego ego handle, NULL for end of list
1721 * @param ctx context for application to store data for this ego
1722 * (during the lifetime of this process, initially NULL)
1723 * @param name name assigned by the user for this ego,
1724 * NULL if the user just deleted the ego and it
1725 * must thus no longer be used
1726 */
1727static void
1728identity_cb (void *cls,
1729 struct GNUNET_IDENTITY_Ego *ego,
1730 void **ctx,
1731 const char *name)
1732{
1733 (void) cls;
1734 (void) ctx;
1735
1736 if (NULL == ego)
1737 {
1738 /* end of iteration */
1739 if (NULL == zone_head)
1740 {
1741 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No zone found\n");
1742 GNUNET_SCHEDULER_shutdown ();
1743 return;
1744 }
1745 /* zone_head non-null, process hostnames from stdin */
1746 t = GNUNET_SCHEDULER_add_now (&process_stdin, NULL);
1747 return;
1748 }
1749 if (NULL != name)
1750 {
1751 struct Zone *zone;
1752
1753 zone = GNUNET_new (struct Zone);
1754 zone->key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1755 zone->domain = GNUNET_strdup (name);
1756 GNUNET_CONTAINER_DLL_insert (zone_head, zone_tail, zone);
1757 }
1758}
1759
1760
1761/**
1762 * Process requests from the queue, then if the queue is
1763 * not empty, try again.
1764 *
1765 * @param cls NULL
1766 * @param args remaining command-line arguments
1767 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1768 * @param cfg configuration
1769 */
1770static void
1771run (void *cls,
1772 char *const *args,
1773 const char *cfgfile,
1774 const struct GNUNET_CONFIGURATION_Handle *cfg)
1775{
1776 (void) cls;
1777 (void) args;
1778 (void) cfgfile;
1779 stats = GNUNET_STATISTICS_create ("zoneimport", cfg);
1780 req_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1781 ns_pending = GNUNET_CONTAINER_multihashmap_create (map_size, GNUNET_NO);
1782 if (NULL == ns_pending)
1783 {
1784 fprintf (stderr, "Failed to allocate memory for main hash map\n");
1785 return;
1786 }
1787 ctx = GNUNET_DNSSTUB_start (256);
1788 if (NULL == ctx)
1789 {
1790 fprintf (stderr, "Failed to initialize GNUnet DNS STUB\n");
1791 return;
1792 }
1793 if (NULL == args[0])
1794 {
1795 fprintf (stderr,
1796 "You must provide a list of DNS resolvers on the command line\n");
1797 return;
1798 }
1799 for (unsigned int i = 0; NULL != args[i]; i++)
1800 {
1801 if (GNUNET_OK != GNUNET_DNSSTUB_add_dns_ip (ctx, args[i]))
1802 {
1803 fprintf (stderr, "Failed to use `%s' for DNS resolver\n", args[i]);
1804 return;
1805 }
1806 }
1807
1808
1809 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1810 ns = GNUNET_NAMESTORE_connect (cfg);
1811 if (NULL == ns)
1812 {
1813 GNUNET_SCHEDULER_shutdown ();
1814 return;
1815 }
1816 id = GNUNET_IDENTITY_connect (cfg, &identity_cb, NULL);
1817}
1818
1819
1820/**
1821 * Call with IP address of resolver to query.
1822 *
1823 * @param argc should be 2
1824 * @param argv[1] should contain IP address
1825 * @return 0 on success
1826 */
1827int
1828main (int argc, char *const *argv)
1829{
1830 struct GNUNET_GETOPT_CommandLineOption options[] =
1831 { GNUNET_GETOPT_option_uint ('s',
1832 "size",
1833 "MAPSIZE",
1834 gettext_noop (
1835 "size to use for the main hash map"),
1836 &map_size),
1837 GNUNET_GETOPT_option_relative_time (
1838 'm',
1839 "minimum-expiration",
1840 "RELATIVETIME",
1841 gettext_noop ("minimum expiration time we assume for imported records"),
1842 &minimum_expiration_time),
1843 GNUNET_GETOPT_OPTION_END };
1844 int ret;
1845
1846 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1847 return 2;
1848 if (GNUNET_OK != (ret = GNUNET_PROGRAM_run (argc,
1849 argv,
1850 "gnunet-zoneimport",
1851 "import DNS zone into namestore",
1852 options,
1853 &run,
1854 NULL)))
1855 return ret;
1856 GNUNET_free_nz ((void *) argv);
1857 fprintf (stderr,
1858 "Rejected %u names, had %u cached, did %u lookups, stored %u record sets\n"
1859 "Found %u records, %u lookups failed, %u/%u pending on shutdown\n",
1860 rejects,
1861 cached,
1862 lookups,
1863 record_sets,
1864 records,
1865 failures,
1866 pending,
1867 pending_rs);
1868 return 0;
1869}
1870
1871
1872/* end of gnunet-zoneimport.c */
diff --git a/src/namestore/meson.build b/src/namestore/meson.build
deleted file mode 100644
index fd7cfe553..000000000
--- a/src/namestore/meson.build
+++ /dev/null
@@ -1,139 +0,0 @@
1libgnunetnamestore_src = ['namestore_api.c', 'namestore_api_monitor.c']
2libgnunetpluginnamestore_sqlite_src = ['plugin_namestore_sqlite.c']
3
4gnunetnamestore_src = ['gnunet-namestore.c']
5gnunetservicenamestore_src = ['gnunet-service-namestore.c']
6
7configure_file(input : 'namestore.conf.in',
8 output : 'namestore.conf',
9 configuration : cdata,
10 install: true,
11 install_dir: pkgcfgdir)
12
13
14if get_option('monolith')
15 foreach p : libgnunetnamestore_src + libgnunetpluginnamestore_sqlite_src + gnunetservicenamestore_src
16 gnunet_src += 'namestore/' + p
17 endforeach
18 subdir_done()
19endif
20
21libgnunetnamestore = library('gnunetnamestore',
22 libgnunetnamestore_src,
23 soversion: '0',
24 version: '0.0.1',
25 dependencies: [libgnunetutil_dep,
26 libgnunetgnsrecord_dep,
27 libgnunetidentity_dep],
28 include_directories: [incdir, configuration_inc],
29 install: true,
30 install_dir: get_option('libdir'))
31libgnunetnamestore_dep = declare_dependency(link_with : libgnunetnamestore)
32pkg.generate(libgnunetnamestore, url: 'https://www.gnunet.org',
33 description : 'Provides API for storing GNS records to a database')
34
35shared_module('gnunet_plugin_rest_namestore',
36 ['plugin_rest_namestore.c'],
37 dependencies: [libgnunetrest_dep,
38 libgnunetidentity_dep,
39 libgnunetgnsrecordjson_dep,
40 libgnunetgnsrecord_dep,
41 libgnunetnamestore_dep,
42 libgnunetjson_dep,
43 libgnunetutil_dep,
44 json_dep,
45 mhd_dep],
46 include_directories: [incdir, configuration_inc],
47 install: true,
48 install_dir: get_option('libdir') / 'gnunet')
49
50
51shared_module('gnunet_plugin_namestore_sqlite',
52 libgnunetpluginnamestore_sqlite_src,
53 dependencies: [libgnunetutil_dep,
54 libgnunetgnsrecord_dep,
55 libgnunetidentity_dep,
56 libgnunetsq_dep,
57 libgnunetstatistics_dep,
58 sqlite_dep],
59 include_directories: [incdir, configuration_inc],
60 install: true,
61 install_dir: get_option('libdir')/'gnunet')
62
63if pq_dep.found()
64 shared_module('gnunet_plugin_namestore_postgres',
65 ['plugin_namestore_postgres.c'],
66 dependencies: [libgnunetutil_dep,
67 libgnunetgnsrecord_dep,
68 libgnunetidentity_dep,
69 libgnunetpq_dep,
70 libgnunetstatistics_dep,
71 pq_dep],
72 include_directories: [incdir, configuration_inc],
73 install: true,
74 install_dir: get_option('libdir')/'gnunet')
75endif
76
77executable ('gnunet-namestore',
78 gnunetnamestore_src,
79 dependencies: [libgnunetnamestore_dep,
80 libgnunetutil_dep,
81 libgnunetgnsrecord_dep,
82 libgnunetidentity_dep],
83 include_directories: [incdir, configuration_inc],
84 install: true,
85 install_dir: get_option('bindir'))
86executable ('gnunet-namestore-dbtool',
87 ['gnunet-namestore-dbtool.c'],
88 dependencies: [libgnunetnamestore_dep,
89 libgnunetutil_dep,
90 libgnunetgnsrecord_dep,
91 libgnunetidentity_dep],
92 include_directories: [incdir, configuration_inc],
93 install: true,
94 install_dir: get_option('bindir'))
95executable ('gnunet-namestore-zonefile',
96 ['gnunet-namestore-zonefile.c'],
97 dependencies: [libgnunetnamestore_dep,
98 libgnunetutil_dep,
99 libgnunetgnsrecord_dep,
100 libgnunetidentity_dep],
101 include_directories: [incdir, configuration_inc],
102 install: true,
103 install_dir: get_option('bindir'))
104executable ('gnunet-zoneimport',
105 ['gnunet-zoneimport.c'],
106 dependencies: [libgnunetnamestore_dep,
107 libgnunetutil_dep,
108 libgnunetstatistics_dep,
109 libgnunetgnsrecord_dep,
110 libgnunetidentity_dep],
111 include_directories: [incdir, configuration_inc],
112 install: true,
113 install_dir: get_option('bindir'))
114executable ('gnunet-service-namestore',
115 gnunetservicenamestore_src,
116 dependencies: [libgnunetnamestore_dep,
117 libgnunetutil_dep,
118 libgnunetnamecache_dep,
119 libgnunetgnsrecord_dep,
120 libgnunetidentity_dep,
121 libgnunetstatistics_dep],
122 include_directories: [incdir, configuration_inc],
123 install: true,
124 install_dir: get_option('libdir')/'gnunet'/'libexec')
125executable ('gnunet-namestore-fcfsd',
126 ['gnunet-namestore-fcfsd.c'],
127 dependencies: [libgnunetnamestore_dep,
128 libgnunetutil_dep,
129 libgnunetnamecache_dep,
130 libgnunetgnsrecord_dep,
131 libgnunetidentity_dep,
132 mhd_dep,
133 json_dep,
134 libgnunetjson_dep,
135 libgnunetstatistics_dep],
136 include_directories: [incdir, configuration_inc],
137 install: true,
138 install_dir: get_option('libdir')/'gnunet'/'libexec')
139
diff --git a/src/namestore/namestore-0001.sql b/src/namestore/namestore-0001.sql
deleted file mode 100644
index bdfb31976..000000000
--- a/src/namestore/namestore-0001.sql
+++ /dev/null
@@ -1,48 +0,0 @@
1--
2-- This file is part of GNUnet
3-- Copyright (C) 2014--2022 GNUnet e.V.
4--
5-- GNUnet is free software; you can redistribute it and/or modify it under the
6-- terms of the GNU 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 General Public License for more details.
12--
13-- You should have received a copy of the GNU General Public License along with
14-- GNUnet; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15--
16
17-- Everything in one big transaction
18BEGIN;
19
20-- Check patch versioning is in place.
21SELECT _v.register_patch('namestore-0001', NULL, NULL);
22
23-------------------- Schema ----------------------------
24
25CREATE SCHEMA namestore;
26COMMENT ON SCHEMA namestore IS 'gnunet-namestore data';
27
28SET search_path TO namestore;
29
30CREATE TABLE ns098records (
31 seq BIGSERIAL PRIMARY KEY,
32 zone_private_key BYTEA NOT NULL DEFAULT '',
33 pkey BYTEA DEFAULT '',
34 rvalue BYTEA NOT NULL DEFAULT '',
35 record_count INTEGER NOT NULL DEFAULT 0,
36 record_data BYTEA NOT NULL DEFAULT '',
37 label TEXT NOT NULL DEFAULT '',
38 CONSTRAINT zl UNIQUE (zone_private_key,label));
39
40CREATE INDEX IF NOT EXISTS ir_pkey_reverse
41 ON ns098records (zone_private_key,pkey);
42CREATE INDEX IF NOT EXISTS ir_pkey_iter
43 ON ns098records (zone_private_key,seq);
44CREATE INDEX IF NOT EXISTS ir_label
45 ON ns098records (label);
46
47
48COMMIT;
diff --git a/src/namestore/namestore-drop.sql b/src/namestore/namestore-drop.sql
deleted file mode 100644
index 231417af8..000000000
--- a/src/namestore/namestore-drop.sql
+++ /dev/null
@@ -1,25 +0,0 @@
1--
2-- This file is part of GNUnet
3-- Copyright (C) 2014--2022 GNUnet e.V.
4--
5-- GNUnet is free software; you can redistribute it and/or modify it under the
6-- terms of the GNU 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 General Public License for more details.
12--
13-- You should have received a copy of the GNU General Public License along with
14-- GNUnet; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15--
16
17-- Everything in one big transaction
18BEGIN;
19
20
21SELECT _v.unregister_patch('namestore-0001');
22
23DROP SCHEMA namestore CASCADE;
24
25COMMIT;
diff --git a/src/namestore/namestore.conf.in b/src/namestore/namestore.conf.in
deleted file mode 100644
index d817f3f95..000000000
--- a/src/namestore/namestore.conf.in
+++ /dev/null
@@ -1,47 +0,0 @@
1[namestore]
2START_ON_DEMAND = @START_ON_DEMAND@
3RUN_PER_USER = YES
4UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-namestore.sock
5UNIX_MATCH_UID = NO
6UNIX_MATCH_GID = YES
7@UNIXONLY@ PORT = 2099
8HOSTNAME = localhost
9BINARY = gnunet-service-namestore
10ACCEPT_FROM = 127.0.0.1;
11ACCEPT_FROM6 = ::1;
12
13# Which database should we use?
14DATABASE = sqlite
15
16# Should we optimize publishing record by caching the mapping
17# from zone private keys to zone public keys in memory?
18# (Set to NO if totally paranoid about keeping private keys
19# in RAM longer than necessary.)
20CACHE_KEYS = YES
21
22
23[namestore-sqlite]
24INIT_ON_CONNECT = YES
25FILENAME = $GNUNET_DATA_HOME/namestore/sqlite.db
26
27[namestore-postgres]
28# How to connect to the database
29CONFIG = postgres:///gnunet
30# Use asynchronous commit (SET synchronous_commit TO OFF).
31ASYNC_COMMIT = NO
32INIT_ON_CONNECT = YES
33SQL_DIR = ${DATADIR}/sql/
34
35[uri]
36gns = gnunet-namestore -e 1a -u
37
38
39[fcfsd]
40# Name of the fcfs registration service binary (for ARM)
41BINARY = gnunet-namestore-fcfsd
42START_ON_DEMAND = NO
43UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-fcfsd.sock
44RELATIVE_RECORD_EXPIRATION = 7 d
45
46# On what port does the FCFS daemon listen for HTTP clients?
47HTTPPORT = 18080
diff --git a/src/namestore/namestore.h b/src/namestore/namestore.h
deleted file mode 100644
index 35d54d317..000000000
--- a/src/namestore/namestore.h
+++ /dev/null
@@ -1,491 +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 namestore/namestore.h
23 * @brief common internal definitions for namestore service
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef NAMESTORE_H
28#define NAMESTORE_H
29
30/**
31 * Maximum length of any name, including 0-termination.
32 */
33#define MAX_NAME_LEN 256
34
35GNUNET_NETWORK_STRUCT_BEGIN
36
37/**
38 * Generic namestore message with op id
39 */
40struct GNUNET_NAMESTORE_Header
41{
42 /**
43 * header.type will be GNUNET_MESSAGE_TYPE_NAMESTORE_*
44 * header.size will be message size
45 */
46 struct GNUNET_MessageHeader header;
47
48 /**
49 * Request ID in NBO
50 */
51 uint32_t r_id GNUNET_PACKED;
52};
53
54struct RecordSet
55{
56 /**
57 * Name length
58 */
59 uint16_t name_len GNUNET_PACKED;
60
61 /**
62 * Length of serialized record data
63 */
64 uint16_t rd_len GNUNET_PACKED;
65
66 /**
67 * Number of records contained
68 */
69 uint16_t rd_count GNUNET_PACKED;
70
71 /**
72 * Reserved for alignment.
73 */
74 uint16_t reserved GNUNET_PACKED;
75
76
77 /* followed by:
78 * name with length name_len
79 * serialized record data with rd_count records
80 */
81};
82
83/**
84 * Store a record to the namestore (as authority).
85 */
86struct RecordStoreMessage
87{
88 /**
89 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE
90 */
91 struct GNUNET_NAMESTORE_Header gns_header;
92
93 /**
94 * Number of record sets
95 */
96 uint16_t rd_set_count;
97
98 /**
99 * Length of the zone key
100 */
101 uint16_t key_len GNUNET_PACKED;
102
103 /**
104 * Followed by the private zone key
105 * Followed by rd_set_count RecordSets
106 */
107};
108
109
110/**
111 * Response to a record storage request.
112 */
113struct RecordStoreResponseMessage
114{
115 /**
116 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
117 */
118 struct GNUNET_NAMESTORE_Header gns_header;
119
120 /**
121 * GNUNET_ErrorCode
122 */
123 uint32_t ec GNUNET_PACKED;
124
125};
126
127
128/**
129 * Lookup a label
130 */
131struct LabelLookupMessage
132{
133 /**
134 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP
135 */
136 struct GNUNET_NAMESTORE_Header gns_header;
137
138 /**
139 * Length of the name
140 */
141 uint16_t label_len GNUNET_PACKED;
142
143 /**
144 * GNUNET_YES if this lookup corresponds to an edit request
145 */
146 uint16_t is_edit_request GNUNET_PACKED;
147
148 /**
149 * The record filter
150 */
151 uint16_t filter;
152
153 /**
154 * Length of the zone key
155 */
156 uint16_t key_len GNUNET_PACKED;
157
158 /* followed by:
159 * the private zone key
160 * name with length name_len
161 */
162};
163
164
165/**
166 * Lookup a label
167 */
168struct LabelLookupResponseMessage
169{
170 /**
171 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE
172 */
173 struct GNUNET_NAMESTORE_Header gns_header;
174
175 /**
176 * Name length
177 */
178 uint16_t name_len GNUNET_PACKED;
179
180 /**
181 * Length of serialized record data
182 */
183 uint16_t rd_len GNUNET_PACKED;
184
185 /**
186 * Number of records contained
187 */
188 uint16_t rd_count GNUNET_PACKED;
189
190 /**
191 * Was the label found in the database??
192 * #GNUNET_YES or #GNUNET_NO
193 */
194 int16_t found GNUNET_PACKED;
195
196 /**
197 * Reserved (alignment)
198 */
199 uint16_t reserved GNUNET_PACKED;
200
201 /**
202 * Length of the zone key
203 */
204 uint16_t key_len GNUNET_PACKED;
205
206 /* followed by:
207 * the private zone key
208 * name with length name_len
209 * serialized record data with rd_count records
210 */
211};
212
213
214/**
215 * Lookup a name for a zone hash
216 */
217struct ZoneToNameMessage
218{
219 /**
220 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME
221 */
222 struct GNUNET_NAMESTORE_Header gns_header;
223
224 /**
225 * Length of the zone key
226 */
227 uint16_t key_len GNUNET_PACKED;
228
229 /**
230 * Length of the public value zone key
231 */
232 uint16_t pkey_len GNUNET_PACKED;
233
234 /**
235 * Followed by
236 * - the private zone key to look up in
237 * - the public key of the target zone
238 */
239};
240
241
242/**
243 * Respone for zone to name lookup
244 */
245struct ZoneToNameResponseMessage
246{
247 /**
248 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE
249 */
250 struct GNUNET_NAMESTORE_Header gns_header;
251
252 /**
253 * result in NBO: #GNUNET_EC_NONE on success,
254 * #GNUNET_EC_NAMESTORE_NO_RESULTS if there were no
255 * results.
256 * Other error messages on error.
257 */
258 int32_t ec GNUNET_PACKED;
259
260 /**
261 * Length of the name
262 */
263 uint16_t name_len GNUNET_PACKED;
264
265 /**
266 * Length of serialized record data
267 */
268 uint16_t rd_len GNUNET_PACKED;
269
270 /**
271 * Number of records contained
272 */
273 uint16_t rd_count GNUNET_PACKED;
274
275 /**
276 * Length of the zone key
277 */
278 uint16_t key_len GNUNET_PACKED;
279
280 /* followed by:
281 * the private zone key
282 * name with length name_len
283 * serialized record data with rd_count records
284 */
285};
286
287
288/**
289 * Record is returned from the namestore (as authority).
290 */
291struct RecordResultMessage
292{
293 /**
294 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT
295 */
296 struct GNUNET_NAMESTORE_Header gns_header;
297
298 /**
299 * Expiration time if the record result (if any).
300 * Takes TOMBSTONEs into account.
301 */
302 struct GNUNET_TIME_AbsoluteNBO expire;
303
304 /**
305 * Name length
306 */
307 uint16_t name_len GNUNET_PACKED;
308
309 /**
310 * Length of serialized record data
311 */
312 uint16_t rd_len GNUNET_PACKED;
313
314 /**
315 * Number of records contained
316 */
317 uint16_t rd_count GNUNET_PACKED;
318
319 /**
320 * Length of the zone key
321 */
322 uint16_t key_len GNUNET_PACKED;
323
324 /* followed by:
325 * the private key of the authority
326 * name with length name_len
327 * serialized record data with rd_count records
328 */
329};
330
331/**
332 * Send a transaction control message.
333 */
334struct TxControlMessage
335{
336 /**
337 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL
338 */
339 struct GNUNET_NAMESTORE_Header gns_header;
340
341 /**
342 * always zero (for alignment)
343 */
344 uint16_t reserved GNUNET_PACKED;
345
346 /**
347 * The type of control message to send
348 */
349 uint16_t control GNUNET_PACKED;
350
351};
352
353/**
354 * Result of a transaction control message.
355 */
356struct TxControlResultMessage
357{
358 /**
359 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL_RESULT
360 */
361 struct GNUNET_NAMESTORE_Header gns_header;
362
363 /**
364 * Of type GNUNET_ErrorCode
365 */
366 uint32_t ec GNUNET_PACKED;
367
368};
369
370
371
372/**
373 * Start monitoring a zone.
374 */
375struct ZoneMonitorStartMessage
376{
377 /**
378 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START
379 */
380 struct GNUNET_MessageHeader header;
381
382 /**
383 * #GNUNET_YES to first iterate over all records,
384 * #GNUNET_NO to only monitor changes.o
385 */
386 uint32_t iterate_first GNUNET_PACKED;
387
388 /**
389 * Record set filter control flags.
390 * See GNUNET_NAMESTORE_Filter enum.
391 */
392 uint16_t filter;
393
394 /**
395 * Length of the zone key
396 */
397 uint16_t key_len GNUNET_PACKED;
398
399 /**
400 * Followed by the private zone key.
401 */
402};
403
404
405/**
406 * Ask for next result of zone iteration for the given operation
407 */
408struct ZoneMonitorNextMessage
409{
410 /**
411 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT
412 */
413 struct GNUNET_MessageHeader header;
414
415 /**
416 * Always zero.
417 */
418 uint32_t reserved;
419
420 /**
421 * Number of records to return to the iterator in one shot
422 * (before #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_MONITOR_NEXT
423 * should be send again). In NBO.
424 */
425 uint64_t limit;
426};
427
428
429/**
430 * Start a zone iteration for the given zone
431 */
432struct ZoneIterationStartMessage
433{
434 /**
435 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START
436 */
437 struct GNUNET_NAMESTORE_Header gns_header;
438
439 /**
440 * Record set filter control flags.
441 * See GNUNET_NAMESTORE_Filter enum.
442 */
443 uint16_t filter;
444
445 /**
446 * Length of the zone key
447 */
448 uint16_t key_len GNUNET_PACKED;
449
450 /**
451 * Followed by the private zone key (optional)
452 */
453};
454
455
456/**
457 * Ask for next result of zone iteration for the given operation
458 */
459struct ZoneIterationNextMessage
460{
461 /**
462 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT
463 */
464 struct GNUNET_NAMESTORE_Header gns_header;
465
466 /**
467 * Number of records to return to the iterator in one shot
468 * (before #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT
469 * should be send again). In NBO.
470 */
471 uint64_t limit;
472};
473
474
475/**
476 * Stop zone iteration for the given operation
477 */
478struct ZoneIterationStopMessage
479{
480 /**
481 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP
482 */
483 struct GNUNET_NAMESTORE_Header gns_header;
484};
485
486
487GNUNET_NETWORK_STRUCT_END
488
489
490/* end of namestore.h */
491#endif
diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c
deleted file mode 100644
index 7a4438e30..000000000
--- a/src/namestore/namestore_api.c
+++ /dev/null
@@ -1,1563 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-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/**
22 * @file namestore/namestore_api.c
23 * @brief API to access the NAMESTORE service
24 * @author Martin Schanzenbach
25 * @author Matthias Wachs
26 * @author Christian Grothoff
27 */
28
29#include "platform.h"
30#include "gnunet_error_codes.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_constants.h"
33#include "gnunet_arm_service.h"
34#include "gnunet_signatures.h"
35#include "gnunet_gns_service.h"
36#include "gnunet_namestore_service.h"
37#include "namestore.h"
38
39
40#define LOG(kind, ...) GNUNET_log_from (kind, "namestore-api", __VA_ARGS__)
41
42/**
43 * We grant the namestore up to 1 minute of latency, if it is slower than
44 * that, store queries will fail.
45 */
46#define NAMESTORE_DELAY_TOLERANCE GNUNET_TIME_UNIT_MINUTES
47
48/**
49 * An QueueEntry used to store information for a pending
50 * NAMESTORE record operation
51 */
52struct GNUNET_NAMESTORE_QueueEntry
53{
54 /**
55 * Kept in a DLL.
56 */
57 struct GNUNET_NAMESTORE_QueueEntry *next;
58
59 /**
60 * Kept in a DLL.
61 */
62 struct GNUNET_NAMESTORE_QueueEntry *prev;
63
64 /**
65 * Main handle to access the namestore.
66 */
67 struct GNUNET_NAMESTORE_Handle *h;
68
69 /**
70 * Continuation to call
71 */
72 GNUNET_NAMESTORE_ContinuationWithStatus cont;
73
74 /**
75 * Closure for @e cont.
76 */
77 void *cont_cls;
78
79 /**
80 * Function to call with the records we get back; or NULL.
81 */
82 GNUNET_NAMESTORE_RecordMonitor proc;
83
84 /**
85 * Function to call with the records we get back; or NULL.
86 */
87 GNUNET_NAMESTORE_RecordSetMonitor proc2;
88
89 /**
90 * Closure for @e proc.
91 */
92 void *proc_cls;
93
94 /**
95 * Function to call on errors.
96 */
97 GNUNET_SCHEDULER_TaskCallback error_cb;
98
99 /**
100 * Closure for @e error_cb.
101 */
102 void *error_cb_cls;
103
104 /**
105 * Envelope of the message to send to the service, if not yet
106 * sent.
107 */
108 struct GNUNET_MQ_Envelope *env;
109
110 /**
111 * Task scheduled to warn us if the namestore is way too slow.
112 */
113 struct GNUNET_SCHEDULER_Task *timeout_task;
114
115 /**
116 * The operation id this zone iteration operation has
117 */
118 uint32_t op_id;
119};
120
121
122/**
123 * Handle for a zone iterator operation
124 */
125struct GNUNET_NAMESTORE_ZoneIterator
126{
127 /**
128 * Kept in a DLL.
129 */
130 struct GNUNET_NAMESTORE_ZoneIterator *next;
131
132 /**
133 * Kept in a DLL.
134 */
135 struct GNUNET_NAMESTORE_ZoneIterator *prev;
136
137 /**
138 * Main handle to access the namestore.
139 */
140 struct GNUNET_NAMESTORE_Handle *h;
141
142 /**
143 * Function to call on completion.
144 */
145 GNUNET_SCHEDULER_TaskCallback finish_cb;
146
147 /**
148 * Closure for @e error_cb.
149 */
150 void *finish_cb_cls;
151
152 /**
153 * The continuation to call with the results
154 */
155 GNUNET_NAMESTORE_RecordMonitor proc;
156
157 /**
158 * The continuation to call with the results
159 */
160 GNUNET_NAMESTORE_RecordSetMonitor proc2;
161
162 /**
163 * Closure for @e proc.
164 */
165 void *proc_cls;
166
167 /**
168 * Function to call on errors.
169 */
170 GNUNET_SCHEDULER_TaskCallback error_cb;
171
172 /**
173 * Closure for @e error_cb.
174 */
175 void *error_cb_cls;
176
177 /**
178 * Envelope of the message to send to the service, if not yet
179 * sent.
180 */
181 struct GNUNET_MQ_Envelope *env;
182
183 /**
184 * Private key of the zone.
185 */
186 struct GNUNET_CRYPTO_PrivateKey zone;
187
188 /**
189 * The operation id this zone iteration operation has
190 */
191 uint32_t op_id;
192};
193
194
195/**
196 * Connection to the NAMESTORE service.
197 */
198struct GNUNET_NAMESTORE_Handle
199{
200 /**
201 * Configuration to use.
202 */
203 const struct GNUNET_CONFIGURATION_Handle *cfg;
204
205 /**
206 * Connection to the service (if available).
207 */
208 struct GNUNET_MQ_Handle *mq;
209
210 /**
211 * Head of pending namestore queue entries
212 */
213 struct GNUNET_NAMESTORE_QueueEntry *op_head;
214
215 /**
216 * Tail of pending namestore queue entries
217 */
218 struct GNUNET_NAMESTORE_QueueEntry *op_tail;
219
220 /**
221 * Head of pending namestore zone iterator entries
222 */
223 struct GNUNET_NAMESTORE_ZoneIterator *z_head;
224
225 /**
226 * Tail of pending namestore zone iterator entries
227 */
228 struct GNUNET_NAMESTORE_ZoneIterator *z_tail;
229
230 /**
231 * Reconnect task
232 */
233 struct GNUNET_SCHEDULER_Task *reconnect_task;
234
235 /**
236 * Delay introduced before we reconnect.
237 */
238 struct GNUNET_TIME_Relative reconnect_delay;
239
240 /**
241 * Should we reconnect to service due to some serious error?
242 */
243 int reconnect;
244
245 /**
246 * The last operation id used for a NAMESTORE operation
247 */
248 uint32_t last_op_id_used;
249};
250
251
252/**
253 * Disconnect from service and then reconnect.
254 *
255 * @param h our handle
256 */
257static void
258force_reconnect (struct GNUNET_NAMESTORE_Handle *h);
259
260
261/**
262 * Find the queue entry that matches the @a rid
263 *
264 * @param h namestore handle
265 * @param rid id to look up
266 * @return NULL if @a rid was not found
267 */
268static struct GNUNET_NAMESTORE_QueueEntry *
269find_qe (struct GNUNET_NAMESTORE_Handle *h, uint32_t rid)
270{
271 struct GNUNET_NAMESTORE_QueueEntry *qe;
272
273 for (qe = h->op_head; qe != NULL; qe = qe->next)
274 if (qe->op_id == rid)
275 return qe;
276 return NULL;
277}
278
279
280/**
281 * Find the zone iteration entry that matches the @a rid
282 *
283 * @param h namestore handle
284 * @param rid id to look up
285 * @return NULL if @a rid was not found
286 */
287static struct GNUNET_NAMESTORE_ZoneIterator *
288find_zi (struct GNUNET_NAMESTORE_Handle *h, uint32_t rid)
289{
290 struct GNUNET_NAMESTORE_ZoneIterator *ze;
291
292 for (ze = h->z_head; ze != NULL; ze = ze->next)
293 if (ze->op_id == rid)
294 return ze;
295 return NULL;
296}
297
298
299/**
300 * Free @a qe.
301 *
302 * @param qe entry to free
303 */
304static void
305free_qe (struct GNUNET_NAMESTORE_QueueEntry *qe)
306{
307 struct GNUNET_NAMESTORE_Handle *h = qe->h;
308
309 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe);
310 if (NULL != qe->env)
311 GNUNET_MQ_discard (qe->env);
312 if (NULL != qe->timeout_task)
313 GNUNET_SCHEDULER_cancel (qe->timeout_task);
314 GNUNET_free (qe);
315}
316
317
318/**
319 * Free @a ze.
320 *
321 * @param ze entry to free
322 */
323static void
324free_ze (struct GNUNET_NAMESTORE_ZoneIterator *ze)
325{
326 struct GNUNET_NAMESTORE_Handle *h = ze->h;
327
328 GNUNET_CONTAINER_DLL_remove (h->z_head, h->z_tail, ze);
329 if (NULL != ze->env)
330 GNUNET_MQ_discard (ze->env);
331 GNUNET_free (ze);
332}
333
334
335/**
336 * Check that @a rd_buf of length @a rd_len contains
337 * @a rd_count records.
338 *
339 * @param rd_len length of @a rd_buf
340 * @param rd_buf buffer with serialized records
341 * @param rd_count number of records expected
342 * @return #GNUNET_OK if @a rd_buf is well-formed
343 */
344static int
345check_rd (size_t rd_len, const void *rd_buf, unsigned int rd_count)
346{
347 struct GNUNET_GNSRECORD_Data rd[rd_count];
348
349 if (GNUNET_OK !=
350 GNUNET_GNSRECORD_records_deserialize (rd_len, rd_buf, rd_count, rd))
351 {
352 GNUNET_break (0);
353 return GNUNET_SYSERR;
354 }
355 return GNUNET_OK;
356}
357
358/**
359 * Handle an incoming message of type
360 * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
361 *
362 * @param cls
363 * @param msg the message we received
364 */
365static void
366handle_record_store_response (void *cls,
367 const struct RecordStoreResponseMessage *msg)
368{
369 struct GNUNET_NAMESTORE_Handle *h = cls;
370 struct GNUNET_NAMESTORE_QueueEntry *qe;
371 enum GNUNET_ErrorCode res;
372
373 qe = find_qe (h, ntohl (msg->gns_header.r_id));
374 res = ntohl (msg->ec);
375 LOG (GNUNET_ERROR_TYPE_DEBUG,
376 "Received RECORD_STORE_RESPONSE with result %d\n",
377 res);
378 if (NULL == qe)
379 return;
380 if (NULL != qe->cont)
381 qe->cont (qe->cont_cls, res);
382 free_qe (qe);
383}
384
385
386/**
387 * Check validity of an incoming message of type
388 * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE
389 *
390 * @param cls
391 * @param msg the message we received
392 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
393 */
394static int
395check_lookup_result (void *cls, const struct LabelLookupResponseMessage *msg)
396{
397 const char *name;
398 size_t exp_msg_len;
399 size_t msg_len;
400 size_t name_len;
401 size_t rd_len;
402 size_t key_len;
403
404 (void) cls;
405 rd_len = ntohs (msg->rd_len);
406 msg_len = ntohs (msg->gns_header.header.size);
407 name_len = ntohs (msg->name_len);
408 key_len = ntohs (msg->key_len);
409 exp_msg_len = sizeof(*msg) + name_len + rd_len + key_len;
410 if (0 != ntohs (msg->reserved))
411 {
412 GNUNET_break (0);
413 return GNUNET_SYSERR;
414 }
415 if (msg_len != exp_msg_len)
416 {
417 GNUNET_break (0);
418 return GNUNET_SYSERR;
419 }
420 name = (const char *) &msg[1] + key_len;
421 if ((name_len > 0) && ('\0' != name[name_len - 1]))
422 {
423 GNUNET_break (0);
424 return GNUNET_SYSERR;
425 }
426 if (GNUNET_NO == ntohs (msg->found))
427 {
428 if (0 != ntohs (msg->rd_count))
429 {
430 GNUNET_break (0);
431 return GNUNET_SYSERR;
432 }
433 return GNUNET_OK;
434 }
435 return check_rd (rd_len, &name[name_len], ntohs (msg->rd_count));
436}
437
438
439/**
440 * Handle an incoming message of type
441 * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE
442 *
443 * @param cls
444 * @param msg the message we received
445 */
446static void
447handle_lookup_result (void *cls, const struct LabelLookupResponseMessage *msg)
448{
449 struct GNUNET_NAMESTORE_Handle *h = cls;
450 struct GNUNET_NAMESTORE_QueueEntry *qe;
451 struct GNUNET_CRYPTO_PrivateKey private_key;
452 const char *name;
453 const char *rd_tmp;
454 size_t name_len;
455 size_t rd_len;
456 size_t key_len;
457 size_t kbytes_read;
458 unsigned int rd_count;
459 int16_t found = (int16_t) ntohs (msg->found);
460
461 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received RECORD_LOOKUP_RESULT (found=%i)\n",
462 found);
463 qe = find_qe (h, ntohl (msg->gns_header.r_id));
464 if (NULL == qe)
465 return;
466 rd_len = ntohs (msg->rd_len);
467 rd_count = ntohs (msg->rd_count);
468 name_len = ntohs (msg->name_len);
469 key_len = ntohs (msg->key_len);
470 GNUNET_assert (GNUNET_SYSERR !=
471 GNUNET_CRYPTO_read_private_key_from_buffer (&msg[1],
472 key_len,
473 &private_key,
474 &kbytes_read));
475 GNUNET_assert (kbytes_read == key_len);
476 name = (const char *) &msg[1] + key_len;
477 if (GNUNET_NO == found)
478 {
479 /* label was not in namestore */
480 if (NULL != qe->proc)
481 qe->proc (qe->proc_cls, &private_key, name, 0, NULL);
482 free_qe (qe);
483 return;
484 }
485 if (GNUNET_SYSERR == found)
486 {
487 if (NULL != qe->error_cb)
488 qe->error_cb (qe->error_cb_cls);
489 free_qe (qe);
490 return;
491 }
492
493 rd_tmp = &name[name_len];
494 {
495 struct GNUNET_GNSRECORD_Data rd[rd_count];
496
497 GNUNET_assert (
498 GNUNET_OK ==
499 GNUNET_GNSRECORD_records_deserialize (rd_len, rd_tmp, rd_count, rd));
500 if (0 == name_len)
501 name = NULL;
502 if (NULL != qe->proc)
503 qe->proc (qe->proc_cls,
504 &private_key,
505 name,
506 rd_count,
507 (rd_count > 0) ? rd : NULL);
508 }
509 free_qe (qe);
510}
511
512
513/**
514 * Handle an incoming message of type
515 * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT
516 *
517 * @param cls
518 * @param msg the message we received
519 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
520 */
521static int
522check_record_result (void *cls, const struct RecordResultMessage *msg)
523{
524 const char *name;
525 size_t msg_len;
526 size_t name_len;
527 size_t rd_len;
528 size_t key_len;
529
530 (void) cls;
531 rd_len = ntohs (msg->rd_len);
532 msg_len = ntohs (msg->gns_header.header.size);
533 key_len = ntohs (msg->key_len);
534 name_len = ntohs (msg->name_len);
535 if (msg_len != sizeof(struct RecordResultMessage) + key_len + name_len
536 + rd_len)
537 {
538 GNUNET_break (0);
539 return GNUNET_SYSERR;
540 }
541 name = (const char *) &msg[1] + key_len;
542 if ((0 == name_len) || ('\0' != name[name_len - 1]))
543 {
544 GNUNET_break (0);
545 return GNUNET_SYSERR;
546 }
547 if (0 == key_len)
548 {
549 GNUNET_break (0);
550 return GNUNET_SYSERR;
551 }
552 return check_rd (rd_len, &name[name_len], ntohs (msg->rd_count));
553}
554
555
556/**
557 * Handle an incoming message of type
558 * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT
559 *
560 * @param cls
561 * @param msg the message we received
562 */
563static void
564handle_record_result (void *cls, const struct RecordResultMessage *msg)
565{
566 struct GNUNET_NAMESTORE_Handle *h = cls;
567 struct GNUNET_NAMESTORE_QueueEntry *qe;
568 struct GNUNET_NAMESTORE_ZoneIterator *ze;
569 struct GNUNET_CRYPTO_PrivateKey private_key;
570 const char *name;
571 const char *rd_tmp;
572 size_t name_len;
573 size_t rd_len;
574 size_t key_len;
575 size_t kbytes_read;
576 unsigned int rd_count;
577
578 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received RECORD_RESULT\n");
579 rd_len = ntohs (msg->rd_len);
580 rd_count = ntohs (msg->rd_count);
581 name_len = ntohs (msg->name_len);
582 key_len = ntohs (msg->key_len);
583 ze = find_zi (h, ntohl (msg->gns_header.r_id));
584 qe = find_qe (h, ntohl (msg->gns_header.r_id));
585 if ((NULL == ze) && (NULL == qe))
586 return; /* rid not found */
587 if ((NULL != ze) && (NULL != qe))
588 {
589 GNUNET_break (0); /* rid ambiguous */
590 force_reconnect (h);
591 return;
592 }
593 name = (const char *) &msg[1] + key_len;
594 GNUNET_assert (GNUNET_SYSERR !=
595 GNUNET_CRYPTO_read_private_key_from_buffer (&msg[1],
596 key_len,
597 &private_key,
598 &kbytes_read));
599 GNUNET_assert (kbytes_read == key_len);
600 rd_tmp = &name[name_len];
601 {
602 struct GNUNET_GNSRECORD_Data rd[rd_count];
603
604 GNUNET_assert (
605 GNUNET_OK ==
606 GNUNET_GNSRECORD_records_deserialize (rd_len, rd_tmp, rd_count, rd));
607 if (0 == name_len)
608 name = NULL;
609 if (NULL != qe)
610 {
611 if (NULL != qe->proc)
612 qe->proc (qe->proc_cls,
613 &private_key,
614 name,
615 rd_count,
616 (rd_count > 0) ? rd : NULL);
617 free_qe (qe);
618 return;
619 }
620 if (NULL != ze)
621 {
622 // Store them here because a callback could free ze
623 GNUNET_NAMESTORE_RecordMonitor proc;
624 GNUNET_NAMESTORE_RecordSetMonitor proc2;
625 void *proc_cls = ze->proc_cls;
626 proc = ze->proc;
627 proc2 = ze->proc2;
628 if (NULL != proc)
629 proc (proc_cls, &private_key, name, rd_count, rd);
630 if (NULL != proc2)
631 proc2 (proc_cls, &private_key, name,
632 rd_count, rd, GNUNET_TIME_absolute_ntoh (msg->expire));
633 return;
634 }
635 }
636 GNUNET_assert (0);
637}
638
639
640/**
641 * Handle an incoming message of type
642 * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END
643 *
644 * @param cls
645 * @param msg the message we received
646 */
647static void
648handle_record_result_end (void *cls, const struct GNUNET_NAMESTORE_Header *msg)
649{
650 struct GNUNET_NAMESTORE_Handle *h = cls;
651 struct GNUNET_NAMESTORE_QueueEntry *qe;
652 struct GNUNET_NAMESTORE_ZoneIterator *ze;
653
654 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received RECORD_RESULT_END\n");
655 ze = find_zi (h, ntohl (msg->r_id));
656 qe = find_qe (h, ntohl (msg->r_id));
657 if ((NULL == ze) && (NULL == qe))
658 return; /* rid not found */
659 if ((NULL != ze) && (NULL != qe))
660 {
661 GNUNET_break (0); /* rid ambiguous */
662 force_reconnect (h);
663 return;
664 }
665 LOG (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration completed!\n");
666 if (NULL == ze)
667 {
668 GNUNET_break (0);
669 force_reconnect (h);
670 return;
671 }
672 if (NULL != ze->finish_cb)
673 ze->finish_cb (ze->finish_cb_cls);
674 free_ze (ze);
675}
676
677static void
678handle_tx_control_result (void *cls,
679 const struct TxControlResultMessage *msg)
680{
681 struct GNUNET_NAMESTORE_Handle *h = cls;
682 struct GNUNET_NAMESTORE_QueueEntry *qe;
683 enum GNUNET_ErrorCode res;
684
685 qe = find_qe (h, ntohl (msg->gns_header.r_id));
686 res = ntohs (msg->ec);
687 LOG (GNUNET_ERROR_TYPE_DEBUG,
688 "Received TX_CONTROL_RESULT with result %d\n",
689 res);
690 if (NULL == qe)
691 return;
692 if (NULL != qe->cont)
693 qe->cont (qe->cont_cls, res);
694 free_qe (qe);
695}
696
697/**
698 * Handle an incoming message of type
699 * #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE.
700 *
701 * @param qe the respective entry in the message queue
702 * @param msg the message we received
703 * @return #GNUNET_OK on success, #GNUNET_SYSERR if message malformed
704 */
705static int
706check_zone_to_name_response (void *cls,
707 const struct ZoneToNameResponseMessage *msg)
708{
709 size_t name_len;
710 size_t rd_ser_len;
711 size_t key_len;
712 const char *name_tmp;
713
714 (void) cls;
715 if (GNUNET_EC_NONE != ntohl (msg->ec))
716 return GNUNET_OK;
717 key_len = ntohs (msg->key_len);
718 name_len = ntohs (msg->name_len);
719 rd_ser_len = ntohs (msg->rd_len);
720 if (ntohs (msg->gns_header.header.size) !=
721 sizeof(struct ZoneToNameResponseMessage) + key_len + name_len
722 + rd_ser_len)
723 {
724 GNUNET_break (0);
725 return GNUNET_SYSERR;
726 }
727 name_tmp = (const char *) &msg[1] + key_len;
728 if ((name_len > 0) && ('\0' != name_tmp[name_len - 1]))
729 {
730 GNUNET_break (0);
731 return GNUNET_SYSERR;
732 }
733 return check_rd (rd_ser_len, &name_tmp[name_len], ntohs (msg->rd_count));
734}
735
736
737/**
738 * Handle an incoming message of type
739 * #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE.
740 *
741 * @param cls
742 * @param msg the message we received
743 */
744static void
745handle_zone_to_name_response (void *cls,
746 const struct ZoneToNameResponseMessage *msg)
747{
748 struct GNUNET_NAMESTORE_Handle *h = cls;
749 struct GNUNET_NAMESTORE_QueueEntry *qe;
750 struct GNUNET_CRYPTO_PrivateKey zone;
751 enum GNUNET_ErrorCode res;
752 size_t name_len;
753 size_t rd_ser_len;
754 unsigned int rd_count;
755 const char *name_tmp;
756 const char *rd_tmp;
757 size_t key_len;
758 size_t kbytes_read;
759
760 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received ZONE_TO_NAME_RESPONSE\n");
761 qe = find_qe (h, ntohl (msg->gns_header.r_id));
762 if (NULL == qe)
763 {
764 LOG (GNUNET_ERROR_TYPE_WARNING,
765 "Response queue already gone...\n");
766 return;
767 }
768 res = ntohl (msg->ec);
769 key_len = ntohs (msg->key_len);
770 GNUNET_assert (GNUNET_SYSERR !=
771 GNUNET_CRYPTO_read_private_key_from_buffer (&msg[1],
772 key_len,
773 &zone,
774 &kbytes_read));
775 GNUNET_assert (kbytes_read == key_len);
776 switch (res)
777 {
778 break;
779
780 case GNUNET_EC_NAMESTORE_NO_RESULTS:
781 LOG (GNUNET_ERROR_TYPE_DEBUG,
782 "Namestore has no result for zone to name mapping \n");
783 if (NULL != qe->proc)
784 qe->proc (qe->proc_cls, &zone, NULL, 0, NULL);
785 free_qe (qe);
786 return;
787
788 case GNUNET_EC_NONE:
789 LOG (GNUNET_ERROR_TYPE_DEBUG,
790 "Namestore has result for zone to name mapping \n");
791 name_len = ntohs (msg->name_len);
792 rd_count = ntohs (msg->rd_count);
793 rd_ser_len = ntohs (msg->rd_len);
794 name_tmp = (const char *) &msg[1] + key_len;
795 rd_tmp = &name_tmp[name_len];
796 {
797 struct GNUNET_GNSRECORD_Data rd[rd_count];
798
799 GNUNET_assert (GNUNET_OK ==
800 GNUNET_GNSRECORD_records_deserialize (rd_ser_len,
801 rd_tmp,
802 rd_count,
803 rd));
804 /* normal end, call continuation with result */
805 if (NULL != qe->proc)
806 qe->proc (qe->proc_cls, &zone, name_tmp, rd_count, rd);
807 /* return is important here: break would call continuation with error! */
808 free_qe (qe);
809 return;
810 }
811
812 default:
813 LOG (GNUNET_ERROR_TYPE_DEBUG,
814 "An error occurred during zone to name operation: %s\n",
815 GNUNET_ErrorCode_get_hint (res));
816 break;
817 }
818 /* error case, call continuation with error */
819 if (NULL != qe->error_cb)
820 qe->error_cb (qe->error_cb_cls);
821 free_qe (qe);
822}
823
824
825/**
826 * Generic error handler, called with the appropriate error code and
827 * the same closure specified at the creation of the message queue.
828 * Not every message queue implementation supports an error handler.
829 *
830 * @param cls closure with the `struct GNUNET_NAMESTORE_Handle *`
831 * @param error error code
832 */
833static void
834mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
835{
836 struct GNUNET_NAMESTORE_Handle *h = cls;
837
838 (void) error;
839 force_reconnect (h);
840}
841
842
843/**
844 * Reconnect to namestore service.
845 *
846 * @param h the handle to the NAMESTORE service
847 */
848static void
849reconnect (struct GNUNET_NAMESTORE_Handle *h)
850{
851 struct GNUNET_MQ_MessageHandler handlers[] =
852 { GNUNET_MQ_hd_fixed_size (record_store_response,
853 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE,
854 struct RecordStoreResponseMessage,
855 h),
856 GNUNET_MQ_hd_var_size (zone_to_name_response,
857 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE,
858 struct ZoneToNameResponseMessage,
859 h),
860 GNUNET_MQ_hd_var_size (record_result,
861 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT,
862 struct RecordResultMessage,
863 h),
864 GNUNET_MQ_hd_fixed_size (record_result_end,
865 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END,
866 struct GNUNET_NAMESTORE_Header,
867 h),
868 GNUNET_MQ_hd_var_size (lookup_result,
869 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE,
870 struct LabelLookupResponseMessage,
871 h),
872 GNUNET_MQ_hd_fixed_size (tx_control_result,
873 GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL_RESULT,
874 struct TxControlResultMessage,
875 h),
876 GNUNET_MQ_handler_end () };
877 struct GNUNET_NAMESTORE_ZoneIterator *it;
878 struct GNUNET_NAMESTORE_QueueEntry *qe;
879
880 GNUNET_assert (NULL == h->mq);
881 h->mq =
882 GNUNET_CLIENT_connect (h->cfg, "namestore", handlers, &mq_error_handler, h);
883 if (NULL == h->mq)
884 return;
885 /* re-transmit pending requests that waited for a reconnect... */
886 for (it = h->z_head; NULL != it; it = it->next)
887 {
888 GNUNET_MQ_send (h->mq, it->env);
889 it->env = NULL;
890 }
891 for (qe = h->op_head; NULL != qe; qe = qe->next)
892 {
893 GNUNET_MQ_send (h->mq, qe->env);
894 qe->env = NULL;
895 }
896}
897
898
899/**
900 * Re-establish the connection to the service.
901 *
902 * @param cls handle to use to re-connect.
903 */
904static void
905reconnect_task (void *cls)
906{
907 struct GNUNET_NAMESTORE_Handle *h = cls;
908
909 h->reconnect_task = NULL;
910 reconnect (h);
911}
912
913
914/**
915 * Disconnect from service and then reconnect.
916 *
917 * @param h our handle
918 */
919static void
920force_reconnect (struct GNUNET_NAMESTORE_Handle *h)
921{
922 struct GNUNET_NAMESTORE_ZoneIterator *ze;
923 struct GNUNET_NAMESTORE_QueueEntry *qe;
924
925 GNUNET_MQ_destroy (h->mq);
926 h->mq = NULL;
927 while (NULL != (ze = h->z_head))
928 {
929 if (NULL != ze->error_cb)
930 ze->error_cb (ze->error_cb_cls);
931 free_ze (ze);
932 }
933 while (NULL != (qe = h->op_head))
934 {
935 if (NULL != qe->error_cb)
936 qe->error_cb (qe->error_cb_cls);
937 if (NULL != qe->cont)
938 qe->cont (qe->cont_cls,
939 GNUNET_EC_NAMESTORE_UNKNOWN);
940 free_qe (qe);
941 }
942
943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting to namestore\n");
944 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
945 h->reconnect_task =
946 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect_task, h);
947}
948
949
950/**
951 * Get a fresh operation id to distinguish between namestore requests
952 *
953 * @param h the namestore handle
954 * @return next operation id to use
955 */
956static uint32_t
957get_op_id (struct GNUNET_NAMESTORE_Handle *h)
958{
959 return h->last_op_id_used++;
960}
961
962
963/**
964 * Initialize the connection with the NAMESTORE service.
965 *
966 * @param cfg configuration to use
967 * @return handle to the GNS service, or NULL on error
968 */
969struct GNUNET_NAMESTORE_Handle *
970GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
971{
972 struct GNUNET_NAMESTORE_Handle *h;
973
974 h = GNUNET_new (struct GNUNET_NAMESTORE_Handle);
975 h->cfg = cfg;
976 reconnect (h);
977 if (NULL == h->mq)
978 {
979 GNUNET_free (h);
980 return NULL;
981 }
982 return h;
983}
984
985
986/**
987 * Disconnect from the namestore service (and free associated
988 * resources).
989 *
990 * @param h handle to the namestore
991 */
992void
993GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h)
994{
995 struct GNUNET_NAMESTORE_QueueEntry *q;
996 struct GNUNET_NAMESTORE_ZoneIterator *z;
997
998 LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
999 GNUNET_break (NULL == h->op_head);
1000 while (NULL != (q = h->op_head))
1001 {
1002 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q);
1003 GNUNET_free (q);
1004 }
1005 GNUNET_break (NULL == h->z_head);
1006 while (NULL != (z = h->z_head))
1007 {
1008 GNUNET_CONTAINER_DLL_remove (h->z_head, h->z_tail, z);
1009 GNUNET_free (z);
1010 }
1011 if (NULL != h->mq)
1012 {
1013 GNUNET_MQ_destroy (h->mq);
1014 h->mq = NULL;
1015 }
1016 if (NULL != h->reconnect_task)
1017 {
1018 GNUNET_SCHEDULER_cancel (h->reconnect_task);
1019 h->reconnect_task = NULL;
1020 }
1021 GNUNET_free (h);
1022}
1023
1024
1025/**
1026 * Task launched to warn the user that the namestore is
1027 * excessively slow and that a query was thus dropped.
1028 *
1029 * @param cls a `struct GNUNET_NAMESTORE_QueueEntry *`
1030 */
1031static void
1032warn_delay (void *cls)
1033{
1034 struct GNUNET_NAMESTORE_QueueEntry *qe = cls;
1035
1036 qe->timeout_task = NULL;
1037 LOG (GNUNET_ERROR_TYPE_WARNING,
1038 "Did not receive response from namestore after %s!\n",
1039 GNUNET_STRINGS_relative_time_to_string (NAMESTORE_DELAY_TOLERANCE,
1040 GNUNET_YES));
1041 if (NULL != qe->cont)
1042 {
1043 qe->cont (qe->cont_cls, GNUNET_EC_NAMESTORE_UNKNOWN);
1044 qe->cont = NULL;
1045 }
1046 GNUNET_NAMESTORE_cancel (qe);
1047}
1048
1049
1050struct GNUNET_NAMESTORE_QueueEntry *
1051GNUNET_NAMESTORE_records_store (
1052 struct GNUNET_NAMESTORE_Handle *h,
1053 const struct GNUNET_CRYPTO_PrivateKey *pkey,
1054 const char *label,
1055 unsigned int rd_count,
1056 const struct GNUNET_GNSRECORD_Data *rd,
1057 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1058 void *cont_cls)
1059{
1060 struct GNUNET_NAMESTORE_RecordInfo ri;
1061 unsigned int rds_sent;
1062 ri.a_label = label;
1063 ri.a_rd_count = rd_count;
1064 ri.a_rd = (struct GNUNET_GNSRECORD_Data *) rd;
1065 return GNUNET_NAMESTORE_records_store2 (h, pkey, 1, &ri, &rds_sent,
1066 cont, cont_cls);
1067}
1068
1069struct GNUNET_NAMESTORE_QueueEntry *
1070GNUNET_NAMESTORE_records_store2 (
1071 struct GNUNET_NAMESTORE_Handle *h,
1072 const struct GNUNET_CRYPTO_PrivateKey *pkey,
1073 unsigned int rd_set_count,
1074 const struct GNUNET_NAMESTORE_RecordInfo *record_info,
1075 unsigned int *rds_sent,
1076 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1077 void *cont_cls)
1078{
1079 struct GNUNET_NAMESTORE_QueueEntry *qe;
1080 struct GNUNET_MQ_Envelope *env;
1081 const char *label;
1082 unsigned int rd_count;
1083 const struct GNUNET_GNSRECORD_Data *rd;
1084 char *name_tmp;
1085 char *rd_ser;
1086 ssize_t rd_ser_len[rd_set_count];
1087 size_t name_len;
1088 uint32_t rid;
1089 struct RecordStoreMessage *msg;
1090 struct RecordSet *rd_set;
1091 ssize_t sret;
1092 int i;
1093 size_t rd_set_len = 0;
1094 size_t key_len = 0;
1095 size_t max_len;
1096 key_len = GNUNET_CRYPTO_private_key_get_length (pkey);
1097 max_len = UINT16_MAX - key_len - sizeof (struct RecordStoreMessage);
1098
1099 *rds_sent = 0;
1100 for (i = 0; i < rd_set_count; i++)
1101 {
1102 label = record_info[i].a_label;
1103 rd_count = record_info[i].a_rd_count;
1104 rd = record_info[i].a_rd;
1105 name_len = strlen (label) + 1;
1106 if (name_len > MAX_NAME_LEN)
1107 {
1108 GNUNET_break (0);
1109 *rds_sent = 0;
1110 return NULL;
1111 }
1112 rd_ser_len[i] = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1113 if (rd_ser_len[i] < 0)
1114 {
1115 GNUNET_break (0);
1116 *rds_sent = 0;
1117 return NULL;
1118 }
1119 if (rd_ser_len[i] > max_len)
1120 {
1121 GNUNET_break (0);
1122 *rds_sent = 0;
1123 return NULL;
1124 }
1125 if ((rd_set_len + sizeof (struct RecordSet) + name_len + rd_ser_len[i]) >
1126 max_len)
1127 break;
1128 rd_set_len += sizeof (struct RecordSet) + name_len + rd_ser_len[i];
1129 }
1130 *rds_sent = i;
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 "Sending %u of %u records!\n", *rds_sent, rd_set_count);
1133 rid = get_op_id (h);
1134 qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1135 qe->h = h;
1136 qe->cont = cont;
1137 qe->cont_cls = cont_cls;
1138 qe->op_id = rid;
1139 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1140 /* setup msg */
1141 env = GNUNET_MQ_msg_extra (msg,
1142 key_len + rd_set_len,
1143 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE);
1144 GNUNET_assert (NULL != msg);
1145 GNUNET_assert (NULL != env);
1146 msg->gns_header.r_id = htonl (rid);
1147 msg->key_len = htons (key_len);
1148 msg->rd_set_count = htons ((uint16_t) (*rds_sent));
1149 GNUNET_CRYPTO_write_private_key_to_buffer (pkey,
1150 &msg[1],
1151 key_len);
1152 rd_set = (struct RecordSet*) (((char*) &msg[1]) + key_len);
1153 for (int i = 0; i < *rds_sent; i++)
1154 {
1155 label = record_info[i].a_label;
1156 rd = record_info[i].a_rd;
1157 name_len = strlen (label) + 1;
1158 rd_set->name_len = htons (name_len);
1159 rd_set->rd_count = htons (record_info[i].a_rd_count);
1160 rd_set->rd_len = htons (rd_ser_len[i]);
1161 rd_set->reserved = ntohs (0);
1162 name_tmp = (char *) &rd_set[1];
1163 GNUNET_memcpy (name_tmp, label, name_len);
1164 rd_ser = &name_tmp[name_len];
1165 sret = GNUNET_GNSRECORD_records_serialize (record_info[i].a_rd_count,
1166 rd, rd_ser_len[i], rd_ser);
1167 if ((0 > sret) || (sret != rd_ser_len[i]))
1168 {
1169 GNUNET_break (0);
1170 GNUNET_free (env);
1171 return NULL;
1172 }
1173 // Point to next RecordSet
1174 rd_set = (struct RecordSet*) &name_tmp[name_len + rd_ser_len[i]];
1175 }
1176 LOG (GNUNET_ERROR_TYPE_DEBUG,
1177 "Sending NAMESTORE_RECORD_STORE message for name %u record sets\n",
1178 *rds_sent);
1179 qe->timeout_task =
1180 GNUNET_SCHEDULER_add_delayed (NAMESTORE_DELAY_TOLERANCE, &warn_delay, qe);
1181 if (NULL == h->mq)
1182 {
1183 qe->env = env;
1184 LOG (GNUNET_ERROR_TYPE_WARNING,
1185 "Delaying NAMESTORE_RECORD_STORE message as namestore is not ready!\n");
1186 }
1187 else
1188 {
1189 GNUNET_MQ_send (h->mq, env);
1190 }
1191 return qe;
1192}
1193
1194
1195static struct GNUNET_NAMESTORE_QueueEntry *
1196records_lookup (
1197 struct GNUNET_NAMESTORE_Handle *h,
1198 const struct GNUNET_CRYPTO_PrivateKey *pkey,
1199 const char *label,
1200 GNUNET_SCHEDULER_TaskCallback error_cb,
1201 void *error_cb_cls,
1202 GNUNET_NAMESTORE_RecordMonitor rm,
1203 void *rm_cls,
1204 int is_edit_request,
1205 enum GNUNET_GNSRECORD_Filter filter)
1206{
1207 struct GNUNET_NAMESTORE_QueueEntry *qe;
1208 struct GNUNET_MQ_Envelope *env;
1209 struct LabelLookupMessage *msg;
1210 size_t label_len;
1211 size_t key_len;
1212
1213 if (1 == (label_len = strlen (label) + 1))
1214 {
1215 GNUNET_break (0);
1216 return NULL;
1217 }
1218
1219 qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1220 qe->h = h;
1221 qe->error_cb = error_cb;
1222 qe->error_cb_cls = error_cb_cls;
1223 qe->proc = rm;
1224 qe->proc_cls = rm_cls;
1225 qe->op_id = get_op_id (h);
1226 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1227
1228 key_len = GNUNET_CRYPTO_private_key_get_length (pkey);
1229 env = GNUNET_MQ_msg_extra (msg,
1230 label_len + key_len,
1231 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP);
1232 msg->gns_header.r_id = htonl (qe->op_id);
1233 GNUNET_CRYPTO_write_private_key_to_buffer (pkey,
1234 &msg[1],
1235 key_len);
1236
1237 msg->key_len = htons (key_len);
1238 msg->is_edit_request = htons (is_edit_request);
1239 msg->label_len = htons (label_len);
1240 msg->filter = htons (filter);
1241 GNUNET_memcpy (((char*) &msg[1]) + key_len, label, label_len);
1242 if (NULL == h->mq)
1243 qe->env = env;
1244 else
1245 GNUNET_MQ_send (h->mq, env);
1246 return qe;
1247}
1248
1249struct GNUNET_NAMESTORE_QueueEntry *
1250GNUNET_NAMESTORE_records_lookup (
1251 struct GNUNET_NAMESTORE_Handle *h,
1252 const struct GNUNET_CRYPTO_PrivateKey *pkey,
1253 const char *label,
1254 GNUNET_SCHEDULER_TaskCallback error_cb,
1255 void *error_cb_cls,
1256 GNUNET_NAMESTORE_RecordMonitor rm,
1257 void *rm_cls)
1258{
1259 return records_lookup (h, pkey, label,
1260 error_cb, error_cb_cls,
1261 rm, rm_cls, GNUNET_NO, GNUNET_GNSRECORD_FILTER_NONE);
1262
1263}
1264
1265struct GNUNET_NAMESTORE_QueueEntry *
1266GNUNET_NAMESTORE_records_lookup2 (
1267 struct GNUNET_NAMESTORE_Handle *h,
1268 const struct GNUNET_CRYPTO_PrivateKey *pkey,
1269 const char *label,
1270 GNUNET_SCHEDULER_TaskCallback error_cb,
1271 void *error_cb_cls,
1272 GNUNET_NAMESTORE_RecordMonitor rm,
1273 void *rm_cls,
1274 enum GNUNET_GNSRECORD_Filter filter)
1275{
1276 return records_lookup (h, pkey, label,
1277 error_cb, error_cb_cls,
1278 rm, rm_cls, GNUNET_NO, filter);
1279
1280}
1281
1282
1283struct GNUNET_NAMESTORE_QueueEntry *
1284GNUNET_NAMESTORE_records_edit (
1285 struct GNUNET_NAMESTORE_Handle *h,
1286 const struct GNUNET_CRYPTO_PrivateKey *pkey,
1287 const char *label,
1288 GNUNET_SCHEDULER_TaskCallback error_cb,
1289 void *error_cb_cls,
1290 GNUNET_NAMESTORE_RecordMonitor rm,
1291 void *rm_cls)
1292{
1293 return records_lookup (h, pkey, label,
1294 error_cb, error_cb_cls,
1295 rm, rm_cls, GNUNET_YES, GNUNET_GNSRECORD_FILTER_NONE);
1296}
1297
1298struct GNUNET_NAMESTORE_QueueEntry *
1299GNUNET_NAMESTORE_zone_to_name (
1300 struct GNUNET_NAMESTORE_Handle *h,
1301 const struct GNUNET_CRYPTO_PrivateKey *zone,
1302 const struct GNUNET_CRYPTO_PublicKey *value_zone,
1303 GNUNET_SCHEDULER_TaskCallback error_cb,
1304 void *error_cb_cls,
1305 GNUNET_NAMESTORE_RecordMonitor proc,
1306 void *proc_cls)
1307{
1308 struct GNUNET_NAMESTORE_QueueEntry *qe;
1309 struct GNUNET_MQ_Envelope *env;
1310 struct ZoneToNameMessage *msg;
1311 uint32_t rid;
1312 size_t key_len;
1313 ssize_t pkey_len;
1314
1315 rid = get_op_id (h);
1316 qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1317 qe->h = h;
1318 qe->error_cb = error_cb;
1319 qe->error_cb_cls = error_cb_cls;
1320 qe->proc = proc;
1321 qe->proc_cls = proc_cls;
1322 qe->op_id = rid;
1323 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1324
1325 key_len = GNUNET_CRYPTO_private_key_get_length (zone);
1326 pkey_len = GNUNET_CRYPTO_public_key_get_length (value_zone);
1327 env = GNUNET_MQ_msg_extra (msg, key_len + pkey_len,
1328 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME);
1329 msg->gns_header.r_id = htonl (rid);
1330 msg->key_len = htons (key_len);
1331 msg->pkey_len = htons (pkey_len);
1332 GNUNET_CRYPTO_write_private_key_to_buffer (zone, &msg[1], key_len);
1333 GNUNET_CRYPTO_write_public_key_to_buffer (value_zone,
1334 (char*) &msg[1] + key_len,
1335 pkey_len);
1336 if (NULL == h->mq)
1337 qe->env = env;
1338 else
1339 GNUNET_MQ_send (h->mq, env);
1340 return qe;
1341}
1342
1343
1344struct GNUNET_NAMESTORE_ZoneIterator *
1345GNUNET_NAMESTORE_zone_iteration_start (
1346 struct GNUNET_NAMESTORE_Handle *h,
1347 const struct GNUNET_CRYPTO_PrivateKey *zone,
1348 GNUNET_SCHEDULER_TaskCallback error_cb,
1349 void *error_cb_cls,
1350 GNUNET_NAMESTORE_RecordMonitor proc,
1351 void *proc_cls,
1352 GNUNET_SCHEDULER_TaskCallback finish_cb,
1353 void *finish_cb_cls)
1354{
1355 struct GNUNET_NAMESTORE_ZoneIterator *it;
1356 struct GNUNET_MQ_Envelope *env;
1357 struct ZoneIterationStartMessage *msg;
1358 uint32_t rid;
1359 size_t key_len = 0;
1360
1361 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ZONE_ITERATION_START message\n");
1362 rid = get_op_id (h);
1363 it = GNUNET_new (struct GNUNET_NAMESTORE_ZoneIterator);
1364 it->h = h;
1365 it->error_cb = error_cb;
1366 it->error_cb_cls = error_cb_cls;
1367 it->finish_cb = finish_cb;
1368 it->finish_cb_cls = finish_cb_cls;
1369 it->proc = proc;
1370 it->proc_cls = proc_cls;
1371 it->op_id = rid;
1372 if (NULL != zone)
1373 {
1374 it->zone = *zone;
1375 key_len = GNUNET_CRYPTO_private_key_get_length (zone);
1376 }
1377 GNUNET_CONTAINER_DLL_insert_tail (h->z_head, h->z_tail, it);
1378 env = GNUNET_MQ_msg_extra (msg,
1379 key_len,
1380 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START);
1381 msg->gns_header.r_id = htonl (rid);
1382 msg->key_len = htons (key_len);
1383 if (NULL != zone)
1384 GNUNET_CRYPTO_write_private_key_to_buffer (zone, &msg[1], key_len);
1385 if (NULL == h->mq)
1386 it->env = env;
1387 else
1388 GNUNET_MQ_send (h->mq, env);
1389 return it;
1390}
1391
1392struct GNUNET_NAMESTORE_ZoneIterator *
1393GNUNET_NAMESTORE_zone_iteration_start2 (
1394 struct GNUNET_NAMESTORE_Handle *h,
1395 const struct GNUNET_CRYPTO_PrivateKey *zone,
1396 GNUNET_SCHEDULER_TaskCallback error_cb,
1397 void *error_cb_cls,
1398 GNUNET_NAMESTORE_RecordSetMonitor proc,
1399 void *proc_cls,
1400 GNUNET_SCHEDULER_TaskCallback finish_cb,
1401 void *finish_cb_cls,
1402 enum GNUNET_GNSRECORD_Filter filter)
1403{
1404 struct GNUNET_NAMESTORE_ZoneIterator *it;
1405 struct GNUNET_MQ_Envelope *env;
1406 struct ZoneIterationStartMessage *msg;
1407 uint32_t rid;
1408 size_t key_len = 0;
1409
1410 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ZONE_ITERATION_START message\n");
1411 rid = get_op_id (h);
1412 it = GNUNET_new (struct GNUNET_NAMESTORE_ZoneIterator);
1413 it->h = h;
1414 it->error_cb = error_cb;
1415 it->error_cb_cls = error_cb_cls;
1416 it->finish_cb = finish_cb;
1417 it->finish_cb_cls = finish_cb_cls;
1418 it->proc2 = proc;
1419 it->proc_cls = proc_cls;
1420 it->op_id = rid;
1421 if (NULL != zone)
1422 {
1423 it->zone = *zone;
1424 key_len = GNUNET_CRYPTO_private_key_get_length (zone);
1425 }
1426 GNUNET_CONTAINER_DLL_insert_tail (h->z_head, h->z_tail, it);
1427 env = GNUNET_MQ_msg_extra (msg,
1428 key_len,
1429 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START);
1430 msg->gns_header.r_id = htonl (rid);
1431 msg->key_len = htons (key_len);
1432 msg->filter = htons ((uint16_t) filter);
1433 if (NULL != zone)
1434 GNUNET_CRYPTO_write_private_key_to_buffer (zone, &msg[1], key_len);
1435 if (NULL == h->mq)
1436 it->env = env;
1437 else
1438 GNUNET_MQ_send (h->mq, env);
1439 return it;
1440}
1441
1442
1443void
1444GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it,
1445 uint64_t limit)
1446{
1447 struct GNUNET_NAMESTORE_Handle *h = it->h;
1448 struct ZoneIterationNextMessage *msg;
1449 struct GNUNET_MQ_Envelope *env;
1450
1451 LOG (GNUNET_ERROR_TYPE_DEBUG,
1452 "Sending ZONE_ITERATION_NEXT message with limit %llu\n",
1453 (unsigned long long) limit);
1454 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT);
1455 msg->gns_header.r_id = htonl (it->op_id);
1456 msg->limit = GNUNET_htonll (limit);
1457 GNUNET_MQ_send (h->mq, env);
1458}
1459
1460
1461/**
1462 * Stops iteration and releases the namestore handle for further calls.
1463 *
1464 * @param it the iterator
1465 */
1466void
1467GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it)
1468{
1469 struct GNUNET_NAMESTORE_Handle *h = it->h;
1470 struct GNUNET_MQ_Envelope *env;
1471 struct ZoneIterationStopMessage *msg;
1472
1473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ZONE_ITERATION_STOP message\n");
1474 if (NULL != h->mq)
1475 {
1476 env =
1477 GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP);
1478 msg->gns_header.r_id = htonl (it->op_id);
1479 GNUNET_MQ_send (h->mq, env);
1480 }
1481 free_ze (it);
1482}
1483
1484
1485/**
1486 * Cancel a namestore operation. The final callback from the
1487 * operation must not have been done yet.
1488 *
1489 * @param qe operation to cancel
1490 */
1491void
1492GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe)
1493{
1494 free_qe (qe);
1495}
1496
1497/**
1498 * New API draft. Experimental
1499 */
1500
1501static struct GNUNET_NAMESTORE_QueueEntry *
1502send_transaction_control_msg (struct GNUNET_NAMESTORE_Handle *h,
1503 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1504 void *cont_cls,
1505 enum GNUNET_NAMESTORE_TxControl ctrl)
1506{
1507 struct GNUNET_NAMESTORE_QueueEntry *qe;
1508 struct GNUNET_MQ_Envelope *env;
1509 struct TxControlMessage *msg;
1510 uint32_t rid;
1511
1512 rid = get_op_id (h);
1513 qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1514 qe->h = h;
1515 qe->cont = cont;
1516 qe->cont_cls = cont_cls;
1517 qe->op_id = rid;
1518 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1519
1520 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL);
1521 msg->gns_header.r_id = htonl (rid);
1522 msg->control = htons (ctrl);
1523 if (NULL == h->mq)
1524 qe->env = env;
1525 else
1526 GNUNET_MQ_send (h->mq, env);
1527 return qe;
1528 GNUNET_break (0);
1529 return NULL;
1530}
1531
1532struct GNUNET_NAMESTORE_QueueEntry *
1533GNUNET_NAMESTORE_transaction_begin (struct GNUNET_NAMESTORE_Handle *h,
1534 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1535 void *cont_cls)
1536{
1537 return send_transaction_control_msg (h, cont, cont_cls,
1538 GNUNET_NAMESTORE_TX_BEGIN);
1539}
1540
1541struct GNUNET_NAMESTORE_QueueEntry *
1542GNUNET_NAMESTORE_transaction_commit (struct GNUNET_NAMESTORE_Handle *h,
1543 GNUNET_NAMESTORE_ContinuationWithStatus
1544 cont,
1545 void *cont_cls)
1546{
1547 return send_transaction_control_msg (h, cont, cont_cls,
1548 GNUNET_NAMESTORE_TX_COMMIT);
1549}
1550
1551
1552struct GNUNET_NAMESTORE_QueueEntry *
1553GNUNET_NAMESTORE_transaction_rollback (struct GNUNET_NAMESTORE_Handle *h,
1554 GNUNET_NAMESTORE_ContinuationWithStatus
1555 cont,
1556 void *cont_cls)
1557{
1558 return send_transaction_control_msg (h, cont, cont_cls,
1559 GNUNET_NAMESTORE_TX_ROLLBACK);
1560}
1561
1562
1563/* end of namestore_api.c */
diff --git a/src/namestore/namestore_api_monitor.c b/src/namestore/namestore_api_monitor.c
deleted file mode 100644
index ec4ba879b..000000000
--- a/src/namestore/namestore_api_monitor.c
+++ /dev/null
@@ -1,443 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/namestore_api_monitor.c
22 * @brief API to monitor changes in the NAMESTORE
23 * @author Christian Grothoff
24 */
25
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_signatures.h"
31#include "gnunet_namestore_service.h"
32#include "namestore.h"
33
34
35/**
36 * Handle for a monitoring activity.
37 */
38struct GNUNET_NAMESTORE_ZoneMonitor
39{
40 /**
41 * Configuration (to reconnect).
42 */
43 const struct GNUNET_CONFIGURATION_Handle *cfg;
44
45 /**
46 * Handle to namestore service.
47 */
48 struct GNUNET_MQ_Handle *mq;
49
50 /**
51 * Function to call on errors.
52 */
53 GNUNET_SCHEDULER_TaskCallback error_cb;
54
55 /**
56 * Closure for @e error_cb.
57 */
58 void *error_cb_cls;
59
60 /**
61 * Function to call on events.
62 */
63 GNUNET_NAMESTORE_RecordMonitor monitor;
64
65 /**
66 * Function to call on events.
67 */
68 GNUNET_NAMESTORE_RecordSetMonitor monitor2;
69
70 /**
71 * Record set filter for this monitor
72 */
73 enum GNUNET_GNSRECORD_Filter filter;
74
75 /**
76 * Closure for @e monitor.
77 */
78 void *monitor_cls;
79
80 /**
81 * Function called when we've synchronized.
82 */
83 GNUNET_SCHEDULER_TaskCallback sync_cb;
84
85 /**
86 * Closure for @e sync_cb.
87 */
88 void *sync_cb_cls;
89
90 /**
91 * Monitored zone.
92 */
93 struct GNUNET_CRYPTO_PrivateKey zone;
94
95 /**
96 * Do we first iterate over all existing records?
97 */
98 int iterate_first;
99
100 /**
101 * Zone key length
102 */
103 uint32_t key_len;
104};
105
106
107/**
108 * Reconnect to the namestore service.
109 *
110 * @param zm monitor to reconnect
111 */
112static void
113reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm);
114
115
116/**
117 * Handle SYNC message from the namestore service.
118 *
119 * @param cls the monitor
120 * @param msg the sync message
121 */
122static void
123handle_sync (void *cls, const struct GNUNET_MessageHeader *msg)
124{
125 struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
126
127 (void) cls;
128 (void) msg;
129 if (NULL != zm->sync_cb)
130 zm->sync_cb (zm->sync_cb_cls);
131}
132
133
134/**
135 * We've received a notification about a change to our zone.
136 * Check that it is well-formed.
137 *
138 * @param cls the zone monitor handle
139 * @param lrm the message from the service.
140 */
141static int
142check_result (void *cls, const struct RecordResultMessage *lrm)
143{
144 struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
145 size_t lrm_len;
146 size_t exp_lrm_len;
147 size_t name_len;
148 size_t rd_len;
149 unsigned rd_count;
150 const char *name_tmp;
151 const char *rd_ser_tmp;
152 size_t key_len;
153
154 (void) zm;
155 key_len = ntohs (lrm->key_len);
156 (void) cls;
157 if (0 == key_len)
158 {
159 GNUNET_break (0);
160 return GNUNET_SYSERR;
161 }
162 lrm_len = ntohs (lrm->gns_header.header.size);
163 rd_len = ntohs (lrm->rd_len);
164 rd_count = ntohs (lrm->rd_count);
165 name_len = ntohs (lrm->name_len);
166 if (name_len > MAX_NAME_LEN)
167 {
168 GNUNET_break (0);
169 return GNUNET_SYSERR;
170 }
171 exp_lrm_len = sizeof(struct RecordResultMessage) + name_len + rd_len + key_len;
172 if (lrm_len != exp_lrm_len)
173 {
174 GNUNET_break (0);
175 return GNUNET_SYSERR;
176 }
177 if (0 == name_len)
178 {
179 GNUNET_break (0);
180 return GNUNET_SYSERR;
181 }
182 name_tmp = (const char *) &lrm[1] + key_len;
183 if (name_tmp[name_len - 1] != '\0')
184 {
185 GNUNET_break (0);
186 return GNUNET_SYSERR;
187 }
188 rd_ser_tmp = (const char *) &name_tmp[name_len];
189 {
190 struct GNUNET_GNSRECORD_Data rd[rd_count];
191
192 if (GNUNET_OK !=
193 GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd))
194 {
195 GNUNET_break (0);
196 return GNUNET_SYSERR;
197 }
198 }
199 return GNUNET_OK;
200}
201
202
203/**
204 * We've received a notification about a change to our zone.
205 * Forward to monitor callback.
206 *
207 * @param cls the zone monitor handle
208 * @param lrm the message from the service.
209 */
210static void
211handle_result (void *cls, const struct RecordResultMessage *lrm)
212{
213 struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
214 struct GNUNET_CRYPTO_PrivateKey private_key;
215 size_t name_len;
216 size_t rd_len;
217 size_t key_len;
218 size_t kbytes_read;
219 unsigned rd_count;
220 const char *name_tmp;
221 const char *rd_ser_tmp;
222
223 key_len = ntohs (lrm->key_len);
224 rd_len = ntohs (lrm->rd_len);
225 rd_count = ntohs (lrm->rd_count);
226 name_len = ntohs (lrm->name_len);
227 name_tmp = (const char *) &lrm[1] + key_len;
228 GNUNET_assert (GNUNET_SYSERR !=
229 GNUNET_CRYPTO_read_private_key_from_buffer (&lrm[1],
230 key_len,
231 &private_key,
232 &kbytes_read));
233 GNUNET_assert (kbytes_read == key_len);
234 rd_ser_tmp = (const char *) &name_tmp[name_len];
235 {
236 struct GNUNET_GNSRECORD_Data rd[rd_count];
237
238 GNUNET_assert (
239 GNUNET_OK ==
240 GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd));
241 if (NULL != zm->monitor2)
242 zm->monitor2 (zm->monitor_cls, &private_key, name_tmp,
243 rd_count, rd, GNUNET_TIME_absolute_ntoh (lrm->expire));
244 else
245 zm->monitor (zm->monitor_cls, &private_key, name_tmp, rd_count, rd);
246 }
247}
248
249
250/**
251 * Generic error handler, called with the appropriate error code and
252 * the same closure specified at the creation of the message queue.
253 * Not every message queue implementation supports an error handler.
254 *
255 * @param cls closure with the `struct GNUNET_NAMESTORE_ZoneMonitor *`
256 * @param error error code
257 */
258static void
259mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
260{
261 struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
262
263 (void) error;
264 reconnect (zm);
265}
266
267
268/**
269 * Reconnect to the namestore service.
270 *
271 * @param zm monitor to reconnect
272 */
273static void
274reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
275{
276 struct GNUNET_MQ_MessageHandler handlers[] =
277 { GNUNET_MQ_hd_fixed_size (sync,
278 GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC,
279 struct GNUNET_MessageHeader,
280 zm),
281 GNUNET_MQ_hd_var_size (result,
282 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT,
283 struct RecordResultMessage,
284 zm),
285 GNUNET_MQ_handler_end () };
286 struct GNUNET_MQ_Envelope *env;
287 struct ZoneMonitorStartMessage *sm;
288
289 if (NULL != zm->mq)
290 {
291 GNUNET_MQ_destroy (zm->mq);
292 zm->error_cb (zm->error_cb_cls);
293 }
294 zm->mq = GNUNET_CLIENT_connect (zm->cfg,
295 "namestore",
296 handlers,
297 &mq_error_handler,
298 zm);
299 if (NULL == zm->mq)
300 return;
301 env = GNUNET_MQ_msg_extra (sm,
302 zm->key_len,
303 GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START);
304 sm->iterate_first = htonl (zm->iterate_first);
305 if (0 < zm->key_len)
306 GNUNET_CRYPTO_write_private_key_to_buffer (&zm->zone,
307 &sm[1],
308 zm->key_len);
309 sm->key_len = htons (zm->key_len);
310 sm->filter = htons (zm->filter);
311 GNUNET_MQ_send (zm->mq, env);
312}
313
314
315struct GNUNET_NAMESTORE_ZoneMonitor *
316GNUNET_NAMESTORE_zone_monitor_start (
317 const struct GNUNET_CONFIGURATION_Handle *cfg,
318 const struct GNUNET_CRYPTO_PrivateKey *zone,
319 int iterate_first,
320 GNUNET_SCHEDULER_TaskCallback error_cb,
321 void *error_cb_cls,
322 GNUNET_NAMESTORE_RecordMonitor monitor,
323 void *monitor_cls,
324 GNUNET_SCHEDULER_TaskCallback sync_cb,
325 void *sync_cb_cls)
326{
327 struct GNUNET_NAMESTORE_ZoneMonitor *zm;
328
329 zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor);
330 if (NULL != zone)
331 {
332 zm->key_len = GNUNET_CRYPTO_private_key_get_length (zone);
333 zm->zone = *zone;
334 }
335 zm->iterate_first = iterate_first;
336 zm->error_cb = error_cb;
337 zm->error_cb_cls = error_cb_cls;
338 zm->monitor = monitor;
339 zm->monitor_cls = monitor_cls;
340 zm->sync_cb = sync_cb;
341 zm->sync_cb_cls = sync_cb_cls;
342 zm->cfg = cfg;
343 reconnect (zm);
344 if (NULL == zm->mq)
345 {
346 GNUNET_free (zm);
347 return NULL;
348 }
349 return zm;
350}
351
352struct GNUNET_NAMESTORE_ZoneMonitor *
353GNUNET_NAMESTORE_zone_monitor_start2 (
354 const struct GNUNET_CONFIGURATION_Handle *cfg,
355 const struct GNUNET_CRYPTO_PrivateKey *zone,
356 int iterate_first,
357 GNUNET_SCHEDULER_TaskCallback error_cb,
358 void *error_cb_cls,
359 GNUNET_NAMESTORE_RecordSetMonitor monitor,
360 void *monitor_cls,
361 GNUNET_SCHEDULER_TaskCallback sync_cb,
362 void *sync_cb_cls,
363 enum GNUNET_GNSRECORD_Filter filter)
364{
365 struct GNUNET_NAMESTORE_ZoneMonitor *zm;
366
367 zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor);
368 if (NULL != zone)
369 {
370 zm->key_len = GNUNET_CRYPTO_private_key_get_length (zone);
371 zm->zone = *zone;
372 }
373 zm->iterate_first = iterate_first;
374 zm->error_cb = error_cb;
375 zm->error_cb_cls = error_cb_cls;
376 zm->monitor2 = monitor;
377 zm->monitor_cls = monitor_cls;
378 zm->sync_cb = sync_cb;
379 zm->sync_cb_cls = sync_cb_cls;
380 zm->cfg = cfg;
381 zm->filter = filter;
382 reconnect (zm);
383 if (NULL == zm->mq)
384 {
385 GNUNET_free (zm);
386 return NULL;
387 }
388 return zm;
389}
390
391
392/**
393 * Calls the monitor processor specified in #GNUNET_NAMESTORE_zone_monitor_start
394 * for the next record(s). This function is used to allow clients that merely
395 * monitor the NAMESTORE to still throttle namestore operations, so we can be
396 * sure that the monitors can keep up.
397 *
398 * Note that #GNUNET_NAMESTORE_records_store() only waits for this
399 * call if the previous limit set by the client was already reached.
400 * Thus, by using a @a limit greater than 1, monitors basically enable
401 * a queue of notifications to be processed asynchronously with some
402 * delay. Note that even with a limit of 1 the
403 * #GNUNET_NAMESTORE_records_store() function will run asynchronously
404 * and the continuation may be invoked before the monitors completed
405 * (or even started) processing the notification. Thus, monitors will
406 * only closely track the current state of the namestore, but not
407 * be involved in the transactions.
408 *
409 * @param zm the monitor
410 * @param limit number of records to return to the iterator in one shot
411 * (before #GNUNET_NAMESTORE_zone_monitor_next is to be called again)
412 */
413void
414GNUNET_NAMESTORE_zone_monitor_next (struct GNUNET_NAMESTORE_ZoneMonitor *zm,
415 uint64_t limit)
416{
417 struct GNUNET_MQ_Envelope *env;
418 struct ZoneMonitorNextMessage *nm;
419
420 env = GNUNET_MQ_msg (nm, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT);
421 nm->limit = GNUNET_htonll (limit);
422 GNUNET_MQ_send (zm->mq, env);
423}
424
425
426/**
427 * Stop monitoring a zone for changes.
428 *
429 * @param zm handle to the monitor activity to stop
430 */
431void
432GNUNET_NAMESTORE_zone_monitor_stop (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
433{
434 if (NULL != zm->mq)
435 {
436 GNUNET_MQ_destroy (zm->mq);
437 zm->mq = NULL;
438 }
439 GNUNET_free (zm);
440}
441
442
443/* end of namestore_api_monitor.c */
diff --git a/src/namestore/perf_namestore_api_import.c b/src/namestore/perf_namestore_api_import.c
deleted file mode 100644
index e56fb961c..000000000
--- a/src/namestore/perf_namestore_api_import.c
+++ /dev/null
@@ -1,406 +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 * @file namestore/perf_namestore_api_import.c
22 * @brief testcase for namestore: Import a lot of records
23 * @author Martin Schanzenbach
24 */
25#include "platform.h"
26#include "gnunet_namestore_service.h"
27#include "gnunet_testing_lib.h"
28#include "namestore.h"
29
30#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
31
32#define TEST_RECORD_COUNT 10000
33
34/**
35 * A #BENCHMARK_SIZE of 1000 takes less than a minute on a reasonably
36 * modern system, so 30 minutes should be OK even for very, very
37 * slow systems.
38 */
39#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
40
41/**
42 * The runtime of the benchmark is expected to be linear
43 * for the iteration phase with a *good* database. The FLAT
44 * database uses a quadratic retrieval algorithm,
45 * hence it should be quadratic in the size.
46 */
47#define BENCHMARK_SIZE 1000
48
49/**
50 * Maximum record size
51 */
52#define MAX_REC_SIZE 500
53
54/**
55 * How big are the blocks we fetch? Note that the first block is
56 * always just 1 record set per current API. Smaller block
57 * sizes will make quadratic iteration-by-offset penalties
58 * more pronounced.
59 */
60#define BLOCK_SIZE 100
61
62static struct GNUNET_NAMESTORE_Handle *nsh;
63
64static struct GNUNET_SCHEDULER_Task *timeout_task;
65
66static struct GNUNET_SCHEDULER_Task *t;
67
68static struct GNUNET_CRYPTO_PrivateKey privkey;
69
70static struct GNUNET_NAMESTORE_QueueEntry *qe;
71
72static int res;
73
74static struct GNUNET_TIME_Absolute start;
75
76struct GNUNET_NAMESTORE_RecordInfo ri[TEST_RECORD_COUNT];
77
78int single_put_pos;
79
80static int bulk_count = 0;
81
82
83/**
84 * Terminate everything
85 *
86 * @param cls NULL
87 */
88static void
89end (void *cls)
90{
91 (void) cls;
92 if (NULL != qe)
93 {
94 GNUNET_NAMESTORE_cancel (qe);
95 qe = NULL;
96 }
97 if (NULL != nsh)
98 {
99 GNUNET_NAMESTORE_disconnect (nsh);
100 nsh = NULL;
101 }
102 if (NULL != t)
103 {
104 GNUNET_SCHEDULER_cancel (t);
105 t = NULL;
106 }
107 if (NULL != timeout_task)
108 {
109 GNUNET_SCHEDULER_cancel (timeout_task);
110 timeout_task = NULL;
111 }
112}
113
114
115/**
116 * End with timeout. As this is a benchmark, we do not
117 * fail hard but return "skipped".
118 */
119static void
120timeout (void *cls)
121{
122 (void) cls;
123 timeout_task = NULL;
124 GNUNET_SCHEDULER_shutdown ();
125 res = 77;
126}
127
128
129static struct GNUNET_GNSRECORD_Data *
130create_record (unsigned int count)
131{
132 struct GNUNET_GNSRECORD_Data *rd;
133
134 rd = GNUNET_malloc (count + sizeof(struct GNUNET_GNSRECORD_Data));
135 rd->expiration_time = GNUNET_TIME_relative_to_absolute (
136 GNUNET_TIME_UNIT_HOURS).abs_value_us;
137 rd->record_type = TEST_RECORD_TYPE;
138 rd->data_size = count;
139 rd->data = (void *) &rd[1];
140 rd->flags = 0;
141 memset (&rd[1],
142 'a',
143 count);
144 return rd;
145}
146
147
148static void
149publish_records_single (void *cls);
150
151static void
152commit_cont (void *cls,
153 enum GNUNET_ErrorCode ec)
154{
155 struct GNUNET_TIME_Relative delay;
156
157 (void) cls;
158 qe = NULL;
159 if (GNUNET_EC_NONE != ec)
160 {
161 GNUNET_break (0);
162 GNUNET_SCHEDULER_shutdown ();
163 return;
164 }
165 single_put_pos++;
166 delay = GNUNET_TIME_absolute_get_duration (start);
167 fprintf (stdout,
168 "BULK-TX: Publishing %u records took %s\n",
169 TEST_RECORD_COUNT,
170 GNUNET_STRINGS_relative_time_to_string (delay,
171 GNUNET_YES));
172 res = 0;
173 GNUNET_SCHEDULER_shutdown ();
174}
175
176static void
177publish_records_bulk_tx (void *cls);
178
179
180static void
181put_cont_bulk_tx (void *cls,
182 enum GNUNET_ErrorCode ec)
183{
184 qe = NULL;
185 if (GNUNET_EC_NONE != ec)
186 {
187 GNUNET_break (0);
188 GNUNET_SCHEDULER_shutdown ();
189 return;
190 }
191 if (bulk_count == TEST_RECORD_COUNT)
192 {
193 qe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont, NULL);
194 return;
195 }
196 t = GNUNET_SCHEDULER_add_now (&publish_records_bulk_tx, NULL);
197}
198
199
200static void
201publish_records_bulk_tx (void *cls)
202{
203 unsigned int sent_rds;
204 t = NULL;
205 qe = GNUNET_NAMESTORE_records_store2 (nsh,
206 &privkey,
207 TEST_RECORD_COUNT - bulk_count,
208 &ri[bulk_count],
209 &sent_rds,
210 &put_cont_bulk_tx,
211 NULL);
212 bulk_count += sent_rds;
213 GNUNET_assert (sent_rds != 0);
214}
215
216
217static void
218begin_cont (void *cls,
219 enum GNUNET_ErrorCode ec)
220{
221 unsigned int sent_rds;
222 qe = GNUNET_NAMESTORE_records_store2 (nsh,
223 &privkey,
224 TEST_RECORD_COUNT - bulk_count,
225 &ri[bulk_count],
226 &sent_rds,
227 &put_cont_bulk_tx,
228 NULL);
229 bulk_count += sent_rds;
230 GNUNET_assert (sent_rds != 0);
231}
232
233static void
234publish_records_bulk (void *cls);
235
236static void
237put_cont_bulk (void *cls,
238 enum GNUNET_ErrorCode ec)
239{
240 struct GNUNET_TIME_Relative delay;
241
242 (void) cls;
243 qe = NULL;
244 if (GNUNET_EC_NONE != ec)
245 {
246 GNUNET_break (0);
247 GNUNET_SCHEDULER_shutdown ();
248 return;
249 }
250
251 if (bulk_count == TEST_RECORD_COUNT)
252 {
253 delay = GNUNET_TIME_absolute_get_duration (start);
254 fprintf (stdout,
255 "BULK: Publishing %u records took %s\n",
256 TEST_RECORD_COUNT,
257 GNUNET_STRINGS_relative_time_to_string (delay,
258 GNUNET_YES));
259 start = GNUNET_TIME_absolute_get ();
260 bulk_count = 0;
261 qe = GNUNET_NAMESTORE_transaction_begin (nsh, begin_cont, NULL);
262 return;
263 }
264 (void) cls;
265 qe = NULL;
266 if (GNUNET_EC_NONE != ec)
267 {
268 GNUNET_break (0);
269 GNUNET_SCHEDULER_shutdown ();
270 return;
271 }
272 t = GNUNET_SCHEDULER_add_now (&publish_records_bulk, NULL);
273}
274
275static void
276publish_records_bulk (void *cls)
277{
278 static unsigned int sent_rds = 0;
279 (void) cls;
280 t = NULL;
281 qe = GNUNET_NAMESTORE_records_store2 (nsh,
282 &privkey,
283 TEST_RECORD_COUNT - bulk_count,
284 &ri[bulk_count],
285 &sent_rds,
286 &put_cont_bulk,
287 NULL);
288 bulk_count += sent_rds;
289 GNUNET_assert (sent_rds != 0);
290}
291
292
293static void
294put_cont_single (void *cls,
295 enum GNUNET_ErrorCode ec)
296{
297 struct GNUNET_TIME_Relative delay;
298 (void) cls;
299 qe = NULL;
300 if (GNUNET_EC_NONE != ec)
301 {
302 GNUNET_break (0);
303 GNUNET_SCHEDULER_shutdown ();
304 return;
305 }
306 single_put_pos++;
307 if (single_put_pos == TEST_RECORD_COUNT)
308 {
309 delay = GNUNET_TIME_absolute_get_duration (start);
310 fprintf (stdout,
311 "SINGLE: Publishing %u records took %s\n",
312 TEST_RECORD_COUNT,
313 GNUNET_STRINGS_relative_time_to_string (delay,
314 GNUNET_YES));
315 start = GNUNET_TIME_absolute_get ();
316 t = GNUNET_SCHEDULER_add_now (&publish_records_bulk, NULL);
317 return;
318 }
319 t = GNUNET_SCHEDULER_add_now (&publish_records_single,
320 NULL);
321}
322
323
324static void
325publish_records_single (void *cls)
326{
327 struct GNUNET_TIME_Relative delay;
328
329 (void) cls;
330 t = NULL;
331 if (single_put_pos == TEST_RECORD_COUNT)
332 {
333 delay = GNUNET_TIME_absolute_get_duration (start);
334 fprintf (stdout,
335 "Publishing %u records took %s\n",
336 TEST_RECORD_COUNT,
337 GNUNET_STRINGS_relative_time_to_string (delay,
338 GNUNET_YES));
339 GNUNET_SCHEDULER_add_now (&publish_records_bulk, NULL);
340 }
341 qe = GNUNET_NAMESTORE_records_store (nsh,
342 &privkey,
343 ri[single_put_pos].a_label,
344 ri[single_put_pos].a_rd_count,
345 ri[single_put_pos].a_rd,
346 &put_cont_single,
347 NULL);
348}
349
350
351static void
352run (void *cls,
353 const struct GNUNET_CONFIGURATION_Handle *cfg,
354 struct GNUNET_TESTING_Peer *peer)
355{
356
357 for (int i = 0; i < TEST_RECORD_COUNT; i++)
358 {
359 ri[i].a_rd = create_record (1);
360 ri[i].a_rd_count = 1;
361 GNUNET_asprintf ((char**) &ri[i].a_label, "label_%d", i);
362 }
363 GNUNET_SCHEDULER_add_shutdown (&end,
364 NULL);
365 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
366 &timeout,
367 NULL);
368 nsh = GNUNET_NAMESTORE_connect (cfg);
369 GNUNET_assert (NULL != nsh);
370 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
371 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
372 start = GNUNET_TIME_absolute_get ();
373 t = GNUNET_SCHEDULER_add_now (&publish_records_single,
374 NULL);
375}
376
377
378#include "test_common.c"
379
380
381int
382main (int argc,
383 char *argv[])
384{
385 const char *plugin_name;
386 char *cfg_name;
387
388 SETUP_CFG2 ("perf_namestore_api_%s.conf", plugin_name, cfg_name);
389 res = 1;
390 if (0 !=
391 GNUNET_TESTING_peer_run ("perf-namestore-api-import",
392 cfg_name,
393 &run,
394 NULL))
395 {
396 res = 1;
397 }
398 GNUNET_DISK_purge_cfg_dir (cfg_name,
399 "GNUNET_TEST_HOME");
400 GNUNET_free (plugin_name);
401 GNUNET_free (cfg_name);
402 return res;
403}
404
405
406/* end of perf_namestore_api_zone_iteration.c */
diff --git a/src/namestore/perf_namestore_api_postgres.conf b/src/namestore/perf_namestore_api_postgres.conf
deleted file mode 100644
index 5e02c2df3..000000000
--- a/src/namestore/perf_namestore_api_postgres.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ test_namestore_api_postgres.conf
2
3[namestore]
4DATABASE = postgres
5
6[namecache]
7DISABLE = YES
8
9[namestore-postgres]
10CONFIG = connect_timeout=10 dbname=gnunetcheck
11#TEMPORARY_TABLE = YES
12INIT_ON_CONNECT = YES
diff --git a/src/namestore/perf_namestore_api_sqlite.conf b/src/namestore/perf_namestore_api_sqlite.conf
deleted file mode 100644
index 55c3dc812..000000000
--- a/src/namestore/perf_namestore_api_sqlite.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ test_namestore_api.conf
2
3[namecache]
4DISABLE = YES
5
6[namestore-sqlite]
7FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
8INIT_ON_CONNECT = YES
diff --git a/src/namestore/perf_namestore_api_zone_iteration.c b/src/namestore/perf_namestore_api_zone_iteration.c
deleted file mode 100644
index e16748f5b..000000000
--- a/src/namestore/perf_namestore_api_zone_iteration.c
+++ /dev/null
@@ -1,378 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/perf_namestore_api_zone_iteration.c
22 * @brief testcase for zone iteration functionality: iterate all zones
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_namestore_service.h"
27#include "gnunet_testing_lib.h"
28#include "namestore.h"
29
30#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
31
32/**
33 * A #BENCHMARK_SIZE of 1000 takes less than a minute on a reasonably
34 * modern system, so 30 minutes should be OK even for very, very
35 * slow systems.
36 */
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
38
39/**
40 * The runtime of the benchmark is expected to be linear
41 * for the iteration phase with a *good* database. The FLAT
42 * database uses a quadratic retrieval algorithm,
43 * hence it should be quadratic in the size.
44 */
45#define BENCHMARK_SIZE 1000
46
47/**
48 * Maximum record size
49 */
50#define MAX_REC_SIZE 500
51
52/**
53 * How big are the blocks we fetch? Note that the first block is
54 * always just 1 record set per current API. Smaller block
55 * sizes will make quadratic iteration-by-offset penalties
56 * more pronounced.
57 */
58#define BLOCK_SIZE 100
59
60static struct GNUNET_NAMESTORE_Handle *nsh;
61
62static struct GNUNET_SCHEDULER_Task *timeout_task;
63
64static struct GNUNET_SCHEDULER_Task *t;
65
66static struct GNUNET_CRYPTO_PrivateKey privkey;
67
68static struct GNUNET_NAMESTORE_ZoneIterator *zi;
69
70static struct GNUNET_NAMESTORE_QueueEntry *qe;
71
72static int res;
73
74static unsigned int off;
75
76static unsigned int left_until_next;
77
78static uint8_t seen[1 + BENCHMARK_SIZE / 8];
79
80static struct GNUNET_TIME_Absolute start;
81
82
83/**
84 * Terminate everything
85 *
86 * @param cls NULL
87 */
88static void
89end (void *cls)
90{
91 (void) cls;
92 if (NULL != qe)
93 {
94 GNUNET_NAMESTORE_cancel (qe);
95 qe = NULL;
96 }
97 if (NULL != zi)
98 {
99 GNUNET_NAMESTORE_zone_iteration_stop (zi);
100 zi = NULL;
101 }
102 if (NULL != nsh)
103 {
104 GNUNET_NAMESTORE_disconnect (nsh);
105 nsh = NULL;
106 }
107 if (NULL != t)
108 {
109 GNUNET_SCHEDULER_cancel (t);
110 t = NULL;
111 }
112 if (NULL != timeout_task)
113 {
114 GNUNET_SCHEDULER_cancel (timeout_task);
115 timeout_task = NULL;
116 }
117}
118
119
120/**
121 * End with timeout. As this is a benchmark, we do not
122 * fail hard but return "skipped".
123 */
124static void
125timeout (void *cls)
126{
127 (void) cls;
128 timeout_task = NULL;
129 GNUNET_SCHEDULER_shutdown ();
130 res = 77;
131}
132
133
134static struct GNUNET_GNSRECORD_Data *
135create_record (unsigned int count)
136{
137 struct GNUNET_GNSRECORD_Data *rd;
138
139 rd = GNUNET_malloc (count + sizeof(struct GNUNET_GNSRECORD_Data));
140 rd->expiration_time = GNUNET_TIME_relative_to_absolute (
141 GNUNET_TIME_UNIT_HOURS).abs_value_us;
142 rd->record_type = TEST_RECORD_TYPE;
143 rd->data_size = count;
144 rd->data = (void *) &rd[1];
145 rd->flags = 0;
146 memset (&rd[1],
147 'a',
148 count);
149 return rd;
150}
151
152
153static void
154zone_end (void *cls)
155{
156 struct GNUNET_TIME_Relative delay;
157
158 zi = NULL;
159 delay = GNUNET_TIME_absolute_get_duration (start);
160 fprintf (stdout,
161 "Iterating over %u records took %s\n",
162 off,
163 GNUNET_STRINGS_relative_time_to_string (delay,
164 GNUNET_YES));
165 if (BENCHMARK_SIZE == off)
166 {
167 res = 0;
168 }
169 else
170 {
171 GNUNET_break (0);
172 res = 1;
173 }
174 GNUNET_SCHEDULER_shutdown ();
175}
176
177
178static void
179fail_cb (void *cls)
180{
181 zi = NULL;
182 res = 2;
183 GNUNET_break (0);
184 GNUNET_SCHEDULER_shutdown ();
185}
186
187
188static void
189zone_proc (void *cls,
190 const struct GNUNET_CRYPTO_PrivateKey *zone,
191 const char *label,
192 unsigned int rd_count,
193 const struct GNUNET_GNSRECORD_Data *rd)
194{
195 struct GNUNET_GNSRECORD_Data *wrd;
196 unsigned int xoff;
197
198 GNUNET_assert (NULL != zone);
199 if (1 != sscanf (label,
200 "l%u",
201 &xoff))
202 {
203 res = 3;
204 GNUNET_break (0);
205 GNUNET_SCHEDULER_shutdown ();
206 return;
207 }
208 if ((xoff > BENCHMARK_SIZE) ||
209 (0 != (seen[xoff / 8] & (1U << (xoff % 8)))))
210 {
211 res = 3;
212 GNUNET_break (0);
213 GNUNET_SCHEDULER_shutdown ();
214 return;
215 }
216 seen[xoff / 8] |= (1U << (xoff % 8));
217 wrd = create_record (xoff % MAX_REC_SIZE);
218 if ((rd->record_type != wrd->record_type) ||
219 (rd->data_size != wrd->data_size) ||
220 (rd->flags != wrd->flags))
221 {
222 res = 4;
223 GNUNET_break (0);
224 GNUNET_SCHEDULER_shutdown ();
225 GNUNET_free (wrd);
226 return;
227 }
228 if (0 != memcmp (rd->data,
229 wrd->data,
230 wrd->data_size))
231 {
232 res = 4;
233 GNUNET_break (0);
234 GNUNET_SCHEDULER_shutdown ();
235 GNUNET_free (wrd);
236 return;
237 }
238 GNUNET_free (wrd);
239 if (0 != GNUNET_memcmp (zone,
240 &privkey))
241 {
242 res = 5;
243 GNUNET_break (0);
244 GNUNET_SCHEDULER_shutdown ();
245 return;
246 }
247 off++;
248 left_until_next--;
249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
250 "Obtained record %u, expecting %u more until asking for more explicitly\n",
251 off,
252 left_until_next);
253 if (0 == left_until_next)
254 {
255 left_until_next = BLOCK_SIZE;
256 GNUNET_NAMESTORE_zone_iterator_next (zi,
257 left_until_next);
258 }
259}
260
261
262static void
263publish_record (void *cls);
264
265
266static void
267put_cont (void *cls,
268 enum GNUNET_ErrorCode ec)
269{
270 (void) cls;
271 qe = NULL;
272 if (GNUNET_EC_NONE != ec)
273 {
274 GNUNET_break (0);
275 GNUNET_SCHEDULER_shutdown ();
276 return;
277 }
278 t = GNUNET_SCHEDULER_add_now (&publish_record,
279 NULL);
280}
281
282
283static void
284publish_record (void *cls)
285{
286 struct GNUNET_GNSRECORD_Data *rd;
287 char *label;
288
289 (void) cls;
290 t = NULL;
291 if (BENCHMARK_SIZE == off)
292 {
293 struct GNUNET_TIME_Relative delay;
294
295 delay = GNUNET_TIME_absolute_get_duration (start);
296 fprintf (stdout,
297 "Inserting %u records took %s\n",
298 off,
299 GNUNET_STRINGS_relative_time_to_string (delay,
300 GNUNET_YES));
301 start = GNUNET_TIME_absolute_get ();
302 off = 0;
303 left_until_next = 1;
304 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
305 NULL,
306 &fail_cb,
307 NULL,
308 &zone_proc,
309 NULL,
310 &zone_end,
311 NULL);
312 GNUNET_assert (NULL != zi);
313 return;
314 }
315 rd = create_record ((++off) % MAX_REC_SIZE);
316 GNUNET_asprintf (&label,
317 "l%u",
318 off);
319 qe = GNUNET_NAMESTORE_records_store (nsh,
320 &privkey,
321 label,
322 1, rd,
323 &put_cont,
324 NULL);
325 GNUNET_free (label);
326 GNUNET_free (rd);
327}
328
329
330static void
331run (void *cls,
332 const struct GNUNET_CONFIGURATION_Handle *cfg,
333 struct GNUNET_TESTING_Peer *peer)
334{
335 GNUNET_SCHEDULER_add_shutdown (&end,
336 NULL);
337 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
338 &timeout,
339 NULL);
340 nsh = GNUNET_NAMESTORE_connect (cfg);
341 GNUNET_assert (NULL != nsh);
342 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
343 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
344 start = GNUNET_TIME_absolute_get ();
345 t = GNUNET_SCHEDULER_add_now (&publish_record,
346 NULL);
347}
348
349
350#include "test_common.c"
351
352
353int
354main (int argc,
355 char *argv[])
356{
357 const char *plugin_name;
358 char *cfg_name;
359
360 SETUP_CFG (plugin_name, cfg_name);
361 res = 1;
362 if (0 !=
363 GNUNET_TESTING_peer_run ("perf-namestore-api-zone-iteration",
364 cfg_name,
365 &run,
366 NULL))
367 {
368 res = 1;
369 }
370 GNUNET_DISK_purge_cfg_dir (cfg_name,
371 "GNUNET_TEST_HOME");
372 GNUNET_free (plugin_name);
373 GNUNET_free (cfg_name);
374 return res;
375}
376
377
378/* end of perf_namestore_api_zone_iteration.c */
diff --git a/src/namestore/plugin_namestore_flat.c b/src/namestore/plugin_namestore_flat.c
deleted file mode 100644
index 8b574d2cf..000000000
--- a/src/namestore/plugin_namestore_flat.c
+++ /dev/null
@@ -1,818 +0,0 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2009-2015, 2018, 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 namestore/plugin_namestore_flat.c
22 * @brief file-based namestore backend
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_namestore_plugin.h"
29#include "gnunet_namestore_service.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "namestore.h"
32
33/**
34 * Context for all functions in this plugin.
35 */
36struct Plugin
37{
38 const struct GNUNET_CONFIGURATION_Handle *cfg;
39
40 /**
41 * Database filename.
42 */
43 char *fn;
44
45 /**
46 * HashMap
47 */
48 struct GNUNET_CONTAINER_MultiHashMap *hm;
49};
50
51
52struct FlatFileEntry
53{
54 /**
55 * Entry zone
56 */
57 struct GNUNET_CRYPTO_PrivateKey private_key;
58
59 /**
60 * Record count.
61 */
62 uint32_t record_count;
63
64 /**
65 * Rvalue
66 */
67 uint64_t rvalue;
68
69 /**
70 * Record data
71 */
72 struct GNUNET_GNSRECORD_Data *record_data;
73
74 /**
75 * Label
76 */
77 char *label;
78};
79
80
81/**
82 * Hash contactenation of @a pkey and @a label into @a h
83 *
84 * @param pkey a key
85 * @param label a label
86 * @param[out] h initialized hash
87 */
88static void
89hash_pkey_and_label (const struct GNUNET_CRYPTO_PrivateKey *pkey,
90 const char *label,
91 struct GNUNET_HashCode *h)
92{
93 char *key;
94 size_t label_len;
95 size_t key_len;
96
97 label_len = strlen (label);
98 key_len = label_len + sizeof(struct GNUNET_CRYPTO_PrivateKey);
99 key = GNUNET_malloc (key_len);
100 GNUNET_memcpy (key,
101 label,
102 label_len);
103 GNUNET_memcpy (key + label_len,
104 pkey,
105 sizeof(struct GNUNET_CRYPTO_PrivateKey));
106 GNUNET_CRYPTO_hash (key,
107 key_len,
108 h);
109 GNUNET_free (key);
110}
111
112
113/**
114 * Initialize the database connections and associated
115 * data structures (create tables and indices
116 * as needed as well).
117 *
118 * @param plugin the plugin context (state for this module)
119 * @return #GNUNET_OK on success
120 */
121static int
122database_setup (struct Plugin *plugin)
123{
124 char *flatdbfile;
125 char *record_data;
126 char *zone_private_key;
127 char *record_data_b64;
128 char *buffer;
129 char *line;
130 char *label;
131 char *rvalue;
132 char *record_count;
133 size_t record_data_size;
134 uint64_t size;
135 struct GNUNET_HashCode hkey;
136 struct GNUNET_DISK_FileHandle *fh;
137 struct FlatFileEntry *entry;
138 struct GNUNET_DISK_MapHandle *mh;
139
140 if (GNUNET_OK !=
141 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
142 "namestore-flat",
143 "FILENAME",
144 &flatdbfile))
145 {
146 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
147 "namestore-flat",
148 "FILENAME");
149 return GNUNET_SYSERR;
150 }
151 if (GNUNET_OK !=
152 GNUNET_DISK_file_test (flatdbfile))
153 {
154 if (GNUNET_OK !=
155 GNUNET_DISK_directory_create_for_file (flatdbfile))
156 {
157 GNUNET_break (0);
158 GNUNET_free (flatdbfile);
159 return GNUNET_SYSERR;
160 }
161 }
162 /* flatdbfile should be UTF-8-encoded. If it isn't, it's a bug */
163 plugin->fn = flatdbfile;
164
165 /* Load data from file into hashmap */
166 plugin->hm = GNUNET_CONTAINER_multihashmap_create (10,
167 GNUNET_NO);
168 fh = GNUNET_DISK_file_open (flatdbfile,
169 GNUNET_DISK_OPEN_CREATE
170 | GNUNET_DISK_OPEN_READWRITE,
171 GNUNET_DISK_PERM_USER_WRITE
172 | GNUNET_DISK_PERM_USER_READ);
173 if (NULL == fh)
174 {
175 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
176 _ ("Unable to initialize file: %s.\n"),
177 flatdbfile);
178 return GNUNET_SYSERR;
179 }
180 if (GNUNET_SYSERR ==
181 GNUNET_DISK_file_size (flatdbfile,
182 &size,
183 GNUNET_YES,
184 GNUNET_YES))
185 {
186 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
187 _ ("Unable to get filesize: %s.\n"),
188 flatdbfile);
189 GNUNET_DISK_file_close (fh);
190 return GNUNET_SYSERR;
191 }
192 if (size > SIZE_MAX)
193 {
194 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
195 _ ("File too big to map: %llu bytes.\n"),
196 (unsigned long long) size);
197 GNUNET_DISK_file_close (fh);
198 return GNUNET_SYSERR;
199 }
200 if (0 == size)
201 {
202 GNUNET_DISK_file_close (fh);
203 return GNUNET_OK;
204 }
205 buffer = GNUNET_DISK_file_map (fh,
206 &mh,
207 GNUNET_DISK_MAP_TYPE_READ,
208 size);
209 if (NULL == buffer)
210 {
211 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
212 "mmap");
213 GNUNET_DISK_file_close (fh);
214 return GNUNET_SYSERR;
215 }
216 if ('\0' != buffer[size - 1])
217 {
218 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
219 _ ("Namestore database file `%s' malformed\n"),
220 flatdbfile);
221 GNUNET_DISK_file_unmap (mh);
222 GNUNET_DISK_file_close (fh);
223 return GNUNET_SYSERR;
224 }
225
226 line = strtok (buffer, "\n");
227 while (NULL != line)
228 {
229 zone_private_key = strtok (line, ",");
230 if (NULL == zone_private_key)
231 break;
232 rvalue = strtok (NULL, ",");
233 if (NULL == rvalue)
234 break;
235 record_count = strtok (NULL, ",");
236 if (NULL == record_count)
237 break;
238 record_data_b64 = strtok (NULL, ",");
239 if (NULL == record_data_b64)
240 break;
241 label = strtok (NULL, ",");
242 if (NULL == label)
243 break;
244 line = strtok (NULL, "\n");
245 entry = GNUNET_new (struct FlatFileEntry);
246 {
247 unsigned long long ll;
248
249 if (1 != sscanf (rvalue,
250 "%llu",
251 &ll))
252 {
253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
254 "Error parsing entry\n");
255 GNUNET_free (entry);
256 break;
257 }
258 entry->rvalue = (uint64_t) ll;
259 }
260 {
261 unsigned int ui;
262
263 if (1 != sscanf (record_count,
264 "%u",
265 &ui))
266 {
267 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
268 "Error parsing entry\n");
269 GNUNET_free (entry);
270 break;
271 }
272 entry->record_count = (uint32_t) ui;
273 }
274 entry->label = GNUNET_strdup (label);
275 record_data_size
276 = GNUNET_STRINGS_base64_decode (record_data_b64,
277 strlen (record_data_b64),
278 (void **) &record_data);
279 entry->record_data =
280 GNUNET_new_array (entry->record_count,
281 struct GNUNET_GNSRECORD_Data);
282 if (GNUNET_OK !=
283 GNUNET_GNSRECORD_records_deserialize (record_data_size,
284 record_data,
285 entry->record_count,
286 entry->record_data))
287 {
288 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
289 "Unable to deserialize record %s\n",
290 label);
291 GNUNET_free (entry->label);
292 GNUNET_free (entry);
293 GNUNET_free (record_data);
294 break;
295 }
296 GNUNET_free (record_data);
297
298 {
299 struct GNUNET_CRYPTO_PrivateKey *private_key;
300
301 GNUNET_STRINGS_base64_decode (zone_private_key,
302 strlen (zone_private_key),
303 (void **) &private_key);
304 entry->private_key = *private_key;
305 GNUNET_free (private_key);
306 }
307
308 hash_pkey_and_label (&entry->private_key,
309 label,
310 &hkey);
311 if (GNUNET_OK !=
312 GNUNET_CONTAINER_multihashmap_put (plugin->hm,
313 &hkey,
314 entry,
315 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
316 {
317 GNUNET_free (entry);
318 GNUNET_break (0);
319 }
320 }
321 GNUNET_DISK_file_unmap (mh);
322 GNUNET_DISK_file_close (fh);
323 return GNUNET_OK;
324}
325
326
327/**
328 * Store values in hashmap in file and free data
329 *
330 * @param plugin the plugin context
331 * @param key key in the map
332 * @param value a `struct FlatFileEntry`
333 */
334static int
335store_and_free_entries (void *cls,
336 const struct GNUNET_HashCode *key,
337 void *value)
338{
339 struct GNUNET_DISK_FileHandle *fh = cls;
340 struct FlatFileEntry *entry = value;
341 char *line;
342 char *zone_private_key;
343 char *record_data_b64;
344 ssize_t data_size;
345
346 (void) key;
347 GNUNET_STRINGS_base64_encode (&entry->private_key,
348 sizeof(struct GNUNET_CRYPTO_PrivateKey),
349 &zone_private_key);
350 data_size = GNUNET_GNSRECORD_records_get_size (entry->record_count,
351 entry->record_data);
352 if (data_size < 0)
353 {
354 GNUNET_break (0);
355 GNUNET_free (zone_private_key);
356 return GNUNET_SYSERR;
357 }
358 if (data_size >= UINT16_MAX)
359 {
360 GNUNET_break (0);
361 GNUNET_free (zone_private_key);
362 return GNUNET_SYSERR;
363 }
364 {
365 char data[data_size];
366 ssize_t ret;
367
368 ret = GNUNET_GNSRECORD_records_serialize (entry->record_count,
369 entry->record_data,
370 data_size,
371 data);
372 if ((ret < 0) ||
373 (data_size != ret))
374 {
375 GNUNET_break (0);
376 GNUNET_free (zone_private_key);
377 return GNUNET_SYSERR;
378 }
379 GNUNET_STRINGS_base64_encode (data,
380 data_size,
381 &record_data_b64);
382 }
383 GNUNET_asprintf (&line,
384 "%s,%llu,%u,%s,%s\n",
385 zone_private_key,
386 (unsigned long long) entry->rvalue,
387 (unsigned int) entry->record_count,
388 record_data_b64,
389 entry->label);
390 GNUNET_free (record_data_b64);
391 GNUNET_free (zone_private_key);
392
393 GNUNET_DISK_file_write (fh,
394 line,
395 strlen (line));
396
397 GNUNET_free (line);
398 GNUNET_free (entry->label);
399 GNUNET_free (entry->record_data);
400 GNUNET_free (entry);
401 return GNUNET_YES;
402}
403
404
405/**
406 * Shutdown database connection and associate data
407 * structures.
408 * @param plugin the plugin context (state for this module)
409 */
410static void
411database_shutdown (struct Plugin *plugin)
412{
413 struct GNUNET_DISK_FileHandle *fh;
414
415 fh = GNUNET_DISK_file_open (plugin->fn,
416 GNUNET_DISK_OPEN_CREATE
417 | GNUNET_DISK_OPEN_TRUNCATE
418 | GNUNET_DISK_OPEN_READWRITE,
419 GNUNET_DISK_PERM_USER_WRITE
420 | GNUNET_DISK_PERM_USER_READ);
421 if (NULL == fh)
422 {
423 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
424 _ ("Unable to initialize file: %s.\n"),
425 plugin->fn);
426 return;
427 }
428
429 GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
430 &store_and_free_entries,
431 fh);
432 GNUNET_CONTAINER_multihashmap_destroy (plugin->hm);
433 /* append 0-terminator */
434 GNUNET_DISK_file_write (fh,
435 "",
436 1);
437 GNUNET_DISK_file_close (fh);
438}
439
440
441/**
442 * Store a record in the datastore. Removes any existing record in the
443 * same zone with the same name.
444 *
445 * @param cls closure (internal context for the plugin)
446 * @param zone_key private key of the zone
447 * @param label name that is being mapped (at most 255 characters long)
448 * @param rd_count number of entries in @a rd array
449 * @param rd array of records with data to store
450 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
451 */
452static int
453namestore_flat_store_records (void *cls,
454 const struct
455 GNUNET_CRYPTO_PrivateKey *zone_key,
456 const char *label,
457 unsigned int rd_count,
458 const struct GNUNET_GNSRECORD_Data *rd)
459{
460 struct Plugin *plugin = cls;
461 uint64_t rvalue;
462 struct GNUNET_HashCode hkey;
463 struct FlatFileEntry *entry;
464
465 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
466 UINT64_MAX);
467 hash_pkey_and_label (zone_key,
468 label,
469 &hkey);
470 GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm,
471 &hkey);
472 if (0 == rd_count)
473 {
474 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
475 "sqlite",
476 "Record deleted\n");
477 return GNUNET_OK;
478 }
479 entry = GNUNET_new (struct FlatFileEntry);
480 GNUNET_asprintf (&entry->label,
481 label,
482 strlen (label));
483 GNUNET_memcpy (&entry->private_key,
484 zone_key,
485 sizeof(struct GNUNET_CRYPTO_PrivateKey));
486 entry->rvalue = rvalue;
487 entry->record_count = rd_count;
488 entry->record_data = GNUNET_new_array (rd_count,
489 struct GNUNET_GNSRECORD_Data);
490 for (unsigned int i = 0; i < rd_count; i++)
491 {
492 entry->record_data[i].expiration_time = rd[i].expiration_time;
493 entry->record_data[i].record_type = rd[i].record_type;
494 entry->record_data[i].flags = rd[i].flags;
495 entry->record_data[i].data_size = rd[i].data_size;
496 entry->record_data[i].data = GNUNET_malloc (rd[i].data_size);
497 GNUNET_memcpy ((char *) entry->record_data[i].data,
498 rd[i].data,
499 rd[i].data_size);
500 }
501 return GNUNET_CONTAINER_multihashmap_put (plugin->hm,
502 &hkey,
503 entry,
504 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
505}
506
507
508/**
509 * Lookup records in the datastore for which we are the authority.
510 *
511 * @param cls closure (internal context for the plugin)
512 * @param zone private key of the zone
513 * @param label name of the record in the zone
514 * @param iter function to call with the result
515 * @param iter_cls closure for @a iter
516 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
517 */
518static int
519namestore_flat_lookup_records (void *cls,
520 const struct GNUNET_CRYPTO_PrivateKey *zone,
521 const char *label,
522 GNUNET_NAMESTORE_RecordIterator iter,
523 void *iter_cls)
524{
525 struct Plugin *plugin = cls;
526 struct FlatFileEntry *entry;
527 struct GNUNET_HashCode hkey;
528
529 if (NULL == zone)
530 {
531 GNUNET_break (0);
532 return GNUNET_SYSERR;
533 }
534 hash_pkey_and_label (zone,
535 label,
536 &hkey);
537 entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm,
538 &hkey);
539
540 if (NULL == entry)
541 return GNUNET_NO;
542 if (NULL != iter)
543 iter (iter_cls,
544 1, /* zero is illegal */
545 &entry->private_key,
546 entry->label,
547 entry->record_count,
548 entry->record_data);
549 return GNUNET_YES;
550}
551
552
553/**
554 * Closure for #iterate_zones.
555 */
556struct IterateContext
557{
558 /**
559 * How many more records should we skip before returning results?
560 */
561 uint64_t offset;
562
563 /**
564 * How many more records should we return?
565 */
566 uint64_t limit;
567
568 /**
569 * What is the position of the current entry, counting
570 * starts from 1.
571 */
572 uint64_t pos;
573
574 /**
575 * Target zone.
576 */
577 const struct GNUNET_CRYPTO_PrivateKey *zone;
578
579 /**
580 * Function to call on each record.
581 */
582 GNUNET_NAMESTORE_RecordIterator iter;
583
584 /**
585 * Closure for @e iter.
586 */
587 void *iter_cls;
588};
589
590
591/**
592 * Helper function for #namestore_flat_iterate_records().
593 *
594 * @param cls a `struct IterateContext`
595 * @param key unused
596 * @param value a `struct FlatFileEntry`
597 * @return #GNUNET_YES to continue the iteration
598 */
599static int
600iterate_zones (void *cls,
601 const struct GNUNET_HashCode *key,
602 void *value)
603{
604 struct IterateContext *ic = cls;
605 struct FlatFileEntry *entry = value;
606
607 (void) key;
608 if (0 == ic->limit)
609 return GNUNET_NO;
610 if ((NULL != ic->zone) &&
611 (0 != GNUNET_memcmp (&entry->private_key,
612 ic->zone)))
613 return GNUNET_YES;
614 ic->pos++;
615 if (ic->offset > 0)
616 {
617 ic->offset--;
618 return GNUNET_YES;
619 }
620 ic->iter (ic->iter_cls,
621 ic->pos,
622 (NULL == ic->zone)
623 ? &entry->private_key
624 : ic->zone,
625 entry->label,
626 entry->record_count,
627 entry->record_data);
628 ic->limit--;
629 if (0 == ic->limit)
630 return GNUNET_NO;
631 return GNUNET_YES;
632}
633
634
635/**
636 * Iterate over the results for a particular key and zone in the
637 * datastore. Will return at most one result to the iterator.
638 *
639 * @param cls closure (internal context for the plugin)
640 * @param zone hash of public key of the zone, NULL to iterate over all zones
641 * @param serial serial number to exclude in the list of all matching records
642 * @param limit maximum number of results to return to @a iter
643 * @param iter function to call with the result
644 * @param iter_cls closure for @a iter
645 * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
646 */
647static int
648namestore_flat_iterate_records (void *cls,
649 const struct
650 GNUNET_CRYPTO_PrivateKey *zone,
651 uint64_t serial,
652 uint64_t limit,
653 GNUNET_NAMESTORE_RecordIterator iter,
654 void *iter_cls)
655{
656 struct Plugin *plugin = cls;
657 struct IterateContext ic;
658
659 ic.offset = serial;
660 ic.pos = 0;
661 ic.limit = limit;
662 ic.iter = iter;
663 ic.iter_cls = iter_cls;
664 ic.zone = zone;
665 GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
666 &iterate_zones,
667 &ic);
668 return (0 == ic.limit) ? GNUNET_OK : GNUNET_NO;
669}
670
671
672/**
673 * Closure for #zone_to_name.
674 */
675struct ZoneToNameContext
676{
677 const struct GNUNET_CRYPTO_PrivateKey *zone;
678 const struct GNUNET_CRYPTO_PublicKey *value_zone;
679 GNUNET_NAMESTORE_RecordIterator iter;
680 void *iter_cls;
681
682 int result_found;
683};
684
685
686static int
687zone_to_name (void *cls,
688 const struct GNUNET_HashCode *key,
689 void *value)
690{
691 struct ZoneToNameContext *ztn = cls;
692 struct FlatFileEntry *entry = value;
693
694 (void) key;
695 if (0 != GNUNET_memcmp (&entry->private_key,
696 ztn->zone))
697 return GNUNET_YES;
698
699 for (unsigned int i = 0; i < entry->record_count; i++)
700 {
701 if (GNUNET_NO ==
702 GNUNET_GNSRECORD_is_zonekey_type (entry->record_data[i].record_type))
703 continue;
704 if (ztn->value_zone->type != entry->record_data[i].record_type)
705 continue;
706 if (0 == memcmp (ztn->value_zone,
707 entry->record_data[i].data,
708 entry->record_data[i].data_size))
709 {
710 ztn->iter (ztn->iter_cls,
711 i + 1, /* zero is illegal! */
712 &entry->private_key,
713 entry->label,
714 entry->record_count,
715 entry->record_data);
716 ztn->result_found = GNUNET_YES;
717 }
718 }
719 return GNUNET_YES;
720}
721
722
723/**
724 * Look for an existing PKEY delegation record for a given public key.
725 * Returns at most one result to the iterator.
726 *
727 * @param cls closure (internal context for the plugin)
728 * @param zone private key of the zone to look up in, never NULL
729 * @param value_zone public key of the target zone (value), never NULL
730 * @param iter function to call with the result
731 * @param iter_cls closure for @a iter
732 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
733 */
734static int
735namestore_flat_zone_to_name (void *cls,
736 const struct GNUNET_CRYPTO_PrivateKey *zone,
737 const struct
738 GNUNET_CRYPTO_PublicKey *value_zone,
739 GNUNET_NAMESTORE_RecordIterator iter,
740 void *iter_cls)
741{
742 struct Plugin *plugin = cls;
743 struct ZoneToNameContext ztn = {
744 .iter = iter,
745 .iter_cls = iter_cls,
746 .zone = zone,
747 .value_zone = value_zone,
748 .result_found = GNUNET_NO
749 };
750
751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
752 "Performing reverse lookup for `%s'\n",
753 GNUNET_GNSRECORD_z2s (value_zone));
754 GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
755 &zone_to_name,
756 &ztn);
757 return ztn.result_found;
758}
759
760
761/**
762 * Entry point for the plugin.
763 *
764 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
765 * @return NULL on error, otherwise the plugin context
766 */
767void *
768libgnunet_plugin_namestore_flat_init (void *cls)
769{
770 static struct Plugin plugin;
771 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
772 struct GNUNET_NAMESTORE_PluginFunctions *api;
773
774 if (NULL != plugin.cfg)
775 return NULL; /* can only initialize once! */
776 memset (&plugin,
777 0,
778 sizeof(struct Plugin));
779 plugin.cfg = cfg;
780 if (GNUNET_OK != database_setup (&plugin))
781 {
782 database_shutdown (&plugin);
783 return NULL;
784 }
785 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
786 api->cls = &plugin;
787 api->store_records = &namestore_flat_store_records;
788 api->iterate_records = &namestore_flat_iterate_records;
789 api->zone_to_name = &namestore_flat_zone_to_name;
790 api->lookup_records = &namestore_flat_lookup_records;
791 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
792 _ ("Flat file database running\n"));
793 return api;
794}
795
796
797/**
798 * Exit point from the plugin.
799 *
800 * @param cls the plugin context (as returned by "init")
801 * @return always NULL
802 */
803void *
804libgnunet_plugin_namestore_flat_done (void *cls)
805{
806 struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
807 struct Plugin *plugin = api->cls;
808
809 database_shutdown (plugin);
810 plugin->cfg = NULL;
811 GNUNET_free (api);
812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
813 "Flat file plugin is finished\n");
814 return NULL;
815}
816
817
818/* end of plugin_namestore_flat.c */
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c
deleted file mode 100644
index c6debf3a9..000000000
--- a/src/namestore/plugin_namestore_postgres.c
+++ /dev/null
@@ -1,796 +0,0 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2009-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/**
22 * @file namestore/plugin_namestore_postgres.c
23 * @brief postgres-based namestore backend
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_namestore_plugin.h"
28#include "gnunet_namestore_service.h"
29#include "gnunet_gnsrecord_lib.h"
30#include "gnunet_pq_lib.h"
31#include "namestore.h"
32
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "namestore-postgres", __VA_ARGS__)
35
36
37/**
38 * Context for all functions in this plugin.
39 */
40struct Plugin
41{
42 /**
43 * Our configuration.
44 */
45 const struct GNUNET_CONFIGURATION_Handle *cfg;
46
47 /**
48 * Postgres database handle.
49 */
50 struct GNUNET_PQ_Context *dbh;
51
52 /**
53 * Database is prepared and ready
54 */
55 bool ready;
56};
57
58
59/**
60 * Initialize the database connections and associated data structures (create
61 * tables and indices as needed as well).
62 *
63 * @param cls the plugin context (state for this module)
64 * @return #GNUNET_OK on success
65 */
66static enum GNUNET_GenericReturnValue
67namestore_postgres_create_tables (void *cls)
68{
69 struct Plugin *plugin = cls;
70 struct GNUNET_PQ_Context *dbh;
71
72 dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
73 "namestore-postgres",
74 "namestore-",
75 NULL,
76 NULL);
77 if (NULL == dbh)
78 return GNUNET_SYSERR;
79 GNUNET_PQ_disconnect (dbh);
80 return GNUNET_OK;
81}
82
83
84/**
85 * Drop existing namestore tables.
86 *
87 * @param cls the plugin context (state for this module)
88 * @return #GNUNET_OK on success
89 */
90static enum GNUNET_GenericReturnValue
91namestore_postgres_drop_tables (void *cls)
92{
93 struct Plugin *plugin = cls;
94 struct GNUNET_PQ_Context *dbh;
95 enum GNUNET_GenericReturnValue ret;
96
97 dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
98 "namestore-postgres",
99 NULL,
100 NULL,
101 NULL);
102 if (NULL == dbh)
103 {
104 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
105 "Failed to connect to database\n");
106 return GNUNET_SYSERR;
107 }
108 ret = GNUNET_PQ_exec_sql (dbh,
109 "namestore-drop");
110 GNUNET_PQ_disconnect (dbh);
111 return ret;
112}
113
114
115static enum GNUNET_GenericReturnValue
116database_prepare (struct Plugin *plugin)
117{
118 enum GNUNET_GenericReturnValue ret;
119
120 if (plugin->ready)
121 return GNUNET_OK;
122 {
123 struct GNUNET_PQ_PreparedStatement ps[] = {
124 GNUNET_PQ_make_prepare ("store_records",
125 "INSERT INTO namestore.ns098records"
126 " (zone_private_key, pkey, rvalue, record_count, record_data, label)"
127 " VALUES ($1, $2, $3, $4, $5, $6)"
128 " ON CONFLICT ON CONSTRAINT zl"
129 " DO UPDATE"
130 " SET pkey=$2,rvalue=$3,record_count=$4,record_data=$5"
131 " WHERE ns098records.zone_private_key = $1"
132 " AND ns098records.label = $6"),
133 GNUNET_PQ_make_prepare ("delete_records",
134 "DELETE FROM namestore.ns098records "
135 "WHERE zone_private_key=$1 AND label=$2"),
136 GNUNET_PQ_make_prepare ("zone_to_name",
137 "SELECT seq,record_count,record_data,label FROM namestore.ns098records"
138 " WHERE zone_private_key=$1 AND pkey=$2"),
139 GNUNET_PQ_make_prepare ("iterate_zone",
140 "SELECT seq,record_count,record_data,label FROM namestore.ns098records "
141 "WHERE zone_private_key=$1 AND seq > $2 ORDER BY seq ASC LIMIT $3"),
142 GNUNET_PQ_make_prepare ("iterate_all_zones",
143 "SELECT seq,record_count,record_data,label,zone_private_key"
144 " FROM namestore.ns098records WHERE seq > $1 ORDER BY seq ASC LIMIT $2"),
145 GNUNET_PQ_make_prepare ("lookup_label",
146 "SELECT seq,record_count,record_data,label "
147 "FROM namestore.ns098records WHERE zone_private_key=$1 AND label=$2"),
148 GNUNET_PQ_make_prepare ("edit_set",
149 "SELECT seq,record_count,record_data,label "
150 "FROM namestore.ns098records WHERE zone_private_key=$1 AND label=$2 FOR UPDATE NOWAIT"),
151 GNUNET_PQ_PREPARED_STATEMENT_END
152 };
153
154 ret = GNUNET_PQ_prepare_statements (plugin->dbh,
155 ps);
156 }
157 if (GNUNET_OK != ret)
158 return ret;
159 plugin->ready = true;
160 return GNUNET_OK;
161}
162
163
164/**
165 * Initialize the database connections and associated
166 * data structures (create tables and indices
167 * as needed as well).
168 *
169 * @param plugin the plugin context (state for this module)
170 * @return #GNUNET_OK on success
171 */
172static enum GNUNET_GenericReturnValue
173database_connect (struct Plugin *plugin)
174{
175 struct GNUNET_PQ_ExecuteStatement ess[] = {
176 GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off"),
177 GNUNET_PQ_EXECUTE_STATEMENT_END
178 };
179 struct GNUNET_PQ_ExecuteStatement *es;
180
181 if (GNUNET_YES ==
182 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
183 "namestore-postgres",
184 "ASYNC_COMMIT"))
185 es = &ess[0];
186 else
187 es = &ess[1];
188
189 if (GNUNET_YES ==
190 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
191 "namestore-postgres",
192 "INIT_ON_CONNECT"))
193 {
194 if (GNUNET_OK !=
195 namestore_postgres_create_tables (plugin))
196 {
197 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
198 "Failed to create tables\n");
199 return GNUNET_SYSERR;
200 }
201 }
202 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
203 "namestore-postgres",
204 NULL,
205 es,
206 NULL);
207 if (NULL == plugin->dbh)
208 return GNUNET_SYSERR;
209 return GNUNET_OK;
210}
211
212
213/**
214 * Store a record in the datastore. Removes any existing record in the
215 * same zone with the same name.
216 *
217 * @param cls closure (internal context for the plugin)
218 * @param zone_key private key of the zone
219 * @param label name that is being mapped (at most 255 characters long)
220 * @param rd_count number of entries in @a rd array
221 * @param rd array of records with data to store
222 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
223 */
224static enum GNUNET_GenericReturnValue
225namestore_postgres_store_records (void *cls,
226 const struct
227 GNUNET_CRYPTO_PrivateKey *zone_key,
228 const char *label,
229 unsigned int rd_count,
230 const struct GNUNET_GNSRECORD_Data *rd)
231{
232 struct Plugin *plugin = cls;
233 struct GNUNET_CRYPTO_PublicKey pkey;
234 uint64_t rvalue;
235 uint32_t rd_count32 = (uint32_t) rd_count;
236 ssize_t data_size;
237
238 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
239 memset (&pkey,
240 0,
241 sizeof(pkey));
242 for (unsigned int i = 0; i < rd_count; i++)
243 if (GNUNET_YES ==
244 GNUNET_GNSRECORD_is_zonekey_type (rd[i].record_type))
245 {
246 GNUNET_break (GNUNET_OK ==
247 GNUNET_GNSRECORD_identity_from_data (rd[i].data,
248 rd[i].data_size,
249 rd[i].record_type,
250 &pkey));
251 break;
252 }
253 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
254 UINT64_MAX);
255 data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
256 rd);
257 if (data_size < 0)
258 {
259 GNUNET_break (0);
260 return GNUNET_SYSERR;
261 }
262 if (data_size >= UINT16_MAX)
263 {
264 GNUNET_break (0);
265 return GNUNET_SYSERR;
266 }
267 /* if record set is empty, delete existing records */
268 if (0 == rd_count)
269 {
270 struct GNUNET_PQ_QueryParam params[] = {
271 GNUNET_PQ_query_param_auto_from_type (zone_key),
272 GNUNET_PQ_query_param_string (label),
273 GNUNET_PQ_query_param_end
274 };
275 enum GNUNET_DB_QueryStatus res;
276
277 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
278 "delete_records",
279 params);
280 if ((GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != res) &&
281 (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != res))
282 {
283 GNUNET_break (0);
284 return GNUNET_SYSERR;
285 }
286 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
287 "postgres",
288 "Record deleted\n");
289 return GNUNET_OK;
290 }
291 /* otherwise, UPSERT (i.e. UPDATE if exists, otherwise INSERT) */
292 {
293 char data[data_size];
294 struct GNUNET_PQ_QueryParam params[] = {
295 GNUNET_PQ_query_param_auto_from_type (zone_key),
296 GNUNET_PQ_query_param_auto_from_type (&pkey),
297 GNUNET_PQ_query_param_uint64 (&rvalue),
298 GNUNET_PQ_query_param_uint32 (&rd_count32),
299 GNUNET_PQ_query_param_fixed_size (data, data_size),
300 GNUNET_PQ_query_param_string (label),
301 GNUNET_PQ_query_param_end
302 };
303 enum GNUNET_DB_QueryStatus res;
304 ssize_t ret;
305
306 ret = GNUNET_GNSRECORD_records_serialize (rd_count,
307 rd,
308 data_size,
309 data);
310 if ((ret < 0) ||
311 (data_size != ret))
312 {
313 GNUNET_break (0);
314 return GNUNET_SYSERR;
315 }
316
317 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
318 "store_records",
319 params);
320 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != res)
321 return GNUNET_SYSERR;
322 }
323 return GNUNET_OK;
324}
325
326
327/**
328 * Closure for #parse_result_call_iterator.
329 */
330struct ParserContext
331{
332 /**
333 * Function to call for each result.
334 */
335 GNUNET_NAMESTORE_RecordIterator iter;
336
337 /**
338 * Closure for @e iter.
339 */
340 void *iter_cls;
341
342 /**
343 * Zone key, NULL if part of record.
344 */
345 const struct GNUNET_CRYPTO_PrivateKey *zone_key;
346
347 /**
348 * Number of results still to return (counted down by
349 * number of results given to iterator).
350 */
351 uint64_t limit;
352};
353
354
355/**
356 * A statement has been run. We should evaluate the result, and if possible
357 * call the @a iter in @a cls with the result.
358 *
359 * @param cls closure of type `struct ParserContext *`
360 * @param res the postgres result
361 * @param num_results the number of results in @a result
362 */
363static void
364parse_result_call_iterator (void *cls,
365 PGresult *res,
366 unsigned int num_results)
367{
368 struct ParserContext *pc = cls;
369
370 if (NULL == pc->iter)
371 return; /* no need to do more work */
372 LOG (GNUNET_ERROR_TYPE_DEBUG,
373 "Got %d results from PQ.\n", num_results);
374 for (unsigned int i = 0; i < num_results; i++)
375 {
376 uint64_t serial;
377 void *data;
378 size_t data_size;
379 uint32_t record_count;
380 char *label;
381 struct GNUNET_CRYPTO_PrivateKey zk;
382 struct GNUNET_PQ_ResultSpec rs_with_zone[] = {
383 GNUNET_PQ_result_spec_uint64 ("seq", &serial),
384 GNUNET_PQ_result_spec_uint32 ("record_count", &record_count),
385 GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size),
386 GNUNET_PQ_result_spec_string ("label", &label),
387 GNUNET_PQ_result_spec_auto_from_type ("zone_private_key", &zk),
388 GNUNET_PQ_result_spec_end
389 };
390 struct GNUNET_PQ_ResultSpec rs_without_zone[] = {
391 GNUNET_PQ_result_spec_uint64 ("seq", &serial),
392 GNUNET_PQ_result_spec_uint32 ("record_count", &record_count),
393 GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size),
394 GNUNET_PQ_result_spec_string ("label", &label),
395 GNUNET_PQ_result_spec_end
396 };
397 struct GNUNET_PQ_ResultSpec *rs;
398
399 rs = (NULL == pc->zone_key) ? rs_with_zone : rs_without_zone;
400 if (GNUNET_YES !=
401 GNUNET_PQ_extract_result (res,
402 rs,
403 i))
404 {
405 GNUNET_break (0);
406 return;
407 }
408
409 if (record_count > 64 * 1024)
410 {
411 /* sanity check, don't stack allocate far too much just
412 because database might contain a large value here */
413 GNUNET_break (0);
414 GNUNET_PQ_cleanup_result (rs);
415 return;
416 }
417
418 {
419 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (record_count)];
420
421 GNUNET_assert (0 != serial);
422 if (GNUNET_OK !=
423 GNUNET_GNSRECORD_records_deserialize (data_size,
424 data,
425 record_count,
426 rd))
427 {
428 GNUNET_break (0);
429 GNUNET_PQ_cleanup_result (rs);
430 return;
431 }
432 pc->iter (pc->iter_cls,
433 serial,
434 (NULL == pc->zone_key) ? &zk : pc->zone_key,
435 label,
436 record_count,
437 rd);
438 }
439 GNUNET_PQ_cleanup_result (rs);
440 }
441 pc->limit -= num_results;
442}
443
444
445/**
446 * Lookup records in the datastore for which we are the authority.
447 *
448 * @param cls closure (internal context for the plugin)
449 * @param zone private key of the zone
450 * @param label name of the record in the zone
451 * @param iter function to call with the result
452 * @param iter_cls closure for @a iter
453 * @param method the method to use "lookup_record" or "edit_set"
454 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
455 */
456static enum GNUNET_GenericReturnValue
457lookup_records (void *cls,
458 const struct
459 GNUNET_CRYPTO_PrivateKey *zone,
460 const char *label,
461 GNUNET_NAMESTORE_RecordIterator iter,
462 void *iter_cls,
463 const char*method)
464{
465 struct Plugin *plugin = cls;
466 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
467 struct GNUNET_PQ_QueryParam params[] = {
468 GNUNET_PQ_query_param_auto_from_type (zone),
469 GNUNET_PQ_query_param_string (label),
470 GNUNET_PQ_query_param_end
471 };
472 struct ParserContext pc;
473 enum GNUNET_DB_QueryStatus res;
474
475 if (NULL == zone)
476 {
477 GNUNET_break (0);
478 return GNUNET_SYSERR;
479 }
480 pc.iter = iter;
481 pc.iter_cls = iter_cls;
482 pc.zone_key = zone;
483 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
484 method,
485 params,
486 &parse_result_call_iterator,
487 &pc);
488 if (res < 0)
489 return GNUNET_SYSERR;
490 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
491 return GNUNET_NO;
492 return GNUNET_OK;
493}
494
495
496/**
497 * Lookup records in the datastore for which we are the authority.
498 *
499 * @param cls closure (internal context for the plugin)
500 * @param zone private key of the zone
501 * @param label name of the record in the zone
502 * @param iter function to call with the result
503 * @param iter_cls closure for @a iter
504 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
505 */
506static enum GNUNET_GenericReturnValue
507namestore_postgres_lookup_records (void *cls,
508 const struct
509 GNUNET_CRYPTO_PrivateKey *zone,
510 const char *label,
511 GNUNET_NAMESTORE_RecordIterator iter,
512 void *iter_cls)
513{
514 return lookup_records (cls, zone, label, iter, iter_cls, "lookup_label");
515}
516
517
518/**
519 * Edit records in the datastore for which we are the authority.
520 *
521 * @param cls closure (internal context for the plugin)
522 * @param zone private key of the zone
523 * @param label name of the record in the zone
524 * @param iter function to call with the result
525 * @param iter_cls closure for @a iter
526 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
527 */
528static int
529namestore_postgres_edit_records (void *cls,
530 const struct
531 GNUNET_CRYPTO_PrivateKey *zone,
532 const char *label,
533 GNUNET_NAMESTORE_RecordIterator iter,
534 void *iter_cls)
535{
536 return lookup_records (cls, zone, label, iter, iter_cls, "edit_set");
537}
538
539
540/**
541 * Iterate over the results for a particular key and zone in the
542 * datastore. Will return at most one result to the iterator.
543 *
544 * @param cls closure (internal context for the plugin)
545 * @param zone hash of public key of the zone, NULL to iterate over all zones
546 * @param serial serial number to exclude in the list of all matching records
547 * @param limit maximum number of results to fetch
548 * @param iter function to call with the result
549 * @param iter_cls closure for @a iter
550 * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
551 */
552static enum GNUNET_GenericReturnValue
553namestore_postgres_iterate_records (void *cls,
554 const struct
555 GNUNET_CRYPTO_PrivateKey *zone,
556 uint64_t serial,
557 uint64_t limit,
558 GNUNET_NAMESTORE_RecordIterator iter,
559 void *iter_cls)
560{
561 struct Plugin *plugin = cls;
562 enum GNUNET_DB_QueryStatus res;
563 struct ParserContext pc;
564
565 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
566 pc.iter = iter;
567 pc.iter_cls = iter_cls;
568 pc.zone_key = zone;
569 pc.limit = limit;
570 if (NULL == zone)
571 {
572 struct GNUNET_PQ_QueryParam params_without_zone[] = {
573 GNUNET_PQ_query_param_uint64 (&serial),
574 GNUNET_PQ_query_param_uint64 (&limit),
575 GNUNET_PQ_query_param_end
576 };
577
578 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
579 "iterate_all_zones",
580 params_without_zone,
581 &parse_result_call_iterator,
582 &pc);
583 }
584 else
585 {
586 struct GNUNET_PQ_QueryParam params_with_zone[] = {
587 GNUNET_PQ_query_param_auto_from_type (zone),
588 GNUNET_PQ_query_param_uint64 (&serial),
589 GNUNET_PQ_query_param_uint64 (&limit),
590 GNUNET_PQ_query_param_end
591 };
592
593 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
594 "iterate_zone",
595 params_with_zone,
596 &parse_result_call_iterator,
597 &pc);
598 }
599 if (res < 0)
600 return GNUNET_SYSERR;
601
602 if ((GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res) ||
603 (pc.limit > 0))
604 return GNUNET_NO;
605 return GNUNET_OK;
606}
607
608
609/**
610 * Look for an existing PKEY delegation record for a given public key.
611 * Returns at most one result to the iterator.
612 *
613 * @param cls closure (internal context for the plugin)
614 * @param zone private key of the zone to look up in, never NULL
615 * @param value_zone public key of the target zone (value), never NULL
616 * @param iter function to call with the result
617 * @param iter_cls closure for @a iter
618 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
619 */
620static enum GNUNET_GenericReturnValue
621namestore_postgres_zone_to_name (void *cls,
622 const struct
623 GNUNET_CRYPTO_PrivateKey *zone,
624 const struct
625 GNUNET_CRYPTO_PublicKey *value_zone,
626 GNUNET_NAMESTORE_RecordIterator iter,
627 void *iter_cls)
628{
629 struct Plugin *plugin = cls;
630 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
631 struct GNUNET_PQ_QueryParam params[] = {
632 GNUNET_PQ_query_param_auto_from_type (zone),
633 GNUNET_PQ_query_param_auto_from_type (value_zone),
634 GNUNET_PQ_query_param_end
635 };
636 enum GNUNET_DB_QueryStatus res;
637 struct ParserContext pc;
638
639 pc.iter = iter;
640 pc.iter_cls = iter_cls;
641 pc.zone_key = zone;
642 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
643 "zone_to_name",
644 params,
645 &parse_result_call_iterator,
646 &pc);
647 if (res < 0)
648 return GNUNET_SYSERR;
649 return GNUNET_OK;
650}
651
652
653/**
654 * Begin a transaction for a client.
655 *
656 * @param cls closure (internal context for the plugin)
657 * @param emsg error message set of return code is #GNUNET_SYSERR
658 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
659 */
660static enum GNUNET_GenericReturnValue
661namestore_postgres_transaction_begin (void *cls,
662 char **emsg)
663{
664 struct Plugin *plugin = cls;
665 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
666 struct GNUNET_PQ_ExecuteStatement es[] = {
667 GNUNET_PQ_make_execute ("BEGIN"),
668 GNUNET_PQ_EXECUTE_STATEMENT_END
669 };
670
671 return GNUNET_PQ_exec_statements (plugin->dbh, es);
672}
673
674
675/**
676 * Commit a transaction for a client.
677 * This releases the lock on the database.
678 *
679 * @param cls closure (internal context for the plugin)
680 * @param emsg error message set of return code is #GNUNET_SYSERR
681 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
682 */
683static enum GNUNET_GenericReturnValue
684namestore_postgres_transaction_rollback (void *cls,
685 char **emsg)
686{
687 struct Plugin *plugin = cls;
688 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
689 struct GNUNET_PQ_ExecuteStatement es[] = {
690 GNUNET_PQ_make_execute ("ROLLBACK"),
691 GNUNET_PQ_EXECUTE_STATEMENT_END
692 };
693
694 return GNUNET_PQ_exec_statements (plugin->dbh, es);
695}
696
697
698/**
699 * Roll back a transaction for a client.
700 * This releases the lock on the database.
701 *
702 * @param cls closure (internal context for the plugin)
703 * @param emsg error message set of return code is #GNUNET_SYSERR
704 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
705 */
706static enum GNUNET_GenericReturnValue
707namestore_postgres_transaction_commit (void *cls,
708 char **emsg)
709{
710 struct Plugin *plugin = cls;
711 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
712 struct GNUNET_PQ_ExecuteStatement es[] = {
713 GNUNET_PQ_make_execute ("COMMIT"),
714 GNUNET_PQ_EXECUTE_STATEMENT_END
715 };
716
717 return GNUNET_PQ_exec_statements (plugin->dbh, es);
718}
719
720
721/**
722 * Shutdown database connection and associate data
723 * structures.
724 *
725 * @param plugin the plugin context (state for this module)
726 */
727static void
728database_shutdown (struct Plugin *plugin)
729{
730 GNUNET_PQ_disconnect (plugin->dbh);
731 plugin->dbh = NULL;
732}
733
734
735/**
736 * Entry point for the plugin.
737 *
738 * @param cls the `struct GNUNET_NAMESTORE_PluginEnvironment*`
739 * @return NULL on error, othrewise the plugin context
740 */
741void *
742libgnunet_plugin_namestore_postgres_init (void *cls)
743{
744 struct Plugin *plugin;
745 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
746 struct GNUNET_NAMESTORE_PluginFunctions *api;
747
748 plugin = GNUNET_new (struct Plugin);
749 plugin->cfg = cfg;
750 if (GNUNET_OK != database_connect (plugin))
751 {
752 database_shutdown (plugin);
753 GNUNET_free (plugin);
754 return NULL;
755 }
756 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
757 api->cls = plugin;
758 api->create_tables = &namestore_postgres_create_tables;
759 api->drop_tables = &namestore_postgres_drop_tables;
760 api->store_records = &namestore_postgres_store_records;
761 api->iterate_records = &namestore_postgres_iterate_records;
762 api->zone_to_name = &namestore_postgres_zone_to_name;
763 api->lookup_records = &namestore_postgres_lookup_records;
764 api->transaction_begin = &namestore_postgres_transaction_begin;
765 api->transaction_commit = &namestore_postgres_transaction_commit;
766 api->transaction_rollback = &namestore_postgres_transaction_rollback;
767 api->edit_records = &namestore_postgres_edit_records;
768 LOG (GNUNET_ERROR_TYPE_INFO,
769 "Postgres namestore plugin running\n");
770 return api;
771}
772
773
774/**
775 * Exit point from the plugin.
776 *
777 * @param cls the plugin context (as returned by "init")
778 * @return always NULL
779 */
780void *
781libgnunet_plugin_namestore_postgres_done (void *cls)
782{
783 struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
784 struct Plugin *plugin = api->cls;
785
786 database_shutdown (plugin);
787 plugin->cfg = NULL;
788 GNUNET_free (plugin);
789 GNUNET_free (api);
790 LOG (GNUNET_ERROR_TYPE_DEBUG,
791 "Postgres namestore plugin is finished\n");
792 return NULL;
793}
794
795
796/* end of plugin_namestore_postgres.c */
diff --git a/src/namestore/plugin_namestore_sqlite.c b/src/namestore/plugin_namestore_sqlite.c
deleted file mode 100644
index d66271ffa..000000000
--- a/src/namestore/plugin_namestore_sqlite.c
+++ /dev/null
@@ -1,983 +0,0 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2009-2017 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file namestore/plugin_namestore_sqlite.c
23 * @brief sqlite-based namestore backend
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_namestore_plugin.h"
29#include "gnunet_namestore_service.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_sq_lib.h"
32#include "namestore.h"
33#include <sqlite3.h>
34
35/**
36 * After how many ms "busy" should a DB operation fail for good? A
37 * low value makes sure that we are more responsive to requests
38 * (especially PUTs). A high value guarantees a higher success rate
39 * (SELECTs in iterate can take several seconds despite LIMIT=1).
40 *
41 * The default value of 1s should ensure that users do not experience
42 * huge latencies while at the same time allowing operations to
43 * succeed with reasonable probability.
44 */
45#define BUSY_TIMEOUT_MS 1000
46
47
48/**
49 * Log an error message at log-level 'level' that indicates
50 * a failure of the command 'cmd' on file 'filename'
51 * with the message given by strerror(errno).
52 */
53#define LOG_SQLITE(db, level, cmd) do { \
54 GNUNET_log_from (level, \
55 "namestore-sqlite", _ ( \
56 "`%s' failed at %s:%d with error: %s\n"), \
57 cmd, \
58 __FILE__, __LINE__, \
59 sqlite3_errmsg ( \
60 db->dbh)); \
61} while (0)
62
63#define LOG(kind, ...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__)
64
65
66/**
67 * Context for all functions in this plugin.
68 */
69struct Plugin
70{
71 const struct GNUNET_CONFIGURATION_Handle *cfg;
72
73 /**
74 * Database filename.
75 */
76 char *fn;
77
78 /**
79 * Statements prepared, we are ready to go if true.
80 */
81 bool ready;
82
83 /**
84 * Native SQLite database handle.
85 */
86 sqlite3 *dbh;
87
88 /**
89 * Precompiled SQL to store records.
90 */
91 sqlite3_stmt *store_records;
92
93 /**
94 * Precompiled SQL to deltete existing records.
95 */
96 sqlite3_stmt *delete_records;
97
98 /**
99 * Precompiled SQL for iterate records within a zone.
100 */
101 sqlite3_stmt *iterate_zone;
102
103 /**
104 * Precompiled SQL for iterate all records within all zones.
105 */
106 sqlite3_stmt *iterate_all_zones;
107
108 /**
109 * Precompiled SQL to for reverse lookup based on PKEY.
110 */
111 sqlite3_stmt *zone_to_name;
112
113 /**
114 * Precompiled SQL to lookup records based on label.
115 */
116 sqlite3_stmt *lookup_label;
117};
118
119
120/**
121 * Initialize the database connections and associated
122 * data structures (create tables and indices
123 * as needed as well).
124 *
125 * @param plugin the plugin context (state for this module)
126 * @return #GNUNET_OK on success
127 */
128static enum GNUNET_GenericReturnValue
129database_prepare (struct Plugin *plugin)
130{
131 if (plugin->ready)
132 return GNUNET_OK;
133 struct GNUNET_SQ_ExecuteStatement es[] = {
134 GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
135 GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
136 GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"),
137 GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"),
138 GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""),
139 GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"),
140 GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"),
141 GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
142 GNUNET_SQ_EXECUTE_STATEMENT_END
143 };
144 struct GNUNET_SQ_PrepareStatement ps[] = {
145 GNUNET_SQ_make_prepare ("INSERT INTO ns098records "
146 "(zone_private_key,pkey,rvalue,record_count,record_data,label)"
147 " VALUES (?, ?, ?, ?, ?, ?)",
148 &plugin->store_records),
149 GNUNET_SQ_make_prepare ("DELETE FROM ns098records "
150 "WHERE zone_private_key=? AND label=?",
151 &plugin->delete_records),
152 GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
153 " FROM ns098records"
154 " WHERE zone_private_key=? AND pkey=?",
155 &plugin->zone_to_name),
156 GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
157 " FROM ns098records"
158 " WHERE zone_private_key=? AND uid > ?"
159 " ORDER BY uid ASC"
160 " LIMIT ?",
161 &plugin->iterate_zone),
162 GNUNET_SQ_make_prepare (
163 "SELECT uid,record_count,record_data,label,zone_private_key"
164 " FROM ns098records"
165 " WHERE uid > ?"
166 " ORDER BY uid ASC"
167 " LIMIT ?",
168 &plugin->iterate_all_zones),
169 GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
170 " FROM ns098records"
171 " WHERE zone_private_key=? AND label=?",
172 &plugin->lookup_label),
173 GNUNET_SQ_PREPARE_END
174 };
175
176 if (GNUNET_OK !=
177 GNUNET_SQ_exec_statements (plugin->dbh,
178 es))
179 {
180 LOG (GNUNET_ERROR_TYPE_ERROR,
181 _ ("Failed to setup database with: `%s'\n"),
182 sqlite3_errmsg (plugin->dbh));
183 return GNUNET_SYSERR;
184 }
185 if (GNUNET_OK !=
186 GNUNET_SQ_prepare (plugin->dbh,
187 ps))
188 {
189 GNUNET_break (0);
190 LOG (GNUNET_ERROR_TYPE_ERROR,
191 _ ("Failed to setup database with: `%s'\n"),
192 sqlite3_errmsg (plugin->dbh));
193 return GNUNET_SYSERR;
194 }
195 plugin->ready = GNUNET_YES;
196 return GNUNET_OK;
197}
198
199
200/**
201 * Shutdown database connection and associate data
202 * structures.
203 * @param plugin the plugin context (state for this module)
204 */
205static void
206database_shutdown (struct Plugin *plugin)
207{
208 int result;
209 sqlite3_stmt *stmt;
210
211 if (NULL != plugin->store_records)
212 sqlite3_finalize (plugin->store_records);
213 if (NULL != plugin->delete_records)
214 sqlite3_finalize (plugin->delete_records);
215 if (NULL != plugin->iterate_zone)
216 sqlite3_finalize (plugin->iterate_zone);
217 if (NULL != plugin->iterate_all_zones)
218 sqlite3_finalize (plugin->iterate_all_zones);
219 if (NULL != plugin->zone_to_name)
220 sqlite3_finalize (plugin->zone_to_name);
221 if (NULL != plugin->lookup_label)
222 sqlite3_finalize (plugin->lookup_label);
223 result = sqlite3_close (plugin->dbh);
224 if (result == SQLITE_BUSY)
225 {
226 LOG (GNUNET_ERROR_TYPE_WARNING,
227 _ (
228 "Tried to close sqlite without finalizing all prepared statements.\n"));
229 stmt = sqlite3_next_stmt (plugin->dbh,
230 NULL);
231 while (NULL != stmt)
232 {
233 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
234 "sqlite",
235 "Closing statement %p\n",
236 stmt);
237 result = sqlite3_finalize (stmt);
238 if (result != SQLITE_OK)
239 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
240 "sqlite",
241 "Failed to close statement %p: %d\n",
242 stmt,
243 result);
244 stmt = sqlite3_next_stmt (plugin->dbh,
245 NULL);
246 }
247 result = sqlite3_close (plugin->dbh);
248 }
249 if (SQLITE_OK != result)
250 LOG_SQLITE (plugin,
251 GNUNET_ERROR_TYPE_ERROR,
252 "sqlite3_close");
253
254}
255
256
257/**
258 * Store a record in the datastore. Removes any existing record in the
259 * same zone with the same name.
260 *
261 * @param cls closure (internal context for the plugin)
262 * @param zone_key private key of the zone
263 * @param label name that is being mapped (at most 255 characters long)
264 * @param rd_count number of entries in @a rd array
265 * @param rd array of records with data to store
266 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
267 */
268static enum GNUNET_GenericReturnValue
269namestore_sqlite_store_records (void *cls,
270 const struct
271 GNUNET_CRYPTO_PrivateKey *zone_key,
272 const char *label,
273 unsigned int rd_count,
274 const struct GNUNET_GNSRECORD_Data *rd)
275{
276 struct Plugin *plugin = cls;
277 int n;
278 struct GNUNET_CRYPTO_PublicKey pkey;
279 uint64_t rvalue;
280 ssize_t data_size;
281
282 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
283 memset (&pkey,
284 0,
285 sizeof(pkey));
286 for (unsigned int i = 0; i < rd_count; i++)
287 {
288 LOG (GNUNET_ERROR_TYPE_DEBUG,
289 "Checking if `%d' is zonekey type\n",
290 rd[i].record_type);
291
292 if (GNUNET_YES == GNUNET_GNSRECORD_is_zonekey_type (rd[i].record_type))
293 {
294 GNUNET_break (GNUNET_YES ==
295 GNUNET_GNSRECORD_identity_from_data (rd[i].data,
296 rd[i].data_size,
297 rd[i].record_type,
298 &pkey));
299 LOG (GNUNET_ERROR_TYPE_DEBUG,
300 "Storing delegation zone record value `%s'\n",
301 GNUNET_GNSRECORD_z2s (&pkey));
302
303 break;
304 }
305 }
306 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
307 UINT64_MAX);
308 data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
309 rd);
310 if (data_size < 0)
311 {
312 GNUNET_break (0);
313 return GNUNET_SYSERR;
314 }
315 if (data_size > 64 * 65536)
316 {
317 GNUNET_break (0);
318 return GNUNET_SYSERR;
319 }
320 {
321 /* First delete 'old' records */
322 char data[data_size];
323 struct GNUNET_SQ_QueryParam dparams[] = {
324 GNUNET_SQ_query_param_auto_from_type (zone_key),
325 GNUNET_SQ_query_param_string (label),
326 GNUNET_SQ_query_param_end
327 };
328 ssize_t ret;
329
330 ret = GNUNET_GNSRECORD_records_serialize (rd_count,
331 rd,
332 data_size,
333 data);
334 if ((ret < 0) ||
335 (data_size != ret))
336 {
337 GNUNET_break (0);
338 return GNUNET_SYSERR;
339 }
340 if (GNUNET_OK !=
341 GNUNET_SQ_bind (plugin->delete_records,
342 dparams))
343 {
344 LOG_SQLITE (plugin,
345 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
346 "sqlite3_bind_XXXX");
347 GNUNET_SQ_reset (plugin->dbh,
348 plugin->delete_records);
349 return GNUNET_SYSERR;
350 }
351 n = sqlite3_step (plugin->delete_records);
352 GNUNET_SQ_reset (plugin->dbh,
353 plugin->delete_records);
354
355 if (0 != rd_count)
356 {
357 uint32_t rd_count32 = (uint32_t) rd_count;
358 struct GNUNET_SQ_QueryParam sparams[] = {
359 GNUNET_SQ_query_param_auto_from_type (zone_key),
360 GNUNET_SQ_query_param_auto_from_type (&pkey),
361 GNUNET_SQ_query_param_uint64 (&rvalue),
362 GNUNET_SQ_query_param_uint32 (&rd_count32),
363 GNUNET_SQ_query_param_fixed_size (data, data_size),
364 GNUNET_SQ_query_param_string (label),
365 GNUNET_SQ_query_param_end
366 };
367
368 if (GNUNET_OK !=
369 GNUNET_SQ_bind (plugin->store_records,
370 sparams))
371 {
372 LOG_SQLITE (plugin,
373 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
374 "sqlite3_bind_XXXX");
375 GNUNET_SQ_reset (plugin->dbh,
376 plugin->store_records);
377 return GNUNET_SYSERR;
378 }
379 n = sqlite3_step (plugin->store_records);
380 GNUNET_SQ_reset (plugin->dbh,
381 plugin->store_records);
382 }
383 }
384 switch (n)
385 {
386 case SQLITE_DONE:
387 if (0 != rd_count)
388 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
389 "sqlite",
390 "Record stored\n");
391 else
392 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
393 "sqlite",
394 "Record deleted\n");
395 return GNUNET_OK;
396
397 case SQLITE_BUSY:
398 LOG_SQLITE (plugin,
399 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
400 "sqlite3_step");
401 return GNUNET_NO;
402
403 default:
404 LOG_SQLITE (plugin,
405 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
406 "sqlite3_step");
407 return GNUNET_SYSERR;
408 }
409}
410
411
412/**
413 * The given 'sqlite' statement has been prepared to be run.
414 * It will return a record which should be given to the iterator.
415 * Runs the statement and parses the returned record.
416 *
417 * @param plugin plugin context
418 * @param stmt to run (and then clean up)
419 * @param zone_key private key of the zone
420 * @param limit maximum number of results to fetch
421 * @param iter iterator to call with the result
422 * @param iter_cls closure for @a iter
423 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
424 */
425static enum GNUNET_GenericReturnValue
426get_records_and_call_iterator (struct Plugin *plugin,
427 sqlite3_stmt *stmt,
428 const struct
429 GNUNET_CRYPTO_PrivateKey *zone_key,
430 uint64_t limit,
431 GNUNET_NAMESTORE_RecordIterator iter,
432 void *iter_cls)
433{
434 int ret;
435 int sret;
436
437 ret = GNUNET_OK;
438 for (uint64_t i = 0; i < limit; i++)
439 {
440 sret = sqlite3_step (stmt);
441
442 if (SQLITE_DONE == sret)
443 {
444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445 "Iteration done (no results)\n");
446 ret = GNUNET_NO;
447 break;
448 }
449 if (SQLITE_ROW != sret)
450 {
451 LOG_SQLITE (plugin,
452 GNUNET_ERROR_TYPE_ERROR,
453 "sqlite_step");
454 ret = GNUNET_SYSERR;
455 break;
456 }
457
458 {
459 uint64_t seq;
460 uint32_t record_count;
461 size_t data_size;
462 void *data;
463 char *label;
464 struct GNUNET_CRYPTO_PrivateKey zk;
465 struct GNUNET_SQ_ResultSpec rs[] = {
466 GNUNET_SQ_result_spec_uint64 (&seq),
467 GNUNET_SQ_result_spec_uint32 (&record_count),
468 GNUNET_SQ_result_spec_variable_size (&data,
469 &data_size),
470 GNUNET_SQ_result_spec_string (&label),
471 GNUNET_SQ_result_spec_end
472 };
473 struct GNUNET_SQ_ResultSpec rsx[] = {
474 GNUNET_SQ_result_spec_uint64 (&seq),
475 GNUNET_SQ_result_spec_uint32 (&record_count),
476 GNUNET_SQ_result_spec_variable_size (&data,
477 &data_size),
478 GNUNET_SQ_result_spec_string (&label),
479 GNUNET_SQ_result_spec_auto_from_type (&zk),
480 GNUNET_SQ_result_spec_end
481 };
482
483 ret = GNUNET_SQ_extract_result (stmt,
484 (NULL == zone_key)
485 ? rsx
486 : rs);
487 if ((GNUNET_OK != ret) ||
488 (record_count > 64 * 1024))
489 {
490 /* sanity check, don't stack allocate far too much just
491 because database might contain a large value here */
492 GNUNET_break (0);
493 ret = GNUNET_SYSERR;
494 break;
495 }
496 else
497 {
498 struct GNUNET_GNSRECORD_Data rd[record_count];
499
500 GNUNET_assert (0 != seq);
501 if (GNUNET_OK !=
502 GNUNET_GNSRECORD_records_deserialize (data_size,
503 data,
504 record_count,
505 rd))
506 {
507 GNUNET_break (0);
508 ret = GNUNET_SYSERR;
509 break;
510 }
511 else
512 {
513 if (NULL != zone_key)
514 zk = *zone_key;
515 if (NULL != iter)
516 iter (iter_cls,
517 seq,
518 &zk,
519 label,
520 record_count,
521 rd);
522 }
523 }
524 GNUNET_SQ_cleanup_result (rs);
525 }
526 }
527 GNUNET_SQ_reset (plugin->dbh,
528 stmt);
529 return ret;
530}
531
532
533/**
534 * Lookup records in the datastore for which we are the authority.
535 *
536 * @param cls closure (internal context for the plugin)
537 * @param zone private key of the zone
538 * @param label name of the record in the zone
539 * @param iter function to call with the result
540 * @param iter_cls closure for @a iter
541 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
542 */
543static enum GNUNET_GenericReturnValue
544namestore_sqlite_lookup_records (void *cls,
545 const struct
546 GNUNET_CRYPTO_PrivateKey *zone,
547 const char *label,
548 GNUNET_NAMESTORE_RecordIterator iter,
549 void *iter_cls)
550{
551 struct Plugin *plugin = cls;
552 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
553 struct GNUNET_SQ_QueryParam params[] = {
554 GNUNET_SQ_query_param_auto_from_type (zone),
555 GNUNET_SQ_query_param_string (label),
556 GNUNET_SQ_query_param_end
557 };
558
559 if (NULL == zone)
560 {
561 GNUNET_break (0);
562 return GNUNET_SYSERR;
563 }
564 if (GNUNET_OK !=
565 GNUNET_SQ_bind (plugin->lookup_label,
566 params))
567 {
568 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
569 "sqlite3_bind_XXXX");
570 GNUNET_SQ_reset (plugin->dbh,
571 plugin->lookup_label);
572 return GNUNET_SYSERR;
573 }
574 return get_records_and_call_iterator (plugin,
575 plugin->lookup_label,
576 zone,
577 1,
578 iter,
579 iter_cls);
580}
581
582
583/**
584 * Iterate over the results for a particular key and zone in the
585 * datastore. Will return at most one result to the iterator.
586 *
587 * @param cls closure (internal context for the plugin)
588 * @param zone hash of public key of the zone, NULL to iterate over all zones
589 * @param serial serial number to exclude in the list of all matching records
590 * @param limit maximum number of results to return
591 * @param iter function to call with the result
592 * @param iter_cls closure for @a iter
593 * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
594 */
595static enum GNUNET_GenericReturnValue
596namestore_sqlite_iterate_records (void *cls,
597 const struct
598 GNUNET_CRYPTO_PrivateKey *zone,
599 uint64_t serial,
600 uint64_t limit,
601 GNUNET_NAMESTORE_RecordIterator iter,
602 void *iter_cls)
603{
604 struct Plugin *plugin = cls;
605 sqlite3_stmt *stmt;
606 int err;
607
608 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
609 if (NULL == zone)
610 {
611 struct GNUNET_SQ_QueryParam params[] = {
612 GNUNET_SQ_query_param_uint64 (&serial),
613 GNUNET_SQ_query_param_uint64 (&limit),
614 GNUNET_SQ_query_param_end
615 };
616
617 stmt = plugin->iterate_all_zones;
618 err = GNUNET_SQ_bind (stmt,
619 params);
620 }
621 else
622 {
623 struct GNUNET_SQ_QueryParam params[] = {
624 GNUNET_SQ_query_param_auto_from_type (zone),
625 GNUNET_SQ_query_param_uint64 (&serial),
626 GNUNET_SQ_query_param_uint64 (&limit),
627 GNUNET_SQ_query_param_end
628 };
629
630 stmt = plugin->iterate_zone;
631 err = GNUNET_SQ_bind (stmt,
632 params);
633 }
634 if (GNUNET_OK != err)
635 {
636 LOG_SQLITE (plugin,
637 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
638 "sqlite3_bind_XXXX");
639 GNUNET_SQ_reset (plugin->dbh,
640 stmt);
641 return GNUNET_SYSERR;
642 }
643 return get_records_and_call_iterator (plugin,
644 stmt,
645 zone,
646 limit,
647 iter,
648 iter_cls);
649}
650
651
652/**
653 * Look for an existing PKEY delegation record for a given public key.
654 * Returns at most one result to the iterator.
655 *
656 * @param cls closure (internal context for the plugin)
657 * @param zone private key of the zone to look up in, never NULL
658 * @param value_zone public key of the target zone (value), never NULL
659 * @param iter function to call with the result
660 * @param iter_cls closure for @a iter
661 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
662 */
663static enum GNUNET_GenericReturnValue
664namestore_sqlite_zone_to_name (void *cls,
665 const struct GNUNET_CRYPTO_PrivateKey *zone,
666 const struct
667 GNUNET_CRYPTO_PublicKey *value_zone,
668 GNUNET_NAMESTORE_RecordIterator iter,
669 void *iter_cls)
670{
671 struct Plugin *plugin = cls;
672 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
673 struct GNUNET_SQ_QueryParam params[] = {
674 GNUNET_SQ_query_param_auto_from_type (zone),
675 GNUNET_SQ_query_param_auto_from_type (value_zone),
676 GNUNET_SQ_query_param_end
677 };
678
679 if (GNUNET_OK !=
680 GNUNET_SQ_bind (plugin->zone_to_name,
681 params))
682 {
683 LOG_SQLITE (plugin,
684 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
685 "sqlite3_bind_XXXX");
686 GNUNET_SQ_reset (plugin->dbh,
687 plugin->zone_to_name);
688 return GNUNET_SYSERR;
689 }
690 LOG (GNUNET_ERROR_TYPE_DEBUG,
691 "Performing reverse lookup for `%s'\n",
692 GNUNET_GNSRECORD_z2s (value_zone));
693 return get_records_and_call_iterator (plugin,
694 plugin->zone_to_name,
695 zone,
696 1,
697 iter,
698 iter_cls);
699}
700
701
702/**
703 * Begin a transaction for a client.
704 * This locks the database. SQLite is unable to discern between different
705 * rows with a specific zone key but the API looks like this anyway.
706 * https://www.sqlite.org/lang_transaction.html
707 *
708 * @param cls closure (internal context for the plugin)
709 * @param emsg error message set of return code is #GNUNET_SYSERR
710 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
711 */
712static enum GNUNET_GenericReturnValue
713namestore_sqlite_transaction_begin (void *cls,
714 char **emsg)
715{
716 struct Plugin *plugin = cls;
717 int rc;
718 char *sqlEmsg;
719
720 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
721 rc = sqlite3_exec (plugin->dbh, "BEGIN IMMEDIATE TRANSACTION;",
722 NULL, NULL, &sqlEmsg);
723 if (SQLITE_OK != rc)
724 {
725 *emsg = GNUNET_strdup (sqlEmsg);
726 sqlite3_free (sqlEmsg);
727 }
728 return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES;
729}
730
731
732/**
733 * Commit a transaction for a client.
734 * This releases the lock on the database.
735 *
736 * @param cls closure (internal context for the plugin)
737 * @param emsg error message set of return code is #GNUNET_SYSERR
738 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
739 */
740static enum GNUNET_GenericReturnValue
741namestore_sqlite_transaction_rollback (void *cls,
742 char **emsg)
743{
744 struct Plugin *plugin = cls;
745 int rc;
746 char *sqlEmsg;
747
748 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
749 rc = sqlite3_exec (plugin->dbh, "ROLLBACK;",
750 NULL, NULL, &sqlEmsg);
751 if (SQLITE_OK != rc)
752 {
753 *emsg = GNUNET_strdup (sqlEmsg);
754 sqlite3_free (sqlEmsg);
755 }
756 return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES;
757}
758
759
760/**
761 * Roll back a transaction for a client.
762 * This releases the lock on the database.
763 *
764 * @param cls closure (internal context for the plugin)
765 * @param emsg error message set of return code is #GNUNET_SYSERR
766 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
767 */
768static enum GNUNET_GenericReturnValue
769namestore_sqlite_transaction_commit (void *cls,
770 char **emsg)
771{
772 struct Plugin *plugin = cls;
773 int rc;
774 char *sqlEmsg;
775
776 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
777 rc = sqlite3_exec (plugin->dbh, "END TRANSACTION;",
778 NULL, NULL, &sqlEmsg);
779 if (SQLITE_OK != rc)
780 {
781 *emsg = GNUNET_strdup (sqlEmsg);
782 sqlite3_free (sqlEmsg);
783 }
784 return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES;
785}
786
787
788static enum GNUNET_GenericReturnValue
789namestore_sqlite_create_tables (void *cls)
790{
791 struct Plugin *plugin = cls;
792 struct GNUNET_SQ_ExecuteStatement es[] = {
793 GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
794 GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
795 GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"),
796 GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"),
797 GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""),
798 GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"),
799 GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"),
800 GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
801 GNUNET_SQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records ("
802 " uid INTEGER PRIMARY KEY,"
803 " zone_private_key BLOB NOT NULL,"
804 " pkey BLOB,"
805 " rvalue INT8 NOT NULL,"
806 " record_count INT NOT NULL,"
807 " record_data BLOB NOT NULL,"
808 " label TEXT NOT NULL"
809 ")"),
810 GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_reverse "
811 "ON ns098records (zone_private_key,pkey)"),
812 GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_iter "
813 "ON ns098records (zone_private_key,uid)"),
814 GNUNET_SQ_EXECUTE_STATEMENT_END
815 };
816
817 if (GNUNET_OK !=
818 GNUNET_SQ_exec_statements (plugin->dbh,
819 es))
820 {
821 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
822 "Failed to setup database with: `%s'\n",
823 sqlite3_errmsg (plugin->dbh));
824 return GNUNET_SYSERR;
825 }
826 return GNUNET_OK;
827}
828
829
830static enum GNUNET_GenericReturnValue
831namestore_sqlite_drop_tables (void *cls)
832{
833 struct Plugin *plugin = cls;
834 struct GNUNET_SQ_ExecuteStatement es_drop[] = {
835 GNUNET_SQ_make_execute ("DROP TABLE IF EXISTS ns098records"),
836 GNUNET_SQ_EXECUTE_STATEMENT_END
837 };
838
839 if (GNUNET_OK !=
840 GNUNET_SQ_exec_statements (plugin->dbh,
841 es_drop))
842 {
843 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
844 "Failed to drop database with: `%s'\n",
845 sqlite3_errmsg (plugin->dbh));
846 return GNUNET_SYSERR;
847 }
848 return GNUNET_OK;
849}
850
851
852/**
853 * Initialize the database connections and associated
854 * data structures (create tables and indices
855 * as needed as well).
856 *
857 * @param plugin the plugin context (state for this module)
858 * @return #GNUNET_OK on success
859 */
860static enum GNUNET_GenericReturnValue
861database_connect (struct Plugin *plugin)
862{
863 char *sqlite_filename;
864
865 if (GNUNET_OK !=
866 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
867 "namestore-sqlite",
868 "FILENAME",
869 &sqlite_filename))
870 {
871 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
872 "namestore-sqlite",
873 "FILENAME");
874 return GNUNET_SYSERR;
875 }
876 if (GNUNET_OK !=
877 GNUNET_DISK_file_test (sqlite_filename))
878 {
879 if (GNUNET_OK !=
880 GNUNET_DISK_directory_create_for_file (sqlite_filename))
881 {
882 GNUNET_break (0);
883 GNUNET_free (sqlite_filename);
884 return GNUNET_SYSERR;
885 }
886 }
887
888 /* Open database and precompile statements */
889 if ((NULL == plugin->dbh) &&
890 (SQLITE_OK != sqlite3_open (sqlite_filename,
891 &plugin->dbh)))
892 {
893 LOG (GNUNET_ERROR_TYPE_ERROR,
894 _ ("Unable to initialize SQLite: %s.\n"),
895 sqlite3_errmsg (plugin->dbh));
896 GNUNET_free (sqlite_filename);
897 return GNUNET_SYSERR;
898 }
899 GNUNET_free (sqlite_filename);
900 GNUNET_break (SQLITE_OK ==
901 sqlite3_busy_timeout (plugin->dbh,
902 BUSY_TIMEOUT_MS));
903 if (GNUNET_YES ==
904 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
905 "namestore-sqlite",
906 "INIT_ON_CONNECT"))
907 {
908 if (GNUNET_OK !=
909 namestore_sqlite_create_tables (plugin))
910 return GNUNET_SYSERR;
911 }
912 return GNUNET_OK;
913}
914
915
916/**
917 * Entry point for the plugin.
918 *
919 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
920 * @return NULL on error, otherwise the plugin context
921 */
922void *
923libgnunet_plugin_namestore_sqlite_init (void *cls)
924{
925 struct Plugin *plugin;
926 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
927 struct GNUNET_NAMESTORE_PluginFunctions *api;
928
929 plugin = GNUNET_new (struct Plugin);
930 plugin->cfg = cfg;
931 if (GNUNET_OK != database_connect (plugin))
932 {
933 LOG (GNUNET_ERROR_TYPE_ERROR,
934 "Database could not be connected to.\n");
935 GNUNET_free (plugin);
936 return NULL;
937 }
938 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
939 api->cls = plugin;
940 api->store_records = &namestore_sqlite_store_records;
941 api->iterate_records = &namestore_sqlite_iterate_records;
942 api->zone_to_name = &namestore_sqlite_zone_to_name;
943 api->lookup_records = &namestore_sqlite_lookup_records;
944 api->transaction_begin = &namestore_sqlite_transaction_begin;
945 api->transaction_commit = &namestore_sqlite_transaction_commit;
946 api->transaction_rollback = &namestore_sqlite_transaction_rollback;
947 api->create_tables = &namestore_sqlite_create_tables;
948 api->drop_tables = &namestore_sqlite_drop_tables;
949 /**
950 * NOTE: Since SQlite does not support SELECT ... FOR UPDATE this is
951 * just an alias to lookup_records. The BEGIN IMMEDIATE mechanic currently
952 * implicitly ensures this API behaves as it should
953 */
954 api->edit_records = &namestore_sqlite_lookup_records;
955 LOG (GNUNET_ERROR_TYPE_DEBUG,
956 _ ("SQlite database running\n"));
957 return api;
958}
959
960
961/**
962 * Exit point from the plugin.
963 *
964 * @param cls the plugin context (as returned by "init")
965 * @return always NULL
966 */
967void *
968libgnunet_plugin_namestore_sqlite_done (void *cls)
969{
970 struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
971 struct Plugin *plugin = api->cls;
972
973 database_shutdown (plugin);
974 plugin->cfg = NULL;
975 GNUNET_free (plugin);
976 GNUNET_free (api);
977 LOG (GNUNET_ERROR_TYPE_DEBUG,
978 "SQlite plugin is finished\n");
979 return NULL;
980}
981
982
983/* end of plugin_namestore_sqlite.c */
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
deleted file mode 100644
index 31e78e6dd..000000000
--- a/src/namestore/plugin_rest_namestore.c
+++ /dev/null
@@ -1,1364 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-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 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file namestore/plugin_rest_namestore.c
24 * @brief GNUnet Namestore REST plugin
25 */
26
27#include "platform.h"
28#include "gnunet_error_codes.h"
29#include "gnunet_rest_plugin.h"
30#include "gnunet_gns_service.h"
31#include "gnunet_namestore_service.h"
32#include "gnunet_identity_service.h"
33#include "gnunet_rest_lib.h"
34#include "gnunet_gnsrecord_json_lib.h"
35#include "microhttpd.h"
36#include <jansson.h>
37
38/**
39 * Namestore namespace
40 */
41#define GNUNET_REST_API_NS_NAMESTORE "/namestore"
42
43/**
44 * Namestore import API namespace
45 */
46#define GNUNET_REST_API_NS_NAMESTORE_IMPORT "/namestore/import"
47
48/**
49 * State while collecting all egos
50 */
51#define ID_REST_STATE_INIT 0
52
53/**
54 * Done collecting egos
55 */
56#define ID_REST_STATE_POST_INIT 1
57/**
58 * The configuration handle
59 */
60const struct GNUNET_CONFIGURATION_Handle *cfg;
61
62/**
63 * HTTP methods allows for this plugin
64 */
65static char *allow_methods;
66
67/**
68 * Ego list
69 */
70static struct EgoEntry *ego_head;
71
72/**
73 * Ego list
74 */
75static struct EgoEntry *ego_tail;
76
77/**
78 * The processing state
79 */
80static int state;
81
82/**
83 * Handle to NAMESTORE
84 */
85static struct GNUNET_NAMESTORE_Handle *ns_handle;
86
87/**
88 * Handle to Identity service.
89 */
90static struct GNUNET_IDENTITY_Handle *identity_handle;
91
92/**
93 * @brief struct returned by the initialization function of the plugin
94 */
95struct Plugin
96{
97 const struct GNUNET_CONFIGURATION_Handle *cfg;
98};
99
100/**
101 * The default namestore ego
102 */
103struct EgoEntry
104{
105 /**
106 * DLL
107 */
108 struct EgoEntry *next;
109
110 /**
111 * DLL
112 */
113 struct EgoEntry *prev;
114
115 /**
116 * Ego Identifier
117 */
118 char *identifier;
119
120 /**
121 * Public key string
122 */
123 char *keystring;
124
125 /**
126 * The Ego
127 */
128 struct GNUNET_IDENTITY_Ego *ego;
129};
130
131
132enum UpdateStrategy
133{
134 UPDATE_STRATEGY_REPLACE,
135 UPDATE_STRATEGY_APPEND
136};
137
138/**
139 * The request handle
140 */
141struct RequestHandle
142{
143 /**
144 * DLL
145 */
146 struct RequestHandle *next;
147
148 /**
149 * DLL
150 */
151 struct RequestHandle *prev;
152
153 /**
154 * Records to store
155 */
156 char *record_name;
157
158 /**
159 * Record type filter
160 */
161 uint32_t record_type;
162
163 /**
164 * How to update the record set
165 */
166 enum UpdateStrategy update_strategy;
167
168 /**
169 * Records to store
170 */
171 struct GNUNET_GNSRECORD_Data *rd;
172
173 /**
174 * Number of records in rd
175 */
176 unsigned int rd_count;
177
178 /**
179 * RecordInfo array
180 */
181 struct GNUNET_NAMESTORE_RecordInfo *ri;
182
183 /**
184 * Size of record info
185 */
186 unsigned int rd_set_count;
187
188 /**
189 * Position of record info
190 */
191 unsigned int rd_set_pos;
192
193 /**
194 * NAMESTORE Operation
195 */
196 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
197
198 /**
199 * For bulk import, we need a dedicated Namestore handle
200 */
201 struct GNUNET_NAMESTORE_Handle *nc;
202
203 /**
204 * Response object
205 */
206 json_t *resp_object;
207
208
209 /**
210 * Handle to NAMESTORE it
211 */
212 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
213
214 /**
215 * Private key for the zone
216 */
217 const struct GNUNET_CRYPTO_PrivateKey *zone_pkey;
218
219 /**
220 * IDENTITY Operation
221 */
222 struct EgoEntry *ego_entry;
223
224 /**
225 * IDENTITY Operation
226 */
227 struct GNUNET_IDENTITY_Operation *op;
228
229 /**
230 * Rest connection
231 */
232 struct GNUNET_REST_RequestHandle *rest_handle;
233
234 /**
235 * Desired timeout for the lookup (default is no timeout).
236 */
237 struct GNUNET_TIME_Relative timeout;
238
239 /**
240 * ID of a task associated with the resolution process.
241 */
242 struct GNUNET_SCHEDULER_Task *timeout_task;
243
244 /**
245 * The plugin result processor
246 */
247 GNUNET_REST_ResultProcessor proc;
248
249 /**
250 * The closure of the result processor
251 */
252 void *proc_cls;
253
254 /**
255 * The url
256 */
257 char *url;
258
259 /**
260 * Error code
261 */
262 enum GNUNET_ErrorCode ec;
263
264};
265
266/**
267 * DLL
268 */
269static struct RequestHandle *requests_head;
270
271/**
272 * DLL
273 */
274static struct RequestHandle *requests_tail;
275
276
277/**
278 * Cleanup lookup handle
279 * @param cls Handle to clean up
280 */
281static void
282cleanup_handle (void *cls)
283{
284 struct RequestHandle *handle = cls;
285
286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
287 if (NULL != handle->timeout_task)
288 {
289 GNUNET_SCHEDULER_cancel (handle->timeout_task);
290 handle->timeout_task = NULL;
291 }
292 if (NULL != handle->record_name)
293 GNUNET_free (handle->record_name);
294 if (NULL != handle->url)
295 GNUNET_free (handle->url);
296 if (NULL != handle->rd)
297 {
298 for (int i = 0; i < handle->rd_count; i++)
299 {
300 if (NULL != handle->rd[i].data)
301 GNUNET_free_nz ((void *) handle->rd[i].data);
302 }
303 GNUNET_free (handle->rd);
304 }
305 if (NULL != handle->timeout_task)
306 GNUNET_SCHEDULER_cancel (handle->timeout_task);
307 if (NULL != handle->list_it)
308 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
309 if (NULL != handle->ns_qe)
310 GNUNET_NAMESTORE_cancel (handle->ns_qe);
311 if (NULL != handle->nc)
312 GNUNET_NAMESTORE_disconnect (handle->nc);
313 if (NULL != handle->resp_object)
314 {
315 json_decref (handle->resp_object);
316 }
317 GNUNET_CONTAINER_DLL_remove (requests_head,
318 requests_tail,
319 handle);
320 GNUNET_free (handle);
321}
322
323
324/**
325 * Task run on errors. Reports an error and cleans up everything.
326 *
327 * @param cls the `struct RequestHandle`
328 */
329static void
330do_error (void *cls)
331{
332 struct RequestHandle *handle = cls;
333 struct MHD_Response *resp;
334 json_t *json_error = json_object ();
335 char *response;
336 const char* emsg;
337 int response_code;
338
339 emsg = GNUNET_ErrorCode_get_hint (handle->ec);
340 json_object_set_new (json_error, "error", json_string (emsg));
341 json_object_set_new (json_error, "error_code", json_integer (handle->ec));
342 response_code = GNUNET_ErrorCode_get_http_status (handle->ec);
343 if (0 == response_code)
344 response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
345 response = json_dumps (json_error, 0);
346 resp = GNUNET_REST_create_response (response);
347 GNUNET_assert (MHD_YES ==
348 MHD_add_response_header (resp, "Content-Type",
349 "application/json"));
350 handle->proc (handle->proc_cls, resp, response_code);
351 json_decref (json_error);
352 GNUNET_free (response);
353 cleanup_handle (handle);
354}
355
356
357/**
358 * Get EgoEntry from list with either a public key or a name
359 * If public key and name are not NULL, it returns the public key result first
360 *
361 * @param handle the RequestHandle
362 * @param pubkey the public key of an identity (only one can be NULL)
363 * @param name the name of an identity (only one can be NULL)
364 * @return EgoEntry or NULL if not found
365 */
366struct EgoEntry *
367get_egoentry_namestore (struct RequestHandle *handle, char *name)
368{
369 struct EgoEntry *ego_entry;
370 char *copy = GNUNET_strdup (name);
371 char *tmp;
372
373 if (NULL == name)
374 return NULL;
375 tmp = strtok (copy, "/");
376 if (NULL == tmp)
377 return NULL;
378 for (ego_entry = ego_head; NULL != ego_entry;
379 ego_entry = ego_entry->next)
380 {
381 if (0 != strcasecmp (tmp, ego_entry->identifier))
382 continue;
383 GNUNET_free (copy);
384 return ego_entry;
385 }
386 GNUNET_free (copy);
387 return NULL;
388}
389
390
391/**
392 * Does internal server error when iteration failed.
393 *
394 * @param cls the `struct RequestHandle`
395 */
396static void
397namestore_iteration_error (void *cls)
398{
399 struct RequestHandle *handle = cls;
400
401 handle->ec = GNUNET_EC_NAMESTORE_ITERATION_FAILED;
402 GNUNET_SCHEDULER_add_now (&do_error, handle);
403 return;
404}
405
406
407static void
408create_finished (void *cls, enum GNUNET_ErrorCode ec)
409{
410 struct RequestHandle *handle = cls;
411 struct MHD_Response *resp;
412
413 handle->ns_qe = NULL;
414 handle->ec = ec;
415 if (GNUNET_EC_NONE != ec)
416 {
417 GNUNET_SCHEDULER_add_now (&do_error, handle);
418 return;
419 }
420 resp = GNUNET_REST_create_response (NULL);
421 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
422 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
423}
424
425
426static void
427del_finished (void *cls, enum GNUNET_ErrorCode ec)
428{
429 struct RequestHandle *handle = cls;
430
431 handle->ns_qe = NULL;
432 handle->ec = ec;
433 if (GNUNET_EC_NONE != ec)
434 {
435 GNUNET_SCHEDULER_add_now (&do_error, handle);
436 return;
437 }
438 handle->proc (handle->proc_cls,
439 GNUNET_REST_create_response (NULL),
440 MHD_HTTP_NO_CONTENT);
441 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
442}
443
444
445/**
446 * Iteration over all results finished, build final
447 * response.
448 *
449 * @param cls the `struct RequestHandle`
450 */
451static void
452namestore_list_finished (void *cls)
453{
454 struct RequestHandle *handle = cls;
455 char *result_str;
456 struct MHD_Response *resp;
457
458 handle->list_it = NULL;
459
460 if (NULL == handle->resp_object)
461 {
462 handle->ec = GNUNET_EC_NAMESTORE_ZONE_EMPTY;
463 GNUNET_SCHEDULER_add_now (&do_error, handle);
464 return;
465 }
466 result_str = json_dumps (handle->resp_object, 0);
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
468 resp = GNUNET_REST_create_response (result_str);
469 GNUNET_assert (MHD_YES ==
470 MHD_add_response_header (resp, "Content-Type",
471 "application/json"));
472 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
473 GNUNET_free (result_str);
474 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
475}
476
477
478/**
479 * Create a response with requested records
480 *
481 * @param handle the RequestHandle
482 */
483static void
484namestore_list_iteration (void *cls,
485 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
486 const char *rname,
487 unsigned int rd_len,
488 const struct GNUNET_GNSRECORD_Data *rd,
489 struct GNUNET_TIME_Absolute expiry)
490{
491 struct RequestHandle *handle = cls;
492 struct GNUNET_GNSRECORD_Data rd_filtered[rd_len];
493 json_t *record_obj;
494 int i = 0;
495 int j = 0;
496
497 if (rd_len == 0)
498 {
499 /** skip **/
500 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
501 return;
502 }
503
504 for (i = 0; i < rd_len; i++)
505 {
506 if ((GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) &&
507 (rd[i].record_type != handle->record_type))
508 continue; /* Apply filter */
509 rd_filtered[j] = rd[i];
510 rd_filtered[j].data = rd[i].data;
511 j++;
512 }
513 /** Only add if not empty **/
514 if (j > 0)
515 {
516 if (NULL == handle->resp_object)
517 handle->resp_object = json_array ();
518 record_obj = GNUNET_GNSRECORD_JSON_from_gnsrecord (rname,
519 rd_filtered,
520 j);
521 json_array_append_new (handle->resp_object, record_obj);
522 }
523 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
524}
525
526
527/**
528 * Handle lookup error
529 *
530 * @param cls the request handle
531 */
532static void
533ns_lookup_error_cb (void *cls)
534{
535 struct RequestHandle *handle = cls;
536
537 handle->ec = GNUNET_EC_NAMESTORE_LOOKUP_ERROR;
538 GNUNET_SCHEDULER_add_now (&do_error, handle);
539}
540
541
542static void
543ns_get_lookup_cb (void *cls,
544 const struct GNUNET_CRYPTO_PrivateKey *zone,
545 const char *label,
546 unsigned int rd_len,
547 const struct GNUNET_GNSRECORD_Data *rd)
548{
549 struct RequestHandle *handle = cls;
550 struct GNUNET_GNSRECORD_Data rd_filtered[rd_len];
551 int i = 0;
552 int j = 0;
553
554 handle->ns_qe = NULL;
555 for (i = 0; i < rd_len; i++)
556 {
557 if ((GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) &&
558 (rd[i].record_type != handle->record_type))
559 continue; /* Apply filter */
560 rd_filtered[j] = rd[i];
561 rd_filtered[j].data = rd[i].data;
562 j++;
563 }
564 /** Return 404 if no set was found **/
565 if (j == 0)
566 {
567 handle->ec = GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND;
568 GNUNET_SCHEDULER_add_now (&do_error, handle);
569 return;
570 }
571 handle->resp_object = GNUNET_GNSRECORD_JSON_from_gnsrecord (label,
572 rd_filtered,
573 j);
574 GNUNET_SCHEDULER_add_now (&namestore_list_finished, handle);
575}
576
577
578/**
579 * Handle namestore GET request
580 *
581 * @param con_handle the connection handle
582 * @param url the url
583 * @param cls the RequestHandle
584 */
585void
586namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
587 const char *url,
588 void *cls)
589{
590 struct RequestHandle *handle = cls;
591 struct EgoEntry *ego_entry;
592 struct GNUNET_HashCode key;
593 enum GNUNET_GNSRECORD_Filter filter_flags;
594 char *egoname;
595 char *labelname;
596 char *typename;
597 char *boolstring;
598
599 egoname = NULL;
600 ego_entry = NULL;
601
602 // set zone to name if given
603 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
604 {
605 handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
606 GNUNET_SCHEDULER_add_now (&do_error, handle);
607 return;
608 }
609 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
610 ego_entry = get_egoentry_namestore (handle, egoname);
611 if (NULL == ego_entry)
612 {
613 handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
614 GNUNET_SCHEDULER_add_now (&do_error, handle);
615 return;
616 }
617 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
618
619 GNUNET_CRYPTO_hash ("record_type", strlen ("record_type"), &key);
620 handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
621 if (GNUNET_YES ==
622 GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
623 {
624 typename = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
625 &key);
626 if (NULL != typename)
627 handle->record_type = GNUNET_GNSRECORD_typename_to_number (typename);
628 }
629 GNUNET_CRYPTO_hash ("omit_private", strlen ("omit_private"), &key);
630 filter_flags = GNUNET_GNSRECORD_FILTER_NONE;
631 if (GNUNET_YES ==
632 GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
633 {
634 boolstring = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
635 &key);
636 if ((0 == strcmp (boolstring, "1")) ||
637 (0 == strcmp (boolstring, "yes")) ||
638 (0 == strcmp (boolstring, "true")))
639 filter_flags = GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE;
640 }
641 GNUNET_CRYPTO_hash ("include_maintenance", strlen ("include_maintenance"),
642 &key);
643 if (GNUNET_YES ==
644 GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
645 {
646 boolstring = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
647 &key);
648 if ((0 == strcmp (boolstring, "1")) ||
649 (0 == strcmp (boolstring, "yes")) ||
650 (0 == strcmp (boolstring, "true")))
651 filter_flags |= GNUNET_GNSRECORD_FILTER_INCLUDE_MAINTENANCE;
652 }
653 labelname = &egoname[strlen (ego_entry->identifier)];
654 if (1 >= strlen (labelname))
655 {
656 /* Iterate over all records */
657 handle->list_it =
658 GNUNET_NAMESTORE_zone_iteration_start2 (ns_handle,
659 handle->zone_pkey,
660 &namestore_iteration_error,
661 handle,
662 &namestore_list_iteration,
663 handle,
664 &namestore_list_finished,
665 handle,
666 filter_flags);
667 if (NULL == handle->list_it)
668 {
669 handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN;
670 GNUNET_SCHEDULER_add_now (&do_error, handle);
671 return;
672 }
673 return;
674 }
675 handle->record_name = GNUNET_strdup (labelname + 1);
676 handle->ns_qe = GNUNET_NAMESTORE_records_lookup2 (ns_handle,
677 handle->zone_pkey,
678 handle->record_name,
679 &ns_lookup_error_cb,
680 handle,
681 &ns_get_lookup_cb,
682 handle,
683 filter_flags);
684 if (NULL == handle->ns_qe)
685 {
686 handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN;
687 GNUNET_SCHEDULER_add_now (&do_error, handle);
688 return;
689 }
690}
691
692
693static void
694ns_lookup_cb (void *cls,
695 const struct GNUNET_CRYPTO_PrivateKey *zone,
696 const char *label,
697 unsigned int rd_count,
698 const struct GNUNET_GNSRECORD_Data *rd)
699{
700 struct RequestHandle *handle = cls;
701 struct GNUNET_GNSRECORD_Data rd_new[rd_count + handle->rd_count];
702 int i = 0;
703 int j = 0;
704
705 if (UPDATE_STRATEGY_APPEND == handle->update_strategy)
706 {
707 for (i = 0; i < rd_count; i++)
708 rd_new[i] = rd[i];
709 }
710 for (j = 0; j < handle->rd_count; j++)
711 rd_new[i + j] = handle->rd[j];
712 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
713 handle->zone_pkey,
714 handle->record_name,
715 i + j,
716 rd_new,
717 &create_finished,
718 handle);
719 if (NULL == handle->ns_qe)
720 {
721 handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN;
722 GNUNET_SCHEDULER_add_now (&do_error, handle);
723 return;
724 }
725}
726
727
728static void
729bulk_tx_commit_cb (void *cls, enum GNUNET_ErrorCode ec)
730{
731 struct RequestHandle *handle = cls;
732 struct MHD_Response *resp;
733
734 handle->ns_qe = NULL;
735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
736 "Commit finished (%d)\n", ec);
737 handle->ec = ec;
738 if (GNUNET_EC_NONE != ec)
739 {
740 GNUNET_SCHEDULER_add_now (&do_error, handle);
741 return;
742 }
743 resp = GNUNET_REST_create_response (NULL);
744 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
745 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
746}
747
748
749static void
750import_next_cb (void *cls, enum GNUNET_ErrorCode ec)
751{
752 struct RequestHandle *handle = cls;
753
754 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
755 "Import finished (%d)\n", ec);
756 handle->ns_qe = NULL;
757 handle->ec = ec;
758 if (GNUNET_EC_NONE != ec)
759 {
760 GNUNET_SCHEDULER_add_now (&do_error, handle);
761 return;
762 }
763 unsigned int remaining = handle->rd_set_count - handle->rd_set_pos;
764 if (0 == remaining)
765 {
766 handle->ns_qe = GNUNET_NAMESTORE_transaction_commit (handle->nc,
767 &bulk_tx_commit_cb,
768 handle);
769 return;
770 }
771 unsigned int sent_rds = 0;
772 // Find the smallest set of records we can send with our message size
773 // restriction of 16 bit
774 handle->ns_qe = GNUNET_NAMESTORE_records_store2 (handle->nc,
775 handle->zone_pkey,
776 remaining,
777 &handle->ri[handle->
778 rd_set_pos],
779 &sent_rds,
780 &import_next_cb,
781 handle);
782 if ((NULL == handle->ns_qe) && (0 == sent_rds))
783 {
784 handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN;
785 GNUNET_SCHEDULER_add_now (&do_error, handle);
786 return;
787 }
788 handle->rd_set_pos += sent_rds;
789}
790
791static void
792bulk_tx_start (void *cls, enum GNUNET_ErrorCode ec)
793{
794 struct RequestHandle *handle = cls;
795 json_t *data_js;
796 json_error_t err;
797
798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
799 "Transaction started...\n");
800 handle->ec = ec;
801 if (GNUNET_EC_NONE != ec)
802 {
803 GNUNET_SCHEDULER_add_now (&do_error, handle);
804 return;
805 }
806 if (0 >= handle->rest_handle->data_size)
807 {
808 handle->ec = GNUNET_EC_NAMESTORE_NO_RECORDS_GIVEN;
809 GNUNET_SCHEDULER_add_now (&do_error, handle);
810 return;
811 }
812 char term_data[handle->rest_handle->data_size + 1];
813 term_data[handle->rest_handle->data_size] = '\0';
814 GNUNET_memcpy (term_data,
815 handle->rest_handle->data,
816 handle->rest_handle->data_size);
817 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
818 if (NULL == data_js)
819 {
820 handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
821 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
822 "Error parsing data: %s", err.text);
823 GNUNET_SCHEDULER_add_now (&do_error, handle);
824 return;
825 }
826 if (! json_is_array (data_js))
827 {
828 handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
829 GNUNET_SCHEDULER_add_now (&do_error, handle);
830 json_decref (data_js);
831 return;
832 }
833 handle->rd_set_count = json_array_size (data_js);
834 handle->ri = GNUNET_malloc (handle->rd_set_count
835 * sizeof (struct GNUNET_NAMESTORE_RecordInfo));
836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
837 "Got record set of size %d\n", handle->rd_set_count);
838 char *albl;
839 size_t index;
840 json_t *value;
841 json_array_foreach (data_js, index, value) {
842 {
843 struct GNUNET_GNSRECORD_Data *rd;
844 struct GNUNET_JSON_Specification gnsspec[] =
845 { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&rd,
846 &handle->ri[index].a_rd_count,
847 &albl),
848 GNUNET_JSON_spec_end () };
849 if (GNUNET_OK != GNUNET_JSON_parse (value, gnsspec, NULL, NULL))
850 {
851 handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
852 GNUNET_SCHEDULER_add_now (&do_error, handle);
853 json_decref (data_js);
854 return;
855 }
856 handle->ri[index].a_rd = rd;
857 handle->ri[index].a_label = albl;
858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
859 "Parsed record set for name %s\n",
860 handle->ri[index].a_label);
861 }
862 }
863 // json_decref (data_js);
864
865 unsigned int sent_rds = 0;
866 // Find the smallest set of records we can send with our message size
867 // restriction of 16 bit
868 handle->ns_qe = GNUNET_NAMESTORE_records_store2 (handle->nc,
869 handle->zone_pkey,
870 handle->rd_set_count,
871 handle->ri,
872 &sent_rds,
873 &import_next_cb,
874 handle);
875 if ((NULL == handle->ns_qe) && (0 == sent_rds))
876 {
877 handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN;
878 GNUNET_SCHEDULER_add_now (&do_error, handle);
879 return;
880 }
881 handle->rd_set_pos += sent_rds;
882}
883
884
885/**
886 * Handle namestore POST import
887 *
888 * @param con_handle the connection handle
889 * @param url the url
890 * @param cls the RequestHandle
891 */
892void
893namestore_import (struct GNUNET_REST_RequestHandle *con_handle,
894 const char *url,
895 void *cls)
896{
897 struct RequestHandle *handle = cls;
898 struct EgoEntry *ego_entry;
899 char *egoname;
900
901 // set zone to name if given
902 if (strlen (GNUNET_REST_API_NS_NAMESTORE_IMPORT) + 1 >= strlen (
903 handle->url))
904 {
905 handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
906 GNUNET_SCHEDULER_add_now (&do_error, handle);
907 return;
908 }
909 ego_entry = NULL;
910
911 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE_IMPORT) + 1];
912 ego_entry = get_egoentry_namestore (handle, egoname);
913
914 if (NULL == ego_entry)
915 {
916 handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
917 GNUNET_SCHEDULER_add_now (&do_error, handle);
918 return;
919 }
920 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
921
922 // We need a per-client connection for a transactional bulk import
923 handle->nc = GNUNET_NAMESTORE_connect (cfg);
924 if (NULL == handle->nc)
925 {
926 handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN;
927 GNUNET_SCHEDULER_add_now (&do_error, handle);
928 return;
929 }
930 handle->ns_qe = GNUNET_NAMESTORE_transaction_begin (handle->nc,
931 &bulk_tx_start,
932 handle);
933}
934
935/**
936 * Handle namestore POST/PUT request
937 *
938 * @param con_handle the connection handle
939 * @param url the url
940 * @param cls the RequestHandle
941 */
942void
943namestore_add_or_update (struct GNUNET_REST_RequestHandle *con_handle,
944 const char *url,
945 void *cls)
946{
947 struct RequestHandle *handle = cls;
948 struct EgoEntry *ego_entry;
949 char *egoname;
950 json_t *data_js;
951 json_error_t err;
952
953 char term_data[handle->rest_handle->data_size + 1];
954
955 if (0 >= handle->rest_handle->data_size)
956 {
957 handle->ec = GNUNET_EC_NAMESTORE_NO_RECORDS_GIVEN;
958 GNUNET_SCHEDULER_add_now (&do_error, handle);
959 return;
960 }
961 term_data[handle->rest_handle->data_size] = '\0';
962 GNUNET_memcpy (term_data,
963 handle->rest_handle->data,
964 handle->rest_handle->data_size);
965 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
966 struct GNUNET_JSON_Specification gnsspec[] =
967 { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&handle->rd, &handle->rd_count,
968 &handle->record_name),
969 GNUNET_JSON_spec_end () };
970 if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
971 {
972 handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
973 GNUNET_SCHEDULER_add_now (&do_error, handle);
974 json_decref (data_js);
975 return;
976 }
977 GNUNET_JSON_parse_free (gnsspec);
978 if (0 >= strlen (handle->record_name))
979 {
980 handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
981 GNUNET_SCHEDULER_add_now (&do_error, handle);
982 json_decref (data_js);
983 return;
984 }
985 json_decref (data_js);
986
987 egoname = NULL;
988 ego_entry = NULL;
989
990 // set zone to name if given
991 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
992 {
993 handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
994 GNUNET_SCHEDULER_add_now (&do_error, handle);
995 return;
996 }
997 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
998 ego_entry = get_egoentry_namestore (handle, egoname);
999
1000 if (NULL == ego_entry)
1001 {
1002 handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
1003 GNUNET_SCHEDULER_add_now (&do_error, handle);
1004 return;
1005 }
1006 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1007 handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
1008 handle->zone_pkey,
1009 handle->record_name,
1010 &ns_lookup_error_cb,
1011 handle,
1012 &ns_lookup_cb,
1013 handle);
1014 if (NULL == handle->ns_qe)
1015 {
1016 handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN;
1017 GNUNET_SCHEDULER_add_now (&do_error, handle);
1018 return;
1019 }
1020}
1021
1022
1023/**
1024 * Handle namestore PUT request
1025 *
1026 * @param con_handle the connection handle
1027 * @param url the url
1028 * @param cls the RequestHandle
1029 */
1030void
1031namestore_update (struct GNUNET_REST_RequestHandle *con_handle,
1032 const char *url,
1033 void *cls)
1034{
1035 struct RequestHandle *handle = cls;
1036 handle->update_strategy = UPDATE_STRATEGY_REPLACE;
1037 namestore_add_or_update (con_handle, url, cls);
1038}
1039
1040
1041/**
1042 * Handle namestore POST request
1043 *
1044 * @param con_handle the connection handle
1045 * @param url the url
1046 * @param cls the RequestHandle
1047 */
1048void
1049namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
1050 const char *url,
1051 void *cls)
1052{
1053 struct RequestHandle *handle = cls;
1054 handle->update_strategy = UPDATE_STRATEGY_APPEND;
1055 namestore_add_or_update (con_handle, url, cls);
1056}
1057
1058
1059/**
1060 * Handle namestore DELETE request
1061 *
1062 * @param con_handle the connection handle
1063 * @param url the url
1064 * @param cls the RequestHandle
1065 */
1066void
1067namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
1068 const char *url,
1069 void *cls)
1070{
1071 struct RequestHandle *handle = cls;
1072 struct EgoEntry *ego_entry;
1073 char *egoname;
1074 char *labelname;
1075
1076 egoname = NULL;
1077 ego_entry = NULL;
1078
1079 // set zone to name if given
1080 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
1081 {
1082 handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
1083 GNUNET_SCHEDULER_add_now (&do_error, handle);
1084 return;
1085 }
1086 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
1087 ego_entry = get_egoentry_namestore (handle, egoname);
1088 if (NULL == ego_entry)
1089 {
1090 handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
1091 GNUNET_SCHEDULER_add_now (&do_error, handle);
1092 return;
1093 }
1094 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1095 labelname = &egoname[strlen (ego_entry->identifier)];
1096 // set zone to name if given
1097 if (1 >= strlen (labelname))
1098 {
1099 /* label is only "/" */
1100 handle->ec = GNUNET_EC_NAMESTORE_NO_LABEL_GIVEN;
1101 GNUNET_SCHEDULER_add_now (&do_error, handle);
1102 }
1103
1104 handle->record_name = GNUNET_strdup (labelname + 1);
1105 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1106 handle->zone_pkey,
1107 handle->record_name,
1108 0,
1109 NULL,
1110 &del_finished,
1111 handle);
1112 if (NULL == handle->ns_qe)
1113 {
1114 handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN;
1115 GNUNET_SCHEDULER_add_now (&do_error, handle);
1116 return;
1117 }
1118}
1119
1120
1121/**
1122 * Respond to OPTIONS request
1123 *
1124 * @param con_handle the connection handle
1125 * @param url the url
1126 * @param cls the RequestHandle
1127 */
1128static void
1129options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1130 const char *url,
1131 void *cls)
1132{
1133 struct MHD_Response *resp;
1134 struct RequestHandle *handle = cls;
1135
1136 // independent of path return all options
1137 resp = GNUNET_REST_create_response (NULL);
1138 GNUNET_assert (MHD_YES ==
1139 MHD_add_response_header (resp,
1140 "Access-Control-Allow-Methods",
1141 allow_methods));
1142 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1143 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1144 return;
1145}
1146
1147
1148static void
1149list_ego (void *cls,
1150 struct GNUNET_IDENTITY_Ego *ego,
1151 void **ctx,
1152 const char *identifier)
1153{
1154 struct EgoEntry *ego_entry;
1155 struct GNUNET_CRYPTO_PublicKey pk;
1156
1157 if ((NULL == ego) && (ID_REST_STATE_INIT == state))
1158 {
1159 state = ID_REST_STATE_POST_INIT;
1160 return;
1161 }
1162 if (NULL == ego)
1163 {
1164 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1165 "Called with NULL ego\n");
1166 return;
1167 }
1168 if (ID_REST_STATE_INIT == state)
1169 {
1170 ego_entry = GNUNET_new (struct EgoEntry);
1171 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1172 ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk);
1173 ego_entry->ego = ego;
1174 ego_entry->identifier = GNUNET_strdup (identifier);
1175 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1176 ego_tail,
1177 ego_entry);
1178 }
1179 /* Ego renamed or added */
1180 if (identifier != NULL)
1181 {
1182 for (ego_entry = ego_head; NULL != ego_entry;
1183 ego_entry = ego_entry->next)
1184 {
1185 if (ego_entry->ego == ego)
1186 {
1187 /* Rename */
1188 GNUNET_free (ego_entry->identifier);
1189 ego_entry->identifier = GNUNET_strdup (identifier);
1190 break;
1191 }
1192 }
1193 if (NULL == ego_entry)
1194 {
1195 /* Add */
1196 ego_entry = GNUNET_new (struct EgoEntry);
1197 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1198 ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk);
1199 ego_entry->ego = ego;
1200 ego_entry->identifier = GNUNET_strdup (identifier);
1201 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1202 ego_tail,
1203 ego_entry);
1204 }
1205 }
1206 else
1207 {
1208 /* Delete */
1209 for (ego_entry = ego_head; NULL != ego_entry;
1210 ego_entry = ego_entry->next)
1211 {
1212 if (ego_entry->ego == ego)
1213 break;
1214 }
1215 if (NULL == ego_entry)
1216 return; /* Not found */
1217
1218 GNUNET_CONTAINER_DLL_remove (ego_head,
1219 ego_tail,
1220 ego_entry);
1221 GNUNET_free (ego_entry->identifier);
1222 GNUNET_free (ego_entry->keystring);
1223 GNUNET_free (ego_entry);
1224 return;
1225 }
1226
1227}
1228
1229
1230/**
1231 * Function processing the REST call
1232 *
1233 * @param method HTTP method
1234 * @param url URL of the HTTP request
1235 * @param data body of the HTTP request (optional)
1236 * @param data_size length of the body
1237 * @param proc callback function for the result
1238 * @param proc_cls closure for callback function
1239 * @return GNUNET_OK if request accepted
1240 */
1241static enum GNUNET_GenericReturnValue
1242rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1243 GNUNET_REST_ResultProcessor proc,
1244 void *proc_cls)
1245{
1246 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1247 struct GNUNET_REST_RequestHandlerError err;
1248 static const struct GNUNET_REST_RequestHandler handlers[] =
1249 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get },
1250 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE_IMPORT,
1251 &namestore_import },
1252 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add },
1253 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_update },
1254 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE,
1255 &namestore_delete },
1256 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont },
1257 GNUNET_REST_HANDLER_END };
1258
1259 handle->ec = GNUNET_EC_NONE;
1260 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1261 handle->proc_cls = proc_cls;
1262 handle->proc = proc;
1263 handle->rest_handle = rest_handle;
1264 handle->zone_pkey = NULL;
1265 handle->timeout_task =
1266 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1267 handle->url = GNUNET_strdup (rest_handle->url);
1268 if (handle->url[strlen (handle->url) - 1] == '/')
1269 handle->url[strlen (handle->url) - 1] = '\0';
1270 GNUNET_CONTAINER_DLL_insert (requests_head,
1271 requests_tail,
1272 handle);
1273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1274 if (GNUNET_NO ==
1275 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
1276 handle))
1277 {
1278 cleanup_handle (handle);
1279 return GNUNET_NO;
1280 }
1281
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1283 return GNUNET_YES;
1284}
1285
1286
1287/**
1288 * Entry point for the plugin.
1289 *
1290 * @param cls Config info
1291 * @return NULL on error, otherwise the plugin context
1292 */
1293void *
1294libgnunet_plugin_rest_namestore_init (void *cls)
1295{
1296 static struct Plugin plugin;
1297 struct GNUNET_REST_Plugin *api;
1298
1299 cfg = cls;
1300 if (NULL != plugin.cfg)
1301 return NULL; /* can only initialize once! */
1302 memset (&plugin, 0, sizeof(struct Plugin));
1303 plugin.cfg = cfg;
1304 api = GNUNET_new (struct GNUNET_REST_Plugin);
1305 api->cls = &plugin;
1306 api->name = GNUNET_REST_API_NS_NAMESTORE;
1307 api->process_request = &rest_process_request;
1308 state = ID_REST_STATE_INIT;
1309 GNUNET_asprintf (&allow_methods,
1310 "%s, %s, %s, %s, %s",
1311 MHD_HTTP_METHOD_GET,
1312 MHD_HTTP_METHOD_POST,
1313 MHD_HTTP_METHOD_PUT,
1314 MHD_HTTP_METHOD_DELETE,
1315 MHD_HTTP_METHOD_OPTIONS);
1316 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1317 identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
1318
1319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ (
1320 "Namestore REST API initialized\n"));
1321 return api;
1322}
1323
1324
1325/**
1326 * Exit point from the plugin.
1327 *
1328 * @param cls the plugin context (as returned by "init")
1329 * @return always NULL
1330 */
1331void *
1332libgnunet_plugin_rest_namestore_done (void *cls)
1333{
1334 struct GNUNET_REST_Plugin *api = cls;
1335 struct Plugin *plugin = api->cls;
1336 struct RequestHandle *request;
1337 struct EgoEntry *ego_entry;
1338 struct EgoEntry *ego_tmp;
1339
1340 plugin->cfg = NULL;
1341 while (NULL != (request = requests_head))
1342 do_error (request);
1343 if (NULL != identity_handle)
1344 GNUNET_IDENTITY_disconnect (identity_handle);
1345 if (NULL != ns_handle)
1346 GNUNET_NAMESTORE_disconnect (ns_handle);
1347
1348 for (ego_entry = ego_head; NULL != ego_entry;)
1349 {
1350 ego_tmp = ego_entry;
1351 ego_entry = ego_entry->next;
1352 GNUNET_free (ego_tmp->identifier);
1353 GNUNET_free (ego_tmp->keystring);
1354 GNUNET_free (ego_tmp);
1355 }
1356
1357 GNUNET_free (allow_methods);
1358 GNUNET_free (api);
1359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore REST plugin is finished\n");
1360 return NULL;
1361}
1362
1363
1364/* end of plugin_rest_namestore.c */
diff --git a/src/namestore/test_common.c b/src/namestore/test_common.c
deleted file mode 100644
index 4df24a7f7..000000000
--- a/src/namestore/test_common.c
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/test_common.c
22 * @brief common functions for testcase setup
23 */
24#include "platform.h"
25#include <gnunet_namestore_plugin.h>
26
27/**
28 * test if we can load the plugin @a name.
29 */
30static int
31TNC_test_plugin (const char *cfg_name)
32{
33 char *database;
34 char *db_lib_name;
35 struct GNUNET_NAMESTORE_PluginFunctions *db;
36 struct GNUNET_CONFIGURATION_Handle *cfg;
37
38 cfg = GNUNET_CONFIGURATION_create ();
39 if (GNUNET_OK !=
40 GNUNET_CONFIGURATION_load (cfg,
41 cfg_name))
42 {
43 GNUNET_break (0);
44 GNUNET_CONFIGURATION_destroy (cfg);
45 return GNUNET_SYSERR;
46 }
47 if (GNUNET_OK !=
48 GNUNET_CONFIGURATION_get_value_string (cfg,
49 "namestore",
50 "database",
51 &database))
52 {
53 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
54 "No database backend configured\n");
55 GNUNET_CONFIGURATION_destroy (cfg);
56 return GNUNET_SYSERR;
57 }
58 GNUNET_asprintf (&db_lib_name,
59 "libgnunet_plugin_namestore_%s",
60 database);
61 GNUNET_free (database);
62 db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
63 if (NULL == db)
64 {
65 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
66 "Failed to load plugin `%s'\n",
67 db_lib_name);
68 }
69 else
70 {
71 if (GNUNET_OK != db->create_tables (db->cls))
72 {
73 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
74 "Error creating tables\n");
75 return GNUNET_SYSERR;
76 }
77 if (GNUNET_OK != db->drop_tables (db->cls))
78 {
79 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
80 "Error dropping tables\n");
81 return GNUNET_SYSERR;
82 }
83 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db));
84 }
85 GNUNET_free (db_lib_name);
86 GNUNET_CONFIGURATION_destroy (cfg);
87 if (NULL == db)
88 return GNUNET_NO;
89 return GNUNET_YES;
90}
91
92
93/**
94 * General setup logic for starting the tests. Obtains the @a
95 * plugin_name and initializes the @a cfg_name.
96 */
97#define SETUP_CFG2(file_template, plugin_name, cfg_name) \
98 do \
99 { \
100 GNUNET_log_setup (__FILE__, "WARNING", NULL); \
101 plugin_name = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); \
102 GNUNET_asprintf (&cfg_name, file_template, plugin_name); \
103 if (! TNC_test_plugin (cfg_name)) \
104 { \
105 GNUNET_free (plugin_name); \
106 GNUNET_free (cfg_name); \
107 return 77; \
108 } \
109 GNUNET_DISK_purge_cfg_dir (cfg_name, "GNUNET_TEST_HOME"); \
110 } while (0)
111/**
112 * General setup logic for starting the tests. Obtains the @a
113 * plugin_name and initializes the @a cfg_name.
114 */
115#define SETUP_CFG(plugin_name, cfg_name) \
116 do \
117 { \
118 GNUNET_log_setup (__FILE__, "WARNING", NULL); \
119 plugin_name = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); \
120 GNUNET_asprintf (&cfg_name, "test_namestore_api_%s.conf", plugin_name); \
121 if (! TNC_test_plugin (cfg_name)) \
122 { \
123 GNUNET_free (plugin_name); \
124 GNUNET_free (cfg_name); \
125 return 77; \
126 } \
127 GNUNET_DISK_purge_cfg_dir (cfg_name, "GNUNET_TEST_HOME"); \
128 } while (0)
diff --git a/src/namestore/test_hostkey b/src/namestore/test_hostkey
deleted file mode 100644
index e69de29bb..000000000
--- a/src/namestore/test_hostkey
+++ /dev/null
diff --git a/src/namestore/test_namestore_api.conf b/src/namestore/test_namestore_api.conf
deleted file mode 100644
index 1648c7cae..000000000
--- a/src/namestore/test_namestore_api.conf
+++ /dev/null
@@ -1,43 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[PATHS]
5GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-namestore/
6
7[namestore]
8DATABASE = sqlite
9START_ON_DEMAND = YES
10#PREFIX = valgrind --track-origins=yes --log-file=/tmp/ns_tx.log
11RETURN_ORPHANED = YES
12
13[namecache]
14DATABASE = sqlite
15START_ON_DEMAND = YES
16
17[zonemaster]
18START_ON_DEMAND = YES
19IMMEDIATE_START = NO
20
21[dht]
22START_ON_DEMAND = YES
23IMMEDIATE_START = NO
24
25
26[zonemaster-monitor]
27START_ON_DEMAND = YES
28IMMEDIATE_START = YES
29
30[identity]
31START_ON_DEMAND = YES
32
33[nse]
34WORKBITS = 0
35
36[rest]
37BASIC_AUTH_ENABLED=NO
38# PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/v_log
39
40
41
42[transport]
43PLUGINS =
diff --git a/src/namestore/test_namestore_api_edit_records.c b/src/namestore/test_namestore_api_edit_records.c
deleted file mode 100644
index a6bce7c17..000000000
--- a/src/namestore/test_namestore_api_edit_records.c
+++ /dev/null
@@ -1,399 +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 * @file namestore/test_namestore_api_edit_records.c
22 * @brief testcase for namestore_api.c: Multiple clients work with record set.
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27
28#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
29
30#define TEST_RECORD_DATALEN 123
31
32#define TEST_RECORD_DATA 'a'
33
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
35
36
37static struct GNUNET_NAMESTORE_Handle *nsh;
38
39static struct GNUNET_NAMESTORE_Handle *nsh2;
40
41static struct GNUNET_SCHEDULER_Task *endbadly_task;
42
43static struct GNUNET_CRYPTO_PrivateKey privkey;
44
45static struct GNUNET_CRYPTO_PublicKey pubkey;
46
47static int res;
48
49static int removed;
50
51static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
52
53static int nonce = 0;
54
55static void
56cleanup ()
57{
58 if (NULL != nsh)
59 {
60 GNUNET_NAMESTORE_disconnect (nsh);
61 nsh = NULL;
62 }
63 GNUNET_SCHEDULER_shutdown ();
64}
65
66
67/**
68 * Re-establish the connection to the service.
69 *
70 * @param cls handle to use to re-connect.
71 */
72static void
73endbadly (void *cls)
74{
75 if (NULL != nsqe)
76 {
77 GNUNET_NAMESTORE_cancel (nsqe);
78 nsqe = NULL;
79 }
80 cleanup ();
81 res = 1;
82}
83
84
85static void
86end (void *cls)
87{
88 cleanup ();
89 res = 0;
90}
91
92static void
93lookup_it (void *cls,
94 const struct GNUNET_CRYPTO_PrivateKey *zone,
95 const char *label,
96 unsigned int rd_count,
97 const struct GNUNET_GNSRECORD_Data *rd)
98{
99 GNUNET_assert (0 == rd_count);
100 GNUNET_SCHEDULER_add_now (&end, NULL);
101}
102
103static void
104fail_cb (void *cls)
105{
106 if (endbadly_task != NULL)
107 GNUNET_SCHEDULER_cancel (endbadly_task);
108 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
109 return;
110}
111
112static void
113remove_cont (void *cls,
114 enum GNUNET_ErrorCode ec)
115{
116 nsqe = NULL;
117 if (GNUNET_EC_NONE != ec)
118 {
119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
120 _ ("Unable to roll back: `%s'\n"),
121 GNUNET_ErrorCode_get_hint (ec));
122 if (NULL != endbadly_task)
123 GNUNET_SCHEDULER_cancel (endbadly_task);
124 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly,
125 NULL);
126 return;
127 }
128 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
129 "Rolled back, perform lookup\n");
130 removed = GNUNET_YES;
131 if (NULL != endbadly_task)
132 GNUNET_SCHEDULER_cancel (endbadly_task);
133 GNUNET_SCHEDULER_add_now (&end, NULL);
134}
135
136static void
137fail_cb_lock (void *cls);
138
139static void
140edit_cont_b (void *cls,
141 const struct GNUNET_CRYPTO_PrivateKey *zone,
142 const char *label,
143 unsigned int rd_count,
144 const struct GNUNET_GNSRECORD_Data *rd)
145{
146 const char *name = cls;
147 /**
148 * We should probably never get here right at first.
149 * We may want to change the blocking of nsh2 so that we do get this
150 * eventually instead of the error callback above when locked.
151 */
152 if (0 == nonce)
153 {
154 if (endbadly_task != NULL)
155 GNUNET_SCHEDULER_cancel (endbadly_task);
156 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
157 return;
158
159 }
160 /* Abort transaction for B */
161 nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh2, remove_cont,
162 (void *) name);
163}
164
165
166static void
167commit_cont_a (void *cls,
168 enum GNUNET_ErrorCode ec)
169{
170 const char *name = cls;
171
172 GNUNET_assert (NULL != cls);
173 nsqe = NULL;
174 if (GNUNET_EC_NONE != ec)
175 {
176 GNUNET_break (0);
177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
178 "Namestore could not store record: `%s'\n",
179 GNUNET_ErrorCode_get_hint (ec));
180 if (endbadly_task != NULL)
181 GNUNET_SCHEDULER_cancel (endbadly_task);
182 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
183 return;
184 }
185
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
187 "Name store added record for `%s': %s\n",
188 name,
189 (GNUNET_EC_NONE == ec) ? "SUCCESS" : "FAIL");
190 /**
191 * Try again for B
192 */
193 nsqe = GNUNET_NAMESTORE_records_edit (nsh2,
194 &privkey,
195 name,
196 &fail_cb_lock,
197 (void *) name,
198 &edit_cont_b,
199 (void *) name);
200
201 GNUNET_assert (NULL != nsqe);
202}
203
204static void
205fail_cb_lock (void *cls)
206{
207 const char *name = cls;
208 if (1 == nonce)
209 {
210 if (endbadly_task != NULL)
211 GNUNET_SCHEDULER_cancel (endbadly_task);
212 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
213 return;
214 }
215 nonce = 1;
216 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
217 "Failed to aquire additional lock\n");
218 /* Now, we stop the transaction for B */
219 nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont_a,
220 (void *) name);
221}
222
223
224static void
225begin_cont_b (void *cls,
226 enum GNUNET_ErrorCode ec)
227{
228 const char *name = cls;
229
230 GNUNET_assert (GNUNET_EC_NONE == ec);
231 /** Now, we expect this to "hang" let's see how this behaves in practice. */
232 nsqe = GNUNET_NAMESTORE_records_edit (nsh2,
233 &privkey,
234 name,
235 &fail_cb_lock,
236 (void *) name,
237 &edit_cont_b,
238 (void *) name);
239
240 GNUNET_assert (NULL != nsqe);
241}
242
243
244static void
245edit_cont (void *cls,
246 const struct GNUNET_CRYPTO_PrivateKey *zone,
247 const char *label,
248 unsigned int rd_count,
249 const struct GNUNET_GNSRECORD_Data *rd)
250{
251 const char *name = cls;
252
253 GNUNET_assert (1 == rd_count);
254 /* Now, we start a transaction for B */
255 nsqe = GNUNET_NAMESTORE_transaction_begin (nsh2, begin_cont_b, (void *) name);
256}
257
258
259static void
260begin_cont (void *cls,
261 enum GNUNET_ErrorCode ec)
262{
263 const char *name = cls;
264
265 GNUNET_assert (GNUNET_EC_NONE == ec);
266 nsqe = GNUNET_NAMESTORE_records_edit (nsh,
267 &privkey,
268 name,
269 &fail_cb,
270 (void *) name,
271 &edit_cont,
272 (void *) name);
273
274 GNUNET_assert (NULL != nsqe);
275}
276
277static void
278preload_cont (void *cls,
279 enum GNUNET_ErrorCode ec)
280{
281 const char *name = cls;
282
283 GNUNET_assert (NULL != cls);
284 nsqe = NULL;
285 if (GNUNET_EC_NONE != ec)
286 {
287 GNUNET_break (0);
288 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
289 "Namestore could not store record: `%s'\n",
290 GNUNET_ErrorCode_get_hint (ec));
291 if (endbadly_task != NULL)
292 GNUNET_SCHEDULER_cancel (endbadly_task);
293 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
294 return;
295 }
296
297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
298 "Name store added record for `%s': %s\n",
299 name,
300 (GNUNET_EC_NONE == ec) ? "SUCCESS" : "FAIL");
301 /* We start transaction for A */
302 nsqe = GNUNET_NAMESTORE_transaction_begin (nsh, begin_cont, (void *) name);
303
304}
305
306
307static void
308run (void *cls,
309 const struct GNUNET_CONFIGURATION_Handle *cfg,
310 struct GNUNET_TESTING_Peer *peer)
311{
312 struct GNUNET_GNSRECORD_Data rd;
313 const char *name = "dummy";
314
315 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
316 &endbadly,
317 NULL);
318 nsh = GNUNET_NAMESTORE_connect (cfg);
319 nsh2 = GNUNET_NAMESTORE_connect (cfg);
320 GNUNET_break (NULL != nsh);
321 GNUNET_break (NULL != nsh2);
322
323 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
324 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
325 GNUNET_CRYPTO_key_get_public (&privkey,
326 &pubkey);
327
328 removed = GNUNET_NO;
329
330 rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us;
331 rd.record_type = TEST_RECORD_TYPE;
332 rd.data_size = TEST_RECORD_DATALEN;
333 rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
334 rd.flags = 0;
335 memset ((char *) rd.data,
336 'a',
337 TEST_RECORD_DATALEN);
338 nsqe = GNUNET_NAMESTORE_records_store (nsh,
339 &privkey,
340 name,
341 1,
342 &rd,
343 &preload_cont,
344 (void *) name);
345 GNUNET_assert (NULL != nsqe);
346 GNUNET_free_nz ((void *) rd.data);
347
348 /*nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont);
349 nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, rollback_cont); Must also happen on disconnect
350 nsqe = GNUNET_NAMESTORE_records_edit (nsh,
351 &privkey,
352 name,
353 1,
354 &rd,
355 &edit_cont,
356 (void *) name);
357 nsqe = GNUNET_NAMESTORE_records_insert_bulk (nsh,
358 count,
359 &rd,
360 &
361 nsqe = GNUNET_NAMESTORE_records_store (nsh,
362 &privkey,
363 name,
364 1,
365 &rd,
366 &put_cont,
367 (void *) name);*/
368 GNUNET_assert (NULL != nsqe);
369}
370
371
372#include "test_common.c"
373
374
375int
376main (int argc, char *argv[])
377{
378 const char *plugin_name;
379 char *cfg_name;
380
381 SETUP_CFG (plugin_name, cfg_name);
382 res = 1;
383 if (0 !=
384 GNUNET_TESTING_peer_run ("test-namestore-api-remove",
385 cfg_name,
386 &run,
387 NULL))
388 {
389 res = 1;
390 }
391 GNUNET_DISK_purge_cfg_dir (cfg_name,
392 "GNUNET_TEST_HOME");
393 GNUNET_free (plugin_name);
394 GNUNET_free (cfg_name);
395 return res;
396}
397
398
399/* end of test_namestore_api_remove.c */
diff --git a/src/namestore/test_namestore_api_lookup_nick.c b/src/namestore/test_namestore_api_lookup_nick.c
deleted file mode 100644
index 21fc1ef79..000000000
--- a/src/namestore/test_namestore_api_lookup_nick.c
+++ /dev/null
@@ -1,347 +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 * @file namestore/test_namestore_api_lookup_nick.c
22 * @brief testcase for namestore_api.c: NICK records
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_gns_service.h"
27#include "gnunet_testing_lib.h"
28
29#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
30
31#define TEST_RECORD_DATALEN 123
32
33#define TEST_NICK "gnunettestnick"
34
35#define TEST_RECORD_DATA 'a'
36
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
38
39static struct GNUNET_NAMESTORE_Handle *nsh;
40
41static struct GNUNET_SCHEDULER_Task *endbadly_task;
42
43static struct GNUNET_CRYPTO_PrivateKey privkey;
44
45static struct GNUNET_CRYPTO_PublicKey pubkey;
46
47static int res;
48
49static struct GNUNET_GNSRECORD_Data rd_orig;
50
51static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
52
53// static const char * name = "dummy.dummy.gnunet";
54static const char *name = "d";
55
56static char *record_data;
57
58static void
59cleanup ()
60{
61 GNUNET_free (record_data);
62 if (NULL != nsh)
63 {
64 GNUNET_NAMESTORE_disconnect (nsh);
65 nsh = NULL;
66 }
67 GNUNET_SCHEDULER_shutdown ();
68}
69
70
71/**
72 * Re-establish the connection to the service.
73 *
74 * @param cls handle to use to re-connect.
75 * @param tc scheduler context
76 */
77static void
78endbadly (void *cls)
79{
80 if (NULL != nsqe)
81 {
82 GNUNET_NAMESTORE_cancel (nsqe);
83 nsqe = NULL;
84 }
85 cleanup ();
86 res = 1;
87}
88
89
90static void
91end (void *cls)
92{
93 cleanup ();
94 res = 0;
95}
96
97
98static void
99lookup_it (void *cls,
100 const struct GNUNET_CRYPTO_PrivateKey *zone,
101 const char *label,
102 unsigned int rd_count,
103 const struct GNUNET_GNSRECORD_Data *rd)
104{
105 nsqe = NULL;
106 int c;
107 int found_record = GNUNET_NO;
108 int found_nick = GNUNET_NO;
109
110 if (0 != GNUNET_memcmp (&privkey, zone))
111 {
112 GNUNET_break (0);
113 GNUNET_SCHEDULER_cancel (endbadly_task);
114 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
115 return;
116 }
117
118 if (NULL == label)
119 {
120 GNUNET_break (0);
121 GNUNET_SCHEDULER_cancel (endbadly_task);
122 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
123 return;
124 }
125
126 if (0 != strcmp (label, name))
127 {
128 GNUNET_break (0);
129 GNUNET_SCHEDULER_cancel (endbadly_task);
130 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
131 return;
132 }
133
134 if (2 != rd_count)
135 {
136 GNUNET_break (0);
137 GNUNET_SCHEDULER_cancel (endbadly_task);
138 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
139 return;
140 }
141
142 for (c = 0; c < rd_count; c++)
143 {
144 if (GNUNET_GNSRECORD_TYPE_NICK == rd[c].record_type)
145 {
146 if (rd[c].data_size != strlen (TEST_NICK) + 1)
147 {
148 GNUNET_break (0);
149 GNUNET_SCHEDULER_cancel (endbadly_task);
150 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
151 return;
152 }
153 if (0 != (rd[c].flags & GNUNET_GNSRECORD_RF_PRIVATE))
154 {
155 GNUNET_break (0);
156 GNUNET_SCHEDULER_cancel (endbadly_task);
157 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
158 return;
159 }
160 if (0 != strcmp (rd[c].data, TEST_NICK))
161 {
162 GNUNET_SCHEDULER_cancel (endbadly_task);
163 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
164 return;
165 }
166 found_nick = GNUNET_YES;
167 }
168 else
169 {
170 if (rd[c].record_type != TEST_RECORD_TYPE)
171 {
172 GNUNET_break (0);
173 GNUNET_SCHEDULER_cancel (endbadly_task);
174 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
175 return;
176 }
177 if (rd[c].data_size != TEST_RECORD_DATALEN)
178 {
179 GNUNET_break (0);
180 GNUNET_SCHEDULER_cancel (endbadly_task);
181 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
182 return;
183 }
184 if (0 != memcmp (rd[c].data, rd_orig.data, TEST_RECORD_DATALEN))
185 {
186 GNUNET_break (0);
187 GNUNET_SCHEDULER_cancel (endbadly_task);
188 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
189 return;
190 }
191 if (rd[c].flags != rd->flags)
192 {
193 GNUNET_break (0);
194 GNUNET_SCHEDULER_cancel (endbadly_task);
195 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
196 return;
197 }
198 found_record = GNUNET_YES;
199 }
200 }
201
202 /* Done */
203 if ((GNUNET_YES == found_nick) && (GNUNET_YES == found_record))
204 {
205 GNUNET_SCHEDULER_cancel (endbadly_task);
206 endbadly_task = NULL;
207 GNUNET_SCHEDULER_add_now (&end, NULL);
208 }
209 else
210 {
211 GNUNET_break (0);
212 GNUNET_SCHEDULER_cancel (endbadly_task);
213 endbadly_task = NULL;
214 GNUNET_SCHEDULER_add_now (&endbadly, NULL);
215 }
216}
217
218
219static void
220fail_cb (void *cls)
221{
222 GNUNET_assert (0);
223}
224
225
226static void
227put_cont (void *cls, enum GNUNET_ErrorCode ec)
228{
229 const char *name = cls;
230
231 nsqe = NULL;
232 GNUNET_assert (NULL != cls);
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "Name store added record for `%s': %s\n",
235 name,
236 (ec == GNUNET_EC_NONE) ? "SUCCESS" : "FAIL");
237
238 if (GNUNET_EC_NONE != ec)
239 {
240 GNUNET_SCHEDULER_cancel (endbadly_task);
241 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
242 return;
243 }
244 /* Lookup */
245 nsqe = GNUNET_NAMESTORE_records_lookup (nsh,
246 &privkey,
247 name,
248 &fail_cb,
249 NULL,
250 &lookup_it,
251 NULL);
252}
253
254
255static void
256nick_cont (void *cls, enum GNUNET_ErrorCode ec)
257{
258 const char *name = cls;
259
260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261 "Nick added : %s\n",
262 (ec == GNUNET_EC_NONE) ? "SUCCESS" : "FAIL");
263
264 rd_orig.expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
265 rd_orig.record_type = TEST_RECORD_TYPE;
266 rd_orig.data_size = TEST_RECORD_DATALEN;
267 record_data = GNUNET_malloc (TEST_RECORD_DATALEN);
268 rd_orig.data = record_data;
269 rd_orig.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
270 memset ((char *) rd_orig.data, 'a', TEST_RECORD_DATALEN);
271
272 nsqe = GNUNET_NAMESTORE_records_store (nsh, &privkey,
273 name,
274 1,
275 &rd_orig,
276 &put_cont, (void *) name);
277}
278
279
280static void
281run (void *cls,
282 const struct GNUNET_CONFIGURATION_Handle *cfg,
283 struct GNUNET_TESTING_Peer *peer)
284{
285 struct GNUNET_GNSRECORD_Data rd;
286
287 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
288 &endbadly,
289 NULL);
290 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
291 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
292 GNUNET_CRYPTO_key_get_public (&privkey,
293 &pubkey);
294
295 nsh = GNUNET_NAMESTORE_connect (cfg);
296 GNUNET_break (NULL != nsh);
297
298 memset (&rd, 0, sizeof(rd));
299 rd.data = TEST_NICK;
300 rd.data_size = strlen (TEST_NICK) + 1;
301 rd.record_type = GNUNET_GNSRECORD_TYPE_NICK;
302 rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
303 rd.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
304 nsqe = GNUNET_NAMESTORE_records_store (nsh,
305 &privkey,
306 GNUNET_GNS_EMPTY_LABEL_AT,
307 1,
308 &rd,
309 &nick_cont,
310 (void *) name);
311
312 if (NULL == nsqe)
313 {
314 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
315 _ ("Namestore cannot store no block\n"));
316 }
317}
318
319
320#include "test_common.c"
321
322
323int
324main (int argc, char *argv[])
325{
326 const char *plugin_name;
327 char *cfg_name;
328
329 SETUP_CFG (plugin_name, cfg_name);
330 res = 1;
331 if (0 !=
332 GNUNET_TESTING_peer_run ("test-namestore-api-lookup-nick",
333 cfg_name,
334 &run,
335 NULL))
336 {
337 res = 1;
338 }
339 GNUNET_DISK_purge_cfg_dir (cfg_name,
340 "GNUNET_TEST_HOME");
341 GNUNET_free (plugin_name);
342 GNUNET_free (cfg_name);
343 return res;
344}
345
346
347/* end of test_namestore_api_store.c */
diff --git a/src/namestore/test_namestore_api_monitoring.c b/src/namestore/test_namestore_api_monitoring.c
deleted file mode 100644
index 74dad3749..000000000
--- a/src/namestore/test_namestore_api_monitoring.c
+++ /dev/null
@@ -1,378 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/test_namestore_api_monitoring.c
22 * @brief testcase for zone monitoring functionality: monitor first, then add records
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27#include "namestore.h"
28
29#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
30
31
32#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
33
34
35static struct GNUNET_NAMESTORE_Handle *nsh;
36
37static struct GNUNET_SCHEDULER_Task *endbadly_task;
38
39static struct GNUNET_CRYPTO_PrivateKey privkey;
40
41static struct GNUNET_CRYPTO_PrivateKey privkey2;
42
43static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
44
45static int res;
46
47static char *s_name_1;
48
49static struct GNUNET_GNSRECORD_Data *s_rd_1;
50
51static char *s_name_2;
52
53static struct GNUNET_GNSRECORD_Data *s_rd_2;
54
55static char *s_name_3;
56
57static struct GNUNET_GNSRECORD_Data *s_rd_3;
58
59struct GNUNET_NAMESTORE_QueueEntry *ns_ops[3];
60
61
62static void
63do_shutdown ()
64{
65 if (NULL != zm)
66 {
67 GNUNET_NAMESTORE_zone_monitor_stop (zm);
68 zm = NULL;
69 }
70 if (NULL != ns_ops[0])
71 {
72 GNUNET_NAMESTORE_cancel (ns_ops[0]);
73 ns_ops[0] = NULL;
74 }
75 if (NULL != ns_ops[1])
76 {
77 GNUNET_NAMESTORE_cancel (ns_ops[1]);
78 ns_ops[1] = NULL;
79 }
80 if (NULL != ns_ops[2])
81 {
82 GNUNET_NAMESTORE_cancel (ns_ops[2]);
83 ns_ops[2] = NULL;
84 }
85 if (NULL != nsh)
86 {
87 GNUNET_NAMESTORE_disconnect (nsh);
88 nsh = NULL;
89 }
90 GNUNET_free (s_name_1);
91 GNUNET_free (s_name_2);
92 GNUNET_free (s_name_3);
93
94 if (s_rd_1 != NULL)
95 {
96 GNUNET_free_nz ((void *) s_rd_1->data);
97 GNUNET_free (s_rd_1);
98 }
99 if (s_rd_2 != NULL)
100 {
101 GNUNET_free_nz ((void *) s_rd_2->data);
102 GNUNET_free (s_rd_2);
103 }
104 if (s_rd_3 != NULL)
105 {
106 GNUNET_free_nz ((void *) s_rd_3->data);
107 GNUNET_free (s_rd_3);
108 }
109}
110
111
112/**
113 * Re-establish the connection to the service.
114 *
115 * @param cls handle to use to re-connect.
116 */
117static void
118endbadly (void *cls)
119{
120 do_shutdown ();
121 res = 1;
122}
123
124
125static void
126end (void *cls)
127{
128 do_shutdown ();
129 res = 0;
130}
131
132
133static void
134zone_proc (void *cls,
135 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
136 const char *name,
137 unsigned int rd_count,
138 const struct GNUNET_GNSRECORD_Data *rd)
139{
140 static int returned_records;
141 static int fail = GNUNET_NO;
142
143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
144 "Comparing results name %s\n",
145 name);
146 if (0 != GNUNET_memcmp (zone_key,
147 &privkey))
148 {
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150 "Monitoring returned wrong zone key\n");
151 GNUNET_break (0);
152 GNUNET_SCHEDULER_cancel (endbadly_task);
153 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
154 return;
155 }
156
157 if (0 == strcmp (name, s_name_1))
158 {
159 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_1))
160 {
161 GNUNET_break (0);
162 fail = GNUNET_YES;
163 }
164 }
165 else if (0 == strcmp (name, s_name_2))
166 {
167 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_2))
168 {
169 GNUNET_break (0);
170 fail = GNUNET_YES;
171 }
172 }
173 else
174 {
175 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
176 "Invalid name %s\n",
177 name);
178 GNUNET_break (0);
179 fail = GNUNET_YES;
180 }
181 GNUNET_NAMESTORE_zone_monitor_next (zm,
182 1);
183 if (2 == ++returned_records)
184 {
185 if (endbadly_task != NULL)
186 {
187 GNUNET_SCHEDULER_cancel (endbadly_task);
188 endbadly_task = NULL;
189 }
190 if (GNUNET_YES == fail)
191 GNUNET_SCHEDULER_add_now (&endbadly, NULL);
192 else
193 GNUNET_SCHEDULER_add_now (&end, NULL);
194 }
195}
196
197
198static void
199put_cont (void *cls,
200 enum GNUNET_ErrorCode ec)
201{
202 static int c = 0;
203 char *label = cls;
204
205 if (0 == strcmp (label, s_name_1))
206 ns_ops[0] = NULL;
207 else if (0 == strcmp (label, s_name_2))
208 ns_ops[1] = NULL;
209 else if (0 == strcmp (label, s_name_3))
210 ns_ops[2] = NULL;
211
212 if (GNUNET_EC_NONE == ec)
213 {
214 c++;
215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
216 "Created record %u: `%s'\n",
217 c,
218 label);
219 }
220 else
221 {
222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
223 "Failed to create record `%s'\n",
224 label);
225 GNUNET_break (0);
226 GNUNET_SCHEDULER_cancel (endbadly_task);
227 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly,
228 NULL);
229 }
230}
231
232
233static struct GNUNET_GNSRECORD_Data *
234create_record (unsigned int count)
235{
236 struct GNUNET_GNSRECORD_Data *rd;
237
238 rd = GNUNET_new_array (count,
239 struct GNUNET_GNSRECORD_Data);
240 for (unsigned int c = 0; c < count; c++)
241 {
242 rd[c].expiration_time = GNUNET_TIME_relative_to_absolute (
243 GNUNET_TIME_UNIT_HOURS).abs_value_us;
244 rd[c].record_type = TEST_RECORD_TYPE;
245 rd[c].data_size = 50;
246 rd[c].data = GNUNET_malloc (50);
247 rd[c].flags = 0;
248 memset ((char *) rd[c].data, 'a', 50);
249 }
250 return rd;
251}
252
253
254static void
255fail_cb (void *cls)
256{
257 GNUNET_assert (0);
258}
259
260
261static void
262sync_cb (void *cls)
263{
264 /* do nothing */
265}
266
267
268static void
269run (void *cls,
270 const struct GNUNET_CONFIGURATION_Handle *cfg,
271 struct GNUNET_TESTING_Peer *peer)
272{
273 res = 1;
274 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
275 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
276 /* Start monitoring */
277 zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
278 &privkey,
279 GNUNET_YES,
280 &fail_cb,
281 NULL,
282 &zone_proc,
283 NULL,
284 &sync_cb,
285 NULL);
286 if (NULL == zm)
287 {
288 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
289 "Failed to create zone monitor\n");
290 GNUNET_break (0);
291 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
292 return;
293 }
294
295 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &endbadly, NULL);
296 /* Connect to namestore */
297 nsh = GNUNET_NAMESTORE_connect (cfg);
298 if (NULL == nsh)
299 {
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connect to namestore\n");
301 GNUNET_break (0);
302 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
303 return;
304 }
305
306 privkey2.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
307 GNUNET_CRYPTO_ecdsa_key_create (&privkey2.ecdsa_key);
308
309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310 "Created record 3\n");
311 /* name in different zone */
312 GNUNET_asprintf (&s_name_3, "dummy3");
313 s_rd_3 = create_record (1);
314 GNUNET_assert (NULL != (ns_ops[2] =
315 GNUNET_NAMESTORE_records_store (nsh,
316 &privkey2,
317 s_name_3,
318 1,
319 s_rd_3,
320 &put_cont,
321 s_name_3)));
322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
323 "Created record 1\n");
324 GNUNET_asprintf (&s_name_1, "dummy1");
325 s_rd_1 = create_record (1);
326 GNUNET_assert (NULL != (ns_ops[0] =
327 GNUNET_NAMESTORE_records_store (nsh,
328 &privkey,
329 s_name_1,
330 1,
331 s_rd_1,
332 &put_cont,
333 s_name_1)));
334
335
336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 2 \n");
337 GNUNET_asprintf (&s_name_2, "dummy2");
338 s_rd_2 = create_record (1);
339 GNUNET_assert (NULL != (ns_ops[1] =
340 GNUNET_NAMESTORE_records_store (nsh,
341 &privkey,
342 s_name_2,
343 1,
344 s_rd_2,
345 &put_cont,
346 s_name_2)));
347}
348
349
350#include "test_common.c"
351
352
353int
354main (int argc,
355 char *argv[])
356{
357 const char *plugin_name;
358 char *cfg_name;
359
360 SETUP_CFG (plugin_name, cfg_name);
361 res = 1;
362 if (0 !=
363 GNUNET_TESTING_peer_run ("test-namestore-api-monitoring",
364 cfg_name,
365 &run,
366 NULL))
367 {
368 res = 1;
369 }
370 GNUNET_DISK_purge_cfg_dir (cfg_name,
371 "GNUNET_TEST_HOME");
372 GNUNET_free (plugin_name);
373 GNUNET_free (cfg_name);
374 return res;
375}
376
377
378/* end of test_namestore_api_monitoring.c */
diff --git a/src/namestore/test_namestore_api_monitoring_existing.c b/src/namestore/test_namestore_api_monitoring_existing.c
deleted file mode 100644
index fe17833c8..000000000
--- a/src/namestore/test_namestore_api_monitoring_existing.c
+++ /dev/null
@@ -1,393 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/test_namestore_api_monitoring_existing.c
22 * @brief testcase for zone monitoring functionality: add records first, then monitor
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27#include "namestore.h"
28
29#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
30
31
32#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
33
34static const struct GNUNET_CONFIGURATION_Handle *cfg;
35
36static struct GNUNET_NAMESTORE_Handle *nsh;
37
38static struct GNUNET_SCHEDULER_Task *endbadly_task;
39
40static struct GNUNET_CRYPTO_PrivateKey privkey;
41
42static struct GNUNET_CRYPTO_PrivateKey privkey2;
43
44static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
45
46static int res;
47
48static const char *s_name_1;
49
50static struct GNUNET_GNSRECORD_Data *s_rd_1;
51
52static const char *s_name_2;
53
54static struct GNUNET_GNSRECORD_Data *s_rd_2;
55
56static const char *s_name_3;
57
58static struct GNUNET_GNSRECORD_Data *s_rd_3;
59
60struct GNUNET_NAMESTORE_QueueEntry *ns_ops[3];
61
62
63/**
64 * Re-establish the connection to the service.
65 *
66 * @param cls handle to use to re-connect.
67 */
68static void
69endbadly (void *cls)
70{
71 endbadly_task = NULL;
72 GNUNET_break (0);
73 GNUNET_SCHEDULER_shutdown ();
74 res = 1;
75}
76
77
78static void
79end (void *cls)
80{
81 if (NULL != zm)
82 {
83 GNUNET_NAMESTORE_zone_monitor_stop (zm);
84 zm = NULL;
85 }
86 if (NULL != ns_ops[0])
87 {
88 GNUNET_NAMESTORE_cancel (ns_ops[0]);
89 ns_ops[0] = NULL;
90 }
91 if (NULL != ns_ops[1])
92 {
93 GNUNET_NAMESTORE_cancel (ns_ops[1]);
94 ns_ops[1] = NULL;
95 }
96 if (NULL != ns_ops[2])
97 {
98 GNUNET_NAMESTORE_cancel (ns_ops[2]);
99 ns_ops[2] = NULL;
100 }
101 if (NULL != endbadly_task)
102 {
103 GNUNET_SCHEDULER_cancel (endbadly_task);
104 endbadly_task = NULL;
105 }
106 if (NULL != nsh)
107 {
108 GNUNET_NAMESTORE_disconnect (nsh);
109 nsh = NULL;
110 }
111 if (NULL != s_rd_1)
112 {
113 GNUNET_free_nz ((void *) s_rd_1->data);
114 GNUNET_free (s_rd_1);
115 }
116 if (NULL != s_rd_2)
117 {
118 GNUNET_free_nz ((void *) s_rd_2->data);
119 GNUNET_free (s_rd_2);
120 }
121 if (NULL != s_rd_3)
122 {
123 GNUNET_free_nz ((void *) s_rd_3->data);
124 GNUNET_free (s_rd_3);
125 }
126}
127
128
129static void
130zone_proc (void *cls,
131 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
132 const char *name,
133 unsigned int rd_count,
134 const struct GNUNET_GNSRECORD_Data *rd)
135{
136 static int returned_records;
137 static int fail = GNUNET_NO;
138
139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
140 "Comparing results name %s\n",
141 name);
142 if (0 != GNUNET_memcmp (zone_key,
143 &privkey))
144 {
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146 "Monitoring returned wrong zone key\n");
147 GNUNET_break (0);
148 GNUNET_SCHEDULER_shutdown ();
149 return;
150 }
151
152 if (0 == strcmp (name,
153 s_name_1))
154 {
155 if (GNUNET_YES !=
156 GNUNET_GNSRECORD_records_cmp (rd,
157 s_rd_1))
158 {
159 GNUNET_break (0);
160 fail = GNUNET_YES;
161 }
162 }
163 else if (0 == strcmp (name,
164 s_name_2))
165 {
166 if (GNUNET_YES !=
167 GNUNET_GNSRECORD_records_cmp (rd,
168 s_rd_2))
169 {
170 GNUNET_break (0);
171 fail = GNUNET_YES;
172 }
173 }
174 else
175 {
176 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
177 "Invalid name %s\n",
178 name);
179 GNUNET_break (0);
180 fail = GNUNET_YES;
181 }
182 GNUNET_NAMESTORE_zone_monitor_next (zm,
183 1);
184 if (2 == ++returned_records)
185 {
186 GNUNET_SCHEDULER_shutdown ();
187 if (GNUNET_YES == fail)
188 {
189 GNUNET_break (0);
190 res = 1;
191 }
192 else
193 {
194 res = 0;
195 }
196 }
197}
198
199
200static void
201fail_cb (void *cls)
202{
203 GNUNET_assert (0);
204}
205
206
207static void
208sync_cb (void *cls)
209{
210 /* do nothing */
211}
212
213
214static void
215put_cont (void *cls,
216 enum GNUNET_ErrorCode ec)
217{
218 static int c = 0;
219 const char *label = cls;
220
221 if (0 == strcmp (label,
222 s_name_1))
223 ns_ops[0] = NULL;
224 else if (0 == strcmp (label,
225 s_name_2))
226 ns_ops[1] = NULL;
227 else if (0 == strcmp (label,
228 s_name_3))
229 ns_ops[2] = NULL;
230
231 if (GNUNET_EC_NONE == ec)
232 {
233 c++;
234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
235 "Created record %u: `%s'\n",
236 c,
237 label);
238 }
239 else
240 {
241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
242 "Failed to created records\n");
243 GNUNET_break (0);
244 res = 1;
245 GNUNET_SCHEDULER_shutdown ();
246 return;
247 }
248
249}
250
251
252static struct GNUNET_GNSRECORD_Data *
253create_record (unsigned int count)
254{
255 struct GNUNET_GNSRECORD_Data *rd;
256
257 rd = GNUNET_new_array (count,
258 struct GNUNET_GNSRECORD_Data);
259 for (unsigned int c = 0; c < count; c++)
260 {
261 rd[c].expiration_time = GNUNET_TIME_relative_to_absolute (
262 GNUNET_TIME_UNIT_HOURS).abs_value_us;
263 rd[c].record_type = TEST_RECORD_TYPE;
264 rd[c].data_size = 50;
265 rd[c].data = GNUNET_malloc (50);
266 rd[c].flags = 0;
267 memset ((char *) rd[c].data,
268 'a',
269 50);
270 }
271 return rd;
272}
273
274
275static void
276run (void *cls,
277 const struct GNUNET_CONFIGURATION_Handle *mycfg,
278 struct GNUNET_TESTING_Peer *peer)
279{
280 res = 1;
281 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
282 privkey2.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
283 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
284 GNUNET_CRYPTO_ecdsa_key_create (&privkey2.ecdsa_key);
285
286 cfg = mycfg;
287 GNUNET_SCHEDULER_add_shutdown (&end,
288 NULL);
289 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
290 &endbadly,
291 NULL);
292 /* Connect to namestore */
293 nsh = GNUNET_NAMESTORE_connect (cfg);
294 if (NULL == nsh)
295 {
296 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
297 "Connect to namestore failed\n");
298 GNUNET_break (0);
299 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly,
300 NULL);
301 return;
302 }
303 /* Start monitoring */
304 zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
305 &privkey,
306 GNUNET_YES,
307 &fail_cb,
308 NULL,
309 &zone_proc,
310 NULL,
311 &sync_cb,
312 NULL);
313 if (NULL == zm)
314 {
315 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
316 "Failed to create zone monitor\n");
317 GNUNET_break (0);
318 res = 1;
319 GNUNET_SCHEDULER_shutdown ();
320 return;
321 }
322
323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324 "Created record 3\n");
325 /* name in different zone */
326 s_name_3 = "dummy3";
327 s_rd_3 = create_record (1);
328 GNUNET_assert (NULL != (ns_ops[2] =
329 GNUNET_NAMESTORE_records_store (nsh,
330 &privkey2,
331 s_name_3,
332 1,
333 s_rd_3,
334 &put_cont,
335 (void *) s_name_3)));
336
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 "Created record 1\n");
339 s_name_1 = "dummy1";
340 s_rd_1 = create_record (1);
341 GNUNET_assert (NULL != (ns_ops[0] =
342 GNUNET_NAMESTORE_records_store (nsh,
343 &privkey,
344 s_name_1,
345 1,
346 s_rd_1,
347 &put_cont,
348 (void *) s_name_1)));
349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
350 "Created record 2 \n");
351 s_name_2 = "dummy2";
352 s_rd_2 = create_record (1);
353 GNUNET_assert (NULL != (ns_ops[1] =
354 GNUNET_NAMESTORE_records_store (nsh,
355 &privkey,
356 s_name_2,
357 1,
358 s_rd_2,
359 &put_cont,
360 (void *) s_name_2)));
361}
362
363
364#include "test_common.c"
365
366
367int
368main (int argc,
369 char *argv[])
370{
371 const char *plugin_name;
372 char *cfg_name;
373
374 SETUP_CFG (plugin_name, cfg_name);
375 res = 1;
376 if (0 !=
377 GNUNET_TESTING_peer_run ("test-namestore-api-monitoring-existing",
378 cfg_name,
379 &run,
380 NULL))
381 {
382 GNUNET_break (0);
383 res = 1;
384 }
385 GNUNET_DISK_purge_cfg_dir (cfg_name,
386 "GNUNET_TEST_HOME");
387 GNUNET_free (plugin_name);
388 GNUNET_free (cfg_name);
389 return res;
390}
391
392
393/* end of test_namestore_api_monitoring_existing.c */
diff --git a/src/namestore/test_namestore_api_postgres.conf b/src/namestore/test_namestore_api_postgres.conf
deleted file mode 100644
index 007168280..000000000
--- a/src/namestore/test_namestore_api_postgres.conf
+++ /dev/null
@@ -1,10 +0,0 @@
1@INLINE@ test_namestore_api.conf
2
3[namestore]
4DATABASE = postgres
5
6
7[namestore-postgres]
8CONFIG = connect_timeout=10 dbname=gnunetcheck
9TEMPORARY_TABLE = NO
10INIT_ON_CONNECT = YES
diff --git a/src/namestore/test_namestore_api_remove.c b/src/namestore/test_namestore_api_remove.c
deleted file mode 100644
index 1a4a7c867..000000000
--- a/src/namestore/test_namestore_api_remove.c
+++ /dev/null
@@ -1,219 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/test_namestore_api.c
22 * @brief testcase for namestore_api.c to: remove record
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27
28#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
29
30#define TEST_RECORD_DATALEN 123
31
32#define TEST_RECORD_DATA 'a'
33
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
35
36
37static struct GNUNET_NAMESTORE_Handle *nsh;
38
39static struct GNUNET_SCHEDULER_Task *endbadly_task;
40
41static struct GNUNET_CRYPTO_PrivateKey privkey;
42
43static struct GNUNET_CRYPTO_PublicKey pubkey;
44
45static int res;
46
47static int removed;
48
49static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
50
51
52static void
53cleanup ()
54{
55 if (NULL != nsh)
56 {
57 GNUNET_NAMESTORE_disconnect (nsh);
58 nsh = NULL;
59 }
60 GNUNET_SCHEDULER_shutdown ();
61}
62
63
64/**
65 * Re-establish the connection to the service.
66 *
67 * @param cls handle to use to re-connect.
68 */
69static void
70endbadly (void *cls)
71{
72 if (NULL != nsqe)
73 {
74 GNUNET_NAMESTORE_cancel (nsqe);
75 nsqe = NULL;
76 }
77 cleanup ();
78 res = 1;
79}
80
81
82static void
83end (void *cls)
84{
85 cleanup ();
86 res = 0;
87}
88
89
90static void
91remove_cont (void *cls,
92 enum GNUNET_ErrorCode ec)
93{
94 nsqe = NULL;
95 if (GNUNET_EC_NONE != ec)
96 {
97 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
98 _ ("Records could not be removed: `%s'\n"),
99 GNUNET_ErrorCode_get_hint (ec));
100 if (NULL != endbadly_task)
101 GNUNET_SCHEDULER_cancel (endbadly_task);
102 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly,
103 NULL);
104 return;
105 }
106 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
107 "Records were removed, perform lookup\n");
108 removed = GNUNET_YES;
109 if (NULL != endbadly_task)
110 GNUNET_SCHEDULER_cancel (endbadly_task);
111 GNUNET_SCHEDULER_add_now (&end, NULL);
112}
113
114
115static void
116put_cont (void *cls,
117 enum GNUNET_ErrorCode ec)
118{
119 const char *name = cls;
120
121 GNUNET_assert (NULL != cls);
122 nsqe = NULL;
123 if (GNUNET_EC_NONE != ec)
124 {
125 GNUNET_break (0);
126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
127 "Namestore could not store record: `%s'\n",
128 GNUNET_ErrorCode_get_hint (ec));
129 if (endbadly_task != NULL)
130 GNUNET_SCHEDULER_cancel (endbadly_task);
131 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
132 return;
133 }
134
135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
136 "Name store added record for `%s': %s\n",
137 name,
138 (GNUNET_EC_NONE == ec) ? "SUCCESS" : "FAIL");
139 nsqe = GNUNET_NAMESTORE_records_store (nsh,
140 &privkey,
141 name,
142 0, NULL,
143 &remove_cont, (void *) name);
144}
145
146
147static void
148run (void *cls,
149 const struct GNUNET_CONFIGURATION_Handle *cfg,
150 struct GNUNET_TESTING_Peer *peer)
151{
152 struct GNUNET_GNSRECORD_Data rd;
153 const char *name = "dummy";
154
155 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
156 &endbadly,
157 NULL);
158 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
159 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
160 GNUNET_CRYPTO_key_get_public (&privkey,
161 &pubkey);
162
163 removed = GNUNET_NO;
164
165 rd.expiration_time = GNUNET_TIME_UNIT_MINUTES.rel_value_us;
166 rd.record_type = TEST_RECORD_TYPE;
167 rd.data_size = TEST_RECORD_DATALEN;
168 rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
169 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
170 memset ((char *) rd.data,
171 'a',
172 TEST_RECORD_DATALEN);
173
174 nsh = GNUNET_NAMESTORE_connect (cfg);
175 GNUNET_break (NULL != nsh);
176 nsqe = GNUNET_NAMESTORE_records_store (nsh,
177 &privkey,
178 name,
179 1,
180 &rd,
181 &put_cont,
182 (void *) name);
183 if (NULL == nsqe)
184 {
185 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
186 _ ("Namestore cannot store no block\n"));
187 }
188 GNUNET_free_nz ((void *) rd.data);
189}
190
191
192#include "test_common.c"
193
194
195int
196main (int argc, char *argv[])
197{
198 const char *plugin_name;
199 char *cfg_name;
200
201 SETUP_CFG (plugin_name, cfg_name);
202 res = 1;
203 if (0 !=
204 GNUNET_TESTING_peer_run ("test-namestore-api-remove",
205 cfg_name,
206 &run,
207 NULL))
208 {
209 res = 1;
210 }
211 GNUNET_DISK_purge_cfg_dir (cfg_name,
212 "GNUNET_TEST_HOME");
213 GNUNET_free (plugin_name);
214 GNUNET_free (cfg_name);
215 return res;
216}
217
218
219/* end of test_namestore_api_remove.c */
diff --git a/src/namestore/test_namestore_api_remove_not_existing_record.c b/src/namestore/test_namestore_api_remove_not_existing_record.c
deleted file mode 100644
index 11a69bea1..000000000
--- a/src/namestore/test_namestore_api_remove_not_existing_record.c
+++ /dev/null
@@ -1,179 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/test_namestore_api_remove_not_existing_record.c
22 * @brief testcase for namestore_api.c
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27
28#define TEST_RECORD_TYPE 1234
29
30#define TEST_RECORD_DATALEN 123
31
32#define TEST_RECORD_DATA 'a'
33
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
35
36
37static struct GNUNET_NAMESTORE_Handle *nsh;
38
39static struct GNUNET_SCHEDULER_Task *endbadly_task;
40
41static struct GNUNET_CRYPTO_PrivateKey privkey;
42
43static struct GNUNET_CRYPTO_PublicKey pubkey;
44
45static int res;
46
47static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
48
49
50static void
51cleanup (void)
52{
53 if (NULL != nsh)
54 {
55 GNUNET_NAMESTORE_disconnect (nsh);
56 nsh = NULL;
57 }
58 GNUNET_SCHEDULER_shutdown ();
59}
60
61
62/**
63 * Re-establish the connection to the service.
64 *
65 * @param cls handle to use to re-connect.
66 */
67static void
68endbadly (void *cls)
69{
70 if (NULL != nsqe)
71 {
72 GNUNET_NAMESTORE_cancel (nsqe);
73 nsqe = NULL;
74 }
75 cleanup ();
76 res = 1;
77}
78
79
80static void
81end (void *cls)
82{
83 cleanup ();
84 res = 0;
85}
86
87
88static void
89put_cont (void *cls,
90 enum GNUNET_ErrorCode ec)
91{
92 GNUNET_assert (NULL != cls);
93 nsqe = NULL;
94 if (endbadly_task != NULL)
95 {
96 GNUNET_SCHEDULER_cancel (endbadly_task);
97 endbadly_task = NULL;
98 }
99 switch (ec)
100 {
101 case GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND:
102 /* We expect that the record is not found */
103 GNUNET_SCHEDULER_add_now (&end, NULL);
104 break;
105
106 case GNUNET_EC_NONE:
107 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
108 "Namestore could remove non-existing record: `%s'\n",
109 GNUNET_ErrorCode_get_hint (ec));
110 GNUNET_SCHEDULER_add_now (&endbadly, NULL);
111 break;
112
113 default:
114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
115 "Namestore failed: `%s'\n",
116 GNUNET_ErrorCode_get_hint (ec));
117 GNUNET_SCHEDULER_add_now (&endbadly, NULL);
118 break;
119 }
120}
121
122
123static void
124run (void *cls,
125 const struct GNUNET_CONFIGURATION_Handle *cfg,
126 struct GNUNET_TESTING_Peer *peer)
127{
128 const char *name = "dummy";
129
130 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
131 &endbadly,
132 NULL);
133 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
134 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
135 GNUNET_CRYPTO_key_get_public (&privkey, &pubkey);
136
137 nsh = GNUNET_NAMESTORE_connect (cfg);
138 GNUNET_break (NULL != nsh);
139 nsqe = GNUNET_NAMESTORE_records_store (nsh,
140 &privkey,
141 name,
142 0, NULL,
143 &put_cont, (void *) name);
144 if (NULL == nsqe)
145 {
146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
147 _ ("Namestore cannot store no block\n"));
148 }
149}
150
151
152#include "test_common.c"
153
154
155int
156main (int argc, char *argv[])
157{
158 const char *plugin_name;
159 char *cfg_name;
160
161 SETUP_CFG (plugin_name, cfg_name);
162 res = 1;
163 if (0 !=
164 GNUNET_TESTING_peer_run ("test-namestore-api-remove-non-existing-record",
165 cfg_name,
166 &run,
167 NULL))
168 {
169 res = 1;
170 }
171 GNUNET_DISK_purge_cfg_dir (cfg_name,
172 "GNUNET_TEST_HOME");
173 GNUNET_free (plugin_name);
174 GNUNET_free (cfg_name);
175 return res;
176}
177
178
179/* end of test_namestore_api_remove_not_existing_record.c */
diff --git a/src/namestore/test_namestore_api_sqlite.conf b/src/namestore/test_namestore_api_sqlite.conf
deleted file mode 100644
index 342356247..000000000
--- a/src/namestore/test_namestore_api_sqlite.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ test_namestore_api.conf
2
3[namestore]
4DATABASE = sqlite
5# PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/v_log
6
7[namestore-sqlite]
8FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
9INIT_ON_CONNECT = YES
diff --git a/src/namestore/test_namestore_api_store.c b/src/namestore/test_namestore_api_store.c
deleted file mode 100644
index 22b92fbe5..000000000
--- a/src/namestore/test_namestore_api_store.c
+++ /dev/null
@@ -1,172 +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 * @file namestore/test_namestore_api_store.c
22 * @brief testcase for namestore_api.c: store a record
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27
28#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
29
30#define TEST_RECORD_DATALEN 123
31
32#define TEST_RECORD_DATA 'a'
33
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
35
36
37static struct GNUNET_NAMESTORE_Handle *nsh;
38
39static struct GNUNET_SCHEDULER_Task *endbadly_task;
40
41static struct GNUNET_CRYPTO_PrivateKey privkey;
42
43static struct GNUNET_CRYPTO_PublicKey pubkey;
44
45static int res;
46
47static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
48
49
50static void
51cleanup ()
52{
53 if (NULL != nsh)
54 {
55 GNUNET_NAMESTORE_disconnect (nsh);
56 nsh = NULL;
57 }
58 GNUNET_SCHEDULER_shutdown ();
59}
60
61
62/**
63 * Re-establish the connection to the service.
64 *
65 * @param cls handle to use to re-connect.
66 */
67static void
68endbadly (void *cls)
69{
70 if (NULL != nsqe)
71 {
72 GNUNET_NAMESTORE_cancel (nsqe);
73 nsqe = NULL;
74 }
75 cleanup ();
76 res = 1;
77}
78
79
80static void
81end (void *cls)
82{
83 cleanup ();
84 res = 0;
85}
86
87
88static void
89put_cont (void *cls, enum GNUNET_ErrorCode ec)
90{
91 const char *name = cls;
92
93 nsqe = NULL;
94 GNUNET_assert (NULL != cls);
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96 "Name store added record for `%s': %s\n",
97 name,
98 (GNUNET_EC_NONE == ec) ? "SUCCESS" : "FAIL");
99 GNUNET_SCHEDULER_cancel (endbadly_task);
100 endbadly_task = NULL;
101 GNUNET_SCHEDULER_add_now (&end, NULL);
102}
103
104
105static void
106run (void *cls,
107 const struct GNUNET_CONFIGURATION_Handle *cfg,
108 struct GNUNET_TESTING_Peer *peer)
109{
110 struct GNUNET_GNSRECORD_Data rd;
111 const char *name = "dummy.dummy.gnunet";
112
113 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
114 &endbadly, NULL);
115 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
116 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
117 GNUNET_CRYPTO_key_get_public (&privkey, &pubkey);
118
119
120 rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us;
121 rd.record_type = TEST_RECORD_TYPE;
122 rd.data_size = TEST_RECORD_DATALEN;
123 rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
124 rd.flags = 0;
125 memset ((char *) rd.data, 'a', TEST_RECORD_DATALEN);
126
127 nsh = GNUNET_NAMESTORE_connect (cfg);
128 GNUNET_break (NULL != nsh);
129 nsqe = GNUNET_NAMESTORE_records_store (nsh,
130 &privkey,
131 name,
132 1,
133 &rd,
134 &put_cont,
135 (void *) name);
136 if (NULL == nsqe)
137 {
138 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
139 _ ("Namestore cannot store no block\n"));
140 }
141 GNUNET_free_nz ((void *) rd.data);
142}
143
144
145#include "test_common.c"
146
147
148int
149main (int argc, char *argv[])
150{
151 const char *plugin_name;
152 char *cfg_name;
153
154 SETUP_CFG (plugin_name, cfg_name);
155 res = 1;
156 if (0 !=
157 GNUNET_TESTING_peer_run ("test-namestore-api",
158 cfg_name,
159 &run,
160 NULL))
161 {
162 res = 1;
163 }
164 GNUNET_DISK_purge_cfg_dir (cfg_name,
165 "GNUNET_TEST_HOME");
166 GNUNET_free (plugin_name);
167 GNUNET_free (cfg_name);
168 return res;
169}
170
171
172/* end of test_namestore_api_store.c */
diff --git a/src/namestore/test_namestore_api_store_update.c b/src/namestore/test_namestore_api_store_update.c
deleted file mode 100644
index 86495e261..000000000
--- a/src/namestore/test_namestore_api_store_update.c
+++ /dev/null
@@ -1,269 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 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 namestore/test_namestore_api_store_update.c
22 * @brief testcase for namestore_api.c: store a record, update it and perform a lookup
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_namestore_service.h"
28#include "gnunet_testing_lib.h"
29
30#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
31
32#define TEST_RECORD_DATALEN 123
33
34#define TEST_RECORD_DATA 'a'
35
36#define TEST_RECORD_DATALEN2 234
37
38#define TEST_RECORD_DATA2 'b'
39
40#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
41
42
43static struct GNUNET_NAMESTORE_Handle *nsh;
44
45static struct GNUNET_SCHEDULER_Task *endbadly_task;
46
47static struct GNUNET_CRYPTO_PrivateKey privkey;
48
49static struct GNUNET_CRYPTO_PublicKey pubkey;
50
51static int res;
52
53static int update_performed;
54
55static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
56
57static const char *name = "dummy";
58
59
60/**
61 * Terminate test with error.
62 *
63 * @param cls handle to use to re-connect.
64 */
65static void
66endbadly (void *cls)
67{
68 GNUNET_break (0);
69 endbadly_task = NULL;
70 GNUNET_SCHEDULER_shutdown ();
71 res = 1;
72}
73
74
75static void
76end (void *cls)
77{
78 if (NULL != endbadly_task)
79 {
80 GNUNET_SCHEDULER_cancel (endbadly_task);
81 endbadly_task = NULL;
82 }
83 if (NULL != nsqe)
84 {
85 GNUNET_NAMESTORE_cancel (nsqe);
86 nsqe = NULL;
87 }
88 if (NULL != nsh)
89 {
90 GNUNET_NAMESTORE_disconnect (nsh);
91 nsh = NULL;
92 }
93}
94
95
96static void
97put_cont (void *cls,
98 enum GNUNET_ErrorCode ec);
99
100
101static void
102lookup_success (void *cls,
103 const struct GNUNET_CRYPTO_PrivateKey *zone,
104 const char* label,
105 unsigned int rd_count,
106 const struct GNUNET_GNSRECORD_Data *rd)
107{
108 struct GNUNET_GNSRECORD_Data rd_new;
109
110 GNUNET_assert (1 == rd_count);
111 GNUNET_assert (NULL != rd);
112 nsqe = NULL;
113 if (GNUNET_NO == update_performed)
114 {
115 char rd_cmp_data[TEST_RECORD_DATALEN];
116
117 memset (rd_cmp_data,
118 TEST_RECORD_DATA,
119 TEST_RECORD_DATALEN);
120 GNUNET_assert (TEST_RECORD_TYPE == rd[0].record_type);
121 GNUNET_assert (TEST_RECORD_DATALEN == rd[0].data_size);
122 GNUNET_assert (0 == memcmp (&rd_cmp_data,
123 rd[0].data,
124 TEST_RECORD_DATALEN));
125
126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
127 "Block was decrypted successfully, updating record \n");
128
129 rd_new.flags = GNUNET_GNSRECORD_RF_NONE;
130 rd_new.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us
131 + 1000000000;
132 rd_new.record_type = TEST_RECORD_TYPE;
133 rd_new.data_size = TEST_RECORD_DATALEN2;
134 rd_new.data = GNUNET_malloc (TEST_RECORD_DATALEN2);
135 memset ((char *) rd_new.data,
136 TEST_RECORD_DATA2,
137 TEST_RECORD_DATALEN2);
138
139 nsqe = GNUNET_NAMESTORE_records_store (nsh,
140 &privkey,
141 name,
142 1,
143 &rd_new,
144 &put_cont,
145 (void *) name);
146 GNUNET_free (rd_new.data);
147 update_performed = GNUNET_YES;
148 }
149 else
150 {
151 char rd_cmp_data[TEST_RECORD_DATALEN2];
152
153 memset (rd_cmp_data,
154 TEST_RECORD_DATA2,
155 TEST_RECORD_DATALEN2);
156 GNUNET_assert (TEST_RECORD_TYPE == rd[0].record_type);
157 GNUNET_assert (TEST_RECORD_DATALEN2 == rd[0].data_size);
158 GNUNET_assert (0 == memcmp (&rd_cmp_data,
159 rd[0].data,
160 TEST_RECORD_DATALEN2));
161 GNUNET_SCHEDULER_shutdown ();
162 res = 0;
163 }
164}
165
166
167static void
168put_cont (void *cls,
169 enum GNUNET_ErrorCode ec)
170{
171 const char *name = cls;
172 struct GNUNET_HashCode derived_hash;
173
174 nsqe = NULL;
175 GNUNET_assert (NULL != cls);
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
177 "Name store added record for `%s': %s\n",
178 name,
179 (GNUNET_EC_NONE == ec) ? "SUCCESS" : "FAIL");
180 /* Create derived hash */
181 GNUNET_GNSRECORD_query_from_private_key (&privkey,
182 name,
183 &derived_hash);
184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185 "Looking in namestore for `%s'\n",
186 GNUNET_h2s (&derived_hash));
187 nsqe = GNUNET_NAMESTORE_records_lookup (nsh,
188 &privkey,
189 name,
190 &endbadly,
191 (void *) name,
192 & lookup_success,
193 (void *) name);
194}
195
196
197static void
198run (void *cls,
199 const struct GNUNET_CONFIGURATION_Handle *cfg,
200 struct GNUNET_TESTING_Peer *peer)
201{
202 struct GNUNET_GNSRECORD_Data rd;
203
204 update_performed = GNUNET_NO;
205 GNUNET_SCHEDULER_add_shutdown (&end,
206 NULL);
207 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
208 &endbadly,
209 NULL);
210 memset (&privkey, 0, sizeof (privkey));
211 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
212 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
213 GNUNET_CRYPTO_key_get_public (&privkey, &pubkey);
214 rd.flags = GNUNET_GNSRECORD_RF_NONE;
215 rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us + 1000000000;
216 rd.record_type = TEST_RECORD_TYPE;
217 rd.data_size = TEST_RECORD_DATALEN;
218 rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
219 memset ((char *) rd.data,
220 TEST_RECORD_DATA,
221 TEST_RECORD_DATALEN);
222
223 nsh = GNUNET_NAMESTORE_connect (cfg);
224 GNUNET_break (NULL != nsh);
225 nsqe = GNUNET_NAMESTORE_records_store (nsh,
226 &privkey,
227 name,
228 1,
229 &rd,
230 &put_cont,
231 (void *) name);
232 if (NULL == nsqe)
233 {
234 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
235 _ ("Namestore cannot store no block\n"));
236 }
237 GNUNET_free_nz ((void *) rd.data);
238}
239
240
241#include "test_common.c"
242
243
244int
245main (int argc,
246 char *argv[])
247{
248 const char *plugin_name;
249 char *cfg_name;
250
251 SETUP_CFG (plugin_name, cfg_name);
252 res = 1;
253 if (0 !=
254 GNUNET_TESTING_peer_run ("test--store-update",
255 cfg_name,
256 &run,
257 NULL))
258 {
259 res = 1;
260 }
261 GNUNET_DISK_purge_cfg_dir (cfg_name,
262 "GNUNET_TEST_HOME");
263 GNUNET_free (plugin_name);
264 GNUNET_free (cfg_name);
265 return res;
266}
267
268
269/* end of test_namestore_api_store_update.c */
diff --git a/src/namestore/test_namestore_api_tx_rollback.c b/src/namestore/test_namestore_api_tx_rollback.c
deleted file mode 100644
index 4a701f60e..000000000
--- a/src/namestore/test_namestore_api_tx_rollback.c
+++ /dev/null
@@ -1,264 +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 * @file namestore/test_namestore_api_tx_rollback.c
22 * @brief testcase for namestore_api_tx_rollback.c to: rollback changes in TX
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27
28#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
29
30#define TEST_RECORD_DATALEN 123
31
32#define TEST_RECORD_DATA 'a'
33
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
35
36
37static struct GNUNET_NAMESTORE_Handle *nsh;
38
39static struct GNUNET_SCHEDULER_Task *endbadly_task;
40
41static struct GNUNET_CRYPTO_PrivateKey privkey;
42
43static struct GNUNET_CRYPTO_PublicKey pubkey;
44
45static int res;
46
47static int removed;
48
49static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
50
51
52static void
53cleanup ()
54{
55 if (NULL != nsh)
56 {
57 GNUNET_NAMESTORE_disconnect (nsh);
58 nsh = NULL;
59 }
60 GNUNET_SCHEDULER_shutdown ();
61}
62
63
64/**
65 * Re-establish the connection to the service.
66 *
67 * @param cls handle to use to re-connect.
68 */
69static void
70endbadly (void *cls)
71{
72 if (NULL != nsqe)
73 {
74 GNUNET_NAMESTORE_cancel (nsqe);
75 nsqe = NULL;
76 }
77 cleanup ();
78 res = 1;
79}
80
81
82static void
83end (void *cls)
84{
85 cleanup ();
86 res = 0;
87}
88
89static void
90lookup_it (void *cls,
91 const struct GNUNET_CRYPTO_PrivateKey *zone,
92 const char *label,
93 unsigned int rd_count,
94 const struct GNUNET_GNSRECORD_Data *rd)
95{
96 GNUNET_assert (0 == rd_count);
97 GNUNET_SCHEDULER_add_now (&end, NULL);
98}
99
100static void
101fail_cb (void *cls)
102{
103 GNUNET_assert (0);
104}
105
106static void
107remove_cont (void *cls,
108 enum GNUNET_ErrorCode ec)
109{
110 nsqe = NULL;
111 if (GNUNET_EC_NONE != ec)
112 {
113 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
114 _ ("Unable to roll back: `%s'\n"),
115 GNUNET_ErrorCode_get_hint (ec));
116 if (NULL != endbadly_task)
117 GNUNET_SCHEDULER_cancel (endbadly_task);
118 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly,
119 NULL);
120 return;
121 }
122 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
123 "Rolled back, perform lookup\n");
124 removed = GNUNET_YES;
125 if (NULL != endbadly_task)
126 GNUNET_SCHEDULER_cancel (endbadly_task);
127 /* FIXME not actually doing lookup here */
128 nsqe = GNUNET_NAMESTORE_records_lookup (nsh,
129 &privkey,
130 (char*) cls,
131 &fail_cb,
132 NULL,
133 &lookup_it,
134 NULL);
135}
136
137
138static void
139put_cont (void *cls,
140 enum GNUNET_ErrorCode ec)
141{
142 const char *name = cls;
143
144 GNUNET_assert (NULL != cls);
145 nsqe = NULL;
146 if (GNUNET_EC_NONE != ec)
147 {
148 GNUNET_break (0);
149 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
150 "Namestore could not store record: `%s'\n",
151 GNUNET_ErrorCode_get_hint (ec));
152 if (endbadly_task != NULL)
153 GNUNET_SCHEDULER_cancel (endbadly_task);
154 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
155 return;
156 }
157
158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159 "Name store added record for `%s': %s\n",
160 name,
161 (GNUNET_EC_NONE == ec) ? "SUCCESS" : "FAIL");
162 nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, remove_cont,
163 (void *) name);
164}
165
166static void
167begin_cont (void *cls,
168 enum GNUNET_ErrorCode ec)
169{
170 struct GNUNET_GNSRECORD_Data rd;
171 const char *name = cls;
172
173 GNUNET_assert (GNUNET_EC_NONE == ec);
174 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
175 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
176 GNUNET_CRYPTO_key_get_public (&privkey,
177 &pubkey);
178
179 removed = GNUNET_NO;
180
181 rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us;
182 rd.record_type = TEST_RECORD_TYPE;
183 rd.data_size = TEST_RECORD_DATALEN;
184 rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
185 rd.flags = 0;
186 memset ((char *) rd.data,
187 'a',
188 TEST_RECORD_DATALEN);
189 nsqe = GNUNET_NAMESTORE_records_store (nsh,
190 &privkey,
191 name,
192 1,
193 &rd,
194 &put_cont,
195 (void *) name);
196 GNUNET_assert (NULL != nsqe);
197 GNUNET_free_nz ((void *) rd.data);
198}
199
200static void
201run (void *cls,
202 const struct GNUNET_CONFIGURATION_Handle *cfg,
203 struct GNUNET_TESTING_Peer *peer)
204{
205 const char *name = "dummy";
206
207 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
208 &endbadly,
209 NULL);
210 nsh = GNUNET_NAMESTORE_connect (cfg);
211 GNUNET_break (NULL != nsh);
212 nsqe = GNUNET_NAMESTORE_transaction_begin (nsh, begin_cont, (void *) name);
213 /*nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont);
214 nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, rollback_cont); Must also happen on disconnect
215 nsqe = GNUNET_NAMESTORE_records_edit (nsh,
216 &privkey,
217 name,
218 1,
219 &rd,
220 &edit_cont,
221 (void *) name);
222 nsqe = GNUNET_NAMESTORE_records_insert_bulk (nsh,
223 count,
224 &rd,
225 &
226 nsqe = GNUNET_NAMESTORE_records_store (nsh,
227 &privkey,
228 name,
229 1,
230 &rd,
231 &put_cont,
232 (void *) name);*/
233 GNUNET_assert (NULL != nsqe);
234}
235
236
237#include "test_common.c"
238
239
240int
241main (int argc, char *argv[])
242{
243 const char *plugin_name;
244 char *cfg_name;
245
246 SETUP_CFG (plugin_name, cfg_name);
247 res = 1;
248 if (0 !=
249 GNUNET_TESTING_peer_run ("test-namestore-api-remove",
250 cfg_name,
251 &run,
252 NULL))
253 {
254 res = 1;
255 }
256 GNUNET_DISK_purge_cfg_dir (cfg_name,
257 "GNUNET_TEST_HOME");
258 GNUNET_free (plugin_name);
259 GNUNET_free (cfg_name);
260 return res;
261}
262
263
264/* end of test_namestore_api_remove.c */
diff --git a/src/namestore/test_namestore_api_zone_iteration.c b/src/namestore/test_namestore_api_zone_iteration.c
deleted file mode 100644
index fb69fffcc..000000000
--- a/src/namestore/test_namestore_api_zone_iteration.c
+++ /dev/null
@@ -1,464 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/test_namestore_api_zone_iteration.c
22 * @brief testcase for zone iteration functionality: iterate all zones
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27#include "namestore.h"
28
29#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
30
31
32#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
33
34
35static struct GNUNET_NAMESTORE_Handle *nsh;
36
37static struct GNUNET_SCHEDULER_Task *endbadly_task;
38
39static struct GNUNET_CRYPTO_PrivateKey privkey;
40
41static struct GNUNET_CRYPTO_PrivateKey privkey2;
42
43static struct GNUNET_NAMESTORE_ZoneIterator *zi;
44
45static int res;
46
47static int returned_records;
48
49static char *s_name_1;
50
51static struct GNUNET_GNSRECORD_Data *s_rd_1;
52
53static char *s_name_2;
54
55static struct GNUNET_GNSRECORD_Data *s_rd_2;
56
57static char *s_name_3;
58
59static struct GNUNET_GNSRECORD_Data *s_rd_3;
60
61
62/**
63 * Re-establish the connection to the service.
64 *
65 * @param cls handle to use to re-connect.
66 * @param tc scheduler context
67 */
68static void
69endbadly (void *cls)
70{
71 endbadly_task = NULL;
72 GNUNET_SCHEDULER_shutdown ();
73 res = 1;
74}
75
76
77static void
78end (void *cls)
79{
80 if (NULL != zi)
81 {
82 GNUNET_NAMESTORE_zone_iteration_stop (zi);
83 zi = NULL;
84 }
85 if (NULL != endbadly_task)
86 {
87 GNUNET_SCHEDULER_cancel (endbadly_task);
88 endbadly_task = NULL;
89 }
90 GNUNET_free (s_name_1);
91 GNUNET_free (s_name_2);
92 GNUNET_free (s_name_3);
93 if (NULL != s_rd_1)
94 {
95 GNUNET_free_nz ((void *) s_rd_1->data);
96 GNUNET_free (s_rd_1);
97 }
98 if (NULL != s_rd_2)
99 {
100 GNUNET_free_nz ((void *) s_rd_2->data);
101 GNUNET_free (s_rd_2);
102 }
103 if (NULL != s_rd_3)
104 {
105 GNUNET_free_nz ((void *) s_rd_3->data);
106 GNUNET_free (s_rd_3);
107 }
108 if (NULL != nsh)
109 {
110 GNUNET_NAMESTORE_disconnect (nsh);
111 nsh = NULL;
112 }
113}
114
115
116static void
117zone_end (void *cls)
118{
119 GNUNET_break (3 == returned_records);
120 if (3 == returned_records)
121 {
122 res = 0; /* Last iteraterator callback, we are done */
123 zi = NULL;
124 }
125 else
126 res = 1;
127
128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
129 "Received last result, iteration done after receing %u results\n",
130 returned_records);
131 GNUNET_SCHEDULER_shutdown ();
132}
133
134
135static void
136fail_cb (void *cls)
137{
138 GNUNET_assert (0);
139}
140
141
142static void
143zone_proc (void *cls,
144 const struct GNUNET_CRYPTO_PrivateKey *zone,
145 const char *label,
146 unsigned int rd_count,
147 const struct GNUNET_GNSRECORD_Data *rd)
148{
149 int failed = GNUNET_NO;
150
151 GNUNET_assert (NULL != zone);
152 if (0 == GNUNET_memcmp (zone,
153 &privkey))
154 {
155 if (0 == strcmp (label, s_name_1))
156 {
157 if (rd_count == 1)
158 {
159 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_1))
160 {
161 failed = GNUNET_YES;
162 GNUNET_break (0);
163 }
164 }
165 else
166 {
167 failed = GNUNET_YES;
168 GNUNET_break (0);
169 }
170 }
171 else if (0 == strcmp (label, s_name_2))
172 {
173 if (rd_count == 1)
174 {
175 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_2))
176 {
177 failed = GNUNET_YES;
178 GNUNET_break (0);
179 }
180 }
181 else
182 {
183 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
184 "Received invalid record count\n");
185 failed = GNUNET_YES;
186 GNUNET_break (0);
187 }
188 }
189 else
190 {
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192 "Comparing result failed: got name `%s' for first zone\n",
193 label);
194 failed = GNUNET_YES;
195 GNUNET_break (0);
196 }
197 }
198 else if (0 == GNUNET_memcmp (zone,
199 &privkey2))
200 {
201 if (0 == strcmp (label, s_name_3))
202 {
203 if (rd_count == 1)
204 {
205 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_3))
206 {
207 failed = GNUNET_YES;
208 GNUNET_break (0);
209 }
210 }
211 else
212 {
213 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
214 "Received invalid record count\n");
215 failed = GNUNET_YES;
216 GNUNET_break (0);
217 }
218 }
219 else
220 {
221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222 "Comparing result failed: got name `%s' for first zone\n",
223 label);
224 failed = GNUNET_YES;
225 GNUNET_break (0);
226 }
227 }
228 else
229 {
230 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
231 "Received invalid zone\n");
232 failed = GNUNET_YES;
233 GNUNET_break (0);
234 }
235
236 if (failed == GNUNET_NO)
237 {
238 returned_records++;
239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
240 "Telling namestore to send the next result\n");
241 GNUNET_NAMESTORE_zone_iterator_next (zi,
242 1);
243 }
244 else
245 {
246 GNUNET_break (0);
247 GNUNET_SCHEDULER_shutdown ();
248 res = 1;
249 }
250}
251
252
253static void
254put_cont (void *cls,
255 enum GNUNET_ErrorCode ec)
256{
257 static int c = 0;
258
259 if (GNUNET_EC_NONE == ec)
260 {
261 c++;
262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
263 "Created record %u \n",
264 c);
265 }
266 else
267 {
268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
269 "Failed to created records: `%s'\n",
270 GNUNET_ErrorCode_get_hint (ec));
271 GNUNET_break (0);
272 GNUNET_SCHEDULER_shutdown ();
273 res = 1;
274 return;
275 }
276
277 if (c == 3)
278 {
279 res = 1;
280 returned_records = 0;
281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282 "All records created, starting iteration over all zones \n");
283 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
284 NULL,
285 &fail_cb,
286 NULL,
287 &zone_proc,
288 NULL,
289 &zone_end,
290 NULL);
291 if (zi == NULL)
292 {
293 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
294 "Failed to create zone iterator\n");
295 GNUNET_break (0);
296 GNUNET_SCHEDULER_shutdown ();
297 res = 1;
298 return;
299 }
300 }
301}
302
303
304static struct GNUNET_GNSRECORD_Data *
305create_record (unsigned int count)
306{
307 struct GNUNET_GNSRECORD_Data *rd;
308
309 rd = GNUNET_new_array (count,
310 struct GNUNET_GNSRECORD_Data);
311 for (unsigned int c = 0; c < count; c++)
312 {
313 rd[c].expiration_time = GNUNET_TIME_relative_to_absolute (
314 GNUNET_TIME_UNIT_HOURS).abs_value_us;
315 rd[c].record_type = TEST_RECORD_TYPE;
316 rd[c].data_size = 50;
317 rd[c].data = GNUNET_malloc (50);
318 rd[c].flags = 0;
319 memset ((char *) rd[c].data, 'a', 50);
320 }
321 return rd;
322}
323
324
325/**
326 * Callback called from the zone iterator when we iterate over
327 * the empty zone. Check that we got no records and then
328 * start the actual tests by filling the zone.
329 */
330static void
331empty_zone_proc (void *cls,
332 const struct GNUNET_CRYPTO_PrivateKey *zone,
333 const char *label,
334 unsigned int rd_count,
335 const struct GNUNET_GNSRECORD_Data *rd)
336{
337 GNUNET_assert (nsh == cls);
338 if (NULL != zone)
339 {
340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
341 _ ("Expected empty zone but received zone private key\n"));
342 GNUNET_break (0);
343 GNUNET_SCHEDULER_shutdown ();
344 res = 1;
345 return;
346 }
347 if ((NULL != label) || (NULL != rd) || (0 != rd_count))
348 {
349 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
350 _ ("Expected no zone content but received data\n"));
351 GNUNET_break (0);
352 GNUNET_SCHEDULER_shutdown ();
353 res = 1;
354 return;
355 }
356 GNUNET_assert (0);
357}
358
359
360static void
361empty_zone_end (void *cls)
362{
363 zi = NULL;
364 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
365 privkey2.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
366 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
367 GNUNET_CRYPTO_ecdsa_key_create (&privkey2.ecdsa_key);
368
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 1\n");
370
371 GNUNET_asprintf (&s_name_1, "dummy1");
372 s_rd_1 = create_record (1);
373 GNUNET_NAMESTORE_records_store (nsh,
374 &privkey,
375 s_name_1,
376 1, s_rd_1,
377 &put_cont,
378 NULL);
379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
380 "Created record 2 \n");
381 GNUNET_asprintf (&s_name_2, "dummy2");
382 s_rd_2 = create_record (1);
383 GNUNET_NAMESTORE_records_store (nsh,
384 &privkey,
385 s_name_2,
386 1, s_rd_2,
387 &put_cont,
388 NULL);
389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390 "Created record 3\n");
391 /* name in different zone */
392 GNUNET_asprintf (&s_name_3, "dummy3");
393 s_rd_3 = create_record (1);
394 GNUNET_NAMESTORE_records_store (nsh,
395 &privkey2,
396 s_name_3,
397 1,
398 s_rd_3,
399 &put_cont,
400 NULL);
401}
402
403
404static void
405run (void *cls,
406 const struct GNUNET_CONFIGURATION_Handle *cfg,
407 struct GNUNET_TESTING_Peer *peer)
408{
409 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
410 &endbadly,
411 NULL);
412 GNUNET_SCHEDULER_add_shutdown (&end,
413 NULL);
414
415 nsh = GNUNET_NAMESTORE_connect (cfg);
416 GNUNET_break (NULL != nsh);
417 /* first, iterate over empty namestore */
418 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
419 NULL,
420 &fail_cb,
421 NULL,
422 &empty_zone_proc,
423 nsh,
424 &empty_zone_end,
425 NULL);
426 if (NULL == zi)
427 {
428 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
429 "Failed to create zone iterator\n");
430 GNUNET_break (0);
431 res = 1;
432 GNUNET_SCHEDULER_shutdown ();
433 }
434}
435
436
437#include "test_common.c"
438
439
440int
441main (int argc, char *argv[])
442{
443 const char *plugin_name;
444 char *cfg_name;
445
446 SETUP_CFG (plugin_name, cfg_name);
447 res = 1;
448 if (0 !=
449 GNUNET_TESTING_peer_run ("test-namestore-api-zone-iteration",
450 cfg_name,
451 &run,
452 NULL))
453 {
454 res = 1;
455 }
456 GNUNET_DISK_purge_cfg_dir (cfg_name,
457 "GNUNET_TEST_HOME");
458 GNUNET_free (plugin_name);
459 GNUNET_free (cfg_name);
460 return res;
461}
462
463
464/* end of test_namestore_api_zone_iteration.c */
diff --git a/src/namestore/test_namestore_api_zone_iteration_nick.c b/src/namestore/test_namestore_api_zone_iteration_nick.c
deleted file mode 100644
index c494051d0..000000000
--- a/src/namestore/test_namestore_api_zone_iteration_nick.c
+++ /dev/null
@@ -1,460 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/test_namestore_api_zone_iteration.c
22 * @brief testcase for zone iteration functionality: iterate all zones
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_gns_service.h"
27#include "gnunet_testing_lib.h"
28#include "namestore.h"
29
30#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
31
32#define ZONE_NICK_1 "nick1"
33#define ZONE_NICK_2 "nick2"
34
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
36
37
38static struct GNUNET_NAMESTORE_Handle *nsh;
39
40static struct GNUNET_CRYPTO_PrivateKey privkey;
41
42static struct GNUNET_CRYPTO_PrivateKey privkey2;
43
44static struct GNUNET_NAMESTORE_ZoneIterator *zi;
45
46static int res;
47
48static int returned_records;
49
50static char *s_name_1;
51
52static struct GNUNET_GNSRECORD_Data *s_rd_1;
53
54static char *s_name_2;
55
56static struct GNUNET_GNSRECORD_Data *s_rd_2;
57
58static char *s_name_3;
59
60static struct GNUNET_GNSRECORD_Data *s_rd_3;
61
62static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
63
64
65/**
66 * Re-establish the connection to the service.
67 *
68 * @param cls handle to use to re-connect.
69 * @param tc scheduler context
70 */
71static void
72end (void *cls)
73{
74 if (NULL != zi)
75 {
76 GNUNET_NAMESTORE_zone_iteration_stop (zi);
77 zi = NULL;
78 }
79 if (nsh != NULL)
80 {
81 GNUNET_NAMESTORE_disconnect (nsh);
82 nsh = NULL;
83 }
84 GNUNET_free (s_name_1);
85 GNUNET_free (s_name_2);
86 GNUNET_free (s_name_3);
87
88 if (s_rd_1 != NULL)
89 {
90 GNUNET_free_nz ((void *) s_rd_1->data);
91 GNUNET_free (s_rd_1);
92 }
93 if (s_rd_2 != NULL)
94 {
95 GNUNET_free_nz ((void *) s_rd_2->data);
96 GNUNET_free (s_rd_2);
97 }
98 if (s_rd_3 != NULL)
99 {
100 GNUNET_free_nz ((void *) s_rd_3->data);
101 GNUNET_free (s_rd_3);
102 }
103}
104
105
106static int
107check_zone_1 (const char *label, unsigned int rd_count,
108 const struct GNUNET_GNSRECORD_Data *rd)
109{
110 for (unsigned int c = 0; c < rd_count; c++)
111 {
112 if ((rd[c].record_type == GNUNET_GNSRECORD_TYPE_NICK) &&
113 (0 != strcmp (rd[c].data, ZONE_NICK_1)))
114 {
115 GNUNET_break (0);
116 return GNUNET_YES;
117 }
118 }
119 return GNUNET_NO;
120}
121
122
123static int
124check_zone_2 (const char *label,
125 unsigned int rd_count,
126 const struct GNUNET_GNSRECORD_Data *rd)
127{
128 for (unsigned int c = 0; c < rd_count; c++)
129 {
130 if ((rd[c].record_type == GNUNET_GNSRECORD_TYPE_NICK) &&
131 (0 != strcmp (rd[c].data, ZONE_NICK_2)))
132 {
133 GNUNET_break (0);
134 return GNUNET_YES;
135 }
136 }
137 return GNUNET_NO;
138}
139
140
141static void
142zone_proc_end (void *cls)
143{
144 zi = NULL;
145 res = 0;
146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
147 "Received last result, iteration done after receing %u results\n",
148 returned_records);
149 GNUNET_SCHEDULER_shutdown ();
150}
151
152
153static void
154zone_proc (void *cls,
155 const struct GNUNET_CRYPTO_PrivateKey *zone,
156 const char *label,
157 unsigned int rd_count,
158 const struct GNUNET_GNSRECORD_Data *rd)
159{
160 int failed = GNUNET_NO;
161
162 GNUNET_assert (NULL != zone);
163 if (0 == GNUNET_memcmp (zone, &privkey))
164 {
165 failed = check_zone_1 (label, rd_count, rd);
166 if (GNUNET_YES == failed)
167 GNUNET_break (0);
168 }
169 else if (0 == GNUNET_memcmp (zone, &privkey2))
170 {
171 failed = check_zone_2 (label, rd_count, rd);
172 if (GNUNET_YES == failed)
173 GNUNET_break (0);
174 }
175 else
176 {
177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
178 "Received invalid zone\n");
179 failed = GNUNET_YES;
180 GNUNET_break (0);
181 }
182
183 if (failed == GNUNET_NO)
184 {
185 returned_records++;
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
187 "Telling namestore to send the next result\n");
188 GNUNET_NAMESTORE_zone_iterator_next (zi,
189 1);
190 }
191 else
192 {
193 GNUNET_break (0);
194 res = 1;
195 GNUNET_SCHEDULER_shutdown ();
196 }
197}
198
199
200static void
201fail_cb (void *cls)
202{
203 GNUNET_assert (0);
204}
205
206
207static void
208put_cont (void *cls,
209 enum GNUNET_ErrorCode ec)
210{
211 static int c = 0;
212
213 if (GNUNET_EC_NONE == ec)
214 {
215 c++;
216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record %u \n", c);
217 }
218 else
219 {
220 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to created records: `%s'\n",
221 GNUNET_ErrorCode_get_hint (ec));
222 GNUNET_break (0);
223 GNUNET_SCHEDULER_shutdown ();
224 return;
225 }
226
227 if (c == 3)
228 {
229 res = 1;
230 returned_records = 0;
231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232 "All records created, starting iteration over all zones \n");
233 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
234 NULL,
235 &fail_cb,
236 NULL,
237 &zone_proc,
238 NULL,
239 &zone_proc_end,
240 NULL);
241 if (zi == NULL)
242 {
243 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create zone iterator\n");
244 GNUNET_break (0);
245 GNUNET_SCHEDULER_shutdown ();
246 return;
247 }
248 }
249}
250
251
252static struct GNUNET_GNSRECORD_Data *
253create_record (unsigned int count)
254{
255 struct GNUNET_GNSRECORD_Data *rd;
256
257 rd = GNUNET_new_array (count,
258 struct GNUNET_GNSRECORD_Data);
259 for (unsigned int c = 0; c < count; c++)
260 {
261 rd[c].expiration_time = GNUNET_TIME_relative_to_absolute (
262 GNUNET_TIME_UNIT_HOURS).abs_value_us;
263 rd[c].record_type = TEST_RECORD_TYPE;
264 rd[c].data_size = 50;
265 rd[c].data = GNUNET_malloc (50);
266 rd[c].flags = 0;
267 memset ((char *) rd[c].data, 'a', 50);
268 }
269 return rd;
270}
271
272
273static void
274nick_2_cont (void *cls,
275 enum GNUNET_ErrorCode ec)
276{
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "Nick added : %s\n",
279 (GNUNET_EC_NONE == ec) ? "SUCCESS" : "FAIL");
280
281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 1\n");
282
283 GNUNET_asprintf (&s_name_1, "dummy1");
284 s_rd_1 = create_record (1);
285 GNUNET_NAMESTORE_records_store (nsh, &privkey, s_name_1,
286 1, s_rd_1,
287 &put_cont, NULL);
288
289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
290 "Created record 2 \n");
291 GNUNET_asprintf (&s_name_2, "dummy2");
292 s_rd_2 = create_record (1);
293 GNUNET_NAMESTORE_records_store (nsh, &privkey, s_name_2,
294 1, s_rd_2, &put_cont, NULL);
295
296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
297 "Created record 3\n");
298
299 /* name in different zone */
300 GNUNET_asprintf (&s_name_3, "dummy3");
301 s_rd_3 = create_record (1);
302 GNUNET_NAMESTORE_records_store (nsh, &privkey2, s_name_3,
303 1, s_rd_3,
304 &put_cont, NULL);
305}
306
307
308static void
309nick_1_cont (void *cls, enum GNUNET_ErrorCode ec)
310{
311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
312 "Nick 1 added : %s\n",
313 (GNUNET_EC_NONE == ec) ? "SUCCESS" : "FAIL");
314 struct GNUNET_GNSRECORD_Data rd;
315
316 memset (&rd, 0, sizeof(rd));
317 rd.data = ZONE_NICK_2;
318 rd.data_size = strlen (ZONE_NICK_2) + 1;
319 rd.record_type = GNUNET_GNSRECORD_TYPE_NICK;
320 rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
321 rd.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
322 nsqe = GNUNET_NAMESTORE_records_store (nsh,
323 &privkey2,
324 GNUNET_GNS_EMPTY_LABEL_AT,
325 1,
326 &rd,
327 &nick_2_cont,
328 &privkey2);
329
330 if (NULL == nsqe)
331 {
332 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
333 _ ("Namestore cannot store no block\n"));
334 }
335}
336
337
338/**
339 * Callback called from the zone iterator when we iterate over
340 * the empty zone. Check that we got no records and then
341 * start the actual tests by filling the zone.
342 */
343static void
344empty_zone_proc (void *cls,
345 const struct GNUNET_CRYPTO_PrivateKey *zone,
346 const char *label,
347 unsigned int rd_count,
348 const struct GNUNET_GNSRECORD_Data *rd)
349{
350 GNUNET_assert (nsh == cls);
351
352 if (NULL != zone)
353 {
354 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
355 _ ("Expected empty zone but received zone private key\n"));
356 GNUNET_break (0);
357 GNUNET_SCHEDULER_shutdown ();
358 return;
359 }
360 if ((NULL != label) || (NULL != rd) || (0 != rd_count))
361 {
362 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
363 _ ("Expected no zone content but received data\n"));
364 GNUNET_break (0);
365 GNUNET_SCHEDULER_shutdown ();
366 return;
367 }
368 GNUNET_assert (0);
369}
370
371
372static void
373empty_zone_end (void *cls)
374{
375 GNUNET_assert (nsh == cls);
376 struct GNUNET_GNSRECORD_Data rd;
377
378 zi = NULL;
379 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
380 privkey2.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
381 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
382 GNUNET_CRYPTO_ecdsa_key_create (&privkey2.ecdsa_key);
383
384 memset (&rd, 0, sizeof(rd));
385 rd.data = ZONE_NICK_1;
386 rd.data_size = strlen (ZONE_NICK_1) + 1;
387 rd.record_type = GNUNET_GNSRECORD_TYPE_NICK;
388 rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
389 rd.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
390 nsqe = GNUNET_NAMESTORE_records_store (nsh,
391 &privkey,
392 GNUNET_GNS_EMPTY_LABEL_AT,
393 1,
394 &rd,
395 &nick_1_cont,
396 NULL);
397 if (NULL == nsqe)
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
400 _ ("Namestore cannot store no block\n"));
401 }
402}
403
404
405static void
406run (void *cls,
407 const struct GNUNET_CONFIGURATION_Handle *cfg,
408 struct GNUNET_TESTING_Peer *peer)
409{
410 nsh = GNUNET_NAMESTORE_connect (cfg);
411 GNUNET_break (NULL != nsh);
412 GNUNET_SCHEDULER_add_shutdown (&end,
413 NULL);
414 /* first, iterate over empty namestore */
415 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
416 NULL,
417 &fail_cb,
418 NULL,
419 &empty_zone_proc,
420 nsh,
421 &empty_zone_end,
422 nsh);
423 if (NULL == zi)
424 {
425 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
426 "Failed to create zone iterator\n");
427 GNUNET_break (0);
428 GNUNET_SCHEDULER_shutdown ();
429 }
430}
431
432
433#include "test_common.c"
434
435
436int
437main (int argc, char *argv[])
438{
439 const char *plugin_name;
440 char *cfg_name;
441
442 SETUP_CFG (plugin_name, cfg_name);
443 res = 1;
444 if (0 !=
445 GNUNET_TESTING_peer_run ("test-namestore-api-zone-iteration-nick",
446 cfg_name,
447 &run,
448 NULL))
449 {
450 res = 1;
451 }
452 GNUNET_DISK_purge_cfg_dir (cfg_name,
453 "GNUNET_TEST_HOME");
454 GNUNET_free (plugin_name);
455 GNUNET_free (cfg_name);
456 return res;
457}
458
459
460/* end of test_namestore_api_zone_iteration.c */
diff --git a/src/namestore/test_namestore_api_zone_iteration_specific_zone.c b/src/namestore/test_namestore_api_zone_iteration_specific_zone.c
deleted file mode 100644
index 02587706c..000000000
--- a/src/namestore/test_namestore_api_zone_iteration_specific_zone.c
+++ /dev/null
@@ -1,447 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 namestore/test_namestore_api_zone_iteration_specific_zone.c
22 * @brief testcase for zone iteration functionality: iterate over a specific zone
23 * @author Matthias Wachs
24 */
25#include "platform.h"
26#include "gnunet_namestore_service.h"
27#include "gnunet_testing_lib.h"
28#include "namestore.h"
29
30#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
31
32
33#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
34
35
36static struct GNUNET_NAMESTORE_Handle *nsh;
37
38static struct GNUNET_SCHEDULER_Task *endbadly_task;
39
40static struct GNUNET_CRYPTO_PrivateKey privkey;
41
42static struct GNUNET_CRYPTO_PrivateKey privkey2;
43
44static struct GNUNET_NAMESTORE_ZoneIterator *zi;
45
46static int res;
47
48static int returned_records;
49
50static char *s_name_1;
51
52static struct GNUNET_GNSRECORD_Data *s_rd_1;
53
54static char *s_name_2;
55
56static struct GNUNET_GNSRECORD_Data *s_rd_2;
57
58static char *s_name_3;
59
60static struct GNUNET_GNSRECORD_Data *s_rd_3;
61
62
63/**
64 * Handle timeout.
65 *
66 * @param cls handle to use to re-connect.
67 */
68static void
69endbadly (void *cls)
70{
71 endbadly_task = NULL;
72 GNUNET_SCHEDULER_shutdown ();
73 res = 1;
74}
75
76
77static void
78end (void *cls)
79{
80 if (NULL != zi)
81 {
82 GNUNET_NAMESTORE_zone_iteration_stop (zi);
83 zi = NULL;
84 }
85 if (NULL != endbadly_task)
86 {
87 GNUNET_SCHEDULER_cancel (endbadly_task);
88 endbadly_task = NULL;
89 }
90 GNUNET_free (s_name_1);
91 GNUNET_free (s_name_2);
92 GNUNET_free (s_name_3);
93 if (s_rd_1 != NULL)
94 {
95 GNUNET_free_nz ((void *) s_rd_1->data);
96 GNUNET_free (s_rd_1);
97 }
98 if (s_rd_2 != NULL)
99 {
100 GNUNET_free_nz ((void *) s_rd_2->data);
101 GNUNET_free (s_rd_2);
102 }
103 if (s_rd_3 != NULL)
104 {
105 GNUNET_free_nz ((void *) s_rd_3->data);
106 GNUNET_free (s_rd_3);
107 }
108 if (nsh != NULL)
109 {
110 GNUNET_NAMESTORE_disconnect (nsh);
111 nsh = NULL;
112 }
113}
114
115
116static void
117fail_cb (void *cls)
118{
119 GNUNET_assert (0);
120 zi = NULL;
121}
122
123
124static void
125zone_proc (void *cls,
126 const struct GNUNET_CRYPTO_PrivateKey *zone,
127 const char *label,
128 unsigned int rd_count,
129 const struct GNUNET_GNSRECORD_Data *rd)
130{
131 int failed = GNUNET_NO;
132
133 GNUNET_assert (NULL != zone);
134 if (0 == GNUNET_memcmp (zone,
135 &privkey))
136 {
137 if (0 == strcmp (label, s_name_1))
138 {
139 if (rd_count == 1)
140 {
141 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_1))
142 {
143 failed = GNUNET_YES;
144 GNUNET_break (0);
145 }
146 }
147 else
148 {
149 failed = GNUNET_YES;
150 GNUNET_break (0);
151 }
152 }
153 else if (0 == strcmp (label, s_name_2))
154 {
155 if (rd_count == 1)
156 {
157 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_2))
158 {
159 failed = GNUNET_YES;
160 GNUNET_break (0);
161 }
162 }
163 else
164 {
165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
166 "Received invalid record count\n");
167 failed = GNUNET_YES;
168 GNUNET_break (0);
169 }
170 }
171 else
172 {
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
174 "Comparing result failed: got name `%s' for first zone\n",
175 label);
176 failed = GNUNET_YES;
177 GNUNET_break (0);
178 }
179 }
180 else if (0 == GNUNET_memcmp (zone, &privkey2))
181 {
182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
183 "Received data for not requested zone\n");
184 failed = GNUNET_YES;
185 GNUNET_break (0);
186 }
187 else
188 {
189 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
190 "Received invalid zone\n");
191 failed = GNUNET_YES;
192 GNUNET_break (0);
193 }
194 if (failed == GNUNET_NO)
195 {
196 returned_records++;
197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
198 "Telling namestore to send the next result\n");
199 GNUNET_NAMESTORE_zone_iterator_next (zi,
200 1);
201 }
202 else
203 {
204 GNUNET_break (0);
205 res = 2;
206 GNUNET_SCHEDULER_shutdown ();
207 }
208}
209
210
211static void
212zone_proc_end (void *cls)
213{
214 zi = NULL;
215 GNUNET_break (2 == returned_records);
216 if (2 == returned_records)
217 {
218 res = 0; /* Last iteraterator callback, we are done */
219 }
220 else
221 {
222 res = 1;
223 }
224
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226 "Received last result, iteration done after receing %u results\n",
227 returned_records);
228 GNUNET_SCHEDULER_shutdown ();
229}
230
231
232static void
233put_cont (void *cls,
234 enum GNUNET_ErrorCode ec)
235{
236 static int c = 0;
237
238 if (GNUNET_EC_NONE == ec)
239 {
240 c++;
241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242 "Created record %u \n", c);
243 }
244 else
245 {
246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
247 "Failed to created records: `%s'\n",
248 GNUNET_ErrorCode_get_hint (ec));
249 GNUNET_break (0);
250 res = 2;
251 GNUNET_SCHEDULER_shutdown ();
252 return;
253 }
254
255 if (c == 3)
256 {
257 res = 1;
258 returned_records = 0;
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260 "All records created, starting iteration over all zones \n");
261 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
262 &privkey,
263 &fail_cb,
264 NULL,
265 &zone_proc,
266 NULL,
267 &zone_proc_end,
268 NULL);
269 if (zi == NULL)
270 {
271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
272 "Failed to create zone iterator\n");
273 GNUNET_break (0);
274 res = 2;
275 GNUNET_SCHEDULER_shutdown ();
276 return;
277 }
278 }
279}
280
281
282static struct GNUNET_GNSRECORD_Data *
283create_record (unsigned int count)
284{
285 struct GNUNET_GNSRECORD_Data *rd;
286
287 rd = GNUNET_new_array (count,
288 struct GNUNET_GNSRECORD_Data);
289 for (unsigned int c = 0; c < count; c++)
290 {
291 rd[c].expiration_time = GNUNET_TIME_relative_to_absolute (
292 GNUNET_TIME_UNIT_HOURS).abs_value_us;
293 rd[c].record_type = TEST_RECORD_TYPE;
294 rd[c].data_size = 50;
295 rd[c].data = GNUNET_malloc (50);
296 rd[c].flags = 0;
297 memset ((char *) rd[c].data, 'a', 50);
298 }
299 return rd;
300}
301
302
303/**
304 * Callback called from the zone iterator when we iterate over
305 * the empty zone. Check that we got no records and then
306 * start the actual tests by filling the zone.
307 */
308static void
309empty_zone_proc (void *cls,
310 const struct GNUNET_CRYPTO_PrivateKey *zone,
311 const char *label,
312 unsigned int rd_count,
313 const struct GNUNET_GNSRECORD_Data *rd)
314{
315 GNUNET_assert (nsh == cls);
316 if (NULL != zone)
317 {
318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
319 _ ("Expected empty zone but received zone private key\n"));
320 GNUNET_break (0);
321 res = 2;
322 GNUNET_SCHEDULER_shutdown ();
323 return;
324 }
325 if ((NULL != label) || (NULL != rd) || (0 != rd_count))
326 {
327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328 _ ("Expected no zone content but received data\n"));
329 GNUNET_break (0);
330 res = 2;
331 GNUNET_SCHEDULER_shutdown ();
332 return;
333 }
334 GNUNET_assert (0);
335}
336
337
338static void
339empty_zone_proc_end (void *cls)
340{
341 zi = NULL;
342 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
343 privkey2.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
344 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
345 GNUNET_CRYPTO_ecdsa_key_create (&privkey2.ecdsa_key);
346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
347 "Created record 1\n");
348 GNUNET_asprintf (&s_name_1,
349 "dummy1");
350 s_rd_1 = create_record (1);
351 GNUNET_NAMESTORE_records_store (nsh,
352 &privkey,
353 s_name_1,
354 1,
355 s_rd_1,
356 &put_cont,
357 NULL);
358
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360 "Created record 2 \n");
361 GNUNET_asprintf (&s_name_2,
362 "dummy2");
363 s_rd_2 = create_record (1);
364 GNUNET_NAMESTORE_records_store (nsh,
365 &privkey,
366 s_name_2,
367 1,
368 s_rd_2,
369 &put_cont,
370 NULL);
371
372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
373 "Created record 3\n");
374
375 /* name in different zone */
376 GNUNET_asprintf (&s_name_3,
377 "dummy3");
378 s_rd_3 = create_record (1);
379 GNUNET_NAMESTORE_records_store (nsh,
380 &privkey2,
381 s_name_3,
382 1, s_rd_3,
383 &put_cont,
384 NULL);
385}
386
387
388static void
389run (void *cls,
390 const struct GNUNET_CONFIGURATION_Handle *cfg,
391 struct GNUNET_TESTING_Peer *peer)
392{
393 GNUNET_SCHEDULER_add_shutdown (&end,
394 NULL);
395 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
396 &endbadly,
397 NULL);
398 nsh = GNUNET_NAMESTORE_connect (cfg);
399 GNUNET_break (NULL != nsh);
400 /* first, iterate over empty namestore */
401 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
402 NULL,
403 &fail_cb,
404 NULL,
405 &empty_zone_proc,
406 nsh,
407 &empty_zone_proc_end,
408 nsh);
409 if (NULL == zi)
410 {
411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
412 "Failed to create zone iterator\n");
413 GNUNET_break (0);
414 GNUNET_SCHEDULER_shutdown ();
415 }
416}
417
418
419#include "test_common.c"
420
421
422int
423main (int argc, char *argv[])
424{
425 const char *plugin_name;
426 char *cfg_name;
427
428 SETUP_CFG (plugin_name, cfg_name);
429 res = 1;
430 if (0 !=
431 GNUNET_TESTING_peer_run (
432 "test-namestore-api-zone-iteration-specific-zone",
433 cfg_name,
434 &run,
435 NULL))
436 {
437 res = 1;
438 }
439 GNUNET_DISK_purge_cfg_dir (cfg_name,
440 "GNUNET_TEST_HOME");
441 GNUNET_free (plugin_name);
442 GNUNET_free (cfg_name);
443 return res;
444}
445
446
447/* end of test_namestore_api_zone_iteration_specific_zone.c */
diff --git a/src/namestore/test_namestore_api_zone_iteration_stop.c b/src/namestore/test_namestore_api_zone_iteration_stop.c
deleted file mode 100644
index b6b0787ef..000000000
--- a/src/namestore/test_namestore_api_zone_iteration_stop.c
+++ /dev/null
@@ -1,449 +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 namestore/test_namestore_api_zone_iteration_stop.c
22 * @brief testcase for zone iteration functionality: stop iterating of zones
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27#include "namestore.h"
28
29#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
30
31#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
32#define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
33
34static struct GNUNET_NAMESTORE_Handle *nsh;
35
36static struct GNUNET_CRYPTO_PrivateKey privkey;
37
38static struct GNUNET_CRYPTO_PrivateKey privkey2;
39
40static struct GNUNET_NAMESTORE_ZoneIterator *zi;
41
42static int res;
43
44static int returned_records;
45
46static char *s_name_1;
47
48static struct GNUNET_GNSRECORD_Data *s_rd_1;
49
50static char *s_name_2;
51
52static struct GNUNET_GNSRECORD_Data *s_rd_2;
53
54static char *s_name_3;
55
56static struct GNUNET_GNSRECORD_Data *s_rd_3;
57
58
59/**
60 * Re-establish the connection to the service.
61 *
62 * @param cls handle to use to re-connect.
63 */
64static void
65end (void *cls)
66{
67 if (NULL != zi)
68 {
69 GNUNET_NAMESTORE_zone_iteration_stop (zi);
70 zi = NULL;
71 }
72 if (nsh != NULL)
73 {
74 GNUNET_NAMESTORE_disconnect (nsh);
75 nsh = NULL;
76 }
77 GNUNET_free (s_name_1);
78 GNUNET_free (s_name_2);
79 GNUNET_free (s_name_3);
80 if (s_rd_1 != NULL)
81 {
82 GNUNET_free_nz ((void *) s_rd_1->data);
83 GNUNET_free (s_rd_1);
84 }
85 if (s_rd_2 != NULL)
86 {
87 GNUNET_free_nz ((void *) s_rd_2->data);
88 GNUNET_free (s_rd_2);
89 }
90 if (s_rd_3 != NULL)
91 {
92 GNUNET_free_nz ((void *) s_rd_3->data);
93 GNUNET_free (s_rd_3);
94 }
95}
96
97
98static void
99delayed_end (void *cls)
100{
101 GNUNET_SCHEDULER_shutdown ();
102}
103
104
105static void
106fail_cb (void *cls)
107{
108 GNUNET_assert (0);
109}
110
111
112static void
113zone_proc (void *cls,
114 const struct GNUNET_CRYPTO_PrivateKey *zone,
115 const char *label,
116 unsigned int rd_count,
117 const struct GNUNET_GNSRECORD_Data *rd)
118{
119 int failed = GNUNET_NO;
120
121 GNUNET_assert (NULL != zone);
122 if (0 == GNUNET_memcmp (zone, &privkey))
123 {
124 if (0 == strcmp (label, s_name_1))
125 {
126 if (rd_count == 1)
127 {
128 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_1))
129 {
130 failed = GNUNET_YES;
131 GNUNET_break (0);
132 }
133 }
134 else
135 {
136 failed = GNUNET_YES;
137 GNUNET_break (0);
138 }
139 }
140 else if (0 == strcmp (label, s_name_2))
141 {
142 if (rd_count == 1)
143 {
144 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_2))
145 {
146 failed = GNUNET_YES;
147 GNUNET_break (0);
148 }
149 }
150 else
151 {
152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
153 "Received invalid record count\n");
154 failed = GNUNET_YES;
155 GNUNET_break (0);
156 }
157 }
158 else
159 {
160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
161 "Comparing result failed: got name `%s' for first zone\n",
162 label);
163 failed = GNUNET_YES;
164 GNUNET_break (0);
165 }
166 }
167 else if (0 == GNUNET_memcmp (zone, &privkey2))
168 {
169 if (0 == strcmp (label, s_name_3))
170 {
171 if (rd_count == 1)
172 {
173 if (GNUNET_YES != GNUNET_GNSRECORD_records_cmp (rd, s_rd_3))
174 {
175 failed = GNUNET_YES;
176 GNUNET_break (0);
177 }
178 }
179 else
180 {
181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
182 "Received invalid record count\n");
183 failed = GNUNET_YES;
184 GNUNET_break (0);
185 }
186 }
187 else
188 {
189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
190 "Comparing result failed: got name `%s' for first zone\n",
191 label);
192 failed = GNUNET_YES;
193 GNUNET_break (0);
194 }
195 }
196 else
197 {
198 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
199 "Received invalid zone\n");
200 failed = GNUNET_YES;
201 GNUNET_break (0);
202 }
203 if (failed == GNUNET_NO)
204 {
205 if (1 == returned_records)
206 {
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
208 "Telling namestore to stop zone iteration\n");
209 GNUNET_NAMESTORE_zone_iteration_stop (zi);
210 zi = NULL;
211 res = 0;
212 GNUNET_SCHEDULER_add_delayed (WAIT,
213 &delayed_end,
214 NULL);
215 return;
216 }
217 returned_records++;
218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
219 "Telling namestore to send the next result\n");
220 GNUNET_NAMESTORE_zone_iterator_next (zi,
221 1);
222 }
223 else
224 {
225 GNUNET_break (0);
226 GNUNET_SCHEDULER_shutdown ();
227 }
228}
229
230
231static void
232zone_proc_end (void *cls)
233{
234 GNUNET_break (1 <= returned_records);
235 if (1 >= returned_records)
236 res = 1; /* Last iteraterator callback, we are done */
237 else
238 res = 0;
239 zi = NULL;
240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
241 "Received last result, iteration done after receing %u results\n",
242 returned_records);
243 GNUNET_SCHEDULER_add_now (&end, NULL);
244}
245
246
247static void
248put_cont (void *cls, enum GNUNET_ErrorCode ec)
249{
250 static int c = 0;
251
252 if (GNUNET_EC_NONE == ec)
253 {
254 c++;
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record %u \n", c);
256 }
257 else
258 {
259 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to created records: `%s'\n",
260 GNUNET_ErrorCode_get_hint (ec));
261 GNUNET_break (0);
262 GNUNET_SCHEDULER_shutdown ();
263 return;
264 }
265
266 if (c == 3)
267 {
268 res = 1;
269 returned_records = 0;
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
271 "All records created, starting iteration over all zones \n");
272 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
273 NULL,
274 &fail_cb,
275 NULL,
276 &zone_proc,
277 NULL,
278 &zone_proc_end,
279 NULL);
280 if (zi == NULL)
281 {
282 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
283 "Failed to create zone iterator\n");
284 GNUNET_break (0);
285 GNUNET_SCHEDULER_shutdown ();
286 return;
287 }
288 }
289}
290
291
292static struct GNUNET_GNSRECORD_Data *
293create_record (unsigned int count)
294{
295 struct GNUNET_GNSRECORD_Data *rd;
296
297 rd = GNUNET_new_array (count,
298 struct GNUNET_GNSRECORD_Data);
299 for (unsigned int c = 0; c < count; c++)
300 {
301 rd[c].expiration_time = GNUNET_TIME_relative_to_absolute (
302 GNUNET_TIME_UNIT_HOURS).abs_value_us;
303 rd[c].record_type = TEST_RECORD_TYPE;
304 rd[c].data_size = 50;
305 rd[c].data = GNUNET_malloc (50);
306 rd[c].flags = 0;
307 memset ((char *) rd[c].data, 'a', 50);
308 }
309 return rd;
310}
311
312
313/**
314 * Callback called from the zone iterator when we iterate over
315 * the empty zone. Check that we got no records and then
316 * start the actual tests by filling the zone.
317 */
318static void
319empty_zone_proc (void *cls,
320 const struct GNUNET_CRYPTO_PrivateKey *zone,
321 const char *label,
322 unsigned int rd_count,
323 const struct GNUNET_GNSRECORD_Data *rd)
324{
325 GNUNET_assert (nsh == cls);
326 if (NULL != zone)
327 {
328 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
329 _ ("Expected empty zone but received zone private key\n"));
330 GNUNET_break (0);
331 GNUNET_SCHEDULER_shutdown ();
332 return;
333 }
334 if ((NULL != label) || (NULL != rd) || (0 != rd_count))
335 {
336 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
337 _ ("Expected no zone content but received data\n"));
338 GNUNET_break (0);
339 GNUNET_SCHEDULER_shutdown ();
340 return;
341 }
342 GNUNET_assert (0);
343}
344
345
346static void
347empty_zone_proc_end (void *cls)
348{
349 GNUNET_assert (nsh == cls);
350 zi = NULL;
351 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
352 privkey2.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
353 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
354 GNUNET_CRYPTO_ecdsa_key_create (&privkey2.ecdsa_key);
355
356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
357 "Created record 1\n");
358
359 GNUNET_asprintf (&s_name_1,
360 "dummy1");
361 s_rd_1 = create_record (1);
362 GNUNET_NAMESTORE_records_store (nsh,
363 &privkey, s_name_1,
364 1, s_rd_1, &put_cont, NULL);
365
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367 "Created record 2 \n");
368 GNUNET_asprintf (&s_name_2,
369 "dummy2");
370 s_rd_2 = create_record (1);
371 GNUNET_NAMESTORE_records_store (nsh,
372 &privkey,
373 s_name_2,
374 1,
375 s_rd_2,
376 &put_cont, NULL);
377
378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
379 "Created record 3\n");
380
381 /* name in different zone */
382 GNUNET_asprintf (&s_name_3, "dummy3");
383 s_rd_3 = create_record (1);
384 GNUNET_NAMESTORE_records_store (nsh,
385 &privkey2,
386 s_name_3,
387 1,
388 s_rd_3,
389 &put_cont, NULL);
390}
391
392
393static void
394run (void *cls,
395 const struct GNUNET_CONFIGURATION_Handle *cfg,
396 struct GNUNET_TESTING_Peer *peer)
397{
398 nsh = GNUNET_NAMESTORE_connect (cfg);
399 GNUNET_break (NULL != nsh);
400 GNUNET_SCHEDULER_add_shutdown (&end,
401 NULL);
402 /* first, iterate over empty namestore */
403 zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
404 NULL,
405 &fail_cb,
406 NULL,
407 &empty_zone_proc,
408 nsh,
409 &empty_zone_proc_end,
410 nsh);
411 if (NULL == zi)
412 {
413 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
414 "Failed to create zone iterator\n");
415 GNUNET_break (0);
416 GNUNET_SCHEDULER_shutdown ();
417 }
418}
419
420
421#include "test_common.c"
422
423
424int
425main (int argc, char *argv[])
426{
427 const char *plugin_name;
428 char *cfg_name;
429
430 SETUP_CFG (plugin_name, cfg_name);
431 res = 1;
432 if (0 !=
433 GNUNET_TESTING_peer_run ("test-namestore-api-zone-iteration-stop",
434 cfg_name,
435 &run,
436 NULL))
437 {
438 res = 1;
439 }
440 GNUNET_DISK_purge_cfg_dir (cfg_name,
441 "GNUNET_TEST_HOME");
442 GNUNET_free (plugin_name);
443 GNUNET_free (cfg_name);
444
445 return res;
446}
447
448
449/* end of test_namestore_api_zone_iteration_stop.c */
diff --git a/src/namestore/test_namestore_api_zone_to_name.c b/src/namestore/test_namestore_api_zone_to_name.c
deleted file mode 100644
index c70eef53a..000000000
--- a/src/namestore/test_namestore_api_zone_to_name.c
+++ /dev/null
@@ -1,266 +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 namestore/test_namestore_api_zone_to_name.c
22 * @brief testcase for zone to name translation
23 */
24#include "platform.h"
25#include "gnunet_namestore_service.h"
26#include "gnunet_testing_lib.h"
27#include "namestore.h"
28
29#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
30
31#define RECORDS 5
32
33#define TEST_RECORD_DATALEN 123
34
35#define TEST_RECORD_DATA 'a'
36
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
38
39
40static struct GNUNET_NAMESTORE_Handle *nsh;
41
42static struct GNUNET_SCHEDULER_Task *endbadly_task;
43
44static struct GNUNET_CRYPTO_PrivateKey privkey;
45
46static struct GNUNET_CRYPTO_PublicKey pubkey;
47
48static struct GNUNET_CRYPTO_PublicKey s_zone_value;
49
50static char *s_name;
51
52static int res;
53
54static struct GNUNET_NAMESTORE_QueueEntry *qe;
55
56
57/**
58 * Re-establish the connection to the service.
59 *
60 * @param cls handle to use to re-connect.
61 */
62static void
63endbadly (void *cls)
64{
65 (void) cls;
66 GNUNET_SCHEDULER_shutdown ();
67 res = 1;
68}
69
70
71static void
72end (void *cls)
73{
74 if (NULL != qe)
75 {
76 GNUNET_NAMESTORE_cancel (qe);
77 qe = NULL;
78 }
79 if (NULL != endbadly_task)
80 {
81 GNUNET_SCHEDULER_cancel (endbadly_task);
82 endbadly_task = NULL;
83 }
84 if (NULL != nsh)
85 {
86 GNUNET_NAMESTORE_disconnect (nsh);
87 nsh = NULL;
88 }
89}
90
91
92static void
93zone_to_name_proc (void *cls,
94 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
95 const char *n,
96 unsigned int rd_count,
97 const struct GNUNET_GNSRECORD_Data *rd)
98{
99 int fail = GNUNET_NO;
100
101 qe = NULL;
102 if ((NULL == zone_key) &&
103 (NULL == n) &&
104 (0 == rd_count) &&
105 (NULL == rd))
106 {
107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
108 "No result found\n");
109 res = 1;
110 }
111 else
112 {
113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
114 "Result found: `%s'\n",
115 n);
116 if ((NULL == n) ||
117 (0 != strcmp (n,
118 s_name)))
119 {
120 fail = GNUNET_YES;
121 GNUNET_break (0);
122 }
123 if (1 != rd_count)
124 {
125 fail = GNUNET_YES;
126 GNUNET_break (0);
127 }
128 if ((NULL == zone_key) ||
129 (0 != GNUNET_memcmp (zone_key,
130 &privkey)))
131 {
132 fail = GNUNET_YES;
133 GNUNET_break (0);
134 }
135 if (fail == GNUNET_NO)
136 res = 0;
137 else
138 res = 1;
139 }
140 GNUNET_SCHEDULER_add_now (&end,
141 NULL);
142}
143
144
145static void
146error_cb (void *cls)
147{
148 (void) cls;
149 qe = NULL;
150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
151 "Not found!\n");
152 GNUNET_SCHEDULER_shutdown ();
153 res = 2;
154}
155
156
157static void
158put_cont (void *cls,
159 enum GNUNET_ErrorCode ec)
160{
161 char *name = cls;
162
163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164 "Name store added record for `%s': %s\n",
165 name,
166 (GNUNET_EC_NONE == ec) ?
167 "SUCCESS" : GNUNET_ErrorCode_get_hint (ec));
168 if (GNUNET_EC_NONE == ec)
169 {
170 res = 0;
171
172 qe = GNUNET_NAMESTORE_zone_to_name (nsh,
173 &privkey,
174 &s_zone_value,
175 &error_cb,
176 NULL,
177 &zone_to_name_proc,
178 NULL);
179 }
180 else
181 {
182 res = 1;
183 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
184 "Failed to put records for name `%s'\n",
185 name);
186 GNUNET_SCHEDULER_add_now (&end,
187 NULL);
188 }
189}
190
191
192static void
193run (void *cls,
194 const struct GNUNET_CONFIGURATION_Handle *cfg,
195 struct GNUNET_TESTING_Peer *peer)
196{
197 (void) cls;
198 (void) peer;
199 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
200 &endbadly,
201 NULL);
202 GNUNET_SCHEDULER_add_shutdown (&end,
203 NULL);
204 GNUNET_asprintf (&s_name, "dummy");
205 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
206 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
207 /* get public key */
208 GNUNET_CRYPTO_key_get_public (&privkey,
209 &pubkey);
210
211 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
212 &s_zone_value,
213 sizeof(s_zone_value));
214 s_zone_value.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
215 {
216 struct GNUNET_GNSRECORD_Data rd;
217
218 rd.expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
219 rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
220 rd.data_size = sizeof (s_zone_value.ecdsa_key);
221 rd.data = &s_zone_value.ecdsa_key;
222 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
223
224 nsh = GNUNET_NAMESTORE_connect (cfg);
225 GNUNET_break (NULL != nsh);
226 GNUNET_NAMESTORE_records_store (nsh,
227 &privkey,
228 s_name,
229 1,
230 &rd,
231 &put_cont,
232 s_name);
233 }
234}
235
236
237#include "test_common.c"
238
239
240int
241main (int argc,
242 char *argv[])
243{
244 const char *plugin_name;
245 char *cfg_name;
246
247 (void) argc;
248 SETUP_CFG (plugin_name, cfg_name);
249 res = 1;
250 if (0 !=
251 GNUNET_TESTING_peer_run ("test-namestore-api-zone-to-name",
252 cfg_name,
253 &run,
254 NULL))
255 {
256 res = 1;
257 }
258 GNUNET_DISK_purge_cfg_dir (cfg_name,
259 "GNUNET_TEST_HOME");
260 GNUNET_free (plugin_name);
261 GNUNET_free (cfg_name);
262 return res;
263}
264
265
266/* end of test_namestore_api_zone_to_name.c */
diff --git a/src/namestore/test_namestore_delete.sh b/src/namestore/test_namestore_delete.sh
deleted file mode 100755
index b861a4bc0..000000000
--- a/src/namestore/test_namestore_delete.sh
+++ /dev/null
@@ -1,68 +0,0 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_DOMAIN_PLUS="www.gnu"
19TEST_DOMAIN_DNS="www3.gnu"
20TEST_IP_PLUS="127.0.0.1"
21TEST_IP_DNS="131.159.74.67"
22TEST_RECORD_CNAME_SERVER="server"
23TEST_RECORD_CNAME_PLUS="server.+"
24TEST_RECORD_CNAME_DNS="gnunet.org"
25TEST_RECORD_NAME_SERVER="server"
26TEST_RECORD_NAME_PLUS="www"
27TEST_RECORD_NAME_DNS="www3"
28which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
29
30function start_peer
31{
32 gnunet-arm -s -c $CONFIGURATION
33 gnunet-identity -C testego -c $CONFIGURATION
34}
35
36function stop_peer
37{
38 gnunet-identity -D testego -c $CONFIGURATION
39 gnunet-arm -e -c $CONFIGURATION
40}
41
42
43start_peer
44# Create a public record
45gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME_DNS -t A -V $TEST_IP_PLUS -e never -c $CONFIGURATION
46# Delete record
47gnunet-namestore -p -z testego -d -n $TEST_RECORD_NAME_DNS -t A -V $TEST_IP_PLUS -e never -c $CONFIGURATION
48# List all records
49OUTPUT=`gnunet-namestore -p -z testego -D`
50FOUND_IP=false
51FOUND_NAME=false
52for LINE in $OUTPUT ;
53 do
54 if echo "$LINE" | grep -q "$TEST_RECORD_NAME_DNS"; then
55 FOUND_NAME=true;
56 fi
57 if echo "$LINE" | grep -q "$TEST_IP_PLUS"; then
58 FOUND_IP=true;
59 fi
60 done
61stop_peer
62
63
64if [ $FOUND_IP = true ]
65then
66 echo "FAIL: Delete name in namestore: IP returned"
67 exit 1
68fi
diff --git a/src/namestore/test_namestore_lookup.sh b/src/namestore/test_namestore_lookup.sh
deleted file mode 100755
index 1c96e102a..000000000
--- a/src/namestore/test_namestore_lookup.sh
+++ /dev/null
@@ -1,63 +0,0 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_IP_PLUS="127.0.0.1"
19TEST_RECORD_NAME_DNS="www3"
20which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
21
22# start peer
23gnunet-arm -s -c $CONFIGURATION
24gnunet-identity -C testego -c $CONFIGURATION
25
26# Create a public record
27gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME_DNS -t A -V $TEST_IP_PLUS -e never -c $CONFIGURATION
28NAMESTORE_RES=$?
29# Lookup specific name
30OUTPUT=`gnunet-namestore -p -z testego -n $TEST_RECORD_NAME_DNS -D`
31
32
33FOUND_IP=false
34FOUND_NAME=false
35for LINE in $OUTPUT ;
36 do
37 if echo "$LINE" | grep -q "$TEST_RECORD_NAME_DNS"; then
38 FOUND_NAME=true;
39 #echo $FOUND_NAME
40 fi
41 if echo "$LINE" | grep -q "$TEST_IP_PLUS"; then
42 FOUND_IP=true;
43 #echo $FOUND_IP
44 fi
45done
46# stop peer
47gnunet-identity -D testego -c $CONFIGURATION
48gnunet-arm -e -c $CONFIGURATION
49
50
51if [ $FOUND_NAME = true -a $FOUND_IP = true ]
52then
53 echo "PASS: Lookup name in namestore"
54 exit 0
55elif [ $FOUND_NAME = false ]
56then
57 echo "FAIL: Lookup name in namestore: name not returned"
58 exit 1
59elif [ $FOUND_IP = false ]
60then
61 echo "FAIL: Lookup name in namestore: IP not returned"
62 exit 1
63fi
diff --git a/src/namestore/test_namestore_put.sh b/src/namestore/test_namestore_put.sh
deleted file mode 100755
index eaf7d44b4..000000000
--- a/src/namestore/test_namestore_put.sh
+++ /dev/null
@@ -1,55 +0,0 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_DOMAIN_PLUS="www.gnu"
19TEST_DOMAIN_DNS="www3.gnu"
20TEST_IP_PLUS="127.0.0.1"
21TEST_IP_DNS="131.159.74.67"
22TEST_RECORD_CNAME_SERVER="server"
23TEST_RECORD_CNAME_PLUS="server.+"
24TEST_RECORD_CNAME_DNS="gnunet.org"
25TEST_RECORD_NAME_SERVER="server"
26TEST_RECORD_NAME_PLUS="www"
27TEST_RECORD_NAME_DNS="www3"
28which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
29
30function start_peer
31{
32 gnunet-arm -s -c $CONFIGURATION
33 gnunet-identity -C testego -c $CONFIGURATION
34}
35
36function stop_peer
37{
38 gnunet-identity -D testego -c $CONFIGURATION
39 gnunet-arm -e -c $CONFIGURATION
40}
41
42
43start_peer
44# Create a public record
45gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME_DNS -t A -V $TEST_IP_PLUS -e never -c $CONFIGURATION
46NAMESTORE_RES=$?
47stop_peer
48
49if [ $NAMESTORE_RES = 0 ]
50then
51 echo "PASS: Creating name in namestore"
52else
53 echo "FAIL: Creating name in namestore failed with $NAMESTORE_RES."
54 exit 1
55fi
diff --git a/src/namestore/test_namestore_put_multiple.sh b/src/namestore/test_namestore_put_multiple.sh
deleted file mode 100755
index 4c7340440..000000000
--- a/src/namestore/test_namestore_put_multiple.sh
+++ /dev/null
@@ -1,112 +0,0 @@
1#!/bin/bash
2
3# Check for required packages
4if ! [ -x "$(command -v gnunet-namestore)" ]; then
5 echo 'bind/named is not installed' >&2
6 exit 1
7fi
8
9# Check if gnunet is running
10gnunet-arm -I 2&>1 /dev/null
11ret=$?
12if [ 0 -ne $ret ]; then
13 echo 'gnunet services are not running'
14 exit 1
15fi
16
17## GNUNET part
18# Check if identity exists and deletes and readds it to get rid of entries in zone
19gnunet-identity -d | grep randomtestingid 2>&1 /dev/null
20ret=$?
21
22if [ 0 -ne $ret ]; then
23 gnunet-identity -D randomtestingid
24 gnunet-identity -C randomtestingid
25fi
26
27function get_record_type {
28 arr=$1
29 typ=$(echo -n "${arr[0]}" | cut -d' ' -f1)
30 echo "$typ"
31}
32
33function get_value {
34 arr=$1
35 val=$(echo -n "${arr[0]}" | cut -d' ' -f4-)
36 echo "$val"
37}
38
39function testing {
40 label=$1
41 records=$2
42 recordstring=""
43 typ=$(get_record_type "${records[@]}")
44 for i in "${records[@]}"
45 do
46 recordstring+="$i"$'\n'
47 done
48 echo "$recordstring"
49 gnunet-namestore -a -S <<EOF
50$label.randomtestingid:
51 $recordstring
52EOF
53 ret=$?
54 if [ 0 -ne $ret ]; then
55 echo "failed to add record $label: $recordstring"
56 fi
57 gnunet-gns -t "$typ" -u foo2.randomtestingid 2>&1 /dev/null
58 if [ 0 -ne $ret ]; then
59 echo "record $label could not be found"
60 fi
61}
62
63# TEST CASES
64# 1
65echo "Testing adding of single A record with -R"
66declare -a arr=('A 1200 [r] 127.0.0.1')
67testing test1 "${arr[@]}"
68# 2
69echo "Testing adding of multiple A records with -R"
70declare -a arr=('A 1200 [r] 127.0.0.1' 'A 2400 [r] 127.0.0.2')
71testing test2 "${arr[@]}"
72# 3
73echo "Testing adding of multiple different records with -R"
74declare -a arr=('A 1200 [r] 127.0.0.1' 'AAAA 2400 [r] 2002::')
75testing test3 "${arr[@]}"
76# 4
77echo "Testing adding of single GNS2DNS record with -R"
78declare -a arr=('GNS2DNS 86400 [r] gnu.org@127.0.0.1')
79testing test4 "${arr[@]}"
80# 5
81echo "Testing adding of single GNS2DNS shadow record with -R"
82declare -a arr=('GNS2DNS 86409 [rs] gnu.org@127.0.0.250')
83testing test5 "${arr[@]}"
84# 6
85echo "Testing adding of multiple GNS2DNS record with -R"
86declare -a arr=('GNS2DNS 1 [r] gnunet.org@127.0.0.1' 'GNS2DNS 3600 [s] gnunet.org@127.0.0.2')
87testing test6 "${arr[@]}"
88val=$(gnunet-gns -t GNS2DNS -u test6.randomtestingid)
89if [[ $val == *"127.0.0.1"* ]]; then
90 echo "shadow!"
91fi
92echo "Sleeping to let record expire"
93sleep 5
94val=$(gnunet-gns -t GNS2DNS -u test6.randomtestingid)
95if [[ $val == *"127.0.0.2"* ]]; then
96 echo "no shadow!"
97fi
98# 7
99echo "Testing adding MX record with -R"
100declare -a arr=('MX 3600 [r] 10,mail')
101testing test7 "${arr[@]}"
102# 8
103echo "Testing adding TXT record with -R"
104declare -a arr=('TXT 3600 [r] Pretty_Unicorns')
105testing test8 "${arr[@]}"
106# 8
107#echo "Testing adding TXT record with -R"
108#declare -a arr=('SRV 3600 [r] _autodiscover_old._tcp.bfh.ch.')
109#testing test8 "${arr[@]}"
110
111# CLEANUP
112gnunet-identity -D randomtestingid
diff --git a/src/namestore/test_namestore_put_stdin.sh b/src/namestore/test_namestore_put_stdin.sh
deleted file mode 100755
index deb7bc4cb..000000000
--- a/src/namestore/test_namestore_put_stdin.sh
+++ /dev/null
@@ -1,68 +0,0 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_RECORD_NAME="www3"
19TEST_RECORD_NAME2="www"
20TEST_IP="8.7.6.5"
21TEST_IP2="1.2.3.4"
22
23which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
24
25function start_peer
26{
27 gnunet-arm -s -c $CONFIGURATION
28 gnunet-identity -C testego -c $CONFIGURATION
29 gnunet-identity -C testego2 -c $CONFIGURATION
30}
31
32function stop_peer
33{
34 gnunet-identity -D testego -c $CONFIGURATION
35 gnunet-identity -D testego2 -c $CONFIGURATION
36 gnunet-arm -e -c $CONFIGURATION
37}
38
39
40start_peer
41# Create a public record
42EGOKEY=`gnunet-identity -d | grep testego2 | cut -d' ' -f3`
43gnunet-namestore -a -c $CONFIGURATION -S <<EOF
44$TEST_RECORD_NAME.testego:
45 A 3600000000 [pr] $TEST_IP
46 TXT 21438201833 [r] $TEST_IP2
47
48 TXT 21438201833 [r] aslkdj asdlkjaslkd 232!
49
50$TEST_RECORD_NAME2.testego:
51 AAAA 324241223 [prS] ::dead:beef
52 A 111324241223000000 [pC] 1.1.1.1
53
54www7.$EGOKEY:
55 A 3600000000 [pr] $TEST_IP
56
57EOF
58NAMESTORE_RES=$?
59gnunet-namestore -D -r -c $CONFIGURATION
60stop_peer
61
62if [ $NAMESTORE_RES = 0 ]
63then
64 echo "PASS: Creating name in namestore"
65else
66 echo "FAIL: Creating name in namestore failed with $NAMESTORE_RES."
67 exit 1
68fi
diff --git a/src/namestore/test_namestore_zonefile_import.sh b/src/namestore/test_namestore_zonefile_import.sh
deleted file mode 100755
index d6345257f..000000000
--- a/src/namestore/test_namestore_zonefile_import.sh
+++ /dev/null
@@ -1,33 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_namestore_api.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_namestore_api.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
19
20MY_EGO="myego"
21gnunet-arm -s -c test_namestore_api.conf
22gnunet-identity -C $MY_EGO -c test_namestore_api.conf
23gnunet-namestore-zonefile -c test_namestore_api.conf < example_zonefile
24res=$?
25gnunet-identity -D $MY_EGO -c test_namestore_api.conf
26gnunet-arm -e -c test_namestore_api.conf
27
28if [ $res != 0 ]; then
29 echo "FAIL: Zone import failed."
30 exit 1
31fi
32
33
diff --git a/src/namestore/test_plugin_namestore.c b/src/namestore/test_plugin_namestore.c
deleted file mode 100644
index 388b23f57..000000000
--- a/src/namestore/test_plugin_namestore.c
+++ /dev/null
@@ -1,218 +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 * @file namestore/test_plugin_namestore.c
22 * @brief Test for the namestore plugins
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_namestore_plugin.h"
28#include "gnunet_testing_lib.h"
29
30#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
31
32static int ok;
33
34/**
35 * Name of plugin under test.
36 */
37static const char *plugin_name;
38
39
40/**
41 * Function called when the service shuts down. Unloads our namestore
42 * plugin.
43 *
44 * @param api api to unload
45 */
46static void
47unload_plugin (struct GNUNET_NAMESTORE_PluginFunctions *api)
48{
49 char *libname;
50
51 GNUNET_asprintf (&libname, "libgnunet_plugin_namestore_%s", plugin_name);
52 GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
53 GNUNET_free (libname);
54}
55
56
57/**
58 * Load the namestore plugin.
59 *
60 * @param cfg configuration to pass
61 * @return NULL on error
62 */
63static struct GNUNET_NAMESTORE_PluginFunctions *
64load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
65{
66 struct GNUNET_NAMESTORE_PluginFunctions *ret;
67 char *libname;
68
69 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
70 "Loading `%s' namestore plugin\n",
71 plugin_name);
72 GNUNET_asprintf (&libname,
73 "libgnunet_plugin_namestore_%s",
74 plugin_name);
75 if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void *) cfg)))
76 {
77 fprintf (stderr,
78 "Failed to load plugin `%s'!\n",
79 plugin_name);
80 GNUNET_free (libname);
81 return NULL;
82 }
83 GNUNET_free (libname);
84 if (GNUNET_OK != ret->drop_tables (ret->cls))
85 {
86 GNUNET_break (0);
87 return NULL;
88 }
89 if (GNUNET_OK != ret->create_tables (ret->cls))
90 {
91 GNUNET_break (0);
92 return NULL;
93 }
94 return ret;
95}
96
97
98static void
99test_record (void *cls,
100 uint64_t seq,
101 const struct GNUNET_CRYPTO_PrivateKey *private_key,
102 const char *label,
103 unsigned int rd_count,
104 const struct GNUNET_GNSRECORD_Data *rd)
105{
106 int *idp = cls;
107 int id = *idp;
108 struct GNUNET_CRYPTO_PrivateKey tzone_private_key;
109 char tname[64];
110 unsigned int trd_count = 1 + (id % 1024);
111
112 GNUNET_snprintf (tname, sizeof(tname), "a%u", (unsigned int) id);
113 GNUNET_assert (trd_count == rd_count);
114 for (unsigned int i = 0; i < trd_count; i++)
115 {
116 GNUNET_assert (rd[i].data_size == id % 10);
117 GNUNET_assert (0 == memcmp ("Hello World", rd[i].data, id % 10));
118 GNUNET_assert (rd[i].record_type == TEST_RECORD_TYPE);
119 GNUNET_assert (rd[i].flags == 0);
120 }
121 memset (&tzone_private_key, (id % 241), sizeof(tzone_private_key));
122 GNUNET_assert (0 == strcmp (label, tname));
123 GNUNET_assert (0 == GNUNET_memcmp (&tzone_private_key, private_key));
124}
125
126
127static void
128get_record (struct GNUNET_NAMESTORE_PluginFunctions *nsp, int id)
129{
130 GNUNET_assert (
131 GNUNET_OK ==
132 nsp->iterate_records (nsp->cls, NULL, 0, 1, &test_record, &id));
133}
134
135
136static void
137put_record (struct GNUNET_NAMESTORE_PluginFunctions *nsp, int id)
138{
139 struct GNUNET_CRYPTO_PrivateKey zone_private_key;
140 char label[64];
141 unsigned int rd_count = 1 + (id % 1024);
142 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
143 struct GNUNET_CRYPTO_EcdsaSignature signature;
144
145 GNUNET_snprintf (label, sizeof(label), "a%u", (unsigned int) id);
146 for (unsigned int i = 0; i < rd_count; i++)
147 {
148 rd[i].data = "Hello World";
149 rd[i].data_size = id % 10;
150 rd[i].expiration_time =
151 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES).abs_value_us;
152 rd[i].record_type = TEST_RECORD_TYPE;
153 rd[i].flags = 0;
154 }
155 memset (&zone_private_key, (id % 241), sizeof(zone_private_key));
156 memset (&signature, (id % 243), sizeof(signature));
157 GNUNET_assert (
158 GNUNET_OK ==
159 nsp->store_records (nsp->cls, &zone_private_key, label, rd_count, rd));
160}
161
162
163static void
164run (void *cls,
165 char *const *args,
166 const char *cfgfile,
167 const struct GNUNET_CONFIGURATION_Handle *cfg)
168{
169 struct GNUNET_NAMESTORE_PluginFunctions *nsp;
170
171 ok = 0;
172 nsp = load_plugin (cfg);
173 if (NULL == nsp)
174 {
175 fprintf (
176 stderr,
177 "%s",
178 "Failed to initialize namestore. Database likely not setup, skipping test.\n");
179 return;
180 }
181 put_record (nsp, 1);
182 get_record (nsp, 1);
183#ifndef DARWIN // #5582
184 unload_plugin (nsp);
185#endif
186}
187
188
189int
190main (int argc, char *argv[])
191{
192 char cfg_name[PATH_MAX];
193 char *const xargv[] = { "test-plugin-namestore", "-c", cfg_name, NULL };
194 struct GNUNET_GETOPT_CommandLineOption options[] =
195 { GNUNET_GETOPT_OPTION_END };
196
197 GNUNET_log_setup ("test-plugin-namestore", "WARNING", NULL);
198 plugin_name = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
199 GNUNET_snprintf (cfg_name,
200 sizeof(cfg_name),
201 "test_plugin_namestore_%s.conf",
202 plugin_name);
203 GNUNET_DISK_purge_cfg_dir (cfg_name, "GNUNET_TMP");
204 GNUNET_PROGRAM_run ((sizeof(xargv) / sizeof(char *)) - 1,
205 xargv,
206 "test-plugin-namestore",
207 "nohelp",
208 options,
209 &run,
210 NULL);
211 GNUNET_DISK_purge_cfg_dir (cfg_name, "GNUNET_TMP");
212 if (ok != 0)
213 fprintf (stderr, "Missed some testcases: %d\n", ok);
214 return ok;
215}
216
217
218/* end of test_plugin_namestore.c */
diff --git a/src/namestore/test_plugin_namestore_postgres.conf b/src/namestore/test_plugin_namestore_postgres.conf
deleted file mode 100644
index 140d54623..000000000
--- a/src/namestore/test_plugin_namestore_postgres.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1[namestore-postgres]
2CONFIG = connect_timeout=10 dbname=gnunetcheck
3INIT_ON_CONNECT = YES
4#TEMPORARY_TABLE = YES
diff --git a/src/namestore/test_plugin_namestore_sqlite.conf b/src/namestore/test_plugin_namestore_sqlite.conf
deleted file mode 100644
index 365198db2..000000000
--- a/src/namestore/test_plugin_namestore_sqlite.conf
+++ /dev/null
@@ -1,3 +0,0 @@
1[namestore-sqlite]
2FILENAME = $GNUNET_TMP/gnunet-test-plugin-namestore-sqlite/sqlite.db
3INIT_ON_CONNECT = YES
diff --git a/src/namestore/test_plugin_rest_namestore.sh b/src/namestore/test_plugin_rest_namestore.sh
deleted file mode 100755
index 4f117db8b..000000000
--- a/src/namestore/test_plugin_rest_namestore.sh
+++ /dev/null
@@ -1,131 +0,0 @@
1#!/bin/sh
2trap "gnunet-arm -e -c test_gns_lookup.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_namestore_api.conf -f -s paths -o GNUNET_TEST_HOME`
17
18namestore_link="http://localhost:7776/namestore"
19wrong_link="http://localhost:7776/namestoreandmore"
20
21curl_get () {
22 #$1 is link
23 #$2 is grep
24 resp=$(curl -v "$1" 2>&1)
25 cache="$(echo $resp | grep "$2")"
26 #echo $cache
27 if [ "" = "$cache" ]
28 then
29 echo "Error in get response: $resp, expected $2"
30 gnunet-arm -e -c test_namestore_api.conf
31 exit 1
32 fi
33}
34
35curl_post () {
36 #$1 is link
37 #$2 is data
38 #$3 is grep
39 resp=$(curl -v -X "POST" "$1" --data "$2" 2>&1)
40 cache="$(echo $resp | grep "$3")"
41 #echo $cache
42 if [ "" = "$cache" ]
43 then
44 echo "Error in post response: $resp ($2), expected $3"
45 gnunet-arm -e -c test_namestore_api.conf
46 exit 1
47 fi
48}
49
50curl_delete () {
51 #$1 is link
52 #$2 is grep
53 resp=$(curl -v -X "DELETE" "$1" 2>&1)
54 cache="$(echo $resp | grep "$2")"
55 #echo $cache
56 if [ "" = "$cache" ]
57 then
58 echo "Error in delete response: $resp, expected $2"
59 gnunet-arm -e -c test_namestore_api.conf
60 exit 1
61 fi
62}
63
64# curl_put () {
65# #$1 is link
66# #$2 is data
67# #$3 is grep
68# cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")"
69# #echo $cache
70# if [ "" == "$cache" ]
71# then
72# exit 1
73# fi
74# }
75
76#Test subsystem default identity
77
78TEST_ID="test"
79gnunet-arm -s -c test_namestore_api.conf
80#Test GET
81gnunet-identity -C $TEST_ID -c test_namestore_api.conf
82test="$(gnunet-namestore -D -z $TEST_ID -c test_namestore_api.conf)"
83name=$TEST_ID
84public="$(gnunet-identity -d -c test_namestore_api.conf | grep $TEST_ID | awk 'NR==1{print $3}')"
85echo "$name $public"
86gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "000G006WVZ8HQ5YTVFNX09HK0VJVVQ9ZCBYDSCH3ERT04N5ZRBKEB82EP8" -t "PKEY" -c test_namestore_api.conf
87sleep 1
88gnunet-arm -i rest -c test_namestore_api.conf
89sleep 1
90curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK"
91curl_get "${namestore_link}/$public" "error"
92gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf
93
94#Test POST with NAME
95curl_post "${namestore_link}/$name" '{"data": [{"value":"000G006WVZ8HQ5YTVFNX09HK0VJVVQ9ZCBYDSCH3ERT04N5ZRBKEB82EP8", "record_type":"PKEY", "relative_expiration": 86400000000, "is_relative_expiration": false, "is_supplemental": false, "is_shadow": false, "is_private": false}],"record_name":"test_entry"}' "HTTP/1.1 204 No Content"
96gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
97
98# invalid values
99curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "relative_expiration": 86400000000, "is_relative_expiration": false, "is_supplemental": false, "is_shadow": false, "is_private": false}],"record_name":"test_entry"}' "error"
100gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
101
102
103curl_post "${namestore_link}/$name" '{"data": [{"value":"", "record_type":"PKEY", "relative_expiration": 86400000000,"flag":0,"record_name"}]:"test_entry"}' "error"
104gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
105
106curl_post "${namestore_link}/$name" '{"data": [{"record_type":"PKEY", "relative_expiration": 86400000000,"flag":0}],"record_name":"test_entry"}' "error"
107gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
108
109#expirations
110curl_post "${namestore_link}/$name" '{"data": [{"value":"000G006WVZ8HQ5YTVFNX09HK0VJVVQ9ZCBYDSCH3ERT04N5ZRBKEB82EP8", "record_type":"PKEY", "relative_expiration":0, "is_relative_expiration": true, "is_supplemental": false, "is_shadow": false, "is_private": false}],"record_name":"test_entry"}' "HTTP/1.1 204"
111gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
112
113curl_post "${namestore_link}/$name" '{"data": [{"value":"000G006WVZ8HQ5YTVFNX09HK0VJVVQ9ZCBYDSCH3ERT04N5ZRBKEB82EP8", "record_type":"PKEY", "relative_expiration":864000000000000, "is_relative_expiration": true, "is_supplemental": false, "is_shadow": false, "is_private": false}],"record_name":"test_entry"}' "HTTP/1.1 204"
114gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
115
116curl_post "${namestore_link}/$name" '{"data": [{"value":"000G006WVZ8HQ5YTVFNX09HK0VJVVQ9ZCBYDSCH3ERT04N5ZRBKEB82EP8", "record_type":"PKEY", "expiration_time_missing":"1d", "is_relative_expiration": false, "is_supplemental": false, "is_shadow": false, "is_private": false}],"record_name":"test_entry"}' "error"
117gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
118
119#record_name
120curl_post "${namestore_link}/$name" '{"data": [{"value":"000G006WVZ8HQ5YTVFNX09HK0VJVVQ9ZCBYDSCH3ERT04N5ZRBKEB82EP8", "record_type":"PKEY", "relative_expiration":86400000000, "is_relative_expiration": false, "is_supplemental": false, "is_shadow": false, "is_private": false}],"record_name":""}' "error"
121gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
122curl_post "${namestore_link}/$name" '{"data": [{"value":"000G006WVZ8HQ5YTVFNX09HK0VJVVQ9ZCBYDSCH3ERT04N5ZRBKEB82EP8", "record_type":"PKEY", "relative_expiration":"1d", "is_relative_expiration": false, "is_supplemental": false, "is_shadow": false, "is_private": false}],"record_name_missing":"test_entry"}' "error"
123gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1
124
125#Test DELETE
126gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "000G006WVZ8HQ5YTVFNX09HK0VJVVQ9ZCBYDSCH3ERT04N5ZRBKEB82EP8" -t "PKEY" -c test_namestore_api.conf
127curl_delete "${namestore_link}/$name/test_entry" "HTTP/1.1 204"
128
129gnunet-arm -e -c test_namestore_api.conf
130exit 0;
131