aboutsummaryrefslogtreecommitdiff
path: root/src/namestore
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore')
-rw-r--r--src/namestore/.gitignore39
-rw-r--r--src/namestore/Makefile.am246
-rw-r--r--src/namestore/gnunet-namestore-dbtool.c189
-rw-r--r--src/namestore/gnunet-service-namestore.c784
-rw-r--r--src/namestore/namestore.conf.in6
-rw-r--r--src/namestore/namestore.h124
-rw-r--r--src/namestore/namestore_api.c365
-rw-r--r--src/namestore/namestore_api_monitor.c76
-rw-r--r--src/namestore/perf_namestore_api_flat.conf10
-rw-r--r--src/namestore/perf_namestore_api_postgres.conf1
-rw-r--r--src/namestore/perf_namestore_api_sqlite.conf1
-rw-r--r--src/namestore/plugin_namestore_flat.c818
-rw-r--r--src/namestore/plugin_namestore_postgres.c351
-rw-r--r--src/namestore/plugin_namestore_sqlite.c321
-rw-r--r--src/namestore/plugin_rest_namestore.c163
-rw-r--r--src/namestore/test_common.c10
-rw-r--r--src/namestore/test_namestore_api.conf6
-rw-r--r--src/namestore/test_namestore_api_edit_records.c404
-rw-r--r--src/namestore/test_namestore_api_flat.conf7
-rw-r--r--src/namestore/test_namestore_api_monitoring_existing.c41
-rw-r--r--src/namestore/test_namestore_api_postgres.conf3
-rw-r--r--src/namestore/test_namestore_api_sqlite.conf1
-rw-r--r--src/namestore/test_namestore_api_tx_rollback.c268
-rw-r--r--src/namestore/test_plugin_namestore_flat.conf2
-rw-r--r--src/namestore/test_plugin_namestore_postgres.conf1
-rw-r--r--src/namestore/test_plugin_namestore_sqlite.conf1
-rwxr-xr-xsrc/namestore/test_plugin_rest_namestore.sh1
27 files changed, 2610 insertions, 1629 deletions
diff --git a/src/namestore/.gitignore b/src/namestore/.gitignore
index f159cdaff..907361276 100644
--- a/src/namestore/.gitignore
+++ b/src/namestore/.gitignore
@@ -1,5 +1,6 @@
1gnunet-service-namestore 1gnunet-service-namestore
2gnunet-namestore 2gnunet-namestore
3gnunet-namestore-dbtool
3gnunet-namestore-fcfsd 4gnunet-namestore-fcfsd
4test_namestore_api_lookup_nick.nc 5test_namestore_api_lookup_nick.nc
5test_namestore_api_lookup_private.nc 6test_namestore_api_lookup_private.nc
@@ -18,71 +19,39 @@ test_namestore_api_zone_iteration_specific_zone.nc
18test_namestore_api_zone_iteration_stop.nc 19test_namestore_api_zone_iteration_stop.nc
19test_plugin_namestore_postgres 20test_plugin_namestore_postgres
20test_plugin_namestore_sqlite 21test_plugin_namestore_sqlite
21test_plugin_namestore_flat
22gnunet-zoneimport 22gnunet-zoneimport
23test_namestore_api_lookup_nick_flat
24test_namestore_api_lookup_nick_postgres 23test_namestore_api_lookup_nick_postgres
25test_namestore_api_lookup_nick_sqlite 24test_namestore_api_lookup_nick_sqlite
26test_namestore_api_lookup_private_flat
27test_namestore_api_lookup_private_postgres 25test_namestore_api_lookup_private_postgres
28test_namestore_api_lookup_private_sqlite 26test_namestore_api_lookup_private_sqlite
29test_namestore_api_lookup_public_flat
30test_namestore_api_lookup_public_postgres 27test_namestore_api_lookup_public_postgres
31test_namestore_api_lookup_public_sqlite 28test_namestore_api_lookup_public_sqlite
32test_namestore_api_lookup_shadow_filter_flat
33test_namestore_api_lookup_shadow_filter_postgres 29test_namestore_api_lookup_shadow_filter_postgres
34test_namestore_api_lookup_shadow_filter_sqlite 30test_namestore_api_lookup_shadow_filter_sqlite
35test_namestore_api_lookup_shadow_flat
36test_namestore_api_lookup_shadow_postgres 31test_namestore_api_lookup_shadow_postgres
37test_namestore_api_lookup_shadow_sqlite 32test_namestore_api_lookup_shadow_sqlite
38test_namestore_api_monitoring_existing_flat
39test_namestore_api_monitoring_existing_postgres 33test_namestore_api_monitoring_existing_postgres
40test_namestore_api_monitoring_existing_sqlite 34test_namestore_api_monitoring_existing_sqlite
41test_namestore_api_monitoring_flat
42test_namestore_api_monitoring_postgres 35test_namestore_api_monitoring_postgres
43test_namestore_api_monitoring_sqlite 36test_namestore_api_monitoring_sqlite
44test_namestore_api_remove_flat
45test_namestore_api_remove_not_existing_record_flat
46test_namestore_api_remove_not_existing_record_postgres 37test_namestore_api_remove_not_existing_record_postgres
47test_namestore_api_remove_not_existing_record_sqlite 38test_namestore_api_remove_not_existing_record_sqlite
48test_namestore_api_remove_postgres 39test_namestore_api_remove_postgres
49test_namestore_api_remove_sqlite 40test_namestore_api_remove_sqlite
50test_namestore_api_store_flat
51test_namestore_api_store_postgres 41test_namestore_api_store_postgres
52test_namestore_api_store_sqlite 42test_namestore_api_store_sqlite
53test_namestore_api_store_update_flat
54test_namestore_api_store_update_postgres 43test_namestore_api_store_update_postgres
55test_namestore_api_store_update_sqlite 44test_namestore_api_store_update_sqlite
56test_namestore_api_zone_iteration_flat
57test_namestore_api_zone_iteration_nick_flat
58test_namestore_api_zone_iteration_nick_postgres 45test_namestore_api_zone_iteration_nick_postgres
59test_namestore_api_zone_iteration_nick_sqlite 46test_namestore_api_zone_iteration_nick_sqlite
60test_namestore_api_zone_iteration_postgres 47test_namestore_api_zone_iteration_postgres
61test_namestore_api_zone_iteration_specific_zone_flat
62test_namestore_api_zone_iteration_specific_zone_postgres 48test_namestore_api_zone_iteration_specific_zone_postgres
63test_namestore_api_zone_iteration_specific_zone_sqlite 49test_namestore_api_zone_iteration_specific_zone_sqlite
64test_namestore_api_zone_iteration_sqlite 50test_namestore_api_zone_iteration_sqlite
65test_namestore_api_zone_iteration_stop_flat
66test_namestore_api_zone_iteration_stop_postgres 51test_namestore_api_zone_iteration_stop_postgres
67test_namestore_api_zone_iteration_stop_sqlite 52test_namestore_api_zone_iteration_stop_sqlite
68test_namestore_api_zone_to_name_flat
69test_namestore_api_zone_to_name_postgres 53test_namestore_api_zone_to_name_postgres
70test_namestore_api_zone_to_name_sqlite 54test_namestore_api_zone_to_name_sqlite
71test_namestore_api_lookup_nick_flat 55test_namestore_api_tx_rollback_postgres
72test_namestore_api_lookup_private_flat 56test_namestore_api_tx_rollback_sqlite
73test_namestore_api_lookup_public_flat 57test_namestore_api_edit_records_postgres
74test_namestore_api_lookup_shadow_filter_flat
75test_namestore_api_lookup_shadow_flat
76test_namestore_api_monitoring_existing_flat
77test_namestore_api_monitoring_flat
78test_namestore_api_remove_flat
79test_namestore_api_remove_not_existing_record_flat
80test_namestore_api_store_flat
81test_namestore_api_store_update_flat
82test_namestore_api_zone_iteration_flat
83test_namestore_api_zone_iteration_nick_flat
84test_namestore_api_zone_iteration_specific_zone_flat
85test_namestore_api_zone_iteration_stop_flat
86test_namestore_api_zone_to_name_flat
87test_plugin_namestore_flat
88perf_namestore_api_zone_iteration_flat
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index 51708dd67..d5e110206 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -15,25 +15,6 @@ if USE_COVERAGE
15 XLIBS = -lgcov 15 XLIBS = -lgcov
16endif 16endif
17 17
18HEAP_PLUGIN = libgnunet_plugin_namestore_flat.la
19HEAP_TESTS = test_plugin_namestore_flat \
20 test_namestore_api_store_flat \
21 test_namestore_api_store_update_flat \
22 test_namestore_api_remove_flat \
23 test_namestore_api_zone_iteration_flat \
24 test_namestore_api_lookup_nick_flat \
25 test_namestore_api_monitoring_flat \
26 test_namestore_api_lookup_public_flat \
27 test_namestore_api_lookup_private_flat \
28 test_namestore_api_lookup_shadow_flat \
29 test_namestore_api_lookup_shadow_filter_flat \
30 test_namestore_api_remove_not_existing_record_flat \
31 test_namestore_api_zone_iteration_nick_flat \
32 test_namestore_api_zone_iteration_specific_zone_flat \
33 test_namestore_api_zone_iteration_stop_flat \
34 test_namestore_api_monitoring_existing_flat \
35 test_namestore_api_zone_to_name_flat \
36 perf_namestore_api_zone_iteration_flat
37 18
38if HAVE_SQLITE 19if HAVE_SQLITE
39SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la 20SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la
@@ -54,9 +35,11 @@ SQLITE_TESTS = test_plugin_namestore_sqlite \
54 test_namestore_api_zone_iteration_stop_sqlite \ 35 test_namestore_api_zone_iteration_stop_sqlite \
55 test_namestore_api_monitoring_existing_sqlite \ 36 test_namestore_api_monitoring_existing_sqlite \
56 test_namestore_api_zone_to_name_sqlite \ 37 test_namestore_api_zone_to_name_sqlite \
57 perf_namestore_api_zone_iteration_sqlite 38 perf_namestore_api_zone_iteration_sqlite \
39 test_namestore_api_tx_rollback_sqlite
58endif 40endif
59 41
42
60if HAVE_POSTGRESQL 43if HAVE_POSTGRESQL
61POSTGRES_PLUGIN = libgnunet_plugin_namestore_postgres.la 44POSTGRES_PLUGIN = libgnunet_plugin_namestore_postgres.la
62POSTGRES_TESTS = test_plugin_namestore_postgres \ 45POSTGRES_TESTS = test_plugin_namestore_postgres \
@@ -76,14 +59,17 @@ POSTGRES_TESTS = test_plugin_namestore_postgres \
76 test_namestore_api_zone_iteration_stop_postgres \ 59 test_namestore_api_zone_iteration_stop_postgres \
77 test_namestore_api_monitoring_existing_postgres \ 60 test_namestore_api_monitoring_existing_postgres \
78 test_namestore_api_zone_to_name_postgres \ 61 test_namestore_api_zone_to_name_postgres \
79 perf_namestore_api_zone_iteration_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
80endif 67endif
81 68
82if HAVE_SQLITE 69if HAVE_SQLITE
83check_PROGRAMS = \ 70check_PROGRAMS = \
84 $(SQLITE_TESTS) \ 71 $(SQLITE_TESTS) \
85 $(POSTGRES_TESTS) \ 72 $(POSTGRES_TESTS)
86 $(HEAP_TESTS)
87endif 73endif
88 74
89if ENABLE_TEST_RUN 75if ENABLE_TEST_RUN
@@ -104,6 +90,7 @@ libexec_PROGRAMS = \
104 90
105bin_PROGRAMS = \ 91bin_PROGRAMS = \
106 gnunet-namestore \ 92 gnunet-namestore \
93 gnunet-namestore-dbtool \
107 gnunet-zoneimport 94 gnunet-zoneimport
108 95
109libexec_PROGRAMS += \ 96libexec_PROGRAMS += \
@@ -113,7 +100,6 @@ libexec_PROGRAMS += \
113plugin_LTLIBRARIES = \ 100plugin_LTLIBRARIES = \
114 $(SQLITE_PLUGIN) \ 101 $(SQLITE_PLUGIN) \
115 $(POSTGRES_PLUGIN) \ 102 $(POSTGRES_PLUGIN) \
116 $(HEAP_PLUGIN) \
117 $(REST_PLUGIN) 103 $(REST_PLUGIN)
118 104
119 105
@@ -168,6 +154,14 @@ gnunet_namestore_LDADD = \
168 libgnunetnamestore.la \ 154 libgnunetnamestore.la \
169 $(GN_LIBINTL) 155 $(GN_LIBINTL)
170 156
157gnunet_namestore_dbtool_SOURCES = \
158 gnunet-namestore-dbtool.c
159gnunet_namestore_dbtool_LDADD = \
160 $(top_builddir)/src/util/libgnunetutil.la \
161 libgnunetnamestore.la \
162 $(GN_LIBINTL)
163
164
171 165
172gnunet_namestore_fcfsd_SOURCES = \ 166gnunet_namestore_fcfsd_SOURCES = \
173 gnunet-namestore-fcfsd.c 167 gnunet-namestore-fcfsd.c
@@ -195,18 +189,6 @@ gnunet_service_namestore_LDADD = \
195 189
196 190
197 191
198libgnunet_plugin_namestore_flat_la_SOURCES = \
199 plugin_namestore_flat.c
200libgnunet_plugin_namestore_flat_la_LIBADD = \
201 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
202 $(top_builddir)/src/identity/libgnunetidentity.la \
203 $(top_builddir)/src/statistics/libgnunetstatistics.la \
204 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
205 $(LTLIBINTL)
206libgnunet_plugin_namestore_flat_la_LDFLAGS = \
207 $(GN_PLUGIN_LDFLAGS)
208
209
210libgnunet_plugin_namestore_sqlite_la_SOURCES = \ 192libgnunet_plugin_namestore_sqlite_la_SOURCES = \
211 plugin_namestore_sqlite.c 193 plugin_namestore_sqlite.c
212libgnunet_plugin_namestore_sqlite_la_LIBADD = \ 194libgnunet_plugin_namestore_sqlite_la_LIBADD = \
@@ -231,15 +213,6 @@ libgnunet_plugin_namestore_postgres_la_LIBADD = \
231libgnunet_plugin_namestore_postgres_la_LDFLAGS = \ 213libgnunet_plugin_namestore_postgres_la_LDFLAGS = \
232 $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS) 214 $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS)
233 215
234test_namestore_api_store_flat_SOURCES = \
235 test_namestore_api_store.c
236test_namestore_api_store_flat_LDADD = \
237 $(top_builddir)/src/testing/libgnunettesting.la \
238 $(top_builddir)/src/util/libgnunetutil.la \
239 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
240 $(top_builddir)/src/identity/libgnunetidentity.la \
241 libgnunetnamestore.la
242
243test_namestore_api_store_sqlite_SOURCES = \ 216test_namestore_api_store_sqlite_SOURCES = \
244 test_namestore_api_store.c 217 test_namestore_api_store.c
245test_namestore_api_store_sqlite_LDADD = \ 218test_namestore_api_store_sqlite_LDADD = \
@@ -258,16 +231,6 @@ test_namestore_api_store_postgres_LDADD = \
258 $(top_builddir)/src/identity/libgnunetidentity.la \ 231 $(top_builddir)/src/identity/libgnunetidentity.la \
259 libgnunetnamestore.la 232 libgnunetnamestore.la
260 233
261test_namestore_api_store_update_flat_SOURCES = \
262 test_namestore_api_store_update.c
263test_namestore_api_store_update_flat_LDADD = \
264 $(top_builddir)/src/testing/libgnunettesting.la \
265 $(top_builddir)/src/util/libgnunetutil.la \
266 $(top_builddir)/src/identity/libgnunetidentity.la \
267 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
268 $(top_builddir)/src/namecache/libgnunetnamecache.la \
269 libgnunetnamestore.la
270
271test_namestore_api_store_update_sqlite_SOURCES = \ 234test_namestore_api_store_update_sqlite_SOURCES = \
272 test_namestore_api_store_update.c 235 test_namestore_api_store_update.c
273test_namestore_api_store_update_sqlite_LDADD = \ 236test_namestore_api_store_update_sqlite_LDADD = \
@@ -288,16 +251,6 @@ test_namestore_api_store_update_postgres_LDADD = \
288 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 251 $(top_builddir)/src/namecache/libgnunetnamecache.la \
289 libgnunetnamestore.la 252 libgnunetnamestore.la
290 253
291test_namestore_api_lookup_public_flat_SOURCES = \
292 test_namestore_api_lookup_public.c
293test_namestore_api_lookup_public_flat_LDADD = \
294 $(top_builddir)/src/testing/libgnunettesting.la \
295 $(top_builddir)/src/identity/libgnunetidentity.la \
296 $(top_builddir)/src/util/libgnunetutil.la \
297 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
298 $(top_builddir)/src/namecache/libgnunetnamecache.la \
299 libgnunetnamestore.la
300
301test_namestore_api_lookup_public_sqlite_SOURCES = \ 254test_namestore_api_lookup_public_sqlite_SOURCES = \
302 test_namestore_api_lookup_public.c 255 test_namestore_api_lookup_public.c
303test_namestore_api_lookup_public_sqlite_LDADD = \ 256test_namestore_api_lookup_public_sqlite_LDADD = \
@@ -338,26 +291,6 @@ test_namestore_api_lookup_nick_postgres_LDADD = \
338 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 291 $(top_builddir)/src/namecache/libgnunetnamecache.la \
339 libgnunetnamestore.la 292 libgnunetnamestore.la
340 293
341test_namestore_api_lookup_nick_flat_SOURCES = \
342 test_namestore_api_lookup_nick.c
343test_namestore_api_lookup_nick_flat_LDADD = \
344 $(top_builddir)/src/testing/libgnunettesting.la \
345 $(top_builddir)/src/identity/libgnunetidentity.la \
346 $(top_builddir)/src/util/libgnunetutil.la \
347 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
348 $(top_builddir)/src/namecache/libgnunetnamecache.la \
349 libgnunetnamestore.la
350
351test_namestore_api_lookup_private_flat_SOURCES = \
352 test_namestore_api_lookup_private.c
353test_namestore_api_lookup_private_flat_LDADD = \
354 $(top_builddir)/src/testing/libgnunettesting.la \
355 $(top_builddir)/src/identity/libgnunetidentity.la \
356 $(top_builddir)/src/util/libgnunetutil.la \
357 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
358 $(top_builddir)/src/namecache/libgnunetnamecache.la \
359 libgnunetnamestore.la
360
361test_namestore_api_lookup_private_sqlite_SOURCES = \ 294test_namestore_api_lookup_private_sqlite_SOURCES = \
362 test_namestore_api_lookup_private.c 295 test_namestore_api_lookup_private.c
363test_namestore_api_lookup_private_sqlite_LDADD = \ 296test_namestore_api_lookup_private_sqlite_LDADD = \
@@ -378,16 +311,6 @@ test_namestore_api_lookup_private_postgres_LDADD = \
378 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 311 $(top_builddir)/src/namecache/libgnunetnamecache.la \
379 libgnunetnamestore.la 312 libgnunetnamestore.la
380 313
381test_namestore_api_lookup_shadow_flat_SOURCES = \
382 test_namestore_api_lookup_shadow.c
383test_namestore_api_lookup_shadow_flat_LDADD = \
384 $(top_builddir)/src/testing/libgnunettesting.la \
385 $(top_builddir)/src/identity/libgnunetidentity.la \
386 $(top_builddir)/src/util/libgnunetutil.la \
387 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
388 $(top_builddir)/src/namecache/libgnunetnamecache.la \
389 libgnunetnamestore.la
390
391test_namestore_api_lookup_shadow_sqlite_SOURCES = \ 314test_namestore_api_lookup_shadow_sqlite_SOURCES = \
392 test_namestore_api_lookup_shadow.c 315 test_namestore_api_lookup_shadow.c
393test_namestore_api_lookup_shadow_sqlite_LDADD = \ 316test_namestore_api_lookup_shadow_sqlite_LDADD = \
@@ -408,16 +331,6 @@ test_namestore_api_lookup_shadow_postgres_LDADD = \
408 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 331 $(top_builddir)/src/namecache/libgnunetnamecache.la \
409 libgnunetnamestore.la 332 libgnunetnamestore.la
410 333
411test_namestore_api_lookup_shadow_filter_flat_SOURCES = \
412 test_namestore_api_lookup_shadow_filter.c
413test_namestore_api_lookup_shadow_filter_flat_LDADD = \
414 $(top_builddir)/src/testing/libgnunettesting.la \
415 $(top_builddir)/src/util/libgnunetutil.la \
416 $(top_builddir)/src/identity/libgnunetidentity.la \
417 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
418 $(top_builddir)/src/namecache/libgnunetnamecache.la \
419 libgnunetnamestore.la
420
421test_namestore_api_lookup_shadow_filter_sqlite_SOURCES = \ 334test_namestore_api_lookup_shadow_filter_sqlite_SOURCES = \
422 test_namestore_api_lookup_shadow_filter.c 335 test_namestore_api_lookup_shadow_filter.c
423test_namestore_api_lookup_shadow_filter_sqlite_LDADD = \ 336test_namestore_api_lookup_shadow_filter_sqlite_LDADD = \
@@ -455,24 +368,6 @@ test_namestore_api_remove_postgres_LDADD = \
455 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 368 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
456 libgnunetnamestore.la 369 libgnunetnamestore.la
457 370
458test_namestore_api_remove_flat_SOURCES = \
459 test_namestore_api_remove.c
460test_namestore_api_remove_flat_LDADD = \
461 $(top_builddir)/src/testing/libgnunettesting.la \
462 $(top_builddir)/src/identity/libgnunetidentity.la \
463 $(top_builddir)/src/util/libgnunetutil.la \
464 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
465 libgnunetnamestore.la
466
467test_namestore_api_remove_not_existing_record_flat_SOURCES = \
468 test_namestore_api_remove_not_existing_record.c
469test_namestore_api_remove_not_existing_record_flat_LDADD = \
470 $(top_builddir)/src/testing/libgnunettesting.la \
471 $(top_builddir)/src/identity/libgnunetidentity.la \
472 $(top_builddir)/src/util/libgnunetutil.la \
473 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
474 libgnunetnamestore.la
475
476test_namestore_api_remove_not_existing_record_sqlite_SOURCES = \ 371test_namestore_api_remove_not_existing_record_sqlite_SOURCES = \
477 test_namestore_api_remove_not_existing_record.c 372 test_namestore_api_remove_not_existing_record.c
478test_namestore_api_remove_not_existing_record_sqlite_LDADD = \ 373test_namestore_api_remove_not_existing_record_sqlite_LDADD = \
@@ -491,14 +386,6 @@ test_namestore_api_remove_not_existing_record_postgres_LDADD = \
491 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 386 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
492 libgnunetnamestore.la 387 libgnunetnamestore.la
493 388
494test_namestore_api_zone_to_name_flat_SOURCES = \
495 test_namestore_api_zone_to_name.c
496test_namestore_api_zone_to_name_flat_LDADD = \
497 $(top_builddir)/src/identity/libgnunetidentity.la \
498 $(top_builddir)/src/testing/libgnunettesting.la \
499 $(top_builddir)/src/util/libgnunetutil.la \
500 libgnunetnamestore.la
501
502test_namestore_api_zone_to_name_sqlite_SOURCES = \ 389test_namestore_api_zone_to_name_sqlite_SOURCES = \
503 test_namestore_api_zone_to_name.c 390 test_namestore_api_zone_to_name.c
504test_namestore_api_zone_to_name_sqlite_LDADD = \ 391test_namestore_api_zone_to_name_sqlite_LDADD = \
@@ -515,15 +402,6 @@ test_namestore_api_zone_to_name_postgres_LDADD = \
515 $(top_builddir)/src/util/libgnunetutil.la \ 402 $(top_builddir)/src/util/libgnunetutil.la \
516 libgnunetnamestore.la 403 libgnunetnamestore.la
517 404
518test_namestore_api_monitoring_flat_SOURCES = \
519 test_namestore_api_monitoring.c
520test_namestore_api_monitoring_flat_LDADD = \
521 $(top_builddir)/src/testing/libgnunettesting.la \
522 libgnunetnamestore.la \
523 $(top_builddir)/src/identity/libgnunetidentity.la \
524 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
525 $(top_builddir)/src/util/libgnunetutil.la
526
527test_namestore_api_monitoring_sqlite_SOURCES = \ 405test_namestore_api_monitoring_sqlite_SOURCES = \
528 test_namestore_api_monitoring.c 406 test_namestore_api_monitoring.c
529test_namestore_api_monitoring_sqlite_LDADD = \ 407test_namestore_api_monitoring_sqlite_LDADD = \
@@ -542,41 +420,52 @@ test_namestore_api_monitoring_postgres_LDADD = \
542 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 420 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
543 $(top_builddir)/src/util/libgnunetutil.la 421 $(top_builddir)/src/util/libgnunetutil.la
544 422
545test_namestore_api_monitoring_existing_flat_SOURCES = \ 423test_namestore_api_monitoring_existing_sqlite_SOURCES = \
546 test_namestore_api_monitoring_existing.c 424 test_namestore_api_monitoring_existing.c
547test_namestore_api_monitoring_existing_flat_LDADD = \ 425test_namestore_api_monitoring_existing_sqlite_LDADD = \
548 $(top_builddir)/src/testing/libgnunettesting.la \ 426 $(top_builddir)/src/testing/libgnunettesting.la \
549 $(top_builddir)/src/identity/libgnunetidentity.la \ 427 $(top_builddir)/src/identity/libgnunetidentity.la \
550 libgnunetnamestore.la \ 428 libgnunetnamestore.la \
551 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 429 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
552 $(top_builddir)/src/util/libgnunetutil.la 430 $(top_builddir)/src/util/libgnunetutil.la
553 431
554test_namestore_api_monitoring_existing_sqlite_SOURCES = \ 432test_namestore_api_monitoring_existing_postgres_SOURCES = \
555 test_namestore_api_monitoring_existing.c 433 test_namestore_api_monitoring_existing.c
556test_namestore_api_monitoring_existing_sqlite_LDADD = \ 434test_namestore_api_monitoring_existing_postgres_LDADD = \
557 $(top_builddir)/src/testing/libgnunettesting.la \ 435 $(top_builddir)/src/testing/libgnunettesting.la \
558 $(top_builddir)/src/identity/libgnunetidentity.la \
559 libgnunetnamestore.la \ 436 libgnunetnamestore.la \
560 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 437 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
438 $(top_builddir)/src/identity/libgnunetidentity.la \
561 $(top_builddir)/src/util/libgnunetutil.la 439 $(top_builddir)/src/util/libgnunetutil.la
562 440
563test_namestore_api_monitoring_existing_postgres_SOURCES = \ 441test_namestore_api_tx_rollback_sqlite_SOURCES = \
564 test_namestore_api_monitoring_existing.c 442 test_namestore_api_tx_rollback.c
565test_namestore_api_monitoring_existing_postgres_LDADD = \ 443test_namestore_api_tx_rollback_sqlite_LDADD = \
566 $(top_builddir)/src/testing/libgnunettesting.la \ 444 $(top_builddir)/src/testing/libgnunettesting.la \
445 $(top_builddir)/src/identity/libgnunetidentity.la \
567 libgnunetnamestore.la \ 446 libgnunetnamestore.la \
568 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 447 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
448 $(top_builddir)/src/util/libgnunetutil.la
449
450test_namestore_api_tx_rollback_postgres_SOURCES = \
451 test_namestore_api_tx_rollback.c
452test_namestore_api_tx_rollback_postgres_LDADD = \
453 $(top_builddir)/src/testing/libgnunettesting.la \
569 $(top_builddir)/src/identity/libgnunetidentity.la \ 454 $(top_builddir)/src/identity/libgnunetidentity.la \
455 libgnunetnamestore.la \
456 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
570 $(top_builddir)/src/util/libgnunetutil.la 457 $(top_builddir)/src/util/libgnunetutil.la
571 458
572test_namestore_api_zone_iteration_flat_SOURCES = \ 459if HAVE_EXPERIMENTAL
573 test_namestore_api_zone_iteration.c 460test_namestore_api_edit_records_postgres_SOURCES = \
574test_namestore_api_zone_iteration_flat_LDADD = \ 461 test_namestore_api_edit_records.c
462test_namestore_api_edit_records_postgres_LDADD = \
575 $(top_builddir)/src/testing/libgnunettesting.la \ 463 $(top_builddir)/src/testing/libgnunettesting.la \
576 $(top_builddir)/src/identity/libgnunetidentity.la \ 464 $(top_builddir)/src/identity/libgnunetidentity.la \
577 $(top_builddir)/src/util/libgnunetutil.la \ 465 libgnunetnamestore.la \
578 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 466 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
579 libgnunetnamestore.la 467 $(top_builddir)/src/util/libgnunetutil.la
468endif
580 469
581test_namestore_api_zone_iteration_sqlite_SOURCES = \ 470test_namestore_api_zone_iteration_sqlite_SOURCES = \
582 test_namestore_api_zone_iteration.c 471 test_namestore_api_zone_iteration.c
@@ -614,24 +503,6 @@ perf_namestore_api_zone_iteration_sqlite_LDADD = \
614 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 503 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
615 libgnunetnamestore.la 504 libgnunetnamestore.la
616 505
617perf_namestore_api_zone_iteration_flat_SOURCES = \
618 perf_namestore_api_zone_iteration.c
619perf_namestore_api_zone_iteration_flat_LDADD = \
620 $(top_builddir)/src/testing/libgnunettesting.la \
621 $(top_builddir)/src/identity/libgnunetidentity.la \
622 $(top_builddir)/src/util/libgnunetutil.la \
623 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
624 libgnunetnamestore.la
625
626test_namestore_api_zone_iteration_nick_flat_SOURCES = \
627 test_namestore_api_zone_iteration_nick.c
628test_namestore_api_zone_iteration_nick_flat_LDADD = \
629 $(top_builddir)/src/testing/libgnunettesting.la \
630 $(top_builddir)/src/util/libgnunetutil.la \
631 $(top_builddir)/src/identity/libgnunetidentity.la \
632 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
633 libgnunetnamestore.la
634
635test_namestore_api_zone_iteration_nick_sqlite_SOURCES = \ 506test_namestore_api_zone_iteration_nick_sqlite_SOURCES = \
636 test_namestore_api_zone_iteration_nick.c 507 test_namestore_api_zone_iteration_nick.c
637test_namestore_api_zone_iteration_nick_sqlite_LDADD = \ 508test_namestore_api_zone_iteration_nick_sqlite_LDADD = \
@@ -650,15 +521,6 @@ test_namestore_api_zone_iteration_nick_postgres_LDADD = \
650 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 521 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
651 libgnunetnamestore.la 522 libgnunetnamestore.la
652 523
653test_namestore_api_zone_iteration_specific_zone_flat_SOURCES = \
654 test_namestore_api_zone_iteration_specific_zone.c
655test_namestore_api_zone_iteration_specific_zone_flat_LDADD = \
656 $(top_builddir)/src/testing/libgnunettesting.la \
657 $(top_builddir)/src/identity/libgnunetidentity.la \
658 $(top_builddir)/src/util/libgnunetutil.la \
659 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
660 libgnunetnamestore.la
661
662test_namestore_api_zone_iteration_specific_zone_sqlite_SOURCES = \ 524test_namestore_api_zone_iteration_specific_zone_sqlite_SOURCES = \
663 test_namestore_api_zone_iteration_specific_zone.c 525 test_namestore_api_zone_iteration_specific_zone.c
664test_namestore_api_zone_iteration_specific_zone_sqlite_LDADD = \ 526test_namestore_api_zone_iteration_specific_zone_sqlite_LDADD = \
@@ -677,15 +539,6 @@ test_namestore_api_zone_iteration_specific_zone_postgres_LDADD = \
677 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 539 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
678 libgnunetnamestore.la 540 libgnunetnamestore.la
679 541
680test_namestore_api_zone_iteration_stop_flat_SOURCES = \
681 test_namestore_api_zone_iteration_stop.c
682test_namestore_api_zone_iteration_stop_flat_LDADD = \
683 $(top_builddir)/src/testing/libgnunettesting.la \
684 $(top_builddir)/src/identity/libgnunetidentity.la \
685 $(top_builddir)/src/util/libgnunetutil.la \
686 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
687 libgnunetnamestore.la
688
689test_namestore_api_zone_iteration_stop_sqlite_SOURCES = \ 542test_namestore_api_zone_iteration_stop_sqlite_SOURCES = \
690 test_namestore_api_zone_iteration_stop.c 543 test_namestore_api_zone_iteration_stop.c
691test_namestore_api_zone_iteration_stop_sqlite_LDADD = \ 544test_namestore_api_zone_iteration_stop_sqlite_LDADD = \
@@ -704,13 +557,6 @@ test_namestore_api_zone_iteration_stop_postgres_LDADD = \
704 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 557 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
705 libgnunetnamestore.la 558 libgnunetnamestore.la
706 559
707test_plugin_namestore_flat_SOURCES = \
708 test_plugin_namestore.c
709test_plugin_namestore_flat_LDADD = \
710 $(top_builddir)/src/testing/libgnunettesting.la \
711 $(top_builddir)/src/identity/libgnunetidentity.la \
712 $(top_builddir)/src/util/libgnunetutil.la
713
714test_plugin_namestore_sqlite_SOURCES = \ 560test_plugin_namestore_sqlite_SOURCES = \
715 test_plugin_namestore.c 561 test_plugin_namestore.c
716test_plugin_namestore_sqlite_LDADD = \ 562test_plugin_namestore_sqlite_LDADD = \
@@ -730,20 +576,18 @@ check_SCRIPTS = \
730 test_namestore_lookup.sh \ 576 test_namestore_lookup.sh \
731 test_namestore_delete.sh 577 test_namestore_delete.sh
732 578
733check_SCRIPTS += \ 579# FIXME
734 test_plugin_rest_namestore.sh 580#check_SCRIPTS += \
581# test_plugin_rest_namestore.sh
735 582
736EXTRA_DIST = \ 583EXTRA_DIST = \
737 test_common.c \ 584 test_common.c \
738 test_namestore_api.conf \ 585 test_namestore_api.conf \
739 test_namestore_api_postgres.conf \ 586 test_namestore_api_postgres.conf \
740 test_namestore_api_sqlite.conf \ 587 test_namestore_api_sqlite.conf \
741 test_namestore_api_flat.conf \
742 perf_namestore_api_postgres.conf \ 588 perf_namestore_api_postgres.conf \
743 perf_namestore_api_sqlite.conf \ 589 perf_namestore_api_sqlite.conf \
744 perf_namestore_api_flat.conf \
745 test_plugin_namestore_sqlite.conf \ 590 test_plugin_namestore_sqlite.conf \
746 test_plugin_namestore_postgres.conf \ 591 test_plugin_namestore_postgres.conf \
747 test_plugin_namestore_flat.conf \
748 test_hostkey \ 592 test_hostkey \
749 $(check_SCRIPTS) 593 $(check_SCRIPTS)
diff --git a/src/namestore/gnunet-namestore-dbtool.c b/src/namestore/gnunet-namestore-dbtool.c
new file mode 100644
index 000000000..b0f7e2ab9
--- /dev/null
+++ b/src/namestore/gnunet-namestore-dbtool.c
@@ -0,0 +1,189 @@
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 * Main function that will be run.
64 *
65 * @param cls closure
66 * @param args remaining command-line arguments
67 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
68 * @param cfg configuration
69 */
70static void
71run (void *cls,
72 char *const *args,
73 const char *cfgfile,
74 const struct GNUNET_CONFIGURATION_Handle *cfg)
75{
76 const char *pkey_str;
77 char *db_lib_name;
78 char *emsg;
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, (void *) cfg);
91 if (NULL == pluginname)
92 {
93 fprintf (stderr, "No plugin given!\n");
94 ret = 1;
95 GNUNET_SCHEDULER_shutdown ();
96 return;
97 }
98 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", pluginname);
99 plugin = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
100 if (NULL == plugin)
101 {
102 fprintf (stderr, "Failed to load %s!\n", db_lib_name);
103 ret = 1;
104 GNUNET_SCHEDULER_shutdown ();
105 GNUNET_free (db_lib_name);
106 return;
107 }
108 if (reset)
109 {
110 if (GNUNET_OK != plugin->reset_database (plugin->cls, &emsg))
111 {
112 // FIXME do we want to return a reason?
113 fprintf (stderr, "Failed to reset database: %s\n",
114 emsg);
115 ret = 1;
116 GNUNET_free (emsg);
117 GNUNET_free (db_lib_name);
118 GNUNET_SCHEDULER_shutdown ();
119 return;
120 }
121 }
122 else if (init)
123 {
124 if (GNUNET_OK != plugin->initialize_database (plugin->cls, &emsg))
125 {
126 // FIXME do we want to return a reason?
127 fprintf (stderr, "Failed to initialize database: %s\n",
128 emsg);
129 ret = 1;
130 GNUNET_free (emsg);
131 GNUNET_free (db_lib_name);
132 GNUNET_SCHEDULER_shutdown ();
133 return;
134 }
135 }
136 GNUNET_SCHEDULER_shutdown ();
137 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, plugin));
138 GNUNET_free (db_lib_name);
139}
140
141
142/**
143 * The main function for gnunet-namestore-dbtool.
144 *
145 * @param argc number of arguments from the command line
146 * @param argv command line arguments
147 * @return 0 ok, 1 on error
148 */
149int
150main (int argc, char *const *argv)
151{
152 struct GNUNET_GETOPT_CommandLineOption options[] =
153 { GNUNET_GETOPT_option_flag ('i', "init", gettext_noop (
154 "initialize database"), &init),
155 GNUNET_GETOPT_option_flag ('r',
156 "reset",
157 gettext_noop (
158 "reset database (DANGEROUS: All existing data is lost!"),
159 &reset),
160 GNUNET_GETOPT_option_string (
161 'p',
162 "plugin",
163 "PLUGIN",
164 gettext_noop (
165 "the namestore plugin to work with, e.g. 'sqlite'"),
166 &pluginname),
167 GNUNET_GETOPT_OPTION_END };
168 int lret;
169
170 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
171 return 2;
172
173 GNUNET_log_setup ("gnunet-namestore-dbtool", "WARNING", NULL);
174 if (GNUNET_OK !=
175 (lret = GNUNET_PROGRAM_run (argc,
176 argv,
177 "gnunet-namestore-dbtool",
178 _ (
179 "GNUnet namestore database manipulation tool"),
180 options,
181 &run,
182 NULL)))
183 {
184 GNUNET_free_nz ((void *) argv);
185 return lret;
186 }
187 GNUNET_free_nz ((void *) argv);
188 return ret;
189}
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c
index 6d3cc45ec..fbe188122 100644
--- a/src/namestore/gnunet-service-namestore.c
+++ b/src/namestore/gnunet-service-namestore.c
@@ -85,6 +85,11 @@ struct ZoneIteration
85 struct GNUNET_IDENTITY_PrivateKey zone; 85 struct GNUNET_IDENTITY_PrivateKey zone;
86 86
87 /** 87 /**
88 * The record set filter
89 */
90 enum GNUNET_GNSRECORD_Filter filter;
91
92 /**
88 * Last sequence number in the zone iteration used to address next 93 * Last sequence number in the zone iteration used to address next
89 * result of the zone iteration in the store 94 * result of the zone iteration in the store
90 * 95 *
@@ -132,6 +137,21 @@ struct NamestoreClient
132 struct GNUNET_SERVICE_Client *client; 137 struct GNUNET_SERVICE_Client *client;
133 138
134 /** 139 /**
140 * Database handle for client
141 */
142 struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
143
144 /**
145 * Name of loaded plugin (neeed for cleanup)
146 */
147 char *db_lib_name;
148
149 /**
150 * GNUNET_YES if this nc has begun a transaction which is uncommited.
151 */
152 int in_transaction;
153
154 /**
135 * Message queue for transmission to @e client 155 * Message queue for transmission to @e client
136 */ 156 */
137 struct GNUNET_MQ_Handle *mq; 157 struct GNUNET_MQ_Handle *mq;
@@ -176,6 +196,11 @@ struct ZoneMonitor
176 struct GNUNET_IDENTITY_PrivateKey zone; 196 struct GNUNET_IDENTITY_PrivateKey zone;
177 197
178 /** 198 /**
199 * The record set filter
200 */
201 enum GNUNET_GNSRECORD_Filter filter;
202
203 /**
179 * Task active during initial iteration. 204 * Task active during initial iteration.
180 */ 205 */
181 struct GNUNET_SCHEDULER_Task *task; 206 struct GNUNET_SCHEDULER_Task *task;
@@ -288,20 +313,42 @@ struct StoreActivity
288 struct NamestoreClient *nc; 313 struct NamestoreClient *nc;
289 314
290 /** 315 /**
291 * Copy of the original store message (as data fields in @e rd will 316 * The request ID
317 */
318 uint32_t rid;
319
320 /**
321 * The currently processed record
322 */
323 uint16_t rd_set_pos;
324
325 /**
326 * The number of records in this activity
327 */
328 uint16_t rd_set_count;
329
330 /**
331 * Wheather or not this store action is already commited.
332 * The store activity will not be processed unless this field is GNUNET_YES
333 */
334 int uncommited;
335
336 /**
337 * The zone private key
338 */
339 struct GNUNET_IDENTITY_PrivateKey private_key;
340
341 /**
342 * Copy of the original record set (as data fields in @e rd will
292 * point into it!). 343 * point into it!).
293 */ 344 */
294 const struct RecordStoreMessage *rsm; 345 const struct RecordSet *rs;
295 346
296 /** 347 /**
297 * Next zone monitor that still needs to be notified about this PUT. 348 * Next zone monitor that still needs to be notified about this PUT.
298 */ 349 */
299 struct ZoneMonitor *zm_pos; 350 struct ZoneMonitor *zm_pos;
300 351
301 /**
302 * Label nicely canonicalized (lower case).
303 */
304 char *conv_name;
305}; 352};
306 353
307 354
@@ -353,14 +400,15 @@ static struct GNUNET_STATISTICS_Handle *statistics;
353static struct GNUNET_NAMECACHE_Handle *namecache; 400static struct GNUNET_NAMECACHE_Handle *namecache;
354 401
355/** 402/**
356 * Database handle 403 * Name of the database plugin
357 */ 404 */
358static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database; 405static char *db_lib_name;
359 406
360/** 407/**
361 * Name of the database plugin 408 * Database handle for service
362 */ 409 */
363static char *db_lib_name; 410struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
411
364 412
365/** 413/**
366 * Head of cop DLL. 414 * Head of cop DLL.
@@ -436,9 +484,6 @@ cleanup_task (void *cls)
436 GNUNET_NAMECACHE_disconnect (namecache); 484 GNUNET_NAMECACHE_disconnect (namecache);
437 namecache = NULL; 485 namecache = NULL;
438 } 486 }
439 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
440 GNUNET_free (db_lib_name);
441 db_lib_name = NULL;
442 if (NULL != monitor_nc) 487 if (NULL != monitor_nc)
443 { 488 {
444 GNUNET_notification_context_destroy (monitor_nc); 489 GNUNET_notification_context_destroy (monitor_nc);
@@ -449,6 +494,9 @@ cleanup_task (void *cls)
449 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO); 494 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
450 statistics = NULL; 495 statistics = NULL;
451 } 496 }
497 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
498 GNUNET_free (db_lib_name);
499 db_lib_name = NULL;
452} 500}
453 501
454 502
@@ -461,7 +509,6 @@ static void
461free_store_activity (struct StoreActivity *sa) 509free_store_activity (struct StoreActivity *sa)
462{ 510{
463 GNUNET_CONTAINER_DLL_remove (sa_head, sa_tail, sa); 511 GNUNET_CONTAINER_DLL_remove (sa_head, sa_tail, sa);
464 GNUNET_free (sa->conv_name);
465 GNUNET_free (sa); 512 GNUNET_free (sa);
466} 513}
467 514
@@ -560,6 +607,7 @@ cache_nick (const struct GNUNET_IDENTITY_PrivateKey *zone,
560/** 607/**
561 * Return the NICK record for the zone (if it exists). 608 * Return the NICK record for the zone (if it exists).
562 * 609 *
610 * @param nc the namestore client
563 * @param zone private key for the zone to look for nick 611 * @param zone private key for the zone to look for nick
564 * @return NULL if no NICK record was found 612 * @return NULL if no NICK record was found
565 */ 613 */
@@ -716,38 +764,63 @@ merge_with_nick_records (const struct GNUNET_GNSRECORD_Data *nick_rd,
716 * @param name name 764 * @param name name
717 * @param rd_count number of records in @a rd 765 * @param rd_count number of records in @a rd
718 * @param rd array of records 766 * @param rd array of records
767 * @param filter record set filter
719 */ 768 */
720static void 769static void
721send_lookup_response (struct NamestoreClient *nc, 770send_lookup_response_with_filter (struct NamestoreClient *nc,
722 uint32_t request_id, 771 uint32_t request_id,
723 const struct GNUNET_IDENTITY_PrivateKey *zone_key, 772 const struct
724 const char *name, 773 GNUNET_IDENTITY_PrivateKey *zone_key,
725 unsigned int rd_count, 774 const char *name,
726 const struct GNUNET_GNSRECORD_Data *rd) 775 unsigned int rd_count,
776 const struct GNUNET_GNSRECORD_Data *rd,
777 enum GNUNET_GNSRECORD_Filter filter)
727{ 778{
728 struct GNUNET_MQ_Envelope *env; 779 struct GNUNET_MQ_Envelope *env;
729 struct RecordResultMessage *zir_msg; 780 struct RecordResultMessage *zir_msg;
730 struct GNUNET_GNSRECORD_Data *nick; 781 struct GNUNET_GNSRECORD_Data *nick;
731 struct GNUNET_GNSRECORD_Data *res; 782 struct GNUNET_GNSRECORD_Data *res;
783 struct GNUNET_GNSRECORD_Data rd_nf[rd_count];
784 struct GNUNET_TIME_Absolute block_exp = GNUNET_TIME_UNIT_ZERO_ABS;;
732 unsigned int res_count; 785 unsigned int res_count;
786 unsigned int rd_nf_count;
733 size_t name_len; 787 size_t name_len;
734 ssize_t rd_ser_len; 788 ssize_t rd_ser_len;
735 char *name_tmp; 789 char *name_tmp;
736 char *rd_ser; 790 char *rd_ser;
791 char *emsg;
737 792
738 nick = get_nick_record (zone_key); 793 nick = get_nick_record (zone_key);
739 GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (rd_count, rd)); 794 GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (rd_count, rd));
740 795
796 if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (name,
797 rd,
798 rd_count,
799 rd_nf,
800 &rd_nf_count,
801 &block_exp,
802 filter,
803 &emsg))
804 {
805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
806 GNUNET_free (emsg);
807 GNUNET_assert (0);
808 }
809
810 /**
811 * FIXME if we ever support GNUNET_NAMESTORE_OMIT_PUBLIC,
812 * we need to omit adding this public record here
813 */
741 if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT))) 814 if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT)))
742 { 815 {
743 nick->flags = 816 nick->flags =
744 (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE; 817 (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
745 merge_with_nick_records (nick, rd_count, rd, &res_count, &res); 818 merge_with_nick_records (nick, rd_nf_count, rd_nf, &res_count, &res);
746 } 819 }
747 else 820 else
748 { 821 {
749 res_count = rd_count; 822 res_count = rd_nf_count;
750 res = (struct GNUNET_GNSRECORD_Data *) rd; 823 res = (struct GNUNET_GNSRECORD_Data *) rd_nf;
751 } 824 }
752 if (NULL != nick) 825 if (NULL != nick)
753 GNUNET_free (nick); 826 GNUNET_free (nick);
@@ -759,7 +832,7 @@ send_lookup_response (struct NamestoreClient *nc,
759 rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res); 832 rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res);
760 if (rd_ser_len < 0) 833 if (rd_ser_len < 0)
761 { 834 {
762 if (rd != res) 835 if (rd_nf != res)
763 GNUNET_free (res); 836 GNUNET_free (res);
764 GNUNET_break (0); 837 GNUNET_break (0);
765 GNUNET_SERVICE_client_drop (nc->client); 838 GNUNET_SERVICE_client_drop (nc->client);
@@ -767,7 +840,7 @@ send_lookup_response (struct NamestoreClient *nc,
767 } 840 }
768 if (((size_t) rd_ser_len) >= UINT16_MAX - name_len - sizeof(*zir_msg)) 841 if (((size_t) rd_ser_len) >= UINT16_MAX - name_len - sizeof(*zir_msg))
769 { 842 {
770 if (rd != res) 843 if (rd_nf != res)
771 GNUNET_free (res); 844 GNUNET_free (res);
772 GNUNET_break (0); 845 GNUNET_break (0);
773 GNUNET_SERVICE_client_drop (nc->client); 846 GNUNET_SERVICE_client_drop (nc->client);
@@ -781,6 +854,7 @@ send_lookup_response (struct NamestoreClient *nc,
781 zir_msg->rd_count = htons (res_count); 854 zir_msg->rd_count = htons (res_count);
782 zir_msg->rd_len = htons ((uint16_t) rd_ser_len); 855 zir_msg->rd_len = htons ((uint16_t) rd_ser_len);
783 zir_msg->private_key = *zone_key; 856 zir_msg->private_key = *zone_key;
857 zir_msg->expire = GNUNET_TIME_absolute_hton (block_exp);
784 name_tmp = (char *) &zir_msg[1]; 858 name_tmp = (char *) &zir_msg[1];
785 GNUNET_memcpy (name_tmp, name, name_len); 859 GNUNET_memcpy (name_tmp, name, name_len);
786 rd_ser = &name_tmp[name_len]; 860 rd_ser = &name_tmp[name_len];
@@ -795,10 +869,33 @@ send_lookup_response (struct NamestoreClient *nc,
795 1, 869 1,
796 GNUNET_NO); 870 GNUNET_NO);
797 GNUNET_MQ_send (nc->mq, env); 871 GNUNET_MQ_send (nc->mq, env);
798 if (rd != res) 872 if (rd_nf != res)
799 GNUNET_free (res); 873 GNUNET_free (res);
800} 874}
801 875
876/**
877 * Generate a `struct LookupNameResponseMessage` and send it to the
878 * given client using the given notification context.
879 *
880 * @param nc client to unicast to
881 * @param request_id request ID to use
882 * @param zone_key zone key of the zone
883 * @param name name
884 * @param rd_count number of records in @a rd
885 * @param rd array of records
886 */
887static void
888send_lookup_response (struct NamestoreClient *nc,
889 uint32_t request_id,
890 const struct
891 GNUNET_IDENTITY_PrivateKey *zone_key,
892 const char *name,
893 unsigned int rd_count,
894 const struct GNUNET_GNSRECORD_Data *rd)
895{
896 send_lookup_response_with_filter (nc, request_id, zone_key, name,
897 rd_count, rd, GNUNET_GNSRECORD_FILTER_NONE);
898}
802 899
803/** 900/**
804 * Send response to the store request to the client. 901 * Send response to the store request to the client.
@@ -808,7 +905,7 @@ send_lookup_response (struct NamestoreClient *nc,
808 * @param rid client's request ID 905 * @param rid client's request ID
809 */ 906 */
810static void 907static void
811send_store_response (struct NamestoreClient *nc, int res, const char*emsg, 908send_store_response (struct NamestoreClient *nc, int res, const char *emsg,
812 uint32_t rid) 909 uint32_t rid)
813{ 910{
814 struct GNUNET_MQ_Envelope *env; 911 struct GNUNET_MQ_Envelope *env;
@@ -994,7 +1091,7 @@ refresh_block (struct NamestoreClient *nc,
994 cop->nc = nc; 1091 cop->nc = nc;
995 cop->zi = zi; 1092 cop->zi = zi;
996 if (NULL != zi) 1093 if (NULL != zi)
997 zi->cache_ops ++; 1094 zi->cache_ops++;
998 cop->rid = rid; 1095 cop->rid = rid;
999 GNUNET_CONTAINER_DLL_insert (cop_head, cop_tail, cop); 1096 GNUNET_CONTAINER_DLL_insert (cop_head, cop_tail, cop);
1000 cop->qe = GNUNET_NAMECACHE_block_cache (namecache, 1097 cop->qe = GNUNET_NAMECACHE_block_cache (namecache,
@@ -1034,71 +1131,95 @@ warn_monitor_slow (void *cls)
1034static void 1131static void
1035continue_store_activity (struct StoreActivity *sa) 1132continue_store_activity (struct StoreActivity *sa)
1036{ 1133{
1037 const struct RecordStoreMessage *rp_msg = sa->rsm; 1134 const struct RecordSet *rd_set = sa->rs;
1038 unsigned int rd_count; 1135 unsigned int rd_count;
1039 size_t name_len; 1136 size_t name_len;
1040 size_t rd_ser_len; 1137 size_t rd_ser_len;
1041 uint32_t rid; 1138 uint32_t rid;
1042 const char *name_tmp; 1139 const char *name_tmp;
1043 const char *rd_ser; 1140 const char *rd_ser;
1141 const char *buf;
1142 char *conv_name;
1044 1143
1045 rid = ntohl (rp_msg->gns_header.r_id); 1144 // If we are in a transaction, do not notify monitors or update
1046 name_len = ntohs (rp_msg->name_len); 1145 // cached. This will be done when we are commiting.
1047 rd_count = ntohs (rp_msg->rd_count); 1146 if (GNUNET_YES == sa->uncommited)
1048 rd_ser_len = ntohs (rp_msg->rd_len);
1049 name_tmp = (const char *) &rp_msg[1];
1050 rd_ser = &name_tmp[name_len];
1051 { 1147 {
1052 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; 1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149 "Transaction not yet committed, delaying monitor and cache updates\n");
1150 send_store_response (sa->nc, GNUNET_YES, NULL, sa->rid);
1151 GNUNET_SERVICE_client_continue (sa->nc->client);
1152 return;
1153 }
1154 buf = (const char *) &sa[1];
1155 for (int i = sa->rd_set_pos; i < sa->rd_set_count; i++)
1156 {
1157 rd_set = (struct RecordSet *) buf;
1158 name_len = ntohs (rd_set->name_len);
1159 rd_count = ntohs (rd_set->rd_count);
1160 rd_ser_len = ntohs (rd_set->rd_len);
1161 name_tmp = (const char *) &rd_set[1];
1162 rd_ser = &name_tmp[name_len];
1163 conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
1164 GNUNET_assert (NULL != conv_name);
1165 {
1166 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
1053 1167
1054 /* We did this before, must succeed again */ 1168 /* We did this before, must succeed again */
1055 GNUNET_assert ( 1169 GNUNET_assert (
1056 GNUNET_OK == 1170 GNUNET_OK ==
1057 GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, rd)); 1171 GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count,
1172 rd));
1058 1173
1059 for (struct ZoneMonitor *zm = sa->zm_pos; NULL != zm; zm = sa->zm_pos) 1174 for (struct ZoneMonitor *zm = sa->zm_pos; NULL != zm; zm = sa->zm_pos)
1060 {
1061 if ((0 != GNUNET_memcmp (&rp_msg->private_key, &zm->zone)) &&
1062 (0 != GNUNET_memcmp (&zm->zone, &zero)))
1063 {
1064 sa->zm_pos = zm->next; /* not interesting to this monitor */
1065 continue;
1066 }
1067 if (zm->limit == zm->iteration_cnt)
1068 { 1175 {
1069 zm->sa_waiting = GNUNET_YES; 1176 if ((0 != GNUNET_memcmp (&sa->private_key, &zm->zone)) &&
1070 zm->sa_waiting_start = GNUNET_TIME_absolute_get (); 1177 (0 != GNUNET_memcmp (&zm->zone, &zero)))
1071 if (NULL != zm->sa_wait_warning) 1178 {
1072 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); 1179 sa->zm_pos = zm->next; /* not interesting to this monitor */
1073 zm->sa_wait_warning = 1180 continue;
1074 GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, 1181 }
1075 &warn_monitor_slow, 1182 if (zm->limit == zm->iteration_cnt)
1076 zm); 1183 {
1077 return; /* blocked on zone monitor */ 1184 zm->sa_waiting = GNUNET_YES;
1185 zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
1186 if (NULL != zm->sa_wait_warning)
1187 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
1188 zm->sa_wait_warning =
1189 GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
1190 &warn_monitor_slow,
1191 zm);
1192 GNUNET_free (conv_name);
1193 return; /* blocked on zone monitor */
1194 }
1195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1196 "Notifying monitor about changes under label `%s'\n",
1197 conv_name);
1198 zm->limit--;
1199 send_lookup_response_with_filter (zm->nc,
1200 0,
1201 &sa->private_key,
1202 conv_name,
1203 rd_count,
1204 rd,
1205 zm->filter);
1206 sa->zm_pos = zm->next;
1078 } 1207 }
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1208 /* great, done with the monitors, unpack (again) for refresh_block operation */
1080 "Notifying monitor about changes under label `%s'\n", 1209 sa->rd_set_pos++;
1081 sa->conv_name); 1210 refresh_block ((sa->rd_set_pos == sa->rd_set_count) ? sa->nc : NULL,
1082 zm->limit--; 1211 NULL,
1083 send_lookup_response (zm->nc, 1212 sa->rid,
1084 0, 1213 &sa->private_key,
1085 &rp_msg->private_key, 1214 conv_name,
1086 sa->conv_name, 1215 rd_count,
1087 rd_count, 1216 rd);
1088 rd); 1217 GNUNET_free (conv_name);
1089 sa->zm_pos = zm->next;
1090 } 1218 }
1091 /* great, done with the monitors, unpack (again) for refresh_block operation */
1092 refresh_block (sa->nc,
1093 NULL,
1094 rid,
1095 &rp_msg->private_key,
1096 sa->conv_name,
1097 rd_count,
1098 rd);
1099 } 1219 }
1100 GNUNET_SERVICE_client_continue (sa->nc->client); 1220 GNUNET_SERVICE_client_continue (sa->nc->client);
1101 free_store_activity (sa); 1221 free_store_activity (sa);
1222 return;
1102} 1223}
1103 1224
1104 1225
@@ -1118,13 +1239,43 @@ client_disconnect_cb (void *cls,
1118 struct NamestoreClient *nc = app_ctx; 1239 struct NamestoreClient *nc = app_ctx;
1119 struct ZoneIteration *no; 1240 struct ZoneIteration *no;
1120 struct CacheOperation *cop; 1241 struct CacheOperation *cop;
1242 struct StoreActivity *sa;
1243 struct StoreActivity *sn;
1244 char *emsg;
1121 1245
1122 (void) cls; 1246 (void) cls;
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client); 1247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
1248 if (GNUNET_YES == nc->in_transaction)
1249 {
1250 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1251 "Client in transaction, rolling back...\n");
1252 if (GNUNET_SYSERR == nc->GSN_database->transaction_rollback (
1253 nc->GSN_database->cls,
1254 &emsg))
1255 {
1256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1257 "Unable to roll back: %s\n", emsg);
1258 GNUNET_free (emsg);
1259 }
1260 else
1261 {
1262 nc->in_transaction = GNUNET_NO;
1263 while (NULL != sa)
1264 {
1265 if ((nc != sa->nc) ||
1266 (GNUNET_NO == sa->uncommited))
1267 {
1268 sa = sa->next;
1269 continue;
1270 }
1271 sn = sa->next;
1272 free_store_activity (sa);
1273 sa = sn;
1274 }
1275 }
1276 }
1124 for (struct ZoneMonitor *zm = monitor_head; NULL != zm; zm = zm->next) 1277 for (struct ZoneMonitor *zm = monitor_head; NULL != zm; zm = zm->next)
1125 { 1278 {
1126 struct StoreActivity *san;
1127
1128 if (nc != zm->nc) 1279 if (nc != zm->nc)
1129 continue; 1280 continue;
1130 GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, zm); 1281 GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, zm);
@@ -1138,9 +1289,9 @@ client_disconnect_cb (void *cls,
1138 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); 1289 GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
1139 zm->sa_wait_warning = NULL; 1290 zm->sa_wait_warning = NULL;
1140 } 1291 }
1141 for (struct StoreActivity *sa = sa_head; NULL != sa; sa = san) 1292 for (sa = sa_head; NULL != sa; sa = sn)
1142 { 1293 {
1143 san = sa->next; 1294 sn = sa->next;
1144 if (zm == sa->zm_pos) 1295 if (zm == sa->zm_pos)
1145 { 1296 {
1146 sa->zm_pos = zm->next; 1297 sa->zm_pos = zm->next;
@@ -1168,6 +1319,9 @@ client_disconnect_cb (void *cls,
1168 for (cop = cop_head; NULL != cop; cop = cop->next) 1319 for (cop = cop_head; NULL != cop; cop = cop->next)
1169 if (nc == cop->nc) 1320 if (nc == cop->nc)
1170 cop->nc = NULL; 1321 cop->nc = NULL;
1322 GNUNET_break (NULL == GNUNET_PLUGIN_unload (nc->db_lib_name,
1323 nc->GSN_database));
1324 GNUNET_free (nc->db_lib_name);
1171 GNUNET_free (nc); 1325 GNUNET_free (nc);
1172} 1326}
1173 1327
@@ -1186,12 +1340,36 @@ client_connect_cb (void *cls,
1186 struct GNUNET_MQ_Handle *mq) 1340 struct GNUNET_MQ_Handle *mq)
1187{ 1341{
1188 struct NamestoreClient *nc; 1342 struct NamestoreClient *nc;
1343 char *database;
1189 1344
1190 (void) cls; 1345 (void) cls;
1191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client); 1346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
1192 nc = GNUNET_new (struct NamestoreClient); 1347 nc = GNUNET_new (struct NamestoreClient);
1193 nc->client = client; 1348 nc->client = client;
1194 nc->mq = mq; 1349 nc->mq = mq;
1350 /* Loading database plugin */
1351 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (GSN_cfg,
1352 "namestore",
1353 "database",
1354 &database))
1355 {
1356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
1357 GNUNET_free (nc);
1358 return NULL;
1359 }
1360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading %s\n", db_lib_name);
1361 nc->GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
1362 GNUNET_free (database);
1363 if (NULL == nc->GSN_database)
1364 {
1365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1366 "Could not load database backend `%s'\n",
1367 db_lib_name);
1368 GNUNET_free (nc);
1369 return NULL;
1370 }
1371 nc->db_lib_name = GNUNET_strdup (db_lib_name);
1372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded %s\n", db_lib_name);
1195 return nc; 1373 return nc;
1196} 1374}
1197 1375
@@ -1403,11 +1581,19 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg)
1403 rlc.res_rd = NULL; 1581 rlc.res_rd = NULL;
1404 rlc.rd_ser_len = 0; 1582 rlc.rd_ser_len = 0;
1405 rlc.nick = get_nick_record (&ll_msg->zone); 1583 rlc.nick = get_nick_record (&ll_msg->zone);
1406 res = GSN_database->lookup_records (GSN_database->cls, 1584 if (GNUNET_YES != ntohl (ll_msg->is_edit_request))
1407 &ll_msg->zone, 1585 res = nc->GSN_database->lookup_records (nc->GSN_database->cls,
1408 conv_name, 1586 &ll_msg->zone,
1409 &lookup_it, 1587 conv_name,
1410 &rlc); 1588 &lookup_it,
1589 &rlc);
1590 else
1591 res = nc->GSN_database->edit_records (nc->GSN_database->cls,
1592 &ll_msg->zone,
1593 conv_name,
1594 &lookup_it,
1595 &rlc);
1596
1411 env = 1597 env =
1412 GNUNET_MQ_msg_extra (llr_msg, 1598 GNUNET_MQ_msg_extra (llr_msg,
1413 name_len + rlc.rd_ser_len, 1599 name_len + rlc.rd_ser_len,
@@ -1418,8 +1604,10 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg)
1418 llr_msg->rd_count = htons (rlc.res_rd_count); 1604 llr_msg->rd_count = htons (rlc.res_rd_count);
1419 llr_msg->rd_len = htons (rlc.rd_ser_len); 1605 llr_msg->rd_len = htons (rlc.rd_ser_len);
1420 res_name = (char *) &llr_msg[1]; 1606 res_name = (char *) &llr_msg[1];
1421 if ((GNUNET_YES == rlc.found) && (GNUNET_OK == res)) 1607 if (GNUNET_YES == rlc.found)
1422 llr_msg->found = htons (GNUNET_YES); 1608 llr_msg->found = htons (GNUNET_YES);
1609 else if (GNUNET_SYSERR == res)
1610 llr_msg->found = htons (GNUNET_SYSERR);
1423 else 1611 else
1424 llr_msg->found = htons (GNUNET_NO); 1612 llr_msg->found = htons (GNUNET_NO);
1425 GNUNET_memcpy (&llr_msg[1], conv_name, name_len); 1613 GNUNET_memcpy (&llr_msg[1], conv_name, name_len);
@@ -1441,29 +1629,16 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg)
1441static int 1629static int
1442check_record_store (void *cls, const struct RecordStoreMessage *rp_msg) 1630check_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1443{ 1631{
1444 size_t name_len;
1445 size_t msg_size; 1632 size_t msg_size;
1446 size_t msg_size_exp; 1633 size_t min_size_exp;
1447 size_t rd_ser_len; 1634 size_t rd_set_count;
1448 const char *name_tmp;
1449 1635
1450 (void) cls; 1636 (void) cls;
1451 name_len = ntohs (rp_msg->name_len);
1452 msg_size = ntohs (rp_msg->gns_header.header.size); 1637 msg_size = ntohs (rp_msg->gns_header.header.size);
1453 rd_ser_len = ntohs (rp_msg->rd_len); 1638 rd_set_count = ntohs (rp_msg->rd_set_count);
1454 msg_size_exp = sizeof(struct RecordStoreMessage) + name_len + rd_ser_len; 1639 min_size_exp = sizeof(struct RecordStoreMessage) + sizeof (struct RecordSet)
1455 if (msg_size != msg_size_exp) 1640 * rd_set_count;
1456 { 1641 if (msg_size < min_size_exp)
1457 GNUNET_break (0);
1458 return GNUNET_SYSERR;
1459 }
1460 if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1461 {
1462 GNUNET_break (0);
1463 return GNUNET_SYSERR;
1464 }
1465 name_tmp = (const char *) &rp_msg[1];
1466 if ('\0' != name_tmp[name_len - 1])
1467 { 1642 {
1468 GNUNET_break (0); 1643 GNUNET_break (0);
1469 return GNUNET_SYSERR; 1644 return GNUNET_SYSERR;
@@ -1496,13 +1671,15 @@ get_block_exp_existing (void *cls,
1496 unsigned int rd_pub_count; 1671 unsigned int rd_pub_count;
1497 char *emsg; 1672 char *emsg;
1498 1673
1499 if (GNUNET_OK != GNUNET_GNSRECORD_convert_records_for_export (label, 1674 if (GNUNET_OK !=
1500 rd, 1675 GNUNET_GNSRECORD_normalize_record_set (label,
1501 rd_count, 1676 rd,
1502 rd_pub, 1677 rd_count,
1503 &rd_pub_count, 1678 rd_pub,
1504 exp, 1679 &rd_pub_count,
1505 &emsg)) 1680 exp,
1681 GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE,
1682 &emsg))
1506 { 1683 {
1507 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1508 "%s\n", emsg); 1685 "%s\n", emsg);
@@ -1510,42 +1687,33 @@ get_block_exp_existing (void *cls,
1510 } 1687 }
1511} 1688}
1512 1689
1513 1690static enum GNUNET_GenericReturnValue
1514/** 1691store_record_set (struct NamestoreClient *nc,
1515 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message 1692 const struct GNUNET_IDENTITY_PrivateKey *private_key,
1516 * 1693 const struct RecordSet *rd_set,
1517 * @param cls client sending the message 1694 ssize_t *len,
1518 * @param rp_msg message of type `struct RecordStoreMessage` 1695 char **emsg)
1519 */
1520static void
1521handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1522{ 1696{
1523 struct NamestoreClient *nc = cls;
1524 size_t name_len; 1697 size_t name_len;
1525 size_t rd_ser_len; 1698 size_t rd_ser_len;
1526 uint32_t rid;
1527 const char *name_tmp; 1699 const char *name_tmp;
1528 char *conv_name;
1529 const char *rd_ser; 1700 const char *rd_ser;
1701 char *conv_name;
1530 unsigned int rd_count; 1702 unsigned int rd_count;
1531 int res; 1703 int res;
1532 struct StoreActivity *sa;
1533 struct GNUNET_TIME_Absolute existing_block_exp; 1704 struct GNUNET_TIME_Absolute existing_block_exp;
1534 struct GNUNET_TIME_Absolute new_block_exp; 1705 struct GNUNET_TIME_Absolute new_block_exp;
1535 1706 *len = sizeof (struct RecordSet);
1536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1707
1537 "Received NAMESTORE_RECORD_STORE message\n"); 1708 name_len = ntohs (rd_set->name_len);
1538 existing_block_exp = GNUNET_TIME_UNIT_ZERO_ABS; 1709 *len += name_len;
1539 new_block_exp = GNUNET_TIME_UNIT_ZERO_ABS; 1710 rd_count = ntohs (rd_set->rd_count);
1540 rid = ntohl (rp_msg->gns_header.r_id); 1711 rd_ser_len = ntohs (rd_set->rd_len);
1541 name_len = ntohs (rp_msg->name_len); 1712 *len += rd_ser_len;
1542 rd_count = ntohs (rp_msg->rd_count); 1713 name_tmp = (const char *) &rd_set[1];
1543 rd_ser_len = ntohs (rp_msg->rd_len);
1544 name_tmp = (const char *) &rp_msg[1];
1545 rd_ser = &name_tmp[name_len]; 1714 rd_ser = &name_tmp[name_len];
1546 { 1715 {
1547 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; 1716 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
1548 char *emsg;
1549 1717
1550 /* Extracting and converting private key */ 1718 /* Extracting and converting private key */
1551 conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp); 1719 conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
@@ -1554,33 +1722,27 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1554 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1722 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1555 "Error normalizing name `%s'\n", 1723 "Error normalizing name `%s'\n",
1556 name_tmp); 1724 name_tmp);
1557 send_store_response (nc, GNUNET_SYSERR, _ ("Error normalizing name."), 1725 *emsg = GNUNET_strdup (_ ("Error normalizing name."));
1558 rid); 1726 return GNUNET_SYSERR;
1559 GNUNET_SERVICE_client_continue (nc->client);
1560 return;
1561 } 1727 }
1562 1728
1563 /* Check name for validity */ 1729 /* Check name for validity */
1564 if (GNUNET_OK != GNUNET_GNSRECORD_label_check (conv_name, &emsg)) 1730 if (GNUNET_OK != GNUNET_GNSRECORD_label_check (conv_name, emsg))
1565 { 1731 {
1566 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1732 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1567 "Label invalid: `%s'\n", 1733 "Label invalid: `%s'\n",
1568 emsg); 1734 *emsg);
1569 send_store_response (nc, GNUNET_SYSERR, emsg, rid);
1570 GNUNET_free (emsg);
1571 GNUNET_free (conv_name); 1735 GNUNET_free (conv_name);
1572 GNUNET_SERVICE_client_continue (nc->client); 1736 return -1;
1573 return;
1574 } 1737 }
1575 1738
1576 if (GNUNET_OK != 1739 if (GNUNET_OK !=
1577 GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, rd)) 1740 GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count,
1741 rd))
1578 { 1742 {
1579 send_store_response (nc, GNUNET_SYSERR, 1743 *emsg = GNUNET_strdup (_ ("Error deserializing records."));
1580 _ ("Error deserializing records."), rid);
1581 GNUNET_free (conv_name); 1744 GNUNET_free (conv_name);
1582 GNUNET_SERVICE_client_continue (nc->client); 1745 return GNUNET_SYSERR;
1583 return;
1584 } 1746 }
1585 1747
1586 GNUNET_STATISTICS_update (statistics, 1748 GNUNET_STATISTICS_update (statistics,
@@ -1591,11 +1753,13 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1591 "Creating %u records for name `%s'\n", 1753 "Creating %u records for name `%s'\n",
1592 (unsigned int) rd_count, 1754 (unsigned int) rd_count,
1593 conv_name); 1755 conv_name);
1594 if ((GNUNET_NO == GSN_database->lookup_records (GSN_database->cls, 1756 if ((GNUNET_NO == nc->GSN_database->lookup_records (nc->GSN_database->cls,
1595 &rp_msg->private_key, 1757 private_key,
1596 conv_name, 1758 conv_name,
1597 &get_block_exp_existing, 1759 &
1598 &existing_block_exp)) && 1760 get_block_exp_existing,
1761 &existing_block_exp))
1762 &&
1599 (rd_count == 0)) 1763 (rd_count == 0))
1600 { 1764 {
1601 /* This name does not exist, so cannot be removed */ 1765 /* This name does not exist, so cannot be removed */
@@ -1618,7 +1782,6 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1618 struct GNUNET_GNSRECORD_Data rd_nf[GNUNET_NZL (rd_count) + 1]; 1782 struct GNUNET_GNSRECORD_Data rd_nf[GNUNET_NZL (rd_count) + 1];
1619 unsigned int rd_clean_off; 1783 unsigned int rd_clean_off;
1620 unsigned int rd_nf_count; 1784 unsigned int rd_nf_count;
1621 char *emsg;
1622 int have_nick; 1785 int have_nick;
1623 1786
1624 rd_clean_off = 0; 1787 rd_clean_off = 0;
@@ -1634,27 +1797,27 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1634 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) && 1797 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) &&
1635 (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type)) 1798 (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type))
1636 { 1799 {
1637 cache_nick (&rp_msg->private_key, &rd[i]); 1800 // FIXME: In case this is an uncommited transaction,
1801 // we should not do this here. Can we do this in the store activity?
1802 cache_nick (private_key, &rd[i]);
1638 have_nick = GNUNET_YES; 1803 have_nick = GNUNET_YES;
1639 } 1804 }
1640 } 1805 }
1641 if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (conv_name, 1806 if (GNUNET_OK !=
1642 rd_clean, 1807 GNUNET_GNSRECORD_normalize_record_set (conv_name,
1643 rd_clean_off, 1808 rd_clean,
1644 rd_nf, 1809 rd_clean_off,
1645 &rd_nf_count, 1810 rd_nf,
1646 &new_block_exp, 1811 &rd_nf_count,
1647 GNUNET_YES, 1812 &new_block_exp,
1648 &emsg)) 1813 GNUNET_GNSRECORD_FILTER_NONE,
1814 emsg))
1649 { 1815 {
1650 send_store_response (nc, GNUNET_SYSERR, emsg, rid);
1651 GNUNET_free (emsg);
1652 GNUNET_SERVICE_client_continue (nc->client);
1653 GNUNET_free (conv_name); 1816 GNUNET_free (conv_name);
1654 return; 1817 return GNUNET_SYSERR;
1655 } 1818 }
1656 /* 1819 /*
1657 * If existing_block_exp is 0, then there was not record set 1820 * If existing_block_exp is 0, then there was no record set
1658 * and no tombstone. 1821 * and no tombstone.
1659 * Otherwise, if the existing block expiration is after the 1822 * Otherwise, if the existing block expiration is after the
1660 * new block expiration would be, we need to add a tombstone 1823 * new block expiration would be, we need to add a tombstone
@@ -1674,35 +1837,187 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1674 (GNUNET_NO == have_nick)) 1837 (GNUNET_NO == have_nick))
1675 { 1838 {
1676 /* remove nick record from cache, in case we have one there */ 1839 /* remove nick record from cache, in case we have one there */
1677 cache_nick (&rp_msg->private_key, NULL); 1840 // FIXME: In case this is an uncommited transaction,
1841 // we should not do this here. Can we do this in the store activity?
1842 cache_nick (private_key, NULL);
1678 } 1843 }
1679 res = GSN_database->store_records (GSN_database->cls, 1844 res = nc->GSN_database->store_records (nc->GSN_database->cls,
1680 &rp_msg->private_key, 1845 private_key,
1681 conv_name, 1846 conv_name,
1682 rd_nf_count, 1847 rd_nf_count,
1683 rd_nf); 1848 rd_nf);
1684 } 1849 }
1685 1850
1686 if (GNUNET_OK != res) 1851 if (GNUNET_SYSERR == res)
1687 { 1852 {
1688 /* store not successful, no need to tell monitors */ 1853 /* store not successful, no need to tell monitors */
1689 send_store_response (nc, res, _ ("Store failed"), rid); 1854 *emsg = GNUNET_strdup (_ ("Store failed"));
1690 GNUNET_SERVICE_client_continue (nc->client);
1691 GNUNET_free (conv_name); 1855 GNUNET_free (conv_name);
1856 return GNUNET_SYSERR;
1857 }
1858 }
1859 GNUNET_free (conv_name);
1860 return res;
1861}
1862
1863/**
1864 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
1865 *
1866 * @param cls client sending the message
1867 * @param rp_msg message of type `struct RecordStoreMessage`
1868 */
1869static void
1870handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1871{
1872 struct NamestoreClient *nc = cls;
1873 size_t name_len;
1874 size_t rd_ser_len;
1875 uint32_t rid;
1876 uint16_t rd_set_count;
1877 const char *name_tmp;
1878 char *emsg = NULL;
1879 const char *buf;
1880 const char *rd_ser;
1881 unsigned int rd_count;
1882 ssize_t read;
1883 struct StoreActivity *sa;
1884 struct RecordSet *rs;
1885 struct GNUNET_TIME_Absolute existing_block_exp;
1886 struct GNUNET_TIME_Absolute new_block_exp;
1887 enum GNUNET_GenericReturnValue res;
1888 int blocked = GNUNET_NO;
1889
1890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1891 "Received NAMESTORE_RECORD_STORE message\n");
1892 existing_block_exp = GNUNET_TIME_UNIT_ZERO_ABS;
1893 new_block_exp = GNUNET_TIME_UNIT_ZERO_ABS;
1894 rid = ntohl (rp_msg->gns_header.r_id);
1895 rd_set_count = ntohs (rp_msg->rd_set_count);
1896 buf = (const char *) &rp_msg[1];
1897 for (int i = 0; i < rd_set_count; i++)
1898 {
1899 rs = (struct RecordSet *) buf;
1900 res = store_record_set (nc, &rp_msg->private_key,
1901 rs, &read, &emsg);
1902 if (GNUNET_OK != res)
1903 {
1904 send_store_response (nc, res, emsg,
1905 rid);
1906 GNUNET_free (emsg);
1907 GNUNET_SERVICE_client_continue (nc->client);
1692 return; 1908 return;
1693 } 1909 }
1694 sa = GNUNET_malloc (sizeof(struct StoreActivity) 1910 buf += read;
1695 + ntohs (rp_msg->gns_header.header.size));
1696 GNUNET_CONTAINER_DLL_insert (sa_head, sa_tail, sa);
1697 sa->nc = nc;
1698 sa->rsm = (const struct RecordStoreMessage *) &sa[1];
1699 GNUNET_memcpy (&sa[1], rp_msg, ntohs (rp_msg->gns_header.header.size));
1700 sa->zm_pos = monitor_head;
1701 sa->conv_name = conv_name;
1702 continue_store_activity (sa);
1703 } 1911 }
1912 sa = GNUNET_malloc (sizeof(struct StoreActivity)
1913 + ntohs (rp_msg->gns_header.header.size)
1914 - sizeof (*rp_msg));
1915 GNUNET_CONTAINER_DLL_insert (sa_head, sa_tail, sa);
1916 sa->nc = nc;
1917 sa->rs = (struct RecordSet *) &sa[1];
1918 sa->rd_set_count = rd_set_count;
1919 GNUNET_memcpy (&sa[1], (char *) &rp_msg[1],
1920 ntohs (rp_msg->gns_header.header.size) - sizeof (*rp_msg));
1921 sa->rid = rid;
1922 sa->rd_set_pos = 0;
1923 sa->private_key = rp_msg->private_key;
1924 sa->zm_pos = monitor_head;
1925 sa->uncommited = nc->in_transaction;
1926 continue_store_activity (sa);
1704} 1927}
1705 1928
1929/**
1930 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL message
1931 *
1932 * @param cls client sending the message
1933 * @param tx_msg message of type `struct TxControlMessage`
1934 */
1935static void
1936handle_tx_control (void *cls, const struct TxControlMessage *tx_msg)
1937{
1938 struct NamestoreClient *nc = cls;
1939 struct TxControlResultMessage *txr_msg;
1940 struct GNUNET_MQ_Envelope *env;
1941 struct StoreActivity *sa = sa_head;
1942 struct StoreActivity *sn;
1943 enum GNUNET_GenericReturnValue ret;
1944 char *emsg = NULL;
1945 char *err_tmp;
1946 size_t err_len;
1947
1948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received TX_CONTROL message\n");
1949
1950 switch (ntohs (tx_msg->control))
1951 {
1952 case GNUNET_NAMESTORE_TX_BEGIN:
1953 ret = nc->GSN_database->transaction_begin (nc->GSN_database->cls,
1954 &emsg);
1955 nc->in_transaction = GNUNET_YES;
1956 break;
1957 case GNUNET_NAMESTORE_TX_COMMIT:
1958 ret = nc->GSN_database->transaction_commit (nc->GSN_database->cls,
1959 &emsg);
1960 if (GNUNET_SYSERR != ret)
1961 {
1962 nc->in_transaction = GNUNET_NO;
1963 while (NULL != sa)
1964 {
1965 if ((nc != sa->nc) ||
1966 (GNUNET_NO == sa->uncommited))
1967 {
1968 sa = sa->next;
1969 continue;
1970 }
1971 sa->uncommited = GNUNET_NO;
1972 continue_store_activity (sa);
1973 sa = sa->next;
1974 }
1975 }
1976 break;
1977 case GNUNET_NAMESTORE_TX_ROLLBACK:
1978 ret = nc->GSN_database->transaction_rollback (nc->GSN_database->cls,
1979 &emsg);
1980 if (GNUNET_SYSERR != ret)
1981 {
1982 nc->in_transaction = GNUNET_NO;
1983 while (NULL != sa)
1984 {
1985 if ((nc != sa->nc) ||
1986 (GNUNET_NO == sa->uncommited))
1987 {
1988 sa = sa->next;
1989 continue;
1990 }
1991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Discarding uncommited StoreActivity\n");
1992 sn = sa->next;
1993 free_store_activity (sa);
1994 sa = sn;
1995 }
1996 }
1997 break;
1998 default:
1999 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2000 "Unknown control type %u\n", ntohs (tx_msg->control));
2001 GNUNET_break (0);
2002 }
2003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2004 "TX status is %u\n", ret);
2005 err_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
2006 env =
2007 GNUNET_MQ_msg_extra (txr_msg,
2008 err_len,
2009 GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL_RESULT);
2010 txr_msg->gns_header.header.size = htons (sizeof (struct
2011 TxControlResultMessage)
2012 + err_len);
2013 txr_msg->gns_header.r_id = tx_msg->gns_header.r_id;
2014 txr_msg->success = htons (ret);
2015 err_tmp = (char *) &txr_msg[1];
2016 GNUNET_memcpy (err_tmp, emsg, err_len);
2017 GNUNET_free (emsg);
2018 GNUNET_MQ_send (nc->mq, env);
2019 GNUNET_SERVICE_client_continue (nc->client);
2020}
1706 2021
1707/** 2022/**
1708 * Context for record remove operations passed from #handle_zone_to_name to 2023 * Context for record remove operations passed from #handle_zone_to_name to
@@ -1817,11 +2132,11 @@ handle_zone_to_name (void *cls, const struct ZoneToNameMessage *ztn_msg)
1817 ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id); 2132 ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1818 ztn_ctx.nc = nc; 2133 ztn_ctx.nc = nc;
1819 ztn_ctx.success = GNUNET_NO; 2134 ztn_ctx.success = GNUNET_NO;
1820 if (GNUNET_SYSERR == GSN_database->zone_to_name (GSN_database->cls, 2135 if (GNUNET_SYSERR == nc->GSN_database->zone_to_name (nc->GSN_database->cls,
1821 &ztn_msg->zone, 2136 &ztn_msg->zone,
1822 &ztn_msg->value_zone, 2137 &ztn_msg->value_zone,
1823 &handle_zone_to_name_it, 2138 &handle_zone_to_name_it,
1824 &ztn_ctx)) 2139 &ztn_ctx))
1825 { 2140 {
1826 /* internal error, hang up instead of signalling something 2141 /* internal error, hang up instead of signalling something
1827 that might be wrong */ 2142 that might be wrong */
@@ -1903,12 +2218,13 @@ zone_iterate_proc (void *cls,
1903 } 2218 }
1904 proc->limit--; 2219 proc->limit--;
1905 proc->zi->seq = seq; 2220 proc->zi->seq = seq;
1906 send_lookup_response (proc->zi->nc, 2221 send_lookup_response_with_filter (proc->zi->nc,
1907 proc->zi->request_id, 2222 proc->zi->request_id,
1908 zone_key, 2223 zone_key,
1909 name, 2224 name,
1910 rd_count, 2225 rd_count,
1911 rd); 2226 rd,
2227 proc->zi->filter);
1912 2228
1913 2229
1914 do_refresh_block = GNUNET_NO; 2230 do_refresh_block = GNUNET_NO;
@@ -1935,6 +2251,7 @@ run_zone_iteration_round (struct ZoneIteration *zi, uint64_t limit)
1935 struct ZoneIterationProcResult proc; 2251 struct ZoneIterationProcResult proc;
1936 struct GNUNET_TIME_Absolute start; 2252 struct GNUNET_TIME_Absolute start;
1937 struct GNUNET_TIME_Relative duration; 2253 struct GNUNET_TIME_Relative duration;
2254 struct NamestoreClient *nc = zi->nc;
1938 2255
1939 memset (&proc, 0, sizeof(proc)); 2256 memset (&proc, 0, sizeof(proc));
1940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1945,15 +2262,16 @@ run_zone_iteration_round (struct ZoneIteration *zi, uint64_t limit)
1945 proc.limit = limit; 2262 proc.limit = limit;
1946 start = GNUNET_TIME_absolute_get (); 2263 start = GNUNET_TIME_absolute_get ();
1947 GNUNET_break (GNUNET_SYSERR != 2264 GNUNET_break (GNUNET_SYSERR !=
1948 GSN_database->iterate_records (GSN_database->cls, 2265 nc->GSN_database->iterate_records (nc->GSN_database->cls,
1949 (GNUNET_YES == GNUNET_is_zero ( 2266 (GNUNET_YES ==
1950 &zi->zone)) 2267 GNUNET_is_zero (
2268 &zi->zone))
1951 ? NULL 2269 ? NULL
1952 : &zi->zone, 2270 : &zi->zone,
1953 zi->seq, 2271 zi->seq,
1954 limit, 2272 limit,
1955 &zone_iterate_proc, 2273 &zone_iterate_proc,
1956 &proc)); 2274 &proc));
1957 duration = GNUNET_TIME_absolute_get_duration (start); 2275 duration = GNUNET_TIME_absolute_get_duration (start);
1958 duration = GNUNET_TIME_relative_divide (duration, limit - proc.limit); 2276 duration = GNUNET_TIME_relative_divide (duration, limit - proc.limit);
1959 GNUNET_STATISTICS_set (statistics, 2277 GNUNET_STATISTICS_set (statistics,
@@ -1987,6 +2305,7 @@ handle_iteration_start (void *cls,
1987 "Received ZONE_ITERATION_START message\n"); 2305 "Received ZONE_ITERATION_START message\n");
1988 zi = GNUNET_new (struct ZoneIteration); 2306 zi = GNUNET_new (struct ZoneIteration);
1989 zi->request_id = ntohl (zis_msg->gns_header.r_id); 2307 zi->request_id = ntohl (zis_msg->gns_header.r_id);
2308 zi->filter = ntohs (zis_msg->filter);
1990 zi->offset = 0; 2309 zi->offset = 0;
1991 zi->nc = nc; 2310 zi->nc = nc;
1992 zi->zone = zis_msg->zone; 2311 zi->zone = zis_msg->zone;
@@ -2073,6 +2392,7 @@ static void
2073monitor_unblock (struct ZoneMonitor *zm) 2392monitor_unblock (struct ZoneMonitor *zm)
2074{ 2393{
2075 struct StoreActivity *sa = sa_head; 2394 struct StoreActivity *sa = sa_head;
2395 int blocked = GNUNET_NO;
2076 2396
2077 while ((NULL != sa) && (zm->limit > zm->iteration_cnt)) 2397 while ((NULL != sa) && (zm->limit > zm->iteration_cnt))
2078 { 2398 {
@@ -2181,16 +2501,19 @@ monitor_iterate_cb (void *cls,
2181 * @param zis_msg message from the client 2501 * @param zis_msg message from the client
2182 */ 2502 */
2183static void 2503static void
2184handle_monitor_start (void *cls, const struct ZoneMonitorStartMessage *zis_msg) 2504handle_monitor_start (void *cls, const struct
2505 ZoneMonitorStartMessage *zis_msg)
2185{ 2506{
2186 struct NamestoreClient *nc = cls; 2507 struct NamestoreClient *nc = cls;
2187 struct ZoneMonitor *zm; 2508 struct ZoneMonitor *zm;
2188 2509
2189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ZONE_MONITOR_START message\n"); 2510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2511 "Received ZONE_MONITOR_START message\n");
2190 zm = GNUNET_new (struct ZoneMonitor); 2512 zm = GNUNET_new (struct ZoneMonitor);
2191 zm->nc = nc; 2513 zm->nc = nc;
2192 zm->zone = zis_msg->zone; 2514 zm->zone = zis_msg->zone;
2193 zm->limit = 1; 2515 zm->limit = 1;
2516 zm->filter = ntohs (zis_msg->filter);
2194 zm->in_first_iteration = (GNUNET_YES == ntohl (zis_msg->iterate_first)); 2517 zm->in_first_iteration = (GNUNET_YES == ntohl (zis_msg->iterate_first));
2195 GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm); 2518 GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm);
2196 GNUNET_SERVICE_client_mark_monitor (nc->client); 2519 GNUNET_SERVICE_client_mark_monitor (nc->client);
@@ -2212,23 +2535,22 @@ static void
2212monitor_iteration_next (void *cls) 2535monitor_iteration_next (void *cls)
2213{ 2536{
2214 struct ZoneMonitor *zm = cls; 2537 struct ZoneMonitor *zm = cls;
2538 struct NamestoreClient *nc = zm->nc;
2215 int ret; 2539 int ret;
2216 2540
2217 zm->task = NULL; 2541 zm->task = NULL;
2218 GNUNET_assert (0 == zm->iteration_cnt); 2542 GNUNET_assert (0 == zm->iteration_cnt);
2219 if (zm->limit > 16) 2543 if (zm->limit > 16)
2220 zm->iteration_cnt = zm->limit / 2; /* leave half for monitor events */ 2544 zm->iteration_cnt = zm->limit / 2; /* leave half for monitor events */
2221 else 2545 else
2222 zm->iteration_cnt = zm->limit; /* use it all */ 2546 zm->iteration_cnt = zm->limit; /* use it all */
2223 ret = GSN_database->iterate_records (GSN_database->cls, 2547 ret = nc->GSN_database->iterate_records (nc->GSN_database->cls,
2224 (GNUNET_YES == GNUNET_is_zero ( 2548 (GNUNET_YES == GNUNET_is_zero (
2225 &zm->zone)) 2549 &zm->zone)) ? NULL : &zm->zone,
2226 ? NULL 2550 zm->seq,
2227 : &zm->zone, 2551 zm->iteration_cnt,
2228 zm->seq, 2552 &monitor_iterate_cb,
2229 zm->iteration_cnt, 2553 zm);
2230 &monitor_iterate_cb,
2231 zm);
2232 if (GNUNET_SYSERR == ret) 2554 if (GNUNET_SYSERR == ret)
2233 { 2555 {
2234 GNUNET_SERVICE_client_drop (zm->nc->client); 2556 GNUNET_SERVICE_client_drop (zm->nc->client);
@@ -2315,7 +2637,6 @@ run (void *cls,
2315 struct GNUNET_SERVICE_Handle *service) 2637 struct GNUNET_SERVICE_Handle *service)
2316{ 2638{
2317 char *database; 2639 char *database;
2318
2319 (void) cls; 2640 (void) cls;
2320 (void) service; 2641 (void) service;
2321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n"); 2642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
@@ -2330,26 +2651,31 @@ run (void *cls,
2330 namecache = GNUNET_NAMECACHE_connect (cfg); 2651 namecache = GNUNET_NAMECACHE_connect (cfg);
2331 GNUNET_assert (NULL != namecache); 2652 GNUNET_assert (NULL != namecache);
2332 } 2653 }
2654 statistics = GNUNET_STATISTICS_create ("namestore", cfg);
2333 /* Loading database plugin */ 2655 /* Loading database plugin */
2334 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, 2656 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
2335 "namestore", 2657 "namestore",
2336 "database", 2658 "database",
2337 &database)) 2659 &database))
2660 {
2338 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n"); 2661 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
2339 2662 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2663 return;
2664 }
2340 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database); 2665 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
2341 GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg); 2666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading %s\n", db_lib_name);
2667 GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
2342 GNUNET_free (database); 2668 GNUNET_free (database);
2343 statistics = GNUNET_STATISTICS_create ("namestore", cfg);
2344 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
2345 if (NULL == GSN_database) 2669 if (NULL == GSN_database)
2346 { 2670 {
2347 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2671 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2348 "Could not load database backend `%s'\n", 2672 "Could not load database backend `%s'\n",
2349 db_lib_name); 2673 db_lib_name);
2350 GNUNET_SCHEDULER_shutdown (); 2674 GNUNET_free (db_lib_name);
2675 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2351 return; 2676 return;
2352 } 2677 }
2678 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
2353} 2679}
2354 2680
2355 2681
@@ -2363,6 +2689,10 @@ GNUNET_SERVICE_MAIN (
2363 &client_connect_cb, 2689 &client_connect_cb,
2364 &client_disconnect_cb, 2690 &client_disconnect_cb,
2365 NULL, 2691 NULL,
2692 GNUNET_MQ_hd_fixed_size (tx_control,
2693 GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL,
2694 struct TxControlMessage,
2695 NULL),
2366 GNUNET_MQ_hd_var_size (record_store, 2696 GNUNET_MQ_hd_var_size (record_store,
2367 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE, 2697 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE,
2368 struct RecordStoreMessage, 2698 struct RecordStoreMessage,
diff --git a/src/namestore/namestore.conf.in b/src/namestore/namestore.conf.in
index a9c928c66..fe7d4002c 100644
--- a/src/namestore/namestore.conf.in
+++ b/src/namestore/namestore.conf.in
@@ -21,12 +21,9 @@ CACHE_KEYS = YES
21 21
22 22
23[namestore-sqlite] 23[namestore-sqlite]
24INIT_ON_CONNECT = YES
24FILENAME = $GNUNET_DATA_HOME/namestore/sqlite.db 25FILENAME = $GNUNET_DATA_HOME/namestore/sqlite.db
25 26
26[namestore-heap]
27FILENAME = $GNUNET_DATA_HOME/namestore/heap.db
28
29
30[namestore-postgres] 27[namestore-postgres]
31# How to connect to the database 28# How to connect to the database
32CONFIG = postgres:///gnunet 29CONFIG = postgres:///gnunet
@@ -34,6 +31,7 @@ CONFIG = postgres:///gnunet
34TEMPORARY_TABLE = NO 31TEMPORARY_TABLE = NO
35# Use asynchronous commit (SET synchronous_commit TO OFF). 32# Use asynchronous commit (SET synchronous_commit TO OFF).
36ASYNC_COMMIT = NO 33ASYNC_COMMIT = NO
34INIT_ON_CONNECT = YES
37 35
38[uri] 36[uri]
39gns = gnunet-namestore -e 1a -u 37gns = gnunet-namestore -e 1a -u
diff --git a/src/namestore/namestore.h b/src/namestore/namestore.h
index 583ec1e68..d7b6fd13e 100644
--- a/src/namestore/namestore.h
+++ b/src/namestore/namestore.h
@@ -51,23 +51,9 @@ struct GNUNET_NAMESTORE_Header
51 uint32_t r_id GNUNET_PACKED; 51 uint32_t r_id GNUNET_PACKED;
52}; 52};
53 53
54 54struct RecordSet
55/**
56 * Store a record to the namestore (as authority).
57 */
58struct RecordStoreMessage
59{ 55{
60 /** 56 /**
61 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE
62 */
63 struct GNUNET_NAMESTORE_Header gns_header;
64
65 /**
66 * Expiration time
67 */
68 struct GNUNET_TIME_AbsoluteNBO expire;
69
70 /**
71 * Name length 57 * Name length
72 */ 58 */
73 uint16_t name_len GNUNET_PACKED; 59 uint16_t name_len GNUNET_PACKED;
@@ -87,14 +73,35 @@ struct RecordStoreMessage
87 */ 73 */
88 uint16_t reserved GNUNET_PACKED; 74 uint16_t reserved GNUNET_PACKED;
89 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
90 /** 93 /**
91 * The private key of the authority. 94 * The private key of the authority.
92 */ 95 */
93 struct GNUNET_IDENTITY_PrivateKey private_key; 96 struct GNUNET_IDENTITY_PrivateKey private_key;
94 97
95 /* followed by: 98 /**
96 * name with length name_len 99 * Number of record sets
97 * serialized record data with rd_count records 100 */
101 uint16_t rd_set_count;
102
103 /**
104 * Followed by rd_set_count RecordSets
98 */ 105 */
99}; 106};
100 107
@@ -146,6 +153,11 @@ struct LabelLookupMessage
146 uint32_t label_len GNUNET_PACKED; 153 uint32_t label_len GNUNET_PACKED;
147 154
148 /** 155 /**
156 * GNUNET_YES if this lookup corresponds to an edit request
157 */
158 uint32_t is_edit_request GNUNET_PACKED;
159
160 /**
149 * The private key of the zone to look up in 161 * The private key of the zone to look up in
150 */ 162 */
151 struct GNUNET_IDENTITY_PrivateKey zone; 163 struct GNUNET_IDENTITY_PrivateKey zone;
@@ -275,6 +287,12 @@ struct RecordResultMessage
275 struct GNUNET_NAMESTORE_Header gns_header; 287 struct GNUNET_NAMESTORE_Header gns_header;
276 288
277 /** 289 /**
290 * Expiration time if the record result (if any).
291 * Takes TOMBSTONEs into account.
292 */
293 struct GNUNET_TIME_AbsoluteNBO expire;
294
295 /**
278 * Name length 296 * Name length
279 */ 297 */
280 uint16_t name_len GNUNET_PACKED; 298 uint16_t name_len GNUNET_PACKED;
@@ -305,6 +323,54 @@ struct RecordResultMessage
305 */ 323 */
306}; 324};
307 325
326/**
327 * Send a transaction control message.
328 */
329struct TxControlMessage
330{
331 /**
332 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL
333 */
334 struct GNUNET_NAMESTORE_Header gns_header;
335
336 /**
337 * The type of control message to send
338 */
339 uint16_t control GNUNET_PACKED;
340
341 /**
342 * always zero (for alignment)
343 */
344 uint16_t reserved GNUNET_PACKED;
345
346};
347
348/**
349 * Result of a transaction control message.
350 */
351struct TxControlResultMessage
352{
353 /**
354 * Type will be #GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL_RESULT
355 */
356 struct GNUNET_NAMESTORE_Header gns_header;
357
358 /**
359 * The type of control message to send
360 */
361 uint16_t control GNUNET_PACKED;
362
363 /**
364 * Of type GNUNET_GenericReturnValue
365 */
366 uint16_t success GNUNET_PACKED;
367
368 /* followed by:
369 * an error message if status != ntohs(GNUNET_OK)
370 */
371};
372
373
308 374
309/** 375/**
310 * Start monitoring a zone. 376 * Start monitoring a zone.
@@ -323,6 +389,17 @@ struct ZoneMonitorStartMessage
323 uint32_t iterate_first GNUNET_PACKED; 389 uint32_t iterate_first GNUNET_PACKED;
324 390
325 /** 391 /**
392 * Record set filter control flags.
393 * See GNUNET_NAMESTORE_Filter enum.
394 */
395 uint16_t filter;
396
397 /**
398 * Reserved for alignment
399 */
400 uint16_t reserved;
401
402 /**
326 * Zone key. 403 * Zone key.
327 */ 404 */
328 struct GNUNET_IDENTITY_PrivateKey zone; 405 struct GNUNET_IDENTITY_PrivateKey zone;
@@ -367,6 +444,17 @@ struct ZoneIterationStartMessage
367 * Zone key. All zeros for "all zones". 444 * Zone key. All zeros for "all zones".
368 */ 445 */
369 struct GNUNET_IDENTITY_PrivateKey zone; 446 struct GNUNET_IDENTITY_PrivateKey zone;
447
448 /**
449 * Record set filter control flags.
450 * See GNUNET_NAMESTORE_Filter enum.
451 */
452 uint16_t filter;
453
454 /**
455 * Reserved for alignment
456 */
457 uint16_t reserved;
370}; 458};
371 459
372 460
diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c
index 73f985803..fd348a057 100644
--- a/src/namestore/namestore_api.c
+++ b/src/namestore/namestore_api.c
@@ -83,6 +83,11 @@ struct GNUNET_NAMESTORE_QueueEntry
83 GNUNET_NAMESTORE_RecordMonitor proc; 83 GNUNET_NAMESTORE_RecordMonitor proc;
84 84
85 /** 85 /**
86 * Function to call with the records we get back; or NULL.
87 */
88 GNUNET_NAMESTORE_RecordSetMonitor proc2;
89
90 /**
86 * Closure for @e proc. 91 * Closure for @e proc.
87 */ 92 */
88 void *proc_cls; 93 void *proc_cls;
@@ -151,6 +156,11 @@ struct GNUNET_NAMESTORE_ZoneIterator
151 GNUNET_NAMESTORE_RecordMonitor proc; 156 GNUNET_NAMESTORE_RecordMonitor proc;
152 157
153 /** 158 /**
159 * The continuation to call with the results
160 */
161 GNUNET_NAMESTORE_RecordSetMonitor proc2;
162
163 /**
154 * Closure for @e proc. 164 * Closure for @e proc.
155 */ 165 */
156 void *proc_cls; 166 void *proc_cls;
@@ -630,6 +640,9 @@ handle_record_result (void *cls, const struct RecordResultMessage *msg)
630 { 640 {
631 if (NULL != ze->proc) 641 if (NULL != ze->proc)
632 ze->proc (ze->proc_cls, &msg->private_key, name, rd_count, rd); 642 ze->proc (ze->proc_cls, &msg->private_key, name, rd_count, rd);
643 if (NULL != ze->proc2)
644 ze->proc2 (ze->proc_cls, &msg->private_key, name,
645 rd_count, rd, GNUNET_TIME_absolute_ntoh (msg->expire));
633 return; 646 return;
634 } 647 }
635 } 648 }
@@ -674,6 +687,60 @@ handle_record_result_end (void *cls, const struct GNUNET_NAMESTORE_Header *msg)
674 free_ze (ze); 687 free_ze (ze);
675} 688}
676 689
690/**
691 * Handle an incoming message of type
692 * #GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL_RESULT.
693 *
694 * @param qe the respective entry in the message queue
695 * @param msg the message we received
696 * @return #GNUNET_OK on success, #GNUNET_SYSERR if message malformed
697 */
698static int
699check_tx_control_result (void *cls,
700 const struct TxControlResultMessage *msg)
701{
702 const char *err_tmp;
703 size_t err_len;
704
705 (void) cls;
706 err_len = ntohs (msg->gns_header.header.size)
707 - sizeof (struct TxControlResultMessage);
708 if ((GNUNET_YES == ntohs (msg->success)) && (err_len > 0))
709 {
710 GNUNET_break (0);
711 return GNUNET_SYSERR;
712 }
713 err_tmp = (const char *) &msg[1];
714 if ((err_len > 0) && ('\0' != err_tmp[err_len - 1]))
715 {
716 GNUNET_break (0);
717 return GNUNET_SYSERR;
718 }
719 return GNUNET_OK;
720}
721
722static void
723handle_tx_control_result (void *cls,
724 const struct TxControlResultMessage *msg)
725{
726 struct GNUNET_NAMESTORE_Handle *h = cls;
727 struct GNUNET_NAMESTORE_QueueEntry *qe;
728 int res;
729 const char *emsg;
730
731 qe = find_qe (h, ntohl (msg->gns_header.r_id));
732 emsg = (const char *) &msg[1];
733 res = ntohs (msg->success);
734 LOG (GNUNET_ERROR_TYPE_DEBUG,
735 "Received TX_CONTROL_RESULT with result %d\n",
736 res);
737 if (NULL == qe)
738 return;
739 if (NULL != qe->cont)
740 qe->cont (qe->cont_cls, res,
741 (GNUNET_YES == res) ? NULL : emsg);
742 free_qe (qe);
743}
677 744
678/** 745/**
679 * Handle an incoming message of type 746 * Handle an incoming message of type
@@ -839,6 +906,10 @@ reconnect (struct GNUNET_NAMESTORE_Handle *h)
839 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE, 906 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE,
840 struct LabelLookupResponseMessage, 907 struct LabelLookupResponseMessage,
841 h), 908 h),
909 GNUNET_MQ_hd_var_size (tx_control_result,
910 GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL_RESULT,
911 struct TxControlResultMessage,
912 h),
842 GNUNET_MQ_handler_end () }; 913 GNUNET_MQ_handler_end () };
843 struct GNUNET_NAMESTORE_ZoneIterator *it; 914 struct GNUNET_NAMESTORE_ZoneIterator *it;
844 struct GNUNET_NAMESTORE_QueueEntry *qe; 915 struct GNUNET_NAMESTORE_QueueEntry *qe;
@@ -1024,32 +1095,60 @@ GNUNET_NAMESTORE_records_store (
1024 GNUNET_NAMESTORE_ContinuationWithStatus cont, 1095 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1025 void *cont_cls) 1096 void *cont_cls)
1026{ 1097{
1098 return GNUNET_NAMESTORE_records_store2 (h, pkey, 1, &label, &rd_count, &rd,
1099 cont, cont_cls);
1100}
1101
1102struct GNUNET_NAMESTORE_QueueEntry *
1103GNUNET_NAMESTORE_records_store2 (
1104 struct GNUNET_NAMESTORE_Handle *h,
1105 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1106 unsigned int rd_set_count,
1107 const char **a_label,
1108 unsigned int *a_rd_count,
1109 const struct GNUNET_GNSRECORD_Data **a_rd,
1110 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1111 void *cont_cls)
1112{
1027 struct GNUNET_NAMESTORE_QueueEntry *qe; 1113 struct GNUNET_NAMESTORE_QueueEntry *qe;
1028 struct GNUNET_MQ_Envelope *env; 1114 struct GNUNET_MQ_Envelope *env;
1115 const char *label;
1116 unsigned int rd_count;
1117 const struct GNUNET_GNSRECORD_Data *rd;
1029 char *name_tmp; 1118 char *name_tmp;
1030 char *rd_ser; 1119 char *rd_ser;
1031 ssize_t rd_ser_len; 1120 ssize_t rd_ser_len[rd_set_count];
1032 size_t name_len; 1121 size_t name_len;
1033 uint32_t rid; 1122 uint32_t rid;
1034 struct RecordStoreMessage *msg; 1123 struct RecordStoreMessage *msg;
1124 struct RecordSet *rd_set;
1035 ssize_t sret; 1125 ssize_t sret;
1126 int i;
1127 size_t rd_set_len = 0;
1036 1128
1037 name_len = strlen (label) + 1; 1129 for (i = 0; i < rd_set_count; i++)
1038 if (name_len > MAX_NAME_LEN)
1039 {
1040 GNUNET_break (0);
1041 return NULL;
1042 }
1043 rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1044 if (rd_ser_len < 0)
1045 {
1046 GNUNET_break (0);
1047 return NULL;
1048 }
1049 if (rd_ser_len > UINT16_MAX)
1050 { 1130 {
1051 GNUNET_break (0); 1131 label = a_label[i];
1052 return NULL; 1132 rd_count = a_rd_count[i];
1133 rd = a_rd[i];
1134 name_len = strlen (label) + 1;
1135 if (name_len > MAX_NAME_LEN)
1136 {
1137 GNUNET_break (0);
1138 return NULL;
1139 }
1140 rd_ser_len[i] = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1141 if (rd_ser_len[i] < 0)
1142 {
1143 GNUNET_break (0);
1144 return NULL;
1145 }
1146 if (rd_ser_len[i] > UINT16_MAX)
1147 {
1148 GNUNET_break (0);
1149 return NULL;
1150 }
1151 rd_set_len += sizeof (struct RecordSet) + name_len + rd_ser_len[i];
1053 } 1152 }
1054 rid = get_op_id (h); 1153 rid = get_op_id (h);
1055 qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry); 1154 qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
@@ -1061,30 +1160,38 @@ GNUNET_NAMESTORE_records_store (
1061 1160
1062 /* setup msg */ 1161 /* setup msg */
1063 env = GNUNET_MQ_msg_extra (msg, 1162 env = GNUNET_MQ_msg_extra (msg,
1064 name_len + rd_ser_len, 1163 rd_set_len,
1065 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE); 1164 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE);
1066 msg->gns_header.r_id = htonl (rid); 1165 msg->gns_header.r_id = htonl (rid);
1067 msg->name_len = htons (name_len); 1166 msg->rd_set_count = htons (rd_set_count);
1068 msg->rd_count = htons (rd_count);
1069 msg->rd_len = htons (rd_ser_len);
1070 msg->reserved = ntohs (0);
1071 msg->private_key = *pkey; 1167 msg->private_key = *pkey;
1072 1168 rd_set = (struct RecordSet*) &msg[1];
1073 name_tmp = (char *) &msg[1]; 1169 for (int i = 0; i < rd_set_count; i++)
1074 GNUNET_memcpy (name_tmp, label, name_len);
1075 rd_ser = &name_tmp[name_len];
1076 sret = GNUNET_GNSRECORD_records_serialize (rd_count, rd, rd_ser_len, rd_ser);
1077 if ((0 > sret) || (sret != rd_ser_len))
1078 { 1170 {
1079 GNUNET_break (0); 1171 label = a_label[i];
1080 GNUNET_free (env); 1172 rd = a_rd[i];
1081 return NULL; 1173 name_len = strlen (label) + 1;
1174 rd_set->name_len = htons (name_len);
1175 rd_set->rd_count = htons (a_rd_count[i]);
1176 rd_set->rd_len = htons (rd_ser_len[i]);
1177 rd_set->reserved = ntohs (0);
1178 name_tmp = (char *) &rd_set[1];
1179 GNUNET_memcpy (name_tmp, label, name_len);
1180 rd_ser = &name_tmp[name_len];
1181 sret = GNUNET_GNSRECORD_records_serialize (a_rd_count[i], rd, rd_ser_len[i],
1182 rd_ser);
1183 if ((0 > sret) || (sret != rd_ser_len[i]))
1184 {
1185 GNUNET_break (0);
1186 GNUNET_free (env);
1187 return NULL;
1188 }
1189 // Point to next RecordSet
1190 rd_set = (struct RecordSet*) &name_tmp[name_len + rd_ser_len[i]];
1082 } 1191 }
1083 GNUNET_assert (rd_ser_len == sret);
1084 LOG (GNUNET_ERROR_TYPE_DEBUG, 1192 LOG (GNUNET_ERROR_TYPE_DEBUG,
1085 "Sending NAMESTORE_RECORD_STORE message for name `%s' with %u records\n", 1193 "Sending NAMESTORE_RECORD_STORE message for name %u record sets\n",
1086 label, 1194 rd_set_count);
1087 rd_count);
1088 qe->timeout_task = 1195 qe->timeout_task =
1089 GNUNET_SCHEDULER_add_delayed (NAMESTORE_DELAY_TOLERANCE, &warn_delay, qe); 1196 GNUNET_SCHEDULER_add_delayed (NAMESTORE_DELAY_TOLERANCE, &warn_delay, qe);
1090 if (NULL == h->mq) 1197 if (NULL == h->mq)
@@ -1100,32 +1207,17 @@ GNUNET_NAMESTORE_records_store (
1100 return qe; 1207 return qe;
1101} 1208}
1102 1209
1103/**
1104 * TODO: Experimental API will replace API above.
1105 */
1106struct GNUNET_NAMESTORE_QueueEntry *
1107GNUNET_NAMESTORE_records_replace (
1108 struct GNUNET_NAMESTORE_Handle *h,
1109 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1110 const char *label,
1111 unsigned int rd_count,
1112 const struct GNUNET_GNSRECORD_Data *rd,
1113 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1114 void *cont_cls)
1115{
1116 return GNUNET_NAMESTORE_records_store (h, pkey, label, rd_count, rd,
1117 cont, cont_cls);
1118}
1119 1210
1120struct GNUNET_NAMESTORE_QueueEntry * 1211static struct GNUNET_NAMESTORE_QueueEntry *
1121GNUNET_NAMESTORE_records_lookup ( 1212records_lookup (
1122 struct GNUNET_NAMESTORE_Handle *h, 1213 struct GNUNET_NAMESTORE_Handle *h,
1123 const struct GNUNET_IDENTITY_PrivateKey *pkey, 1214 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1124 const char *label, 1215 const char *label,
1125 GNUNET_SCHEDULER_TaskCallback error_cb, 1216 GNUNET_SCHEDULER_TaskCallback error_cb,
1126 void *error_cb_cls, 1217 void *error_cb_cls,
1127 GNUNET_NAMESTORE_RecordMonitor rm, 1218 GNUNET_NAMESTORE_RecordMonitor rm,
1128 void *rm_cls) 1219 void *rm_cls,
1220 int is_edit_request)
1129{ 1221{
1130 struct GNUNET_NAMESTORE_QueueEntry *qe; 1222 struct GNUNET_NAMESTORE_QueueEntry *qe;
1131 struct GNUNET_MQ_Envelope *env; 1223 struct GNUNET_MQ_Envelope *env;
@@ -1152,6 +1244,7 @@ GNUNET_NAMESTORE_records_lookup (
1152 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP); 1244 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP);
1153 msg->gns_header.r_id = htonl (qe->op_id); 1245 msg->gns_header.r_id = htonl (qe->op_id);
1154 msg->zone = *pkey; 1246 msg->zone = *pkey;
1247 msg->is_edit_request = htonl (is_edit_request);
1155 msg->label_len = htonl (label_len); 1248 msg->label_len = htonl (label_len);
1156 GNUNET_memcpy (&msg[1], label, label_len); 1249 GNUNET_memcpy (&msg[1], label, label_len);
1157 if (NULL == h->mq) 1250 if (NULL == h->mq)
@@ -1161,12 +1254,24 @@ GNUNET_NAMESTORE_records_lookup (
1161 return qe; 1254 return qe;
1162} 1255}
1163 1256
1257struct GNUNET_NAMESTORE_QueueEntry *
1258GNUNET_NAMESTORE_records_lookup (
1259 struct GNUNET_NAMESTORE_Handle *h,
1260 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1261 const char *label,
1262 GNUNET_SCHEDULER_TaskCallback error_cb,
1263 void *error_cb_cls,
1264 GNUNET_NAMESTORE_RecordMonitor rm,
1265 void *rm_cls)
1266{
1267 return records_lookup (h, pkey, label,
1268 error_cb, error_cb_cls,
1269 rm, rm_cls, GNUNET_NO);
1270
1271}
1164 1272
1165/**
1166 * TODO experimental API. Will replace old API above.
1167 */
1168struct GNUNET_NAMESTORE_QueueEntry * 1273struct GNUNET_NAMESTORE_QueueEntry *
1169GNUNET_NAMESTORE_records_select ( 1274GNUNET_NAMESTORE_records_edit (
1170 struct GNUNET_NAMESTORE_Handle *h, 1275 struct GNUNET_NAMESTORE_Handle *h,
1171 const struct GNUNET_IDENTITY_PrivateKey *pkey, 1276 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1172 const char *label, 1277 const char *label,
@@ -1175,9 +1280,9 @@ GNUNET_NAMESTORE_records_select (
1175 GNUNET_NAMESTORE_RecordMonitor rm, 1280 GNUNET_NAMESTORE_RecordMonitor rm,
1176 void *rm_cls) 1281 void *rm_cls)
1177{ 1282{
1178 return GNUNET_NAMESTORE_records_lookup (h, pkey, label, 1283 return records_lookup (h, pkey, label,
1179 error_cb, error_cb_cls, 1284 error_cb, error_cb_cls,
1180 rm, rm_cls); 1285 rm, rm_cls, GNUNET_YES);
1181} 1286}
1182 1287
1183struct GNUNET_NAMESTORE_QueueEntry * 1288struct GNUNET_NAMESTORE_QueueEntry *
@@ -1217,25 +1322,6 @@ GNUNET_NAMESTORE_zone_to_name (
1217} 1322}
1218 1323
1219 1324
1220/**
1221 * Starts a new zone iteration (used to periodically PUT all of our
1222 * records into our DHT). This MUST lock the struct GNUNET_NAMESTORE_Handle
1223 * for any other calls than #GNUNET_NAMESTORE_zone_iterator_next and
1224 * #GNUNET_NAMESTORE_zone_iteration_stop. @a proc will be called once
1225 * immediately, and then again after
1226 * #GNUNET_NAMESTORE_zone_iterator_next is invoked.
1227 *
1228 * @param h handle to the namestore
1229 * @param zone zone to access, NULL for all zones
1230 * @param error_cb function to call on error (i.e. disconnect)
1231 * @param error_cb_cls closure for @a error_cb
1232 * @param proc function to call on each name from the zone; it
1233 * will be called repeatedly with a value (if available)
1234 * @param proc_cls closure for @a proc
1235 * @param finish_cb function to call on completion
1236 * @param finish_cb_cls closure for @a finish_cb
1237 * @return an iterator handle to use for iteration
1238 */
1239struct GNUNET_NAMESTORE_ZoneIterator * 1325struct GNUNET_NAMESTORE_ZoneIterator *
1240GNUNET_NAMESTORE_zone_iteration_start ( 1326GNUNET_NAMESTORE_zone_iteration_start (
1241 struct GNUNET_NAMESTORE_Handle *h, 1327 struct GNUNET_NAMESTORE_Handle *h,
@@ -1277,15 +1363,50 @@ GNUNET_NAMESTORE_zone_iteration_start (
1277 return it; 1363 return it;
1278} 1364}
1279 1365
1366struct GNUNET_NAMESTORE_ZoneIterator *
1367GNUNET_NAMESTORE_zone_iteration_start2 (
1368 struct GNUNET_NAMESTORE_Handle *h,
1369 const struct GNUNET_IDENTITY_PrivateKey *zone,
1370 GNUNET_SCHEDULER_TaskCallback error_cb,
1371 void *error_cb_cls,
1372 GNUNET_NAMESTORE_RecordSetMonitor proc,
1373 void *proc_cls,
1374 GNUNET_SCHEDULER_TaskCallback finish_cb,
1375 void *finish_cb_cls,
1376 enum GNUNET_GNSRECORD_Filter filter)
1377{
1378 struct GNUNET_NAMESTORE_ZoneIterator *it;
1379 struct GNUNET_MQ_Envelope *env;
1380 struct ZoneIterationStartMessage *msg;
1381 uint32_t rid;
1382
1383 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ZONE_ITERATION_START message\n");
1384 rid = get_op_id (h);
1385 it = GNUNET_new (struct GNUNET_NAMESTORE_ZoneIterator);
1386 it->h = h;
1387 it->error_cb = error_cb;
1388 it->error_cb_cls = error_cb_cls;
1389 it->finish_cb = finish_cb;
1390 it->finish_cb_cls = finish_cb_cls;
1391 it->proc2 = proc;
1392 it->proc_cls = proc_cls;
1393 it->op_id = rid;
1394 if (NULL != zone)
1395 it->zone = *zone;
1396 GNUNET_CONTAINER_DLL_insert_tail (h->z_head, h->z_tail, it);
1397 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START);
1398 msg->gns_header.r_id = htonl (rid);
1399 msg->filter = htons ((uint16_t) filter);
1400 if (NULL != zone)
1401 msg->zone = *zone;
1402 if (NULL == h->mq)
1403 it->env = env;
1404 else
1405 GNUNET_MQ_send (h->mq, env);
1406 return it;
1407}
1408
1280 1409
1281/**
1282 * Calls the record processor specified in #GNUNET_NAMESTORE_zone_iteration_start
1283 * for the next record.
1284 *
1285 * @param it the iterator
1286 * @param limit number of records to return to the iterator in one shot
1287 * (before #GNUNET_NAMESTORE_zone_iterator_next is to be called again)
1288 */
1289void 1410void
1290GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it, 1411GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it,
1291 uint64_t limit) 1412 uint64_t limit)
@@ -1344,43 +1465,65 @@ GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe)
1344 * New API draft. Experimental 1465 * New API draft. Experimental
1345 */ 1466 */
1346 1467
1347struct GNUNET_NAMESTORE_QueueEntry * 1468static struct GNUNET_NAMESTORE_QueueEntry *
1348GNUNET_NAMESTORE_transaction_begin (struct GNUNET_NAMESTORE_Handle *h, 1469send_transaction_control_msg (struct GNUNET_NAMESTORE_Handle *h,
1349 GNUNET_SCHEDULER_TaskCallback error_cb, 1470 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1350 void *error_cb_cls) 1471 void *cont_cls,
1472 enum GNUNET_NAMESTORE_TxControl ctrl)
1351{ 1473{
1474 struct GNUNET_NAMESTORE_QueueEntry *qe;
1475 struct GNUNET_MQ_Envelope *env;
1476 struct TxControlMessage *msg;
1477 uint32_t rid;
1478
1479 rid = get_op_id (h);
1480 qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1481 qe->h = h;
1482 qe->cont = cont;
1483 qe->cont_cls = cont_cls;
1484 qe->op_id = rid;
1485 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1486
1487 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL);
1488 msg->gns_header.r_id = htonl (rid);
1489 msg->control = htons (ctrl);
1490 if (NULL == h->mq)
1491 qe->env = env;
1492 else
1493 GNUNET_MQ_send (h->mq, env);
1494 return qe;
1352 GNUNET_break (0); 1495 GNUNET_break (0);
1353 return NULL; 1496 return NULL;
1354} 1497}
1355 1498
1499struct GNUNET_NAMESTORE_QueueEntry *
1500GNUNET_NAMESTORE_transaction_begin (struct GNUNET_NAMESTORE_Handle *h,
1501 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1502 void *cont_cls)
1503{
1504 return send_transaction_control_msg (h, cont, cont_cls,
1505 GNUNET_NAMESTORE_TX_BEGIN);
1506}
1356 1507
1357struct GNUNET_NAMESTORE_QueueEntry * 1508struct GNUNET_NAMESTORE_QueueEntry *
1358GNUNET_NAMESTORE_transaction_abort (struct GNUNET_NAMESTORE_Handle *h, 1509GNUNET_NAMESTORE_transaction_commit (struct GNUNET_NAMESTORE_Handle *h,
1359 GNUNET_SCHEDULER_TaskCallback error_cb, 1510 GNUNET_NAMESTORE_ContinuationWithStatus
1360 void *error_cb_cls) 1511 cont,
1512 void *cont_cls)
1361{ 1513{
1362 GNUNET_break (0); 1514 return send_transaction_control_msg (h, cont, cont_cls,
1363 return NULL; 1515 GNUNET_NAMESTORE_TX_COMMIT);
1364} 1516}
1365 1517
1366 1518
1367/**
1368 * Commit a namestore transaction.
1369 * Saves all actions performed since #GNUNET_NAMESTORE_transaction_begin
1370 *
1371 * @param h handle to the namestore
1372 * @param error_cb function to call on error (i.e. disconnect or unable to get lock)
1373 * the handle is afterwards invalid
1374 * @param error_cb_cls closure for @a error_cb
1375 * @return handle to abort the request
1376 */
1377struct GNUNET_NAMESTORE_QueueEntry * 1519struct GNUNET_NAMESTORE_QueueEntry *
1378GNUNET_NAMESTORE_transaction_commit (struct GNUNET_NAMESTORE_Handle *h, 1520GNUNET_NAMESTORE_transaction_rollback (struct GNUNET_NAMESTORE_Handle *h,
1379 GNUNET_SCHEDULER_TaskCallback error_cb, 1521 GNUNET_NAMESTORE_ContinuationWithStatus
1380 void *error_cb_cls) 1522 cont,
1523 void *cont_cls)
1381{ 1524{
1382 GNUNET_break (0); 1525 return send_transaction_control_msg (h, cont, cont_cls,
1383 return NULL; 1526 GNUNET_NAMESTORE_TX_ROLLBACK);
1384} 1527}
1385 1528
1386 1529
diff --git a/src/namestore/namestore_api_monitor.c b/src/namestore/namestore_api_monitor.c
index 6670e54ce..968d7ed58 100644
--- a/src/namestore/namestore_api_monitor.c
+++ b/src/namestore/namestore_api_monitor.c
@@ -65,6 +65,16 @@ struct GNUNET_NAMESTORE_ZoneMonitor
65 GNUNET_NAMESTORE_RecordMonitor monitor; 65 GNUNET_NAMESTORE_RecordMonitor monitor;
66 66
67 /** 67 /**
68 * Function to call on events.
69 */
70 GNUNET_NAMESTORE_RecordSetMonitor monitor2;
71
72 /**
73 * Record set filter for this monitor
74 */
75 enum GNUNET_GNSRECORD_Filter filter;
76
77 /**
68 * Closure for @e monitor. 78 * Closure for @e monitor.
69 */ 79 */
70 void *monitor_cls; 80 void *monitor_cls;
@@ -213,7 +223,11 @@ handle_result (void *cls, const struct RecordResultMessage *lrm)
213 GNUNET_assert ( 223 GNUNET_assert (
214 GNUNET_OK == 224 GNUNET_OK ==
215 GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd)); 225 GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd));
216 zm->monitor (zm->monitor_cls, &lrm->private_key, name_tmp, rd_count, rd); 226 if (NULL != zm->monitor2)
227 zm->monitor2 (zm->monitor_cls, &lrm->private_key, name_tmp,
228 rd_count, rd, GNUNET_TIME_absolute_ntoh (lrm->expire));
229 else
230 zm->monitor (zm->monitor_cls, &lrm->private_key, name_tmp, rd_count, rd);
217 } 231 }
218} 232}
219 233
@@ -272,33 +286,11 @@ reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
272 env = GNUNET_MQ_msg (sm, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START); 286 env = GNUNET_MQ_msg (sm, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START);
273 sm->iterate_first = htonl (zm->iterate_first); 287 sm->iterate_first = htonl (zm->iterate_first);
274 sm->zone = zm->zone; 288 sm->zone = zm->zone;
289 sm->filter = htons ((uint16_t) zm->filter);
275 GNUNET_MQ_send (zm->mq, env); 290 GNUNET_MQ_send (zm->mq, env);
276} 291}
277 292
278 293
279/**
280 * Begin monitoring a zone for changes. If @a iterate_first is set,
281 * we Will first call the @a monitor function on all existing records
282 * in the selected zone(s). In any case, we will call @a sync and
283 * afterwards call @a monitor whenever a record changes.
284 *
285 * @param cfg configuration to use to connect to namestore
286 * @param zone zone to monitor
287 * @param iterate_first #GNUNET_YES to first iterate over all existing records,
288 * #GNUNET_NO to only return changes that happen from now
289 * on
290 * @param error_cb function to call on error (i.e. disconnect); note that
291 * unlike the other error callbacks in this API, a call to this
292 * function does NOT destroy the monitor handle, it merely signals
293 * that monitoring is down. You need to still explicitly call
294 * #GNUNET_NAMESTORE_zone_monitor_stop().
295 * @param error_cb_cls closure for @a error_cb
296 * @param monitor function to call on zone changes
297 * @param monitor_cls closure for @a monitor
298 * @param sync_cb function called when we're in sync with the namestore
299 * @param cls closure for @a sync_cb
300 * @return handle to stop monitoring
301 */
302struct GNUNET_NAMESTORE_ZoneMonitor * 294struct GNUNET_NAMESTORE_ZoneMonitor *
303GNUNET_NAMESTORE_zone_monitor_start ( 295GNUNET_NAMESTORE_zone_monitor_start (
304 const struct GNUNET_CONFIGURATION_Handle *cfg, 296 const struct GNUNET_CONFIGURATION_Handle *cfg,
@@ -333,6 +325,42 @@ GNUNET_NAMESTORE_zone_monitor_start (
333 return zm; 325 return zm;
334} 326}
335 327
328struct GNUNET_NAMESTORE_ZoneMonitor *
329GNUNET_NAMESTORE_zone_monitor_start2 (
330 const struct GNUNET_CONFIGURATION_Handle *cfg,
331 const struct GNUNET_IDENTITY_PrivateKey *zone,
332 int iterate_first,
333 GNUNET_SCHEDULER_TaskCallback error_cb,
334 void *error_cb_cls,
335 GNUNET_NAMESTORE_RecordSetMonitor monitor,
336 void *monitor_cls,
337 GNUNET_SCHEDULER_TaskCallback sync_cb,
338 void *sync_cb_cls,
339 enum GNUNET_GNSRECORD_Filter filter)
340{
341 struct GNUNET_NAMESTORE_ZoneMonitor *zm;
342
343 zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor);
344 if (NULL != zone)
345 zm->zone = *zone;
346 zm->iterate_first = iterate_first;
347 zm->error_cb = error_cb;
348 zm->error_cb_cls = error_cb_cls;
349 zm->monitor2 = monitor;
350 zm->monitor_cls = monitor_cls;
351 zm->sync_cb = sync_cb;
352 zm->sync_cb_cls = sync_cb_cls;
353 zm->cfg = cfg;
354 zm->filter = filter;
355 reconnect (zm);
356 if (NULL == zm->mq)
357 {
358 GNUNET_free (zm);
359 return NULL;
360 }
361 return zm;
362}
363
336 364
337/** 365/**
338 * Calls the monitor processor specified in #GNUNET_NAMESTORE_zone_monitor_start 366 * Calls the monitor processor specified in #GNUNET_NAMESTORE_zone_monitor_start
diff --git a/src/namestore/perf_namestore_api_flat.conf b/src/namestore/perf_namestore_api_flat.conf
deleted file mode 100644
index 30759ce7a..000000000
--- a/src/namestore/perf_namestore_api_flat.conf
+++ /dev/null
@@ -1,10 +0,0 @@
1@INLINE@ test_namestore_api.conf
2
3[namestore]
4DATABASE = flat
5
6[namecache]
7DISABLE = YES
8
9[namestore-heap]
10FILENAME = $GNUNET_TEST_HOME/namestore/heap.db
diff --git a/src/namestore/perf_namestore_api_postgres.conf b/src/namestore/perf_namestore_api_postgres.conf
index 52d0ecdd5..12fc24d4b 100644
--- a/src/namestore/perf_namestore_api_postgres.conf
+++ b/src/namestore/perf_namestore_api_postgres.conf
@@ -9,3 +9,4 @@ DISABLE = YES
9[namestore-postgres] 9[namestore-postgres]
10CONFIG = connect_timeout=10 dbname=gnunetcheck 10CONFIG = connect_timeout=10 dbname=gnunetcheck
11TEMPORARY_TABLE = YES 11TEMPORARY_TABLE = YES
12INIT_ON_CONNECT = YES
diff --git a/src/namestore/perf_namestore_api_sqlite.conf b/src/namestore/perf_namestore_api_sqlite.conf
index de0fa3f1f..55c3dc812 100644
--- a/src/namestore/perf_namestore_api_sqlite.conf
+++ b/src/namestore/perf_namestore_api_sqlite.conf
@@ -5,3 +5,4 @@ DISABLE = YES
5 5
6[namestore-sqlite] 6[namestore-sqlite]
7FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db 7FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
8INIT_ON_CONNECT = YES
diff --git a/src/namestore/plugin_namestore_flat.c b/src/namestore/plugin_namestore_flat.c
deleted file mode 100644
index 3576b14e0..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_IDENTITY_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 h[out] initialized hash
87 */
88static void
89hash_pkey_and_label (const struct GNUNET_IDENTITY_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_IDENTITY_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_IDENTITY_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_IDENTITY_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_IDENTITY_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_IDENTITY_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_IDENTITY_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_IDENTITY_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_IDENTITY_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_IDENTITY_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_IDENTITY_PrivateKey *zone;
678 const struct GNUNET_IDENTITY_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_IDENTITY_PrivateKey *zone,
737 const struct
738 GNUNET_IDENTITY_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
index bdbaf96b3..6e5c1c718 100644
--- a/src/namestore/plugin_namestore_postgres.c
+++ b/src/namestore/plugin_namestore_postgres.c
@@ -45,6 +45,11 @@ struct Plugin
45 const struct GNUNET_CONFIGURATION_Handle *cfg; 45 const struct GNUNET_CONFIGURATION_Handle *cfg;
46 46
47 /** 47 /**
48 * Database is prepared and ready
49 */
50 int ready;
51
52 /**
48 * Postgres database handle. 53 * Postgres database handle.
49 */ 54 */
50 struct GNUNET_PQ_Context *dbh; 55 struct GNUNET_PQ_Context *dbh;
@@ -60,11 +65,11 @@ struct Plugin
60 * @return #GNUNET_OK on success 65 * @return #GNUNET_OK on success
61 */ 66 */
62static int 67static int
63database_setup (struct Plugin *plugin) 68init_database (struct Plugin *plugin, char **emsg, int drop)
64{ 69{
65 struct GNUNET_PQ_ExecuteStatement es_temporary = 70 struct GNUNET_PQ_ExecuteStatement es_temporary =
66 GNUNET_PQ_make_execute ( 71 GNUNET_PQ_make_execute (
67 "CREATE TEMPORARY TABLE IF NOT EXISTS ns098records (" 72 "CREATE TEMPORARY TABLE ns098records ("
68 " seq BIGSERIAL PRIMARY KEY," 73 " seq BIGSERIAL PRIMARY KEY,"
69 " zone_private_key BYTEA NOT NULL DEFAULT ''," 74 " zone_private_key BYTEA NOT NULL DEFAULT '',"
70 " pkey BYTEA DEFAULT ''," 75 " pkey BYTEA DEFAULT '',"
@@ -75,7 +80,7 @@ database_setup (struct Plugin *plugin)
75 " CONSTRAINT zl UNIQUE (zone_private_key,label)" 80 " CONSTRAINT zl UNIQUE (zone_private_key,label)"
76 ")"); 81 ")");
77 struct GNUNET_PQ_ExecuteStatement es_default = 82 struct GNUNET_PQ_ExecuteStatement es_default =
78 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records (" 83 GNUNET_PQ_make_execute ("CREATE TABLE ns098records ("
79 " seq BIGSERIAL PRIMARY KEY," 84 " seq BIGSERIAL PRIMARY KEY,"
80 " zone_private_key BYTEA NOT NULL DEFAULT ''," 85 " zone_private_key BYTEA NOT NULL DEFAULT '',"
81 " pkey BYTEA DEFAULT ''," 86 " pkey BYTEA DEFAULT '',"
@@ -87,18 +92,15 @@ database_setup (struct Plugin *plugin)
87 ")"); 92 ")");
88 const struct GNUNET_PQ_ExecuteStatement *cr; 93 const struct GNUNET_PQ_ExecuteStatement *cr;
89 struct GNUNET_PQ_ExecuteStatement sc = GNUNET_PQ_EXECUTE_STATEMENT_END; 94 struct GNUNET_PQ_ExecuteStatement sc = GNUNET_PQ_EXECUTE_STATEMENT_END;
90 95 struct GNUNET_PQ_ExecuteStatement es_drop =
96 GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS ns098records");
91 if (GNUNET_YES == 97 if (GNUNET_YES ==
92 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, 98 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
93 "namestore-postgres", 99 "namestore-postgres",
94 "TEMPORARY_TABLE")) 100 "TEMPORARY_TABLE"))
95 {
96 cr = &es_temporary; 101 cr = &es_temporary;
97 }
98 else 102 else
99 {
100 cr = &es_default; 103 cr = &es_default;
101 }
102 104
103 if (GNUNET_YES == 105 if (GNUNET_YES ==
104 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, 106 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
@@ -120,46 +122,134 @@ database_setup (struct Plugin *plugin)
120 sc, 122 sc,
121 GNUNET_PQ_EXECUTE_STATEMENT_END 123 GNUNET_PQ_EXECUTE_STATEMENT_END
122 }; 124 };
123 struct GNUNET_PQ_PreparedStatement ps[] = { 125 struct GNUNET_PQ_ExecuteStatement es_alt[] = {
124 GNUNET_PQ_make_prepare ("store_records", 126 es_drop,
125 "INSERT INTO ns098records" 127 *cr,
126 " (zone_private_key, pkey, rvalue, record_count, record_data, label)" 128 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
127 " VALUES ($1, $2, $3, $4, $5, $6)" 129 "ON ns098records (zone_private_key,pkey)"),
128 " ON CONFLICT ON CONSTRAINT zl" 130 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
129 " DO UPDATE" 131 "ON ns098records (zone_private_key,seq)"),
130 " SET pkey=$2,rvalue=$3,record_count=$4,record_data=$5" 132 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_label "
131 " WHERE ns098records.zone_private_key = $1" 133 "ON ns098records (label)"),
132 " AND ns098records.label = $6", 134 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS zone_label "
133 6), 135 "ON ns098records (zone_private_key,label)"),
134 GNUNET_PQ_make_prepare ("delete_records", 136 sc,
135 "DELETE FROM ns098records " 137 GNUNET_PQ_EXECUTE_STATEMENT_END
136 "WHERE zone_private_key=$1 AND label=$2",
137 2),
138 GNUNET_PQ_make_prepare ("zone_to_name",
139 "SELECT seq,record_count,record_data,label FROM ns098records"
140 " WHERE zone_private_key=$1 AND pkey=$2",
141 2),
142 GNUNET_PQ_make_prepare ("iterate_zone",
143 "SELECT seq,record_count,record_data,label FROM ns098records "
144 "WHERE zone_private_key=$1 AND seq > $2 ORDER BY seq ASC LIMIT $3",
145 3),
146 GNUNET_PQ_make_prepare ("iterate_all_zones",
147 "SELECT seq,record_count,record_data,label,zone_private_key"
148 " FROM ns098records WHERE seq > $1 ORDER BY seq ASC LIMIT $2",
149 2),
150 GNUNET_PQ_make_prepare ("lookup_label",
151 "SELECT seq,record_count,record_data,label "
152 "FROM ns098records WHERE zone_private_key=$1 AND label=$2",
153 2),
154 GNUNET_PQ_PREPARED_STATEMENT_END
155 }; 138 };
139 if (GNUNET_NO == drop)
140 {
141 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
142 "namestore-postgres",
143 NULL,
144 es,
145 NULL);
146 }
147 else {
148 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
149 "namestore-postgres",
150 NULL,
151 es_alt,
152 NULL);
153 }
154 }
155 if (NULL == plugin->dbh)
156 {
157 *emsg = GNUNET_strdup ("Failed to connect to PQ database");
158 return GNUNET_SYSERR;
159 }
160 GNUNET_PQ_disconnect (plugin->dbh);
161 plugin->dbh = NULL;
162 return GNUNET_OK;
163}
164
165static int
166database_prepare (struct Plugin *plugin)
167{
168 enum GNUNET_GenericReturnValue ret;
169 if (GNUNET_YES == plugin->ready)
170 return GNUNET_OK;
171 struct GNUNET_PQ_PreparedStatement ps[] = {
172 GNUNET_PQ_make_prepare ("store_records",
173 "INSERT INTO ns098records"
174 " (zone_private_key, pkey, rvalue, record_count, record_data, label)"
175 " VALUES ($1, $2, $3, $4, $5, $6)"
176 " ON CONFLICT ON CONSTRAINT zl"
177 " DO UPDATE"
178 " SET pkey=$2,rvalue=$3,record_count=$4,record_data=$5"
179 " WHERE ns098records.zone_private_key = $1"
180 " AND ns098records.label = $6",
181 6),
182 GNUNET_PQ_make_prepare ("delete_records",
183 "DELETE FROM ns098records "
184 "WHERE zone_private_key=$1 AND label=$2",
185 2),
186 GNUNET_PQ_make_prepare ("zone_to_name",
187 "SELECT seq,record_count,record_data,label FROM ns098records"
188 " WHERE zone_private_key=$1 AND pkey=$2",
189 2),
190 GNUNET_PQ_make_prepare ("iterate_zone",
191 "SELECT seq,record_count,record_data,label FROM ns098records "
192 "WHERE zone_private_key=$1 AND seq > $2 ORDER BY seq ASC LIMIT $3",
193 3),
194 GNUNET_PQ_make_prepare ("iterate_all_zones",
195 "SELECT seq,record_count,record_data,label,zone_private_key"
196 " FROM ns098records WHERE seq > $1 ORDER BY seq ASC LIMIT $2",
197 2),
198 GNUNET_PQ_make_prepare ("lookup_label",
199 "SELECT seq,record_count,record_data,label "
200 "FROM ns098records WHERE zone_private_key=$1 AND label=$2",
201 2),
202 GNUNET_PQ_make_prepare ("edit_set",
203 "SELECT seq,record_count,record_data,label "
204 "FROM ns098records WHERE zone_private_key=$1 AND label=$2 FOR UPDATE NOWAIT",
205 2),
206 GNUNET_PQ_PREPARED_STATEMENT_END
207 };
208 ret = GNUNET_PQ_prepare_statements (plugin->dbh, ps);
209 if (GNUNET_OK != ret)
210 return ret;
211 plugin->ready = GNUNET_YES;
212 return GNUNET_OK;
213}
214
215
216/**
217 * Initialize the database connections and associated
218 * data structures (create tables and indices
219 * as needed as well).
220 *
221 * @param plugin the plugin context (state for this module)
222 * @return #GNUNET_OK on success
223 */
224static int
225database_connect (struct Plugin *plugin)
226{
227 const struct GNUNET_PQ_ExecuteStatement *cr;
228 char *emsg;
229 struct GNUNET_PQ_ExecuteStatement sc = GNUNET_PQ_EXECUTE_STATEMENT_END;
156 230
157 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, 231 if (GNUNET_YES ==
158 "namestore-postgres", 232 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
159 NULL, 233 "namestore-postgres",
160 es, 234 "INIT_ON_CONNECT"))
161 ps); 235 {
236 /**
237 * Gracefully fail as this should not be a critical error if the
238 * database is already created
239 */
240 if (GNUNET_OK != init_database (plugin, &emsg, GNUNET_NO))
241 {
242 LOG (GNUNET_ERROR_TYPE_WARNING,
243 "Failed to initialize database on connect: `%s'\n",
244 emsg);
245 GNUNET_free (emsg);
246 }
162 } 247 }
248 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
249 "namestore-postgres",
250 NULL,
251 NULL,
252 NULL);
163 if (NULL == plugin->dbh) 253 if (NULL == plugin->dbh)
164 return GNUNET_SYSERR; 254 return GNUNET_SYSERR;
165 return GNUNET_OK; 255 return GNUNET_OK;
@@ -191,6 +281,7 @@ namestore_postgres_store_records (void *cls,
191 uint32_t rd_count32 = (uint32_t) rd_count; 281 uint32_t rd_count32 = (uint32_t) rd_count;
192 ssize_t data_size; 282 ssize_t data_size;
193 283
284 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
194 memset (&pkey, 285 memset (&pkey,
195 0, 286 0,
196 sizeof(pkey)); 287 sizeof(pkey));
@@ -323,7 +414,9 @@ parse_result_call_iterator (void *cls,
323 struct ParserContext *pc = cls; 414 struct ParserContext *pc = cls;
324 415
325 if (NULL == pc->iter) 416 if (NULL == pc->iter)
326 return; /* no need to do more work */ 417 return; /* no need to do more work */
418 LOG (GNUNET_ERROR_TYPE_DEBUG,
419 "Got %d results from PQ.\n", num_results);
327 for (unsigned int i = 0; i < num_results; i++) 420 for (unsigned int i = 0; i < num_results; i++)
328 { 421 {
329 uint64_t serial; 422 uint64_t serial;
@@ -394,7 +487,6 @@ parse_result_call_iterator (void *cls,
394 pc->limit -= num_results; 487 pc->limit -= num_results;
395} 488}
396 489
397
398/** 490/**
399 * Lookup records in the datastore for which we are the authority. 491 * Lookup records in the datastore for which we are the authority.
400 * 492 *
@@ -403,17 +495,20 @@ parse_result_call_iterator (void *cls,
403 * @param label name of the record in the zone 495 * @param label name of the record in the zone
404 * @param iter function to call with the result 496 * @param iter function to call with the result
405 * @param iter_cls closure for @a iter 497 * @param iter_cls closure for @a iter
498 * @param method the method to use "lookup_record" or "edit_set"
406 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR 499 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
407 */ 500 */
408static int 501static int
409namestore_postgres_lookup_records (void *cls, 502lookup_records (void *cls,
410 const struct 503 const struct
411 GNUNET_IDENTITY_PrivateKey *zone, 504 GNUNET_IDENTITY_PrivateKey *zone,
412 const char *label, 505 const char *label,
413 GNUNET_NAMESTORE_RecordIterator iter, 506 GNUNET_NAMESTORE_RecordIterator iter,
414 void *iter_cls) 507 void *iter_cls,
508 const char*method)
415{ 509{
416 struct Plugin *plugin = cls; 510 struct Plugin *plugin = cls;
511 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
417 struct GNUNET_PQ_QueryParam params[] = { 512 struct GNUNET_PQ_QueryParam params[] = {
418 GNUNET_PQ_query_param_auto_from_type (zone), 513 GNUNET_PQ_query_param_auto_from_type (zone),
419 GNUNET_PQ_query_param_string (label), 514 GNUNET_PQ_query_param_string (label),
@@ -431,7 +526,7 @@ namestore_postgres_lookup_records (void *cls,
431 pc.iter_cls = iter_cls; 526 pc.iter_cls = iter_cls;
432 pc.zone_key = zone; 527 pc.zone_key = zone;
433 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, 528 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
434 "lookup_label", 529 method,
435 params, 530 params,
436 &parse_result_call_iterator, 531 &parse_result_call_iterator,
437 &pc); 532 &pc);
@@ -442,6 +537,48 @@ namestore_postgres_lookup_records (void *cls,
442 return GNUNET_OK; 537 return GNUNET_OK;
443} 538}
444 539
540/**
541 * Lookup records in the datastore for which we are the authority.
542 *
543 * @param cls closure (internal context for the plugin)
544 * @param zone private key of the zone
545 * @param label name of the record in the zone
546 * @param iter function to call with the result
547 * @param iter_cls closure for @a iter
548 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
549 */
550static int
551namestore_postgres_lookup_records (void *cls,
552 const struct
553 GNUNET_IDENTITY_PrivateKey *zone,
554 const char *label,
555 GNUNET_NAMESTORE_RecordIterator iter,
556 void *iter_cls)
557{
558 return lookup_records (cls, zone, label, iter, iter_cls, "lookup_label");
559}
560
561/**
562 * Edit records in the datastore for which we are the authority.
563 *
564 * @param cls closure (internal context for the plugin)
565 * @param zone private key of the zone
566 * @param label name of the record in the zone
567 * @param iter function to call with the result
568 * @param iter_cls closure for @a iter
569 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
570 */
571static int
572namestore_postgres_edit_records (void *cls,
573 const struct
574 GNUNET_IDENTITY_PrivateKey *zone,
575 const char *label,
576 GNUNET_NAMESTORE_RecordIterator iter,
577 void *iter_cls)
578{
579 return lookup_records (cls, zone, label, iter, iter_cls, "edit_set");
580}
581
445 582
446/** 583/**
447 * Iterate over the results for a particular key and zone in the 584 * Iterate over the results for a particular key and zone in the
@@ -468,6 +605,7 @@ namestore_postgres_iterate_records (void *cls,
468 enum GNUNET_DB_QueryStatus res; 605 enum GNUNET_DB_QueryStatus res;
469 struct ParserContext pc; 606 struct ParserContext pc;
470 607
608 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
471 pc.iter = iter; 609 pc.iter = iter;
472 pc.iter_cls = iter_cls; 610 pc.iter_cls = iter_cls;
473 pc.zone_key = zone; 611 pc.zone_key = zone;
@@ -532,6 +670,7 @@ namestore_postgres_zone_to_name (void *cls,
532 void *iter_cls) 670 void *iter_cls)
533{ 671{
534 struct Plugin *plugin = cls; 672 struct Plugin *plugin = cls;
673 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
535 struct GNUNET_PQ_QueryParam params[] = { 674 struct GNUNET_PQ_QueryParam params[] = {
536 GNUNET_PQ_query_param_auto_from_type (zone), 675 GNUNET_PQ_query_param_auto_from_type (zone),
537 GNUNET_PQ_query_param_auto_from_type (value_zone), 676 GNUNET_PQ_query_param_auto_from_type (value_zone),
@@ -553,6 +692,88 @@ namestore_postgres_zone_to_name (void *cls,
553 return GNUNET_OK; 692 return GNUNET_OK;
554} 693}
555 694
695/**
696 * Begin a transaction for a client.
697 *
698 * @param cls closure (internal context for the plugin)
699 * @param emsg error message set of return code is #GNUNET_SYSERR
700 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
701 */
702static enum GNUNET_GenericReturnValue
703namestore_postgres_transaction_begin (void *cls,
704 char **emsg)
705{
706 struct Plugin *plugin = cls;
707 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
708 struct GNUNET_PQ_ExecuteStatement es[] = {
709 GNUNET_PQ_make_execute ("BEGIN"),
710 GNUNET_PQ_EXECUTE_STATEMENT_END
711 };
712
713 return GNUNET_PQ_exec_statements (plugin->dbh, es);
714}
715
716/**
717 * Commit a transaction for a client.
718 * This releases the lock on the database.
719 *
720 * @param cls closure (internal context for the plugin)
721 * @param emsg error message set of return code is #GNUNET_SYSERR
722 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
723 */
724static enum GNUNET_GenericReturnValue
725namestore_postgres_transaction_rollback (void *cls,
726 char **emsg)
727{
728 struct Plugin *plugin = cls;
729 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
730 struct GNUNET_PQ_ExecuteStatement es[] = {
731 GNUNET_PQ_make_execute ("ROLLBACK"),
732 GNUNET_PQ_EXECUTE_STATEMENT_END
733 };
734
735 return GNUNET_PQ_exec_statements (plugin->dbh, es);
736}
737
738/**
739 * Roll back a transaction for a client.
740 * This releases the lock on the database.
741 *
742 * @param cls closure (internal context for the plugin)
743 * @param emsg error message set of return code is #GNUNET_SYSERR
744 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
745 */
746static enum GNUNET_GenericReturnValue
747namestore_postgres_transaction_commit (void *cls,
748 char **emsg)
749{
750 struct Plugin *plugin = cls;
751 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
752 struct GNUNET_PQ_ExecuteStatement es[] = {
753 GNUNET_PQ_make_execute ("COMMIT"),
754 GNUNET_PQ_EXECUTE_STATEMENT_END
755 };
756
757 return GNUNET_PQ_exec_statements (plugin->dbh, es);
758}
759
760
761static enum GNUNET_GenericReturnValue
762namestore_postgres_initialize_database (void *cls,
763 char **emsg)
764{
765 return init_database (cls, emsg, GNUNET_NO);
766}
767
768
769static enum GNUNET_GenericReturnValue
770namestore_postgres_reset_database (void *cls,
771 char **emsg)
772{
773 return init_database (cls, emsg, GNUNET_YES);
774}
775
776
556 777
557/** 778/**
558 * Shutdown database connection and associate data 779 * Shutdown database connection and associate data
@@ -577,25 +798,30 @@ database_shutdown (struct Plugin *plugin)
577void * 798void *
578libgnunet_plugin_namestore_postgres_init (void *cls) 799libgnunet_plugin_namestore_postgres_init (void *cls)
579{ 800{
580 static struct Plugin plugin; 801 struct Plugin *plugin;
581 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 802 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
582 struct GNUNET_NAMESTORE_PluginFunctions *api; 803 struct GNUNET_NAMESTORE_PluginFunctions *api;
583 804
584 if (NULL != plugin.cfg) 805 plugin = GNUNET_new (struct Plugin);
585 return NULL; /* can only initialize once! */ 806 plugin->cfg = cfg;
586 memset (&plugin, 0, sizeof(struct Plugin)); 807 if (GNUNET_OK != database_connect (plugin))
587 plugin.cfg = cfg;
588 if (GNUNET_OK != database_setup (&plugin))
589 { 808 {
590 database_shutdown (&plugin); 809 database_shutdown (plugin);
810 GNUNET_free (plugin);
591 return NULL; 811 return NULL;
592 } 812 }
593 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions); 813 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
594 api->cls = &plugin; 814 api->cls = plugin;
595 api->store_records = &namestore_postgres_store_records; 815 api->store_records = &namestore_postgres_store_records;
596 api->iterate_records = &namestore_postgres_iterate_records; 816 api->iterate_records = &namestore_postgres_iterate_records;
597 api->zone_to_name = &namestore_postgres_zone_to_name; 817 api->zone_to_name = &namestore_postgres_zone_to_name;
598 api->lookup_records = &namestore_postgres_lookup_records; 818 api->lookup_records = &namestore_postgres_lookup_records;
819 api->transaction_begin = &namestore_postgres_transaction_begin;
820 api->transaction_commit = &namestore_postgres_transaction_commit;
821 api->transaction_rollback = &namestore_postgres_transaction_rollback;
822 api->initialize_database = &namestore_postgres_initialize_database;
823 api->reset_database = &namestore_postgres_reset_database;
824 api->edit_records = &namestore_postgres_edit_records;
599 LOG (GNUNET_ERROR_TYPE_INFO, 825 LOG (GNUNET_ERROR_TYPE_INFO,
600 "Postgres namestore plugin running\n"); 826 "Postgres namestore plugin running\n");
601 return api; 827 return api;
@@ -616,6 +842,7 @@ libgnunet_plugin_namestore_postgres_done (void *cls)
616 842
617 database_shutdown (plugin); 843 database_shutdown (plugin);
618 plugin->cfg = NULL; 844 plugin->cfg = NULL;
845 GNUNET_free (plugin);
619 GNUNET_free (api); 846 GNUNET_free (api);
620 LOG (GNUNET_ERROR_TYPE_DEBUG, 847 LOG (GNUNET_ERROR_TYPE_DEBUG,
621 "Postgres namestore plugin is finished\n"); 848 "Postgres namestore plugin is finished\n");
diff --git a/src/namestore/plugin_namestore_sqlite.c b/src/namestore/plugin_namestore_sqlite.c
index 0b3aac84f..35fd340ab 100644
--- a/src/namestore/plugin_namestore_sqlite.c
+++ b/src/namestore/plugin_namestore_sqlite.c
@@ -75,6 +75,11 @@ struct Plugin
75 char *fn; 75 char *fn;
76 76
77 /** 77 /**
78 * Statements prepared, we are ready to go if GNUNET_YES
79 */
80 int ready;
81
82 /**
78 * Native SQLite database handle. 83 * Native SQLite database handle.
79 */ 84 */
80 sqlite3 *dbh; 85 sqlite3 *dbh;
@@ -120,31 +125,19 @@ struct Plugin
120 * @return #GNUNET_OK on success 125 * @return #GNUNET_OK on success
121 */ 126 */
122static int 127static int
123database_setup (struct Plugin *plugin) 128database_prepare (struct Plugin *plugin)
124{ 129{
125 char *sqlite_filename; 130 if (GNUNET_YES == plugin->ready)
131 return GNUNET_OK;
126 struct GNUNET_SQ_ExecuteStatement es[] = { 132 struct GNUNET_SQ_ExecuteStatement es[] = {
127 GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"), 133 GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
128 GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"), 134 GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
129 GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"), 135 GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"),
130 GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"), 136 GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"),
131 GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""), 137 GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""),
132 GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=EXCLUSIVE"), 138 GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"),
133 GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"), 139 GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"),
134 GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"), 140 GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
135 GNUNET_SQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records ("
136 " uid INTEGER PRIMARY KEY,"
137 " zone_private_key BLOB NOT NULL,"
138 " pkey BLOB,"
139 " rvalue INT8 NOT NULL,"
140 " record_count INT NOT NULL,"
141 " record_data BLOB NOT NULL,"
142 " label TEXT NOT NULL"
143 ")"),
144 GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
145 "ON ns098records (zone_private_key,pkey)"),
146 GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
147 "ON ns098records (zone_private_key,uid)"),
148 GNUNET_SQ_EXECUTE_STATEMENT_END 141 GNUNET_SQ_EXECUTE_STATEMENT_END
149 }; 142 };
150 struct GNUNET_SQ_PrepareStatement ps[] = { 143 struct GNUNET_SQ_PrepareStatement ps[] = {
@@ -180,64 +173,25 @@ database_setup (struct Plugin *plugin)
180 }; 173 };
181 174
182 if (GNUNET_OK != 175 if (GNUNET_OK !=
183 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
184 "namestore-sqlite",
185 "FILENAME",
186 &sqlite_filename))
187 {
188 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
189 "namestore-sqlite",
190 "FILENAME");
191 return GNUNET_SYSERR;
192 }
193 if (GNUNET_OK !=
194 GNUNET_DISK_file_test (sqlite_filename))
195 {
196 if (GNUNET_OK !=
197 GNUNET_DISK_directory_create_for_file (sqlite_filename))
198 {
199 GNUNET_break (0);
200 GNUNET_free (sqlite_filename);
201 return GNUNET_SYSERR;
202 }
203 }
204 /* sqlite_filename should be UTF-8-encoded. If it isn't, it's a bug */
205 plugin->fn = sqlite_filename;
206
207 /* Open database and precompile statements */
208 if (SQLITE_OK !=
209 sqlite3_open (plugin->fn,
210 &plugin->dbh))
211 {
212 LOG (GNUNET_ERROR_TYPE_ERROR,
213 _ ("Unable to initialize SQLite: %s.\n"),
214 sqlite3_errmsg (plugin->dbh));
215 return GNUNET_SYSERR;
216 }
217 GNUNET_break (SQLITE_OK ==
218 sqlite3_busy_timeout (plugin->dbh,
219 BUSY_TIMEOUT_MS));
220 if (GNUNET_OK !=
221 GNUNET_SQ_exec_statements (plugin->dbh, 176 GNUNET_SQ_exec_statements (plugin->dbh,
222 es)) 177 es))
223 { 178 {
224 GNUNET_break (0);
225 LOG (GNUNET_ERROR_TYPE_ERROR, 179 LOG (GNUNET_ERROR_TYPE_ERROR,
226 _ ("Failed to setup database at `%s'\n"), 180 _("Failed to setup database with: `%s'\n"),
227 plugin->fn); 181 sqlite3_errmsg (plugin->dbh));
228 return GNUNET_SYSERR; 182 return GNUNET_SYSERR;
229 } 183 }
230
231 if (GNUNET_OK != 184 if (GNUNET_OK !=
232 GNUNET_SQ_prepare (plugin->dbh, 185 GNUNET_SQ_prepare (plugin->dbh,
233 ps)) 186 ps))
234 { 187 {
235 GNUNET_break (0); 188 GNUNET_break (0);
236 LOG (GNUNET_ERROR_TYPE_ERROR, 189 LOG (GNUNET_ERROR_TYPE_ERROR,
237 _ ("Failed to setup database at `%s'\n"), 190 _ ("Failed to setup database with: `%s'\n"),
238 plugin->fn); 191 sqlite3_errmsg (plugin->dbh));
239 return GNUNET_SYSERR; 192 return GNUNET_SYSERR;
240 } 193 }
194 plugin->ready = GNUNET_YES;
241 return GNUNET_OK; 195 return GNUNET_OK;
242} 196}
243 197
@@ -296,7 +250,6 @@ database_shutdown (struct Plugin *plugin)
296 GNUNET_ERROR_TYPE_ERROR, 250 GNUNET_ERROR_TYPE_ERROR,
297 "sqlite3_close"); 251 "sqlite3_close");
298 252
299 GNUNET_free (plugin->fn);
300} 253}
301 254
302 255
@@ -325,14 +278,15 @@ namestore_sqlite_store_records (void *cls,
325 uint64_t rvalue; 278 uint64_t rvalue;
326 ssize_t data_size; 279 ssize_t data_size;
327 280
281 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
328 memset (&pkey, 282 memset (&pkey,
329 0, 283 0,
330 sizeof(pkey)); 284 sizeof(pkey));
331 for (unsigned int i = 0; i < rd_count; i++) 285 for (unsigned int i = 0; i < rd_count; i++)
332 { 286 {
333 LOG (GNUNET_ERROR_TYPE_DEBUG, 287 LOG (GNUNET_ERROR_TYPE_DEBUG,
334 "Checking if `%d' is zonekey type\n", 288 "Checking if `%d' is zonekey type\n",
335 rd[i].record_type); 289 rd[i].record_type);
336 290
337 if (GNUNET_YES == GNUNET_GNSRECORD_is_zonekey_type (rd[i].record_type)) 291 if (GNUNET_YES == GNUNET_GNSRECORD_is_zonekey_type (rd[i].record_type))
338 { 292 {
@@ -342,8 +296,8 @@ namestore_sqlite_store_records (void *cls,
342 rd[i].record_type, 296 rd[i].record_type,
343 &pkey)); 297 &pkey));
344 LOG (GNUNET_ERROR_TYPE_DEBUG, 298 LOG (GNUNET_ERROR_TYPE_DEBUG,
345 "Storing delegation zone record value `%s'\n", 299 "Storing delegation zone record value `%s'\n",
346 GNUNET_GNSRECORD_z2s (&pkey)); 300 GNUNET_GNSRECORD_z2s (&pkey));
347 301
348 break; 302 break;
349 } 303 }
@@ -594,6 +548,7 @@ namestore_sqlite_lookup_records (void *cls,
594 void *iter_cls) 548 void *iter_cls)
595{ 549{
596 struct Plugin *plugin = cls; 550 struct Plugin *plugin = cls;
551 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
597 struct GNUNET_SQ_QueryParam params[] = { 552 struct GNUNET_SQ_QueryParam params[] = {
598 GNUNET_SQ_query_param_auto_from_type (zone), 553 GNUNET_SQ_query_param_auto_from_type (zone),
599 GNUNET_SQ_query_param_string (label), 554 GNUNET_SQ_query_param_string (label),
@@ -649,6 +604,7 @@ namestore_sqlite_iterate_records (void *cls,
649 sqlite3_stmt *stmt; 604 sqlite3_stmt *stmt;
650 int err; 605 int err;
651 606
607 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
652 if (NULL == zone) 608 if (NULL == zone)
653 { 609 {
654 struct GNUNET_SQ_QueryParam params[] = { 610 struct GNUNET_SQ_QueryParam params[] = {
@@ -712,6 +668,7 @@ namestore_sqlite_zone_to_name (void *cls,
712 void *iter_cls) 668 void *iter_cls)
713{ 669{
714 struct Plugin *plugin = cls; 670 struct Plugin *plugin = cls;
671 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
715 struct GNUNET_SQ_QueryParam params[] = { 672 struct GNUNET_SQ_QueryParam params[] = {
716 GNUNET_SQ_query_param_auto_from_type (zone), 673 GNUNET_SQ_query_param_auto_from_type (zone),
717 GNUNET_SQ_query_param_auto_from_type (value_zone), 674 GNUNET_SQ_query_param_auto_from_type (value_zone),
@@ -740,6 +697,204 @@ namestore_sqlite_zone_to_name (void *cls,
740 iter_cls); 697 iter_cls);
741} 698}
742 699
700/**
701 * Begin a transaction for a client.
702 * This locks the database. SQLite is unable to discern between different
703 * rows with a specific zone key but the API looks like this anyway.
704 * https://www.sqlite.org/lang_transaction.html
705 *
706 * @param cls closure (internal context for the plugin)
707 * @param emsg error message set of return code is #GNUNET_SYSERR
708 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
709 */
710static enum GNUNET_GenericReturnValue
711namestore_sqlite_transaction_begin (void *cls,
712 char **emsg)
713{
714 struct Plugin *plugin = cls;
715 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
716 return (SQLITE_BUSY == sqlite3_exec (plugin->dbh,
717 "BEGIN IMMEDIATE TRANSACTION;", NULL,
718 NULL, emsg)) ? GNUNET_SYSERR :
719 GNUNET_YES;
720}
721
722/**
723 * Commit a transaction for a client.
724 * This releases the lock on the database.
725 *
726 * @param cls closure (internal context for the plugin)
727 * @param emsg error message set of return code is #GNUNET_SYSERR
728 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
729 */
730static enum GNUNET_GenericReturnValue
731namestore_sqlite_transaction_rollback (void *cls,
732 char **emsg)
733{
734 struct Plugin *plugin = cls;
735 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
736 return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "ROLLBACK;", NULL,
737 NULL, emsg)) ? GNUNET_SYSERR :
738 GNUNET_YES;
739}
740
741/**
742 * Roll back a transaction for a client.
743 * This releases the lock on the database.
744 *
745 * @param cls closure (internal context for the plugin)
746 * @param emsg error message set of return code is #GNUNET_SYSERR
747 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
748 */
749static enum GNUNET_GenericReturnValue
750namestore_sqlite_transaction_commit (void *cls,
751 char **emsg)
752{
753 struct Plugin *plugin = cls;
754 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
755 return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "END TRANSACTION;", NULL,
756 NULL, emsg)) ? GNUNET_SYSERR :
757 GNUNET_YES;
758}
759
760static enum GNUNET_GenericReturnValue
761init_database (void *cls, char **emsg, int drop)
762{
763 struct Plugin *plugin = cls;
764 struct GNUNET_SQ_ExecuteStatement es_drop[] = {
765 GNUNET_SQ_make_execute ("DROP TABLE IF EXISTS ns098records"),
766 GNUNET_SQ_EXECUTE_STATEMENT_END
767 };
768 struct GNUNET_SQ_ExecuteStatement es[] = {
769 GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
770 GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
771 GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"),
772 GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"),
773 GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""),
774 GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"),
775 GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"),
776 GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
777 GNUNET_SQ_make_execute ("CREATE TABLE ns098records ("
778 " uid INTEGER PRIMARY KEY,"
779 " zone_private_key BLOB NOT NULL,"
780 " pkey BLOB,"
781 " rvalue INT8 NOT NULL,"
782 " record_count INT NOT NULL,"
783 " record_data BLOB NOT NULL,"
784 " label TEXT NOT NULL"
785 ")"),
786 GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_reverse "
787 "ON ns098records (zone_private_key,pkey)"),
788 GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_iter "
789 "ON ns098records (zone_private_key,uid)"),
790 GNUNET_SQ_EXECUTE_STATEMENT_END
791 };
792 if ((GNUNET_YES == drop) &&
793 (GNUNET_OK != GNUNET_SQ_exec_statements (plugin->dbh,
794 es_drop)))
795 {
796 GNUNET_asprintf (emsg,
797 _ ("Failed to drop database with: `%s'\n"),
798 sqlite3_errmsg (plugin->dbh));
799 return GNUNET_SYSERR;
800 }
801 if (GNUNET_OK !=
802 GNUNET_SQ_exec_statements (plugin->dbh,
803 es))
804 {
805 GNUNET_asprintf (emsg,
806 _ ("Failed to setup database with: `%s'\n"),
807 sqlite3_errmsg (plugin->dbh));
808 return GNUNET_SYSERR;
809 }
810 return GNUNET_OK;
811}
812
813enum GNUNET_GenericReturnValue
814namestore_sqlite_initialize_database (void *cls, char **emsg)
815{
816 return init_database (cls, emsg, GNUNET_NO);
817}
818
819enum GNUNET_GenericReturnValue
820namestore_sqlite_reset_database (void *cls, char **emsg)
821{
822 return init_database (cls, emsg, GNUNET_YES);
823}
824
825/**
826 * Initialize the database connections and associated
827 * data structures (create tables and indices
828 * as needed as well).
829 *
830 * @param plugin the plugin context (state for this module)
831 * @return #GNUNET_OK on success
832 */
833static int
834database_connect (struct Plugin *plugin)
835{
836 char *sqlite_filename;
837 char *emsg;
838 int try_create = GNUNET_NO;
839
840 if (GNUNET_OK !=
841 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
842 "namestore-sqlite",
843 "FILENAME",
844 &sqlite_filename))
845 {
846 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
847 "namestore-sqlite",
848 "FILENAME");
849 return GNUNET_SYSERR;
850 }
851 if (GNUNET_OK !=
852 GNUNET_DISK_file_test (sqlite_filename))
853 {
854 if (GNUNET_OK !=
855 GNUNET_DISK_directory_create_for_file (sqlite_filename))
856 {
857 GNUNET_break (0);
858 GNUNET_free (sqlite_filename);
859 return GNUNET_SYSERR;
860 }
861 }
862
863 /* Open database and precompile statements */
864 if ((NULL == plugin->dbh) &&
865 (SQLITE_OK != sqlite3_open (sqlite_filename,
866 &plugin->dbh)))
867 {
868 LOG (GNUNET_ERROR_TYPE_ERROR,
869 _ ("Unable to initialize SQLite: %s.\n"),
870 sqlite3_errmsg (plugin->dbh));
871 GNUNET_free (sqlite_filename);
872 return GNUNET_SYSERR;
873 }
874 GNUNET_free (sqlite_filename);
875 GNUNET_break (SQLITE_OK ==
876 sqlite3_busy_timeout (plugin->dbh,
877 BUSY_TIMEOUT_MS));
878 if (GNUNET_YES ==
879 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
880 "namestore-sqlite",
881 "INIT_ON_CONNECT"))
882 {
883 /**
884 * Gracefully fail as this should not be a critical error if the
885 * database is already created
886 */
887 if (GNUNET_OK != init_database (plugin, &emsg, GNUNET_NO))
888 {
889 LOG (GNUNET_ERROR_TYPE_WARNING,
890 "Failed to initialize database on connect: `%s'\n",
891 emsg);
892 GNUNET_free (emsg);
893 }
894 }
895 return GNUNET_OK;
896}
897
743 898
744/** 899/**
745 * Entry point for the plugin. 900 * Entry point for the plugin.
@@ -750,29 +905,38 @@ namestore_sqlite_zone_to_name (void *cls,
750void * 905void *
751libgnunet_plugin_namestore_sqlite_init (void *cls) 906libgnunet_plugin_namestore_sqlite_init (void *cls)
752{ 907{
753 static struct Plugin plugin; 908 struct Plugin *plugin;
754 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 909 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
755 struct GNUNET_NAMESTORE_PluginFunctions *api; 910 struct GNUNET_NAMESTORE_PluginFunctions *api;
756 911
757 if (NULL != plugin.cfg) 912 plugin = GNUNET_new (struct Plugin);
758 return NULL; /* can only initialize once! */ 913 plugin->cfg = cfg;
759 memset (&plugin, 914 if (GNUNET_OK != database_connect (plugin))
760 0,
761 sizeof(struct Plugin));
762 plugin.cfg = cfg;
763 if (GNUNET_OK != database_setup (&plugin))
764 { 915 {
765 database_shutdown (&plugin); 916 LOG (GNUNET_ERROR_TYPE_ERROR,
917 "Database could not be connected to.\n");
918 GNUNET_free (plugin);
766 return NULL; 919 return NULL;
767 } 920 }
768 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions); 921 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
769 api->cls = &plugin; 922 api->cls = plugin;
770 api->store_records = &namestore_sqlite_store_records; 923 api->store_records = &namestore_sqlite_store_records;
771 api->iterate_records = &namestore_sqlite_iterate_records; 924 api->iterate_records = &namestore_sqlite_iterate_records;
772 api->zone_to_name = &namestore_sqlite_zone_to_name; 925 api->zone_to_name = &namestore_sqlite_zone_to_name;
773 api->lookup_records = &namestore_sqlite_lookup_records; 926 api->lookup_records = &namestore_sqlite_lookup_records;
774 LOG (GNUNET_ERROR_TYPE_INFO, 927 api->transaction_begin = &namestore_sqlite_transaction_begin;
775 _ ("Sqlite database running\n")); 928 api->transaction_commit = &namestore_sqlite_transaction_commit;
929 api->transaction_rollback = &namestore_sqlite_transaction_rollback;
930 api->initialize_database = &namestore_sqlite_initialize_database;
931 api->reset_database = &namestore_sqlite_reset_database;
932 /**
933 * NOTE: Since SQlite does not support SELECT ... FOR UPDATE this is
934 * just an alias to lookup_records. The BEGIN IMMEDIATE mechanic currently
935 * implicitly ensures this API behaves as it should
936 */
937 api->edit_records = &namestore_sqlite_lookup_records;
938 LOG (GNUNET_ERROR_TYPE_DEBUG,
939 _ ("SQlite database running\n"));
776 return api; 940 return api;
777} 941}
778 942
@@ -791,9 +955,10 @@ libgnunet_plugin_namestore_sqlite_done (void *cls)
791 955
792 database_shutdown (plugin); 956 database_shutdown (plugin);
793 plugin->cfg = NULL; 957 plugin->cfg = NULL;
958 GNUNET_free (plugin);
794 GNUNET_free (api); 959 GNUNET_free (api);
795 LOG (GNUNET_ERROR_TYPE_DEBUG, 960 LOG (GNUNET_ERROR_TYPE_DEBUG,
796 "sqlite plugin is finished\n"); 961 "SQlite plugin is finished\n");
797 return NULL; 962 return NULL;
798} 963}
799 964
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
index 0475960eb..0eef1aaeb 100644
--- a/src/namestore/plugin_rest_namestore.c
+++ b/src/namestore/plugin_rest_namestore.c
@@ -721,6 +721,148 @@ ns_lookup_cb (void *cls,
721 } 721 }
722} 722}
723 723
724/**
725 * Import callback
726 *
727 * @param cls the `struct RequestHandle`
728 * @param success the success indicating integer, GNUNET_OK on success
729 * @param emsg the error message (can be NULL)
730 */
731static void
732import_finished_cb (void *cls, int32_t success, const char *emsg)
733{
734 struct RequestHandle *handle = cls;
735 struct MHD_Response *resp;
736
737 handle->ns_qe = NULL;
738 if (GNUNET_YES != success)
739 {
740 if (NULL != emsg)
741 {
742 handle->emsg = GNUNET_strdup (emsg);
743 GNUNET_SCHEDULER_add_now (&do_error, handle);
744 return;
745 }
746 handle->emsg = GNUNET_strdup ("Error importing records");
747 GNUNET_SCHEDULER_add_now (&do_error, handle);
748 return;
749 }
750 resp = GNUNET_REST_create_response (NULL);
751 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
752 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
753}
754
755
756/**
757 * Handle namestore POST import
758 *
759 * @param con_handle the connection handle
760 * @param url the url
761 * @param cls the RequestHandle
762 */
763void
764namestore_import (struct GNUNET_REST_RequestHandle *con_handle,
765 const char *url,
766 void *cls)
767{
768 struct RequestHandle *handle = cls;
769 struct EgoEntry *ego_entry;
770 char *egoname;
771 json_t *data_js;
772 json_error_t err;
773
774 char term_data[handle->rest_handle->data_size + 1];
775 // set zone to name if given
776 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
777 {
778 handle->response_code = MHD_HTTP_NOT_FOUND;
779 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
780 GNUNET_SCHEDULER_add_now (&do_error, handle);
781 return;
782 }
783 ego_entry = NULL;
784
785 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
786 ego_entry = get_egoentry_namestore (handle, egoname);
787
788 if (NULL == ego_entry)
789 {
790 handle->response_code = MHD_HTTP_NOT_FOUND;
791 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
792 GNUNET_SCHEDULER_add_now (&do_error, handle);
793 return;
794 }
795
796 if (0 >= handle->rest_handle->data_size)
797 {
798 handle->response_code = MHD_HTTP_BAD_REQUEST;
799 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_NO_DATA);
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 return;
802 }
803 term_data[handle->rest_handle->data_size] = '\0';
804 GNUNET_memcpy (term_data,
805 handle->rest_handle->data,
806 handle->rest_handle->data_size);
807 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
808 if (NULL == data_js)
809 {
810 GNUNET_asprintf (&handle->emsg, "Error parsing data: %s", err.text);
811 GNUNET_SCHEDULER_add_now (&do_error, handle);
812 return;
813 }
814 if (! json_is_array (data_js))
815 {
816 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
817 GNUNET_SCHEDULER_add_now (&do_error, handle);
818 json_decref (data_js);
819 return;
820 }
821 size_t rd_set_count = json_array_size (data_js);
822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
823 "Got record set of size %d\n", rd_set_count);
824 const struct GNUNET_GNSRECORD_Data *a_rd[rd_set_count];
825 unsigned int a_rd_count[rd_set_count];
826 char *a_label[rd_set_count];
827 size_t index;
828 json_t *value;
829 json_array_foreach (data_js, index, value) {
830 {
831 struct GNUNET_GNSRECORD_Data *rd;
832 struct GNUNET_JSON_Specification gnsspec[] =
833 { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&rd, &a_rd_count[index],
834 &a_label[index]),
835 GNUNET_JSON_spec_end () };
836 if (GNUNET_OK != GNUNET_JSON_parse (value, gnsspec, NULL, NULL))
837 {
838 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
839 GNUNET_SCHEDULER_add_now (&do_error, handle);
840 json_decref (data_js);
841 return;
842 }
843 a_rd[index] = rd;
844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
845 "Parsed record set for name %s\n", a_label[index]);
846 }
847 }
848 //json_decref (data_js);
849
850 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
851 handle->ns_qe = GNUNET_NAMESTORE_records_store2 (ns_handle,
852 handle->zone_pkey,
853 rd_set_count,
854 (const char**) a_label,
855 a_rd_count,
856 a_rd,
857 &import_finished_cb,
858 handle);
859 if (NULL == handle->ns_qe)
860 {
861 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
862 GNUNET_SCHEDULER_add_now (&do_error, handle);
863 return;
864 }
865}
724 866
725/** 867/**
726 * Handle namestore POST/PUT request 868 * Handle namestore POST/PUT request
@@ -756,7 +898,7 @@ namestore_add_or_update (struct GNUNET_REST_RequestHandle *con_handle,
756 data_js = json_loads (term_data, JSON_DECODE_ANY, &err); 898 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
757 struct GNUNET_JSON_Specification gnsspec[] = 899 struct GNUNET_JSON_Specification gnsspec[] =
758 { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&handle->rd, &handle->rd_count, 900 { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&handle->rd, &handle->rd_count,
759 &handle->record_name), 901 &handle->record_name),
760 GNUNET_JSON_spec_end () }; 902 GNUNET_JSON_spec_end () };
761 if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL)) 903 if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
762 { 904 {
@@ -932,7 +1074,8 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
932 1074
933 // independent of path return all options 1075 // independent of path return all options
934 resp = GNUNET_REST_create_response (NULL); 1076 resp = GNUNET_REST_create_response (NULL);
935 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); 1077 MHD_add_response_header (resp, "Access-Control-Allow-Methods",
1078 allow_methods);
936 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 1079 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
937 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); 1080 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
938 return; 1081 return;
@@ -1007,7 +1150,7 @@ list_ego (void *cls,
1007 break; 1150 break;
1008 } 1151 }
1009 if (NULL == ego_entry) 1152 if (NULL == ego_entry)
1010 return; /* Not found */ 1153 return; /* Not found */
1011 1154
1012 GNUNET_CONTAINER_DLL_remove (ego_head, 1155 GNUNET_CONTAINER_DLL_remove (ego_head,
1013 ego_tail, 1156 ego_tail,
@@ -1041,9 +1184,11 @@ rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1041 struct GNUNET_REST_RequestHandlerError err; 1184 struct GNUNET_REST_RequestHandlerError err;
1042 static const struct GNUNET_REST_RequestHandler handlers[] = 1185 static const struct GNUNET_REST_RequestHandler handlers[] =
1043 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get }, 1186 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get },
1044 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add }, 1187 //{ MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add },
1188 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_import },
1045 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_update }, 1189 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_update },
1046 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete }, 1190 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE,
1191 &namestore_delete },
1047 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont }, 1192 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont },
1048 GNUNET_REST_HANDLER_END }; 1193 GNUNET_REST_HANDLER_END };
1049 1194
@@ -1063,7 +1208,8 @@ rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1063 handle); 1208 handle);
1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); 1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1065 if (GNUNET_NO == 1210 if (GNUNET_NO ==
1066 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle)) 1211 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
1212 handle))
1067 { 1213 {
1068 cleanup_handle (handle); 1214 cleanup_handle (handle);
1069 return GNUNET_NO; 1215 return GNUNET_NO;
@@ -1088,7 +1234,7 @@ libgnunet_plugin_rest_namestore_init (void *cls)
1088 1234
1089 cfg = cls; 1235 cfg = cls;
1090 if (NULL != plugin.cfg) 1236 if (NULL != plugin.cfg)
1091 return NULL; /* can only initialize once! */ 1237 return NULL; /* can only initialize once! */
1092 memset (&plugin, 0, sizeof(struct Plugin)); 1238 memset (&plugin, 0, sizeof(struct Plugin));
1093 plugin.cfg = cfg; 1239 plugin.cfg = cfg;
1094 api = GNUNET_new (struct GNUNET_REST_Plugin); 1240 api = GNUNET_new (struct GNUNET_REST_Plugin);
@@ -1106,7 +1252,8 @@ libgnunet_plugin_rest_namestore_init (void *cls)
1106 ns_handle = GNUNET_NAMESTORE_connect (cfg); 1252 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1107 identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL); 1253 identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
1108 1254
1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Namestore REST API initialized\n")); 1255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ (
1256 "Namestore REST API initialized\n"));
1110 return api; 1257 return api;
1111} 1258}
1112 1259
diff --git a/src/namestore/test_common.c b/src/namestore/test_common.c
index 58afb0a32..24a88c180 100644
--- a/src/namestore/test_common.c
+++ b/src/namestore/test_common.c
@@ -21,6 +21,7 @@
21 * @file namestore/test_common.c 21 * @file namestore/test_common.c
22 * @brief common functions for testcase setup 22 * @brief common functions for testcase setup
23 */ 23 */
24#include <gnunet_namestore_plugin.h>
24 25
25/** 26/**
26 * test if we can load the plugin @a name. 27 * test if we can load the plugin @a name.
@@ -30,6 +31,7 @@ TNC_test_plugin (const char *cfg_name)
30{ 31{
31 char *database; 32 char *database;
32 char *db_lib_name; 33 char *db_lib_name;
34 char *emsg;
33 struct GNUNET_NAMESTORE_PluginFunctions *db; 35 struct GNUNET_NAMESTORE_PluginFunctions *db;
34 struct GNUNET_CONFIGURATION_Handle *cfg; 36 struct GNUNET_CONFIGURATION_Handle *cfg;
35 37
@@ -53,7 +55,15 @@ TNC_test_plugin (const char *cfg_name)
53 GNUNET_free (database); 55 GNUNET_free (database);
54 db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg); 56 db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
55 if (NULL != db) 57 if (NULL != db)
58 {
59 if (GNUNET_OK != db->reset_database (db->cls, &emsg))
60 {
61 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error resetting database: %s\n", emsg);
62 GNUNET_free (emsg);
63 return GNUNET_SYSERR;
64 }
56 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db)); 65 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db));
66 }
57 GNUNET_free (db_lib_name); 67 GNUNET_free (db_lib_name);
58 GNUNET_CONFIGURATION_destroy (cfg); 68 GNUNET_CONFIGURATION_destroy (cfg);
59 if (NULL == db) 69 if (NULL == db)
diff --git a/src/namestore/test_namestore_api.conf b/src/namestore/test_namestore_api.conf
index 3e75c2ded..ec685e2fe 100644
--- a/src/namestore/test_namestore_api.conf
+++ b/src/namestore/test_namestore_api.conf
@@ -18,5 +18,11 @@ START_ON_DEMAND = YES
18[nse] 18[nse]
19WORKBITS = 0 19WORKBITS = 0
20 20
21[rest]
22BASIC_AUTH_ENABLED=NO
23# PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/v_log
24
25
26
21[transport] 27[transport]
22PLUGINS = 28PLUGINS =
diff --git a/src/namestore/test_namestore_api_edit_records.c b/src/namestore/test_namestore_api_edit_records.c
new file mode 100644
index 000000000..c1c64ee9c
--- /dev/null
+++ b/src/namestore/test_namestore_api_edit_records.c
@@ -0,0 +1,404 @@
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#include "gnunet_dnsparser_lib.h"
28
29#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
30
31#define TEST_RECORD_DATALEN 123
32
33#define TEST_RECORD_DATA 'a'
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_NAMESTORE_Handle *nsh2;
41
42static struct GNUNET_SCHEDULER_Task *endbadly_task;
43
44static struct GNUNET_IDENTITY_PrivateKey privkey;
45
46static struct GNUNET_IDENTITY_PublicKey pubkey;
47
48static int res;
49
50static int removed;
51
52static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
53
54static int nonce = 0;
55
56static void
57cleanup ()
58{
59 if (NULL != nsh)
60 {
61 GNUNET_NAMESTORE_disconnect (nsh);
62 nsh = NULL;
63 }
64 GNUNET_SCHEDULER_shutdown ();
65}
66
67
68/**
69 * Re-establish the connection to the service.
70 *
71 * @param cls handle to use to re-connect.
72 */
73static void
74endbadly (void *cls)
75{
76 if (NULL != nsqe)
77 {
78 GNUNET_NAMESTORE_cancel (nsqe);
79 nsqe = NULL;
80 }
81 cleanup ();
82 res = 1;
83}
84
85
86static void
87end (void *cls)
88{
89 cleanup ();
90 res = 0;
91}
92
93static void
94lookup_it (void *cls,
95 const struct GNUNET_IDENTITY_PrivateKey *zone,
96 const char *label,
97 unsigned int rd_count,
98 const struct GNUNET_GNSRECORD_Data *rd)
99{
100 GNUNET_assert (0 == rd_count);
101 GNUNET_SCHEDULER_add_now (&end, NULL);
102}
103
104static void
105fail_cb (void *cls)
106{
107 if (endbadly_task != NULL)
108 GNUNET_SCHEDULER_cancel (endbadly_task);
109 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
110 return;
111}
112
113static void
114remove_cont (void *cls,
115 int32_t success,
116 const char *emsg)
117{
118 nsqe = NULL;
119 if (GNUNET_YES != success)
120 {
121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
122 _ ("Unable to roll back: `%s'\n"),
123 emsg);
124 if (NULL != endbadly_task)
125 GNUNET_SCHEDULER_cancel (endbadly_task);
126 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly,
127 NULL);
128 return;
129 }
130 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
131 "Rolled back, perform lookup\n");
132 removed = GNUNET_YES;
133 if (NULL != endbadly_task)
134 GNUNET_SCHEDULER_cancel (endbadly_task);
135 GNUNET_SCHEDULER_add_now (&end, NULL);
136}
137
138static void
139fail_cb_lock (void *cls);
140
141static void
142edit_cont_b (void *cls,
143 const struct GNUNET_IDENTITY_PrivateKey *zone,
144 const char *label,
145 unsigned int rd_count,
146 const struct GNUNET_GNSRECORD_Data *rd)
147{
148 const char *name = cls;
149 /**
150 * We should probably never get here right at first.
151 * We may want to change the blocking of nsh2 so that we do get this
152 * eventually instead of the error callback above when locked.
153 */
154 if (0 == nonce)
155 {
156 if (endbadly_task != NULL)
157 GNUNET_SCHEDULER_cancel (endbadly_task);
158 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
159 return;
160
161 }
162 /* Abort transaction for B */
163 nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh2, remove_cont,
164 (void *) name);
165}
166
167
168static void
169commit_cont_a (void *cls,
170 int32_t success,
171 const char *emsg)
172{
173 const char *name = cls;
174
175 GNUNET_assert (NULL != cls);
176 nsqe = NULL;
177 if (GNUNET_SYSERR == success)
178 {
179 GNUNET_break (0);
180 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
181 "Namestore could not store record: `%s'\n",
182 emsg);
183 if (endbadly_task != NULL)
184 GNUNET_SCHEDULER_cancel (endbadly_task);
185 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
186 return;
187 }
188
189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
190 "Name store added record for `%s': %s\n",
191 name,
192 (success == GNUNET_OK) ? "SUCCESS" : "FAIL");
193 /**
194 * Try again for B
195 */
196 nsqe = GNUNET_NAMESTORE_records_edit (nsh2,
197 &privkey,
198 name,
199 &fail_cb_lock,
200 (void *) name,
201 &edit_cont_b,
202 (void *) name);
203
204 GNUNET_assert (NULL != nsqe);
205}
206
207static void
208fail_cb_lock (void *cls)
209{
210 const char *name = cls;
211 if (1 == nonce)
212 {
213 if (endbadly_task != NULL)
214 GNUNET_SCHEDULER_cancel (endbadly_task);
215 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
216 return;
217 }
218 nonce = 1;
219 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
220 "Failed to aquire additional lock\n");
221 /* Now, we stop the transaction for B */
222 nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont_a,
223 (void *) name);
224}
225
226
227static void
228begin_cont_b (void *cls,
229 int32_t success,
230 const char *emsg)
231{
232 const char *name = cls;
233
234 GNUNET_assert (success == GNUNET_YES);
235 /** Now, we expect this to "hang" let's see how this behaves in practice. */
236 nsqe = GNUNET_NAMESTORE_records_edit (nsh2,
237 &privkey,
238 name,
239 &fail_cb_lock,
240 (void *) name,
241 &edit_cont_b,
242 (void *) name);
243
244 GNUNET_assert (NULL != nsqe);
245}
246
247
248static void
249edit_cont (void *cls,
250 const struct GNUNET_IDENTITY_PrivateKey *zone,
251 const char *label,
252 unsigned int rd_count,
253 const struct GNUNET_GNSRECORD_Data *rd)
254{
255 const char *name = cls;
256
257 GNUNET_assert (1 == rd_count);
258 /* Now, we start a transaction for B */
259 nsqe = GNUNET_NAMESTORE_transaction_begin (nsh2, begin_cont_b, (void *) name);
260}
261
262
263static void
264begin_cont (void *cls,
265 int32_t success,
266 const char *emsg)
267{
268 const char *name = cls;
269
270 GNUNET_assert (success == GNUNET_YES);
271 nsqe = GNUNET_NAMESTORE_records_edit (nsh,
272 &privkey,
273 name,
274 &fail_cb,
275 (void *) name,
276 &edit_cont,
277 (void *) name);
278
279 GNUNET_assert (NULL != nsqe);
280}
281
282static void
283preload_cont (void *cls,
284 int32_t success,
285 const char *emsg)
286{
287 const char *name = cls;
288
289 GNUNET_assert (NULL != cls);
290 nsqe = NULL;
291 if (GNUNET_SYSERR == success)
292 {
293 GNUNET_break (0);
294 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
295 "Namestore could not store record: `%s'\n",
296 emsg);
297 if (endbadly_task != NULL)
298 GNUNET_SCHEDULER_cancel (endbadly_task);
299 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
300 return;
301 }
302
303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
304 "Name store added record for `%s': %s\n",
305 name,
306 (success == GNUNET_OK) ? "SUCCESS" : "FAIL");
307 /* We start transaction for A */
308 nsqe = GNUNET_NAMESTORE_transaction_begin (nsh, begin_cont, (void *) name);
309
310}
311
312
313static void
314run (void *cls,
315 const struct GNUNET_CONFIGURATION_Handle *cfg,
316 struct GNUNET_TESTING_Peer *peer)
317{
318 struct GNUNET_GNSRECORD_Data rd;
319 const char *name = "dummy";
320
321 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
322 &endbadly,
323 NULL);
324 nsh = GNUNET_NAMESTORE_connect (cfg);
325 nsh2 = GNUNET_NAMESTORE_connect (cfg);
326 GNUNET_break (NULL != nsh);
327 GNUNET_break (NULL != nsh2);
328
329 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
330 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
331 GNUNET_IDENTITY_key_get_public (&privkey,
332 &pubkey);
333
334 removed = GNUNET_NO;
335
336 rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us;
337 rd.record_type = TEST_RECORD_TYPE;
338 rd.data_size = TEST_RECORD_DATALEN;
339 rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
340 rd.flags = 0;
341 memset ((char *) rd.data,
342 'a',
343 TEST_RECORD_DATALEN);
344 nsqe = GNUNET_NAMESTORE_records_store (nsh,
345 &privkey,
346 name,
347 1,
348 &rd,
349 &preload_cont,
350 (void *) name);
351 GNUNET_assert (NULL != nsqe);
352 GNUNET_free_nz ((void *) rd.data);
353
354 /*nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont);
355 nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, rollback_cont); Must also happen on disconnect
356 nsqe = GNUNET_NAMESTORE_records_edit (nsh,
357 &privkey,
358 name,
359 1,
360 &rd,
361 &edit_cont,
362 (void *) name);
363 nsqe = GNUNET_NAMESTORE_records_insert_bulk (nsh,
364 count,
365 &rd,
366 &
367 nsqe = GNUNET_NAMESTORE_records_store (nsh,
368 &privkey,
369 name,
370 1,
371 &rd,
372 &put_cont,
373 (void *) name);*/
374 GNUNET_assert (NULL != nsqe);
375}
376
377
378#include "test_common.c"
379
380
381int
382main (int argc, char *argv[])
383{
384 const char *plugin_name;
385 char *cfg_name;
386
387 SETUP_CFG (plugin_name, cfg_name);
388 res = 1;
389 if (0 !=
390 GNUNET_TESTING_peer_run ("test-namestore-api-remove",
391 cfg_name,
392 &run,
393 NULL))
394 {
395 res = 1;
396 }
397 GNUNET_DISK_purge_cfg_dir (cfg_name,
398 "GNUNET_TEST_HOME");
399 GNUNET_free (cfg_name);
400 return res;
401}
402
403
404/* end of test_namestore_api_remove.c */
diff --git a/src/namestore/test_namestore_api_flat.conf b/src/namestore/test_namestore_api_flat.conf
deleted file mode 100644
index 8460d143c..000000000
--- a/src/namestore/test_namestore_api_flat.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ test_namestore_api.conf
2
3[namestore]
4DATABASE = flat
5
6[namestore-heap]
7FILENAME = $GNUNET_TEST_HOME/namestore/flat.db
diff --git a/src/namestore/test_namestore_api_monitoring_existing.c b/src/namestore/test_namestore_api_monitoring_existing.c
index 366f5739f..1803b8ba4 100644
--- a/src/namestore/test_namestore_api_monitoring_existing.c
+++ b/src/namestore/test_namestore_api_monitoring_existing.c
@@ -248,28 +248,6 @@ put_cont (void *cls,
248 return; 248 return;
249 } 249 }
250 250
251 if (3 == c)
252 {
253 /* Start monitoring */
254 zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
255 &privkey,
256 GNUNET_YES,
257 &fail_cb,
258 NULL,
259 &zone_proc,
260 NULL,
261 &sync_cb,
262 NULL);
263 if (NULL == zm)
264 {
265 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
266 "Failed to create zone monitor\n");
267 GNUNET_break (0);
268 res = 1;
269 GNUNET_SCHEDULER_shutdown ();
270 return;
271 }
272 }
273} 251}
274 252
275 253
@@ -324,6 +302,25 @@ run (void *cls,
324 NULL); 302 NULL);
325 return; 303 return;
326 } 304 }
305 /* Start monitoring */
306 zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
307 &privkey,
308 GNUNET_YES,
309 &fail_cb,
310 NULL,
311 &zone_proc,
312 NULL,
313 &sync_cb,
314 NULL);
315 if (NULL == zm)
316 {
317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318 "Failed to create zone monitor\n");
319 GNUNET_break (0);
320 res = 1;
321 GNUNET_SCHEDULER_shutdown ();
322 return;
323 }
327 324
328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
329 "Created record 3\n"); 326 "Created record 3\n");
diff --git a/src/namestore/test_namestore_api_postgres.conf b/src/namestore/test_namestore_api_postgres.conf
index 93ef935b5..007168280 100644
--- a/src/namestore/test_namestore_api_postgres.conf
+++ b/src/namestore/test_namestore_api_postgres.conf
@@ -6,4 +6,5 @@ DATABASE = postgres
6 6
7[namestore-postgres] 7[namestore-postgres]
8CONFIG = connect_timeout=10 dbname=gnunetcheck 8CONFIG = connect_timeout=10 dbname=gnunetcheck
9TEMPORARY_TABLE = YES 9TEMPORARY_TABLE = NO
10INIT_ON_CONNECT = YES
diff --git a/src/namestore/test_namestore_api_sqlite.conf b/src/namestore/test_namestore_api_sqlite.conf
index cd4822097..342356247 100644
--- a/src/namestore/test_namestore_api_sqlite.conf
+++ b/src/namestore/test_namestore_api_sqlite.conf
@@ -6,3 +6,4 @@ DATABASE = sqlite
6 6
7[namestore-sqlite] 7[namestore-sqlite]
8FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db 8FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
9INIT_ON_CONNECT = YES
diff --git a/src/namestore/test_namestore_api_tx_rollback.c b/src/namestore/test_namestore_api_tx_rollback.c
new file mode 100644
index 000000000..ccfd8d701
--- /dev/null
+++ b/src/namestore/test_namestore_api_tx_rollback.c
@@ -0,0 +1,268 @@
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#include "gnunet_dnsparser_lib.h"
28
29#define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
30
31#define TEST_RECORD_DATALEN 123
32
33#define TEST_RECORD_DATA 'a'
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_SCHEDULER_Task *endbadly_task;
41
42static struct GNUNET_IDENTITY_PrivateKey privkey;
43
44static struct GNUNET_IDENTITY_PublicKey pubkey;
45
46static int res;
47
48static int removed;
49
50static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
51
52
53static void
54cleanup ()
55{
56 if (NULL != nsh)
57 {
58 GNUNET_NAMESTORE_disconnect (nsh);
59 nsh = NULL;
60 }
61 GNUNET_SCHEDULER_shutdown ();
62}
63
64
65/**
66 * Re-establish the connection to the service.
67 *
68 * @param cls handle to use to re-connect.
69 */
70static void
71endbadly (void *cls)
72{
73 if (NULL != nsqe)
74 {
75 GNUNET_NAMESTORE_cancel (nsqe);
76 nsqe = NULL;
77 }
78 cleanup ();
79 res = 1;
80}
81
82
83static void
84end (void *cls)
85{
86 cleanup ();
87 res = 0;
88}
89
90static void
91lookup_it (void *cls,
92 const struct GNUNET_IDENTITY_PrivateKey *zone,
93 const char *label,
94 unsigned int rd_count,
95 const struct GNUNET_GNSRECORD_Data *rd)
96{
97 GNUNET_assert (0 == rd_count);
98 GNUNET_SCHEDULER_add_now (&end, NULL);
99}
100
101static void
102fail_cb (void *cls)
103{
104 GNUNET_assert (0);
105}
106
107static void
108remove_cont (void *cls,
109 int32_t success,
110 const char *emsg)
111{
112 nsqe = NULL;
113 if (GNUNET_YES != success)
114 {
115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
116 _ ("Unable to roll back: `%s'\n"),
117 emsg);
118 if (NULL != endbadly_task)
119 GNUNET_SCHEDULER_cancel (endbadly_task);
120 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly,
121 NULL);
122 return;
123 }
124 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
125 "Rolled back, perform lookup\n");
126 removed = GNUNET_YES;
127 if (NULL != endbadly_task)
128 GNUNET_SCHEDULER_cancel (endbadly_task);
129 /* FIXME not actually doing lookup here */
130 nsqe = GNUNET_NAMESTORE_records_lookup (nsh,
131 &privkey,
132 (char*) cls,
133 &fail_cb,
134 NULL,
135 &lookup_it,
136 NULL);
137}
138
139
140static void
141put_cont (void *cls,
142 int32_t success,
143 const char *emsg)
144{
145 const char *name = cls;
146
147 GNUNET_assert (NULL != cls);
148 nsqe = NULL;
149 if (GNUNET_SYSERR == success)
150 {
151 GNUNET_break (0);
152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
153 "Namestore could not store record: `%s'\n",
154 emsg);
155 if (endbadly_task != NULL)
156 GNUNET_SCHEDULER_cancel (endbadly_task);
157 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL);
158 return;
159 }
160
161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
162 "Name store added record for `%s': %s\n",
163 name,
164 (success == GNUNET_OK) ? "SUCCESS" : "FAIL");
165 nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, remove_cont,
166 (void *) name);
167}
168
169static void
170begin_cont (void *cls,
171 int32_t success,
172 const char *emsg)
173{
174 struct GNUNET_GNSRECORD_Data rd;
175 const char *name = cls;
176
177 GNUNET_assert (success == GNUNET_YES);
178 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
179 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
180 GNUNET_IDENTITY_key_get_public (&privkey,
181 &pubkey);
182
183 removed = GNUNET_NO;
184
185 rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us;
186 rd.record_type = TEST_RECORD_TYPE;
187 rd.data_size = TEST_RECORD_DATALEN;
188 rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
189 rd.flags = 0;
190 memset ((char *) rd.data,
191 'a',
192 TEST_RECORD_DATALEN);
193 nsqe = GNUNET_NAMESTORE_records_store (nsh,
194 &privkey,
195 name,
196 1,
197 &rd,
198 &put_cont,
199 (void *) name);
200 GNUNET_assert (NULL != nsqe);
201 GNUNET_free_nz ((void *) rd.data);
202}
203
204static void
205run (void *cls,
206 const struct GNUNET_CONFIGURATION_Handle *cfg,
207 struct GNUNET_TESTING_Peer *peer)
208{
209 struct GNUNET_GNSRECORD_Data rd;
210 const char *name = "dummy";
211
212 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
213 &endbadly,
214 NULL);
215 nsh = GNUNET_NAMESTORE_connect (cfg);
216 GNUNET_break (NULL != nsh);
217 nsqe = GNUNET_NAMESTORE_transaction_begin (nsh, begin_cont, (void *) name);
218 /*nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont);
219 nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, rollback_cont); Must also happen on disconnect
220 nsqe = GNUNET_NAMESTORE_records_edit (nsh,
221 &privkey,
222 name,
223 1,
224 &rd,
225 &edit_cont,
226 (void *) name);
227 nsqe = GNUNET_NAMESTORE_records_insert_bulk (nsh,
228 count,
229 &rd,
230 &
231 nsqe = GNUNET_NAMESTORE_records_store (nsh,
232 &privkey,
233 name,
234 1,
235 &rd,
236 &put_cont,
237 (void *) name);*/
238 GNUNET_assert (NULL != nsqe);
239}
240
241
242#include "test_common.c"
243
244
245int
246main (int argc, 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-namestore-api-remove",
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 (cfg_name);
264 return res;
265}
266
267
268/* end of test_namestore_api_remove.c */
diff --git a/src/namestore/test_plugin_namestore_flat.conf b/src/namestore/test_plugin_namestore_flat.conf
deleted file mode 100644
index 5c632f0d1..000000000
--- a/src/namestore/test_plugin_namestore_flat.conf
+++ /dev/null
@@ -1,2 +0,0 @@
1[namestore-flat]
2FILENAME = $GNUNET_TMP/gnunet-test-plugin-namestore-flat/flatdb
diff --git a/src/namestore/test_plugin_namestore_postgres.conf b/src/namestore/test_plugin_namestore_postgres.conf
index 2ce8a7792..3b5cb8699 100644
--- a/src/namestore/test_plugin_namestore_postgres.conf
+++ b/src/namestore/test_plugin_namestore_postgres.conf
@@ -1,3 +1,4 @@
1[namestore-postgres] 1[namestore-postgres]
2CONFIG = connect_timeout=10 dbname=gnunetcheck 2CONFIG = connect_timeout=10 dbname=gnunetcheck
3INIT_ON_CONNECT = YES
3TEMPORARY_TABLE = YES 4TEMPORARY_TABLE = YES
diff --git a/src/namestore/test_plugin_namestore_sqlite.conf b/src/namestore/test_plugin_namestore_sqlite.conf
index 24eecd286..365198db2 100644
--- a/src/namestore/test_plugin_namestore_sqlite.conf
+++ b/src/namestore/test_plugin_namestore_sqlite.conf
@@ -1,2 +1,3 @@
1[namestore-sqlite] 1[namestore-sqlite]
2FILENAME = $GNUNET_TMP/gnunet-test-plugin-namestore-sqlite/sqlite.db 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
index 50b3c8c12..83c6015c7 100755
--- a/src/namestore/test_plugin_rest_namestore.sh
+++ b/src/namestore/test_plugin_rest_namestore.sh
@@ -18,7 +18,6 @@ rm -rf `gnunet-config -c test_namestore_api.conf -f -s paths -o GNUNET_TEST_HOME
18namestore_link="http://localhost:7776/namestore" 18namestore_link="http://localhost:7776/namestore"
19wrong_link="http://localhost:7776/namestoreandmore" 19wrong_link="http://localhost:7776/namestoreandmore"
20 20
21
22curl_get () { 21curl_get () {
23 #$1 is link 22 #$1 is link
24 #$2 is grep 23 #$2 is grep