diff options
Diffstat (limited to 'src/fs')
101 files changed, 0 insertions, 43240 deletions
diff --git a/src/fs/.gitignore b/src/fs/.gitignore deleted file mode 100644 index f0e2a4f7b..000000000 --- a/src/fs/.gitignore +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | gnunet-unindex | ||
2 | gnunet-auto-share | ||
3 | gnunet-daemon-fsprofiler | ||
4 | gnunet-directory | ||
5 | gnunet-download | ||
6 | gnunet-fs | ||
7 | gnunet-fs-profiler | ||
8 | gnunet-helper-fs-publish | ||
9 | gnunet-publish | ||
10 | gnunet-search | ||
11 | gnunet-service-fs | ||
12 | test_fs_directory | ||
13 | test_fs_download | ||
14 | test_fs_download_cadet | ||
15 | test_fs_download_indexed | ||
16 | test_fs_download_persistence | ||
17 | test_fs_file_information | ||
18 | test_fs_getopt | ||
19 | test_fs_list_indexed | ||
20 | test_fs_namespace | ||
21 | test_fs_namespace_list_updateable | ||
22 | test_fs_publish | ||
23 | test_fs_publish_persistence | ||
24 | test_fs_search | ||
25 | test_fs_search_persistence | ||
26 | test_fs_search_probes | ||
27 | test_fs_search_with_and | ||
28 | test_fs_start_stop | ||
29 | test_fs_test_lib | ||
30 | test_fs_unindex | ||
31 | test_fs_unindex_persistence | ||
32 | test_fs_uri | ||
33 | test_gnunet_fs_idx.py | ||
34 | test_gnunet_fs_psd.py | ||
35 | test_gnunet_fs_rec.py | ||
36 | test_gnunet_service_fs_migration | ||
37 | test_gnunet_service_fs_p2p | ||
38 | test_gnunet_service_fs_p2p_cadet | ||
39 | test_plugin_block_fs | ||
40 | perf_gnunet_service_fs_p2p | ||
41 | perf_gnunet_service_fs_p2p_index | ||
42 | perf_gnunet_service_fs_p2p_respect | ||
43 | rdir.gnd | ||
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am deleted file mode 100644 index 3d8ec2bac..000000000 --- a/src/fs/Makefile.am +++ /dev/null | |||
@@ -1,565 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | if USE_COVERAGE | ||
5 | AM_CFLAGS = --coverage -O0 | ||
6 | XLIB = -lgcov | ||
7 | endif | ||
8 | |||
9 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
10 | |||
11 | libexecdir= $(pkglibdir)/libexec/ | ||
12 | |||
13 | pkgcfg_DATA = \ | ||
14 | fs.conf | ||
15 | |||
16 | plugindir = $(libdir)/gnunet | ||
17 | |||
18 | |||
19 | lib_LTLIBRARIES = libgnunetfs.la | ||
20 | |||
21 | plugin_LTLIBRARIES = \ | ||
22 | libgnunet_plugin_block_fs.la | ||
23 | |||
24 | noinst_LIBRARIES = libgnunetfstest.a | ||
25 | |||
26 | libgnunetfs_la_SOURCES = \ | ||
27 | fs_api.c fs_api.h fs.h \ | ||
28 | fs_directory.c \ | ||
29 | fs_dirmetascan.c \ | ||
30 | fs_download.c \ | ||
31 | fs_file_information.c \ | ||
32 | fs_getopt.c \ | ||
33 | fs_list_indexed.c \ | ||
34 | fs_publish.c \ | ||
35 | fs_publish_ksk.c \ | ||
36 | fs_publish_ublock.c fs_publish_ublock.h \ | ||
37 | fs_misc.c \ | ||
38 | fs_namespace.c \ | ||
39 | fs_search.c \ | ||
40 | fs_sharetree.c \ | ||
41 | fs_tree.c fs_tree.h \ | ||
42 | fs_unindex.c \ | ||
43 | fs_uri.c | ||
44 | |||
45 | libgnunetfs_la_LIBADD = \ | ||
46 | $(top_builddir)/src/datastore/libgnunetdatastore.la \ | ||
47 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
48 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
49 | $(GN_LIBINTL) $(XLIB) $(LIBGCRYPT_LIBS) -lunistring | ||
50 | |||
51 | if HAVE_LIBEXTRACTOR | ||
52 | libgnunetfs_la_LIBADD += \ | ||
53 | -lextractor | ||
54 | endif | ||
55 | |||
56 | libgnunetfs_la_LDFLAGS = \ | ||
57 | $(GN_LIB_LDFLAGS) \ | ||
58 | -version-info 3:1:1 | ||
59 | |||
60 | |||
61 | libgnunetfstest_a_SOURCES = \ | ||
62 | fs_test_lib.c fs_test_lib.h | ||
63 | |||
64 | libgnunetfstest_a_LIBADD = \ | ||
65 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
66 | $(top_builddir)/src/testbed/libgnunettestbed.la | ||
67 | |||
68 | libexec_PROGRAMS = \ | ||
69 | gnunet-helper-fs-publish \ | ||
70 | gnunet-service-fs | ||
71 | |||
72 | noinst_PROGRAMS = \ | ||
73 | gnunet-fs-profiler \ | ||
74 | gnunet-daemon-fsprofiler | ||
75 | |||
76 | bin_PROGRAMS = \ | ||
77 | gnunet-auto-share \ | ||
78 | gnunet-directory \ | ||
79 | gnunet-download \ | ||
80 | gnunet-publish \ | ||
81 | gnunet-search \ | ||
82 | gnunet-fs \ | ||
83 | gnunet-unindex | ||
84 | |||
85 | gnunet_directory_SOURCES = \ | ||
86 | gnunet-directory.c | ||
87 | gnunet_directory_LDADD = \ | ||
88 | libgnunetfs.la \ | ||
89 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
90 | $(GN_LIBINTL) | ||
91 | |||
92 | if HAVE_LIBEXTRACTOR | ||
93 | gnunet_directory_LDADD += \ | ||
94 | -lextractor | ||
95 | endif | ||
96 | |||
97 | gnunet_fs_profiler_SOURCES = \ | ||
98 | gnunet-fs-profiler.c | ||
99 | gnunet_fs_profiler_LDADD = \ | ||
100 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
101 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
102 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
103 | $(GN_LIBINTL) | ||
104 | |||
105 | gnunet_fs_SOURCES = \ | ||
106 | gnunet-fs.c | ||
107 | gnunet_fs_LDADD = \ | ||
108 | libgnunetfs.la \ | ||
109 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
110 | $(GN_LIBINTL) | ||
111 | |||
112 | if HAVE_LIBEXTRACTOR | ||
113 | gnunet_fs_LDADD += \ | ||
114 | -lextractor | ||
115 | endif | ||
116 | |||
117 | gnunet_download_SOURCES = \ | ||
118 | gnunet-download.c | ||
119 | gnunet_download_LDADD = \ | ||
120 | libgnunetfs.la \ | ||
121 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
122 | $(GN_LIBINTL) | ||
123 | |||
124 | gnunet_publish_SOURCES = \ | ||
125 | gnunet-publish.c | ||
126 | gnunet_publish_LDADD = \ | ||
127 | $(top_builddir)/src/identity/libgnunetidentity.la \ | ||
128 | libgnunetfs.la \ | ||
129 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
130 | $(GN_LIBINTL) | ||
131 | |||
132 | if HAVE_LIBEXTRACTOR | ||
133 | gnunet_publish_LDADD += \ | ||
134 | -lextractor | ||
135 | endif | ||
136 | |||
137 | gnunet_auto_share_SOURCES = \ | ||
138 | gnunet-auto-share.c | ||
139 | gnunet_auto_share_LDADD = \ | ||
140 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
141 | $(GN_LIBINTL) | ||
142 | |||
143 | if HAVE_LIBEXTRACTOR | ||
144 | gnunet_auto_share_LDADD += \ | ||
145 | -lextractor | ||
146 | endif | ||
147 | |||
148 | gnunet_helper_fs_publish_SOURCES = \ | ||
149 | gnunet-helper-fs-publish.c | ||
150 | gnunet_helper_fs_publish_LDADD = \ | ||
151 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
152 | $(GN_LIBINTL) | ||
153 | |||
154 | if HAVE_LIBEXTRACTOR | ||
155 | gnunet_helper_fs_publish_LDADD += \ | ||
156 | -lextractor | ||
157 | endif | ||
158 | |||
159 | gnunet_search_SOURCES = \ | ||
160 | gnunet-search.c | ||
161 | gnunet_search_LDADD = \ | ||
162 | libgnunetfs.la \ | ||
163 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
164 | $(GN_LIBINTL) | ||
165 | |||
166 | if HAVE_LIBEXTRACTOR | ||
167 | gnunet_search_LDADD += \ | ||
168 | -lextractor | ||
169 | endif | ||
170 | |||
171 | |||
172 | gnunet_daemon_fsprofiler_SOURCES = \ | ||
173 | gnunet-daemon-fsprofiler.c | ||
174 | gnunet_daemon_fsprofiler_LDADD = \ | ||
175 | libgnunetfs.la \ | ||
176 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
177 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
178 | $(GN_LIBINTL) | ||
179 | |||
180 | gnunet_service_fs_SOURCES = \ | ||
181 | gnunet-service-fs.c gnunet-service-fs.h \ | ||
182 | gnunet-service-fs_cp.c gnunet-service-fs_cp.h \ | ||
183 | gnunet-service-fs_indexing.c gnunet-service-fs_indexing.h \ | ||
184 | gnunet-service-fs_pe.c gnunet-service-fs_pe.h \ | ||
185 | gnunet-service-fs_pr.c gnunet-service-fs_pr.h \ | ||
186 | gnunet-service-fs_push.c gnunet-service-fs_push.h \ | ||
187 | gnunet-service-fs_put.c gnunet-service-fs_put.h \ | ||
188 | gnunet-service-fs_cadet_client.c gnunet-service-fs_cadet.h \ | ||
189 | gnunet-service-fs_cadet_server.c | ||
190 | gnunet_service_fs_LDADD = \ | ||
191 | libgnunetfs.la \ | ||
192 | $(top_builddir)/src/dht/libgnunetdht.la \ | ||
193 | $(top_builddir)/src/block/libgnunetblock.la \ | ||
194 | $(top_builddir)/src/datastore/libgnunetdatastore.la \ | ||
195 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
196 | $(top_builddir)/src/cadet/libgnunetcadet.la \ | ||
197 | $(top_builddir)/src/ats/libgnunetats.la \ | ||
198 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
199 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
200 | $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ | ||
201 | $(GN_LIBINTL) -lm | ||
202 | |||
203 | gnunet_unindex_SOURCES = \ | ||
204 | gnunet-unindex.c | ||
205 | gnunet_unindex_LDADD = \ | ||
206 | libgnunetfs.la \ | ||
207 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
208 | $(GN_LIBINTL) | ||
209 | |||
210 | libgnunet_plugin_block_fs_la_SOURCES = \ | ||
211 | plugin_block_fs.c | ||
212 | libgnunet_plugin_block_fs_la_LIBADD = \ | ||
213 | $(top_builddir)/src/block/libgnunetblockgroup.la \ | ||
214 | $(top_builddir)/src/block/libgnunetblock.la \ | ||
215 | libgnunetfs.la \ | ||
216 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
217 | $(LTLIBINTL) | ||
218 | libgnunet_plugin_block_fs_la_LDFLAGS = \ | ||
219 | $(GN_PLUGIN_LDFLAGS) | ||
220 | |||
221 | if HAVE_BENCHMARKS | ||
222 | FS_BENCHMARKS = \ | ||
223 | perf_gnunet_service_fs_p2p \ | ||
224 | perf_gnunet_service_fs_p2p_dht \ | ||
225 | perf_gnunet_service_fs_p2p_index \ | ||
226 | perf_gnunet_service_fs_p2p_respect | ||
227 | endif | ||
228 | |||
229 | check_PROGRAMS = \ | ||
230 | test_plugin_block_fs \ | ||
231 | test_fs_directory \ | ||
232 | test_fs_download \ | ||
233 | test_fs_download_cadet \ | ||
234 | test_fs_download_indexed \ | ||
235 | test_fs_download_persistence \ | ||
236 | test_fs_file_information \ | ||
237 | test_fs_getopt \ | ||
238 | test_fs_list_indexed \ | ||
239 | test_fs_namespace \ | ||
240 | test_fs_namespace_list_updateable \ | ||
241 | test_fs_publish \ | ||
242 | test_fs_publish_persistence \ | ||
243 | test_fs_search \ | ||
244 | test_fs_search_with_and \ | ||
245 | test_fs_search_probes \ | ||
246 | test_fs_search_persistence \ | ||
247 | test_fs_start_stop \ | ||
248 | test_fs_test_lib \ | ||
249 | test_fs_unindex \ | ||
250 | test_fs_unindex_persistence \ | ||
251 | test_fs_uri \ | ||
252 | test_gnunet_service_fs_migration \ | ||
253 | test_gnunet_service_fs_p2p \ | ||
254 | test_gnunet_service_fs_p2p_cadet \ | ||
255 | $(FS_BENCHMARKS) | ||
256 | |||
257 | test_plugin_block_fs_SOURCES = \ | ||
258 | test_plugin_block_fs.c | ||
259 | test_plugin_block_fs_LDADD = \ | ||
260 | $(top_builddir)/src/block/libgnunetblock.la \ | ||
261 | $(top_builddir)/src/util/libgnunetutil.la | ||
262 | |||
263 | if HAVE_PYTHON | ||
264 | check_SCRIPTS = \ | ||
265 | test_gnunet_fs_rec.py \ | ||
266 | test_gnunet_fs_idx.py | ||
267 | |||
268 | if HAVE_LIBEXTRACTOR | ||
269 | check_SCRIPTS += \ | ||
270 | test_gnunet_fs_psd.py | ||
271 | endif | ||
272 | endif | ||
273 | |||
274 | |||
275 | if ENABLE_TEST_RUN | ||
276 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; $(MONKEY) | ||
277 | TESTS = \ | ||
278 | test_fs_directory \ | ||
279 | test_fs_download \ | ||
280 | test_fs_download_indexed \ | ||
281 | test_fs_download_persistence \ | ||
282 | test_fs_file_information \ | ||
283 | test_fs_list_indexed \ | ||
284 | test_fs_namespace \ | ||
285 | test_fs_namespace_list_updateable \ | ||
286 | test_fs_publish \ | ||
287 | test_fs_publish_persistence \ | ||
288 | test_fs_search \ | ||
289 | test_fs_search_with_and \ | ||
290 | test_fs_search_probes \ | ||
291 | test_fs_search_persistence \ | ||
292 | test_fs_start_stop \ | ||
293 | test_fs_unindex \ | ||
294 | test_fs_unindex_persistence \ | ||
295 | test_fs_uri \ | ||
296 | test_fs_test_lib \ | ||
297 | test_gnunet_service_fs_migration \ | ||
298 | test_gnunet_service_fs_p2p \ | ||
299 | test_gnunet_service_fs_p2p_cadet \ | ||
300 | perf_gnunet_service_fs_p2p \ | ||
301 | perf_gnunet_service_fs_p2p_index \ | ||
302 | perf_gnunet_service_fs_p2p_respect \ | ||
303 | $(check_SCRIPTS) | ||
304 | endif | ||
305 | |||
306 | |||
307 | test_fs_directory_SOURCES = \ | ||
308 | test_fs_directory.c | ||
309 | test_fs_directory_LDADD = \ | ||
310 | libgnunetfs.la \ | ||
311 | $(top_builddir)/src/util/libgnunetutil.la | ||
312 | |||
313 | if HAVE_LIBEXTRACTOR | ||
314 | test_fs_directory_LDADD += \ | ||
315 | -lextractor | ||
316 | endif | ||
317 | |||
318 | |||
319 | test_fs_download_SOURCES = \ | ||
320 | test_fs_download.c | ||
321 | test_fs_download_LDADD = \ | ||
322 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
323 | libgnunetfs.la \ | ||
324 | $(top_builddir)/src/util/libgnunetutil.la | ||
325 | |||
326 | test_fs_download_indexed_SOURCES = \ | ||
327 | test_fs_download.c | ||
328 | test_fs_download_indexed_LDADD = \ | ||
329 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
330 | libgnunetfs.la \ | ||
331 | $(top_builddir)/src/util/libgnunetutil.la | ||
332 | |||
333 | test_fs_download_cadet_SOURCES = \ | ||
334 | test_fs_download.c | ||
335 | test_fs_download_cadet_LDADD = \ | ||
336 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
337 | libgnunetfs.la \ | ||
338 | $(top_builddir)/src/util/libgnunetutil.la | ||
339 | |||
340 | test_fs_download_persistence_SOURCES = \ | ||
341 | test_fs_download_persistence.c | ||
342 | test_fs_download_persistence_LDADD = \ | ||
343 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
344 | libgnunetfs.la \ | ||
345 | $(top_builddir)/src/util/libgnunetutil.la | ||
346 | |||
347 | test_fs_file_information_SOURCES = \ | ||
348 | test_fs_file_information.c | ||
349 | test_fs_file_information_LDADD = \ | ||
350 | libgnunetfs.la \ | ||
351 | $(top_builddir)/src/util/libgnunetutil.la | ||
352 | |||
353 | if HAVE_LIBEXTRACTOR | ||
354 | test_fs_file_information_LDADD += \ | ||
355 | -lextractor | ||
356 | endif | ||
357 | |||
358 | |||
359 | test_fs_getopt_SOURCES = \ | ||
360 | test_fs_getopt.c | ||
361 | test_fs_getopt_LDADD = \ | ||
362 | libgnunetfs.la \ | ||
363 | $(top_builddir)/src/util/libgnunetutil.la | ||
364 | |||
365 | test_fs_list_indexed_SOURCES = \ | ||
366 | test_fs_list_indexed.c | ||
367 | test_fs_list_indexed_LDADD = \ | ||
368 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
369 | libgnunetfs.la \ | ||
370 | $(top_builddir)/src/util/libgnunetutil.la | ||
371 | |||
372 | test_fs_namespace_SOURCES = \ | ||
373 | test_fs_namespace.c | ||
374 | test_fs_namespace_LDADD = \ | ||
375 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
376 | libgnunetfs.la \ | ||
377 | $(top_builddir)/src/util/libgnunetutil.la | ||
378 | |||
379 | test_fs_namespace_list_updateable_SOURCES = \ | ||
380 | test_fs_namespace_list_updateable.c | ||
381 | test_fs_namespace_list_updateable_LDADD = \ | ||
382 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
383 | libgnunetfs.la \ | ||
384 | $(top_builddir)/src/util/libgnunetutil.la | ||
385 | |||
386 | test_fs_publish_SOURCES = \ | ||
387 | test_fs_publish.c | ||
388 | test_fs_publish_LDADD = \ | ||
389 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
390 | libgnunetfs.la \ | ||
391 | $(top_builddir)/src/util/libgnunetutil.la | ||
392 | |||
393 | test_fs_publish_persistence_SOURCES = \ | ||
394 | test_fs_publish_persistence.c | ||
395 | test_fs_publish_persistence_LDADD = \ | ||
396 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
397 | libgnunetfs.la \ | ||
398 | $(top_builddir)/src/util/libgnunetutil.la | ||
399 | |||
400 | test_fs_search_SOURCES = \ | ||
401 | test_fs_search.c | ||
402 | test_fs_search_LDADD = \ | ||
403 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
404 | libgnunetfs.la \ | ||
405 | $(top_builddir)/src/util/libgnunetutil.la | ||
406 | |||
407 | test_fs_search_with_and_SOURCES = \ | ||
408 | test_fs_search_with_and.c | ||
409 | test_fs_search_with_and_LDADD = \ | ||
410 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
411 | libgnunetfs.la \ | ||
412 | $(top_builddir)/src/util/libgnunetutil.la | ||
413 | |||
414 | test_fs_search_probes_SOURCES = \ | ||
415 | test_fs_search_probes.c | ||
416 | test_fs_search_probes_LDADD = \ | ||
417 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
418 | libgnunetfs.la \ | ||
419 | $(top_builddir)/src/util/libgnunetutil.la | ||
420 | |||
421 | test_fs_search_persistence_SOURCES = \ | ||
422 | test_fs_search_persistence.c | ||
423 | test_fs_search_persistence_LDADD = \ | ||
424 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
425 | libgnunetfs.la \ | ||
426 | $(top_builddir)/src/util/libgnunetutil.la | ||
427 | |||
428 | test_fs_start_stop_SOURCES = \ | ||
429 | test_fs_start_stop.c | ||
430 | test_fs_start_stop_LDADD = \ | ||
431 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
432 | libgnunetfs.la \ | ||
433 | $(top_builddir)/src/util/libgnunetutil.la | ||
434 | |||
435 | test_fs_unindex_SOURCES = \ | ||
436 | test_fs_unindex.c | ||
437 | test_fs_unindex_LDADD = \ | ||
438 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
439 | libgnunetfs.la \ | ||
440 | $(top_builddir)/src/util/libgnunetutil.la | ||
441 | |||
442 | test_fs_unindex_persistence_SOURCES = \ | ||
443 | test_fs_unindex_persistence.c | ||
444 | test_fs_unindex_persistence_LDADD = \ | ||
445 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
446 | libgnunetfs.la \ | ||
447 | $(top_builddir)/src/util/libgnunetutil.la | ||
448 | |||
449 | test_fs_uri_SOURCES = \ | ||
450 | test_fs_uri.c | ||
451 | test_fs_uri_LDADD = \ | ||
452 | libgnunetfs.la \ | ||
453 | $(top_builddir)/src/util/libgnunetutil.la | ||
454 | |||
455 | test_fs_test_lib_SOURCES = \ | ||
456 | test_fs_test_lib.c | ||
457 | test_fs_test_lib_LDADD = \ | ||
458 | libgnunetfstest.a \ | ||
459 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
460 | libgnunetfs.la \ | ||
461 | $(top_builddir)/src/util/libgnunetutil.la | ||
462 | |||
463 | test_gnunet_service_fs_p2p_SOURCES = \ | ||
464 | test_gnunet_service_fs_p2p.c | ||
465 | test_gnunet_service_fs_p2p_LDADD = \ | ||
466 | libgnunetfstest.a \ | ||
467 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
468 | libgnunetfs.la \ | ||
469 | $(top_builddir)/src/util/libgnunetutil.la | ||
470 | |||
471 | test_gnunet_service_fs_p2p_cadet_SOURCES = \ | ||
472 | test_gnunet_service_fs_p2p.c | ||
473 | test_gnunet_service_fs_p2p_cadet_LDADD = \ | ||
474 | libgnunetfstest.a \ | ||
475 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
476 | libgnunetfs.la \ | ||
477 | $(top_builddir)/src/util/libgnunetutil.la | ||
478 | |||
479 | test_gnunet_service_fs_migration_SOURCES = \ | ||
480 | test_gnunet_service_fs_migration.c | ||
481 | test_gnunet_service_fs_migration_LDADD = \ | ||
482 | libgnunetfstest.a \ | ||
483 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
484 | libgnunetfs.la \ | ||
485 | $(top_builddir)/src/util/libgnunetutil.la | ||
486 | |||
487 | perf_gnunet_service_fs_p2p_SOURCES = \ | ||
488 | perf_gnunet_service_fs_p2p.c | ||
489 | perf_gnunet_service_fs_p2p_LDADD = \ | ||
490 | libgnunetfstest.a \ | ||
491 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
492 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
493 | libgnunetfs.la \ | ||
494 | $(top_builddir)/src/util/libgnunetutil.la | ||
495 | |||
496 | perf_gnunet_service_fs_p2p_index_SOURCES = \ | ||
497 | perf_gnunet_service_fs_p2p.c | ||
498 | perf_gnunet_service_fs_p2p_index_LDADD = \ | ||
499 | libgnunetfstest.a \ | ||
500 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
501 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
502 | libgnunetfs.la \ | ||
503 | $(top_builddir)/src/util/libgnunetutil.la | ||
504 | |||
505 | perf_gnunet_service_fs_p2p_dht_SOURCES = \ | ||
506 | perf_gnunet_service_fs_p2p.c | ||
507 | perf_gnunet_service_fs_p2p_dht_LDADD = \ | ||
508 | libgnunetfstest.a \ | ||
509 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
510 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
511 | libgnunetfs.la \ | ||
512 | $(top_builddir)/src/util/libgnunetutil.la | ||
513 | |||
514 | perf_gnunet_service_fs_p2p_respect_SOURCES = \ | ||
515 | perf_gnunet_service_fs_p2p_respect.c | ||
516 | perf_gnunet_service_fs_p2p_respect_LDADD = \ | ||
517 | libgnunetfstest.a \ | ||
518 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
519 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
520 | libgnunetfs.la \ | ||
521 | $(top_builddir)/src/util/libgnunetutil.la | ||
522 | |||
523 | |||
524 | test_gnunet_fs_psd.py: test_gnunet_fs_psd.py.in Makefile | ||
525 | $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/test_gnunet_fs_psd.py.in > test_gnunet_fs_psd.py | ||
526 | chmod +x test_gnunet_fs_psd.py | ||
527 | |||
528 | test_gnunet_fs_rec.py: test_gnunet_fs_rec.py.in Makefile | ||
529 | $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/test_gnunet_fs_rec.py.in > test_gnunet_fs_rec.py | ||
530 | chmod +x test_gnunet_fs_rec.py | ||
531 | |||
532 | test_gnunet_fs_ns.py: test_gnunet_fs_ns.py.in Makefile | ||
533 | $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/test_gnunet_fs_ns.py.in > test_gnunet_fs_ns.py | ||
534 | chmod +x test_gnunet_fs_ns.py | ||
535 | |||
536 | test_gnunet_fs_idx.py: test_gnunet_fs_idx.py.in Makefile | ||
537 | $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/test_gnunet_fs_idx.py.in > test_gnunet_fs_idx.py | ||
538 | chmod +x test_gnunet_fs_idx.py | ||
539 | |||
540 | |||
541 | EXTRA_DIST = \ | ||
542 | fs_test_lib_data.conf \ | ||
543 | perf_gnunet_service_fs_p2p.conf \ | ||
544 | test_fs_data.conf \ | ||
545 | test_fs_defaults.conf \ | ||
546 | test_fs_download_data.conf \ | ||
547 | test_fs_download_indexed.conf \ | ||
548 | test_fs_file_information_data.conf \ | ||
549 | test_fs_list_indexed_data.conf \ | ||
550 | test_fs_namespace_data.conf \ | ||
551 | test_fs_publish_data.conf \ | ||
552 | test_fs_search_data.conf \ | ||
553 | test_fs_unindex_data.conf \ | ||
554 | test_gnunet_fs_idx_data.conf \ | ||
555 | test_gnunet_fs_psd_data.conf \ | ||
556 | test_gnunet_fs_rec_data.conf \ | ||
557 | test_gnunet_fs_rec_data.tgz \ | ||
558 | test_gnunet_fs_psd.py.in \ | ||
559 | test_gnunet_fs_rec.py.in \ | ||
560 | test_gnunet_fs_idx.py.in \ | ||
561 | test_gnunet_service_fs_migration_data.conf \ | ||
562 | test_gnunet_service_fs_p2p_cadet.conf \ | ||
563 | test_pseudonym_data.conf | ||
564 | |||
565 | CLEANFILES = $(check_SCRIPTS) | ||
diff --git a/src/fs/fs.conf.in b/src/fs/fs.conf.in deleted file mode 100644 index 797109d07..000000000 --- a/src/fs/fs.conf.in +++ /dev/null | |||
@@ -1,62 +0,0 @@ | |||
1 | [fs] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | IMMEDIATE_START = YES | ||
4 | INDEXDB = $GNUNET_DATA_HOME/fs/idxinfo.lst | ||
5 | RESPECT = $GNUNET_DATA_HOME/fs/credit/ | ||
6 | STATE_DIR = $GNUNET_DATA_HOME/fs/persistence/ | ||
7 | UPDATE_DIR = $GNUNET_DATA_HOME/fs/updates/ | ||
8 | @UNIXONLY@ PORT = 2094 | ||
9 | HOSTNAME = localhost | ||
10 | BINARY = gnunet-service-fs | ||
11 | ACCEPT_FROM = 127.0.0.1; | ||
12 | ACCEPT_FROM6 = ::1; | ||
13 | |||
14 | # PREFIX = valgrind | ||
15 | |||
16 | # Do we introduce artificial delays? (may improve anonymity) | ||
17 | DELAY = YES | ||
18 | |||
19 | # Do we cache content from other nodes? (may improve anonymity) | ||
20 | CONTENT_CACHING = YES | ||
21 | |||
22 | # Do we send unsolicited data to other nodes if we have excess bandwidth? | ||
23 | # (may improve anonymity, probably not a good idea if content_caching is NO) | ||
24 | CONTENT_PUSHING = YES | ||
25 | |||
26 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-fs.sock | ||
27 | |||
28 | # Do we require users that want to access file-sharing to run this process | ||
29 | # (usually not a good idea) | ||
30 | UNIX_MATCH_UID = NO | ||
31 | |||
32 | # Do we require users that want to access file-sharing to be in the 'gnunet' group? | ||
33 | UNIX_MATCH_GID = YES | ||
34 | |||
35 | # Maximum number of requests this peer tracks (important for | ||
36 | # memory consumption; 2k RAM/request is not unusual) | ||
37 | MAX_PENDING_REQUESTS = 65536 | ||
38 | |||
39 | # How many requests do we have at most waiting in the queue towards | ||
40 | # the datastore? (important for memory consumption) | ||
41 | DATASTORE_QUEUE_SIZE = 32 | ||
42 | |||
43 | # Maximum frequency we're allowed to poll the datastore | ||
44 | # for content for migration (can be used to reduce | ||
45 | # GNUnet's disk-IO rate) | ||
46 | MIN_MIGRATION_DELAY = 100 ms | ||
47 | |||
48 | # For how many neighbouring peers should we allocate hash maps? | ||
49 | EXPECTED_NEIGHBOUR_COUNT = 128 | ||
50 | |||
51 | # Disable anonymous file-sharing (but keep non-anonymous transfers)? | ||
52 | # This option is mostly for testing. | ||
53 | DISABLE_ANON_TRANSFER = NO | ||
54 | |||
55 | # Maximum number of non-anonymous transfers this peer will support | ||
56 | # at the same time. Excessive values mostly have the problem that | ||
57 | # the service might use more memory, so we need to bound this at | ||
58 | # some reasonable level. And if we have a very, very large | ||
59 | # number, we probably won't have enough bandwidth to support them | ||
60 | # well anyway, so better have a moderate cap. | ||
61 | MAX_CADET_CLIENTS = 128 | ||
62 | |||
diff --git a/src/fs/fs.h b/src/fs/fs.h deleted file mode 100644 index 4c433e774..000000000 --- a/src/fs/fs.h +++ /dev/null | |||
@@ -1,396 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003--2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs.h | ||
23 | * @brief definitions for the entire fs module | ||
24 | * @author Igor Wronsky, Christian Grothoff | ||
25 | */ | ||
26 | #ifndef FS_H | ||
27 | #define FS_H | ||
28 | |||
29 | #include "gnunet_constants.h" | ||
30 | #include "gnunet_datastore_service.h" | ||
31 | #include "gnunet_dht_service.h" | ||
32 | #include "gnunet_fs_service.h" | ||
33 | #include "gnunet_block_lib.h" | ||
34 | #include "block_fs.h" | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Size of the individual blocks used for file-sharing. | ||
39 | */ | ||
40 | #define DBLOCK_SIZE (32 * 1024) | ||
41 | |||
42 | /** | ||
43 | * Blocksize to use when hashing files for indexing (blocksize for IO, | ||
44 | * not for the DBlocks). Larger blocksizes can be more efficient but | ||
45 | * will be more disruptive as far as the scheduler is concerned. | ||
46 | */ | ||
47 | #define HASHING_BLOCKSIZE (1024 * 128) | ||
48 | |||
49 | |||
50 | /** | ||
51 | * @brief content hash key | ||
52 | */ | ||
53 | struct ContentHashKey | ||
54 | { | ||
55 | /** | ||
56 | * Hash of the original content, used for encryption. | ||
57 | */ | ||
58 | struct GNUNET_HashCode key; | ||
59 | |||
60 | /** | ||
61 | * Hash of the encrypted content, used for querying. | ||
62 | */ | ||
63 | struct GNUNET_HashCode query; | ||
64 | }; | ||
65 | |||
66 | |||
67 | GNUNET_NETWORK_STRUCT_BEGIN | ||
68 | |||
69 | |||
70 | /** | ||
71 | * Message sent from a GNUnet (fs) publishing activity to sign | ||
72 | * a LOC URI. | ||
73 | */ | ||
74 | struct RequestLocSignatureMessage | ||
75 | { | ||
76 | /** | ||
77 | * Message type will be #GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN. | ||
78 | */ | ||
79 | struct GNUNET_MessageHeader header; | ||
80 | |||
81 | /** | ||
82 | * Requested signature purpose. For now, always | ||
83 | * #GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT. | ||
84 | */ | ||
85 | uint32_t purpose GNUNET_PACKED; | ||
86 | |||
87 | /** | ||
88 | * Requested expiration time. | ||
89 | */ | ||
90 | struct GNUNET_TIME_AbsoluteNBO expiration_time; | ||
91 | |||
92 | /** | ||
93 | * Information about the shared file (to be signed). | ||
94 | */ | ||
95 | struct ContentHashKey chk; | ||
96 | |||
97 | /** | ||
98 | * Size of the shared file (to be signed). | ||
99 | */ | ||
100 | uint64_t file_length; | ||
101 | }; | ||
102 | |||
103 | |||
104 | /** | ||
105 | * Message sent from the service with the signed LOC URI. | ||
106 | */ | ||
107 | struct ResponseLocSignatureMessage | ||
108 | { | ||
109 | /** | ||
110 | * Message type will be | ||
111 | * #GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE. | ||
112 | */ | ||
113 | struct GNUNET_MessageHeader header; | ||
114 | |||
115 | /** | ||
116 | * Purpose of the generated signature. For now, always | ||
117 | * #GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT. | ||
118 | */ | ||
119 | uint32_t purpose GNUNET_PACKED; | ||
120 | |||
121 | /** | ||
122 | * Expiration time that was actually used (rounded!). | ||
123 | */ | ||
124 | struct GNUNET_TIME_AbsoluteNBO expiration_time; | ||
125 | |||
126 | /** | ||
127 | * The requested signature. | ||
128 | */ | ||
129 | struct GNUNET_CRYPTO_EddsaSignature signature; | ||
130 | |||
131 | /** | ||
132 | * Identity of the peer sharing the file. | ||
133 | */ | ||
134 | struct GNUNET_PeerIdentity peer; | ||
135 | }; | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Message sent from a GNUnet (fs) publishing activity to the | ||
140 | * gnunet-fs-service to initiate indexing of a file. The service is | ||
141 | * supposed to check if the specified file is available and has the | ||
142 | * same cryptographic hash. It should then respond with either a | ||
143 | * confirmation or a denial. | ||
144 | * | ||
145 | * On OSes where this works, it is considered acceptable if the | ||
146 | * service only checks that the path, device and inode match (it can | ||
147 | * then be assumed that the hash will also match without actually | ||
148 | * computing it; this is an optimization that should be safe given | ||
149 | * that the client is not our adversary). | ||
150 | */ | ||
151 | struct IndexStartMessage | ||
152 | { | ||
153 | /** | ||
154 | * Message type will be #GNUNET_MESSAGE_TYPE_FS_INDEX_START. | ||
155 | */ | ||
156 | struct GNUNET_MessageHeader header; | ||
157 | |||
158 | /** | ||
159 | * For alignment. | ||
160 | */ | ||
161 | uint32_t reserved GNUNET_PACKED; | ||
162 | |||
163 | /** | ||
164 | * ID of device containing the file, as seen by the client. This | ||
165 | * device ID is obtained using a call like "statvfs" (and converting | ||
166 | * the "f_fsid" field to a 32-bit big-endian number). Use 0 if the | ||
167 | * OS does not support this, in which case the service must do a | ||
168 | * full hash recomputation. | ||
169 | */ | ||
170 | uint64_t device GNUNET_PACKED; | ||
171 | |||
172 | /** | ||
173 | * Inode of the file on the given device, as seen by the client | ||
174 | * ("st_ino" field from "struct stat"). Use 0 if the OS does not | ||
175 | * support this, in which case the service must do a full hash | ||
176 | * recomputation. | ||
177 | */ | ||
178 | uint64_t inode GNUNET_PACKED; | ||
179 | |||
180 | /** | ||
181 | * Hash of the file that we would like to index. | ||
182 | */ | ||
183 | struct GNUNET_HashCode file_id; | ||
184 | |||
185 | /* this is followed by a 0-terminated | ||
186 | * filename of a file with the hash | ||
187 | * "file_id" as seen by the client */ | ||
188 | }; | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Message send by FS service in response to a request | ||
193 | * asking for a list of all indexed files. | ||
194 | */ | ||
195 | struct IndexInfoMessage | ||
196 | { | ||
197 | /** | ||
198 | * Message type will be | ||
199 | * #GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY. | ||
200 | */ | ||
201 | struct GNUNET_MessageHeader header; | ||
202 | |||
203 | /** | ||
204 | * Always zero. | ||
205 | */ | ||
206 | uint32_t reserved GNUNET_PACKED; | ||
207 | |||
208 | /** | ||
209 | * Hash of the indexed file. | ||
210 | */ | ||
211 | struct GNUNET_HashCode file_id; | ||
212 | |||
213 | /* this is followed by a 0-terminated | ||
214 | * filename of a file with the hash | ||
215 | * "file_id" as seen by the client */ | ||
216 | }; | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Message sent from a GNUnet (fs) unindexing activity to the | ||
221 | * gnunet-service-fs to indicate that a file will be unindexed. The | ||
222 | * service is supposed to remove the file from the list of indexed | ||
223 | * files and response with a confirmation message (even if the file | ||
224 | * was already not on the list). | ||
225 | */ | ||
226 | struct UnindexMessage | ||
227 | { | ||
228 | /** | ||
229 | * Message type will be #GNUNET_MESSAGE_TYPE_FS_UNINDEX. | ||
230 | */ | ||
231 | struct GNUNET_MessageHeader header; | ||
232 | |||
233 | /** | ||
234 | * Always zero. | ||
235 | */ | ||
236 | uint32_t reserved GNUNET_PACKED; | ||
237 | |||
238 | /** | ||
239 | * Hash of the file that we will unindex. | ||
240 | */ | ||
241 | struct GNUNET_HashCode file_id; | ||
242 | }; | ||
243 | |||
244 | |||
245 | /** | ||
246 | * No options. | ||
247 | */ | ||
248 | #define SEARCH_MESSAGE_OPTION_NONE 0 | ||
249 | |||
250 | /** | ||
251 | * Only search the local datastore (no network) | ||
252 | */ | ||
253 | #define SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY 1 | ||
254 | |||
255 | /** | ||
256 | * Request is too large to fit in 64k format. The list of | ||
257 | * already-known search results will be continued in another message | ||
258 | * for the same type/query/target and additional already-known results | ||
259 | * following this one). | ||
260 | */ | ||
261 | #define SEARCH_MESSAGE_OPTION_CONTINUED 2 | ||
262 | |||
263 | |||
264 | /** | ||
265 | * Message sent from a GNUnet (fs) search activity to the | ||
266 | * gnunet-service-fs to start a search. | ||
267 | */ | ||
268 | struct SearchMessage | ||
269 | { | ||
270 | /** | ||
271 | * Message type will be #GNUNET_MESSAGE_TYPE_FS_START_SEARCH. | ||
272 | */ | ||
273 | struct GNUNET_MessageHeader header; | ||
274 | |||
275 | /** | ||
276 | * Bitmask with options. Zero for no options, one for | ||
277 | * loopback-only, two for 'to be continued' (with a second search | ||
278 | * message for the same type/query/target and additional | ||
279 | * already-known results following this one). See | ||
280 | * SEARCH_MESSAGE_OPTION_ defines. | ||
281 | * | ||
282 | * Other bits are currently not defined. | ||
283 | */ | ||
284 | uint32_t options GNUNET_PACKED; | ||
285 | |||
286 | /** | ||
287 | * Type of the content that we're looking for. | ||
288 | */ | ||
289 | uint32_t type GNUNET_PACKED; | ||
290 | |||
291 | /** | ||
292 | * Desired anonymity level, big-endian. | ||
293 | */ | ||
294 | uint32_t anonymity_level GNUNET_PACKED; | ||
295 | |||
296 | /** | ||
297 | * If the request is for a DBLOCK or IBLOCK, this is the identity of | ||
298 | * the peer that is known to have a response. Set to all-zeros if | ||
299 | * such a target is not known (note that even if OUR anonymity | ||
300 | * level is >0 we may happen to know the responder's identity; | ||
301 | * nevertheless, we should probably not use it for a DHT-lookup | ||
302 | * or similar blunt actions in order to avoid exposing ourselves). | ||
303 | * <p> | ||
304 | * Otherwise, "target" must be all zeros. | ||
305 | */ | ||
306 | struct GNUNET_PeerIdentity target; | ||
307 | |||
308 | /** | ||
309 | * Hash of the public key for UBLOCKs; Hash of | ||
310 | * the CHK-encoded block for DBLOCKS and IBLOCKS. | ||
311 | */ | ||
312 | struct GNUNET_HashCode query; | ||
313 | |||
314 | /* this is followed by the hash codes of already-known | ||
315 | * results (which should hence be excluded from what | ||
316 | * the service returns); naturally, this only applies | ||
317 | * to queries that can have multiple results (UBLOCKS). | ||
318 | */ | ||
319 | }; | ||
320 | |||
321 | |||
322 | /** | ||
323 | * Response from FS service with a result for a previous FS search. | ||
324 | * Note that queries for DBLOCKS and IBLOCKS that have received a | ||
325 | * single response are considered done. This message is transmitted | ||
326 | * between peers. | ||
327 | */ | ||
328 | struct PutMessage | ||
329 | { | ||
330 | /** | ||
331 | * Message type will be #GNUNET_MESSAGE_TYPE_FS_PUT. | ||
332 | */ | ||
333 | struct GNUNET_MessageHeader header; | ||
334 | |||
335 | /** | ||
336 | * Type of the block (in big endian). Should never be zero. | ||
337 | */ | ||
338 | uint32_t type GNUNET_PACKED; | ||
339 | |||
340 | /** | ||
341 | * When does this result expire? | ||
342 | */ | ||
343 | struct GNUNET_TIME_AbsoluteNBO expiration; | ||
344 | |||
345 | /* this is followed by the actual encrypted content */ | ||
346 | }; | ||
347 | |||
348 | /** | ||
349 | * Response from FS service with a result for a previous FS search. | ||
350 | * Note that queries for DBLOCKS and IBLOCKS that have received a | ||
351 | * single response are considered done. This message is transmitted | ||
352 | * between the service and a client. | ||
353 | */ | ||
354 | struct ClientPutMessage | ||
355 | { | ||
356 | /** | ||
357 | * Message type will be #GNUNET_MESSAGE_TYPE_FS_PUT. | ||
358 | */ | ||
359 | struct GNUNET_MessageHeader header; | ||
360 | |||
361 | /** | ||
362 | * Type of the block (in big endian). Should never be zero. | ||
363 | */ | ||
364 | uint32_t type GNUNET_PACKED; | ||
365 | |||
366 | /** | ||
367 | * When does this result expire? | ||
368 | */ | ||
369 | struct GNUNET_TIME_AbsoluteNBO expiration; | ||
370 | |||
371 | /** | ||
372 | * When was the last time we've tried to download this block? | ||
373 | * (FOREVER if unknown/not relevant) | ||
374 | */ | ||
375 | struct GNUNET_TIME_AbsoluteNBO last_transmission; | ||
376 | |||
377 | /** | ||
378 | * How often did we transmit this query before getting an | ||
379 | * answer (estimate). | ||
380 | */ | ||
381 | uint32_t num_transmissions; | ||
382 | |||
383 | /** | ||
384 | * How much respect did we offer (in total) before getting an | ||
385 | * answer (estimate). | ||
386 | */ | ||
387 | uint32_t respect_offered; | ||
388 | |||
389 | /* this is followed by the actual encrypted content */ | ||
390 | }; | ||
391 | GNUNET_NETWORK_STRUCT_END | ||
392 | |||
393 | |||
394 | #endif | ||
395 | |||
396 | /* end of fs.h */ | ||
diff --git a/src/fs/fs_api.c b/src/fs/fs_api.c deleted file mode 100644 index 63b17a93e..000000000 --- a/src/fs/fs_api.c +++ /dev/null | |||
@@ -1,3349 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001--2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_api.c | ||
23 | * @brief main FS functions (master initialization, serialization, deserialization, shared code) | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | #include "fs_api.h" | ||
31 | #include "fs_tree.h" | ||
32 | |||
33 | /** | ||
34 | * How many block requests can we have outstanding in parallel at a time by default? | ||
35 | */ | ||
36 | #define DEFAULT_MAX_PARALLEL_REQUESTS (1024 * 10) | ||
37 | |||
38 | /** | ||
39 | * How many downloads can we have outstanding in parallel at a time by default? | ||
40 | */ | ||
41 | #define DEFAULT_MAX_PARALLEL_DOWNLOADS 16 | ||
42 | |||
43 | /** | ||
44 | * Start the given job (send signal, remove from pending queue, update | ||
45 | * counters and state). | ||
46 | * | ||
47 | * @param qe job to start | ||
48 | */ | ||
49 | static void | ||
50 | start_job (struct GNUNET_FS_QueueEntry *qe) | ||
51 | { | ||
52 | qe->active = GNUNET_YES; | ||
53 | qe->start (qe->cls); | ||
54 | qe->start_times++; | ||
55 | qe->h->active_blocks += qe->blocks; | ||
56 | qe->h->active_downloads++; | ||
57 | qe->start_time = GNUNET_TIME_absolute_get (); | ||
58 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
59 | "Starting job %p (%u active)\n", | ||
60 | qe, | ||
61 | qe->h->active_downloads); | ||
62 | GNUNET_CONTAINER_DLL_remove (qe->h->pending_head, qe->h->pending_tail, qe); | ||
63 | GNUNET_CONTAINER_DLL_insert_after (qe->h->running_head, | ||
64 | qe->h->running_tail, | ||
65 | qe->h->running_tail, | ||
66 | qe); | ||
67 | } | ||
68 | |||
69 | |||
70 | /** | ||
71 | * Stop the given job (send signal, remove from active queue, update | ||
72 | * counters and state). | ||
73 | * | ||
74 | * @param qe job to stop | ||
75 | */ | ||
76 | static void | ||
77 | stop_job (struct GNUNET_FS_QueueEntry *qe) | ||
78 | { | ||
79 | qe->active = GNUNET_NO; | ||
80 | qe->stop (qe->cls); | ||
81 | GNUNET_assert (0 < qe->h->active_downloads); | ||
82 | qe->h->active_downloads--; | ||
83 | qe->h->active_blocks -= qe->blocks; | ||
84 | qe->run_time = GNUNET_TIME_relative_add (qe->run_time, | ||
85 | GNUNET_TIME_absolute_get_duration ( | ||
86 | qe->start_time)); | ||
87 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
88 | "Stopping job %p (%u active)\n", | ||
89 | qe, | ||
90 | qe->h->active_downloads); | ||
91 | GNUNET_CONTAINER_DLL_remove (qe->h->running_head, qe->h->running_tail, qe); | ||
92 | GNUNET_CONTAINER_DLL_insert_after (qe->h->pending_head, | ||
93 | qe->h->pending_tail, | ||
94 | qe->h->pending_tail, | ||
95 | qe); | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Process the jobs in the job queue, possibly starting some | ||
101 | * and stopping others. | ||
102 | * | ||
103 | * @param cls the `struct GNUNET_FS_Handle *` | ||
104 | */ | ||
105 | static void | ||
106 | process_job_queue (void *cls) | ||
107 | { | ||
108 | struct GNUNET_FS_Handle *h = cls; | ||
109 | struct GNUNET_FS_QueueEntry *qe; | ||
110 | struct GNUNET_FS_QueueEntry *next; | ||
111 | struct GNUNET_TIME_Relative run_time; | ||
112 | struct GNUNET_TIME_Relative restart_at; | ||
113 | struct GNUNET_TIME_Relative rst; | ||
114 | struct GNUNET_TIME_Absolute end_time; | ||
115 | unsigned int num_downloads_waiting; | ||
116 | unsigned int num_downloads_active; | ||
117 | unsigned int num_downloads_expired; | ||
118 | unsigned int num_probes_active; | ||
119 | unsigned int num_probes_waiting; | ||
120 | unsigned int num_probes_expired; | ||
121 | int num_probes_change; | ||
122 | int num_downloads_change; | ||
123 | int block_limit_hit; | ||
124 | |||
125 | h->queue_job = NULL; | ||
126 | /* restart_at will be set to the time when it makes sense to | ||
127 | re-evaluate the job queue (unless, of course, jobs complete | ||
128 | or are added, then we'll be triggered immediately */ | ||
129 | restart_at = GNUNET_TIME_UNIT_FOREVER_REL; | ||
130 | /* first, calculate some basic statistics on pending jobs */ | ||
131 | num_probes_waiting = 0; | ||
132 | num_downloads_waiting = 0; | ||
133 | for (qe = h->pending_head; NULL != qe; qe = qe->next) | ||
134 | { | ||
135 | switch (qe->priority) | ||
136 | { | ||
137 | case GNUNET_FS_QUEUE_PRIORITY_PROBE: | ||
138 | num_probes_waiting++; | ||
139 | break; | ||
140 | |||
141 | case GNUNET_FS_QUEUE_PRIORITY_NORMAL: | ||
142 | num_downloads_waiting++; | ||
143 | break; | ||
144 | |||
145 | default: | ||
146 | GNUNET_break (0); | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | /* now, calculate some basic statistics on running jobs */ | ||
151 | num_probes_active = 0; | ||
152 | num_probes_expired = 0; | ||
153 | num_downloads_active = 0; | ||
154 | num_downloads_expired = 0; | ||
155 | next = h->running_head; | ||
156 | while (NULL != (qe = next)) | ||
157 | { | ||
158 | next = qe->next; | ||
159 | switch (qe->priority) | ||
160 | { | ||
161 | case GNUNET_FS_QUEUE_PRIORITY_PROBE: | ||
162 | run_time = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2); | ||
163 | end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time); | ||
164 | rst = GNUNET_TIME_absolute_get_remaining (end_time); | ||
165 | if (0 == rst.rel_value_us) | ||
166 | { | ||
167 | num_probes_expired++; | ||
168 | stop_job (qe); | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | num_probes_active++; | ||
173 | restart_at = GNUNET_TIME_relative_min (rst, restart_at); | ||
174 | } | ||
175 | break; | ||
176 | |||
177 | case GNUNET_FS_QUEUE_PRIORITY_NORMAL: | ||
178 | run_time = | ||
179 | GNUNET_TIME_relative_saturating_multiply (h->avg_block_latency, | ||
180 | qe->blocks * qe->start_times); | ||
181 | end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time); | ||
182 | rst = GNUNET_TIME_absolute_get_remaining (end_time); | ||
183 | if (0 == rst.rel_value_us) | ||
184 | { | ||
185 | num_downloads_expired++; | ||
186 | stop_job (qe); | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | num_downloads_active++; | ||
191 | restart_at = GNUNET_TIME_relative_min (rst, restart_at); | ||
192 | } | ||
193 | break; | ||
194 | |||
195 | default: | ||
196 | GNUNET_break (0); | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | GNUNET_break (h->active_downloads == | ||
201 | num_downloads_active + num_probes_active); | ||
202 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
203 | "PA: %u, PE: %u, PW: %u; DA: %u, DE: %u, DW: %u\n", | ||
204 | num_probes_active, | ||
205 | num_probes_expired, | ||
206 | num_probes_waiting, | ||
207 | num_downloads_active, | ||
208 | num_downloads_expired, | ||
209 | num_downloads_waiting); | ||
210 | GNUNET_break (h->active_downloads + num_probes_active <= | ||
211 | h->max_parallel_downloads); | ||
212 | /* calculate start/stop decisions */ | ||
213 | if (h->active_downloads + num_downloads_waiting > h->max_parallel_downloads) | ||
214 | { | ||
215 | /* stop as many probes as there are downloads and probes */ | ||
216 | num_probes_change = -GNUNET_MIN (num_probes_active, num_downloads_waiting); | ||
217 | /* start as many downloads as there are free slots, including those | ||
218 | we just opened up */ | ||
219 | num_downloads_change = | ||
220 | h->max_parallel_downloads - h->active_downloads - num_probes_change; | ||
221 | } | ||
222 | else | ||
223 | { | ||
224 | /* start all downloads (we can) */ | ||
225 | num_downloads_change = num_downloads_waiting; | ||
226 | /* also start probes if there is room, but use a lower cap of (mpd/4) + 1 */ | ||
227 | if (1 + h->max_parallel_downloads / 4 >= | ||
228 | (h->active_downloads + num_downloads_change)) | ||
229 | num_probes_change = | ||
230 | GNUNET_MIN (num_probes_waiting, | ||
231 | (1 + h->max_parallel_downloads / 4) | ||
232 | - (h->active_downloads + num_downloads_change)); | ||
233 | else | ||
234 | num_probes_change = 0; | ||
235 | } | ||
236 | GNUNET_break (num_downloads_change <= num_downloads_waiting); | ||
237 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
238 | "Changing %d probes and %d/%u/%u downloads\n", | ||
239 | num_probes_change, | ||
240 | num_downloads_change, | ||
241 | (unsigned int) h->active_downloads, | ||
242 | (unsigned int) h->max_parallel_downloads); | ||
243 | /* actually stop probes */ | ||
244 | next = h->running_head; | ||
245 | while (NULL != (qe = next)) | ||
246 | { | ||
247 | next = qe->next; | ||
248 | if (GNUNET_FS_QUEUE_PRIORITY_PROBE != qe->priority) | ||
249 | continue; | ||
250 | if (num_probes_change < 0) | ||
251 | { | ||
252 | stop_job (qe); | ||
253 | num_probes_change++; | ||
254 | if (0 == num_probes_change) | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | GNUNET_break (0 <= num_probes_change); | ||
259 | |||
260 | /* start some more tasks if we now have empty slots */ | ||
261 | block_limit_hit = GNUNET_NO; | ||
262 | next = h->pending_head; | ||
263 | while ((NULL != (qe = next)) && | ||
264 | ((num_probes_change > 0) || (num_downloads_change > 0))) | ||
265 | { | ||
266 | next = qe->next; | ||
267 | switch (qe->priority) | ||
268 | { | ||
269 | case GNUNET_FS_QUEUE_PRIORITY_PROBE: | ||
270 | if (num_probes_change > 0) | ||
271 | { | ||
272 | start_job (qe); | ||
273 | num_probes_change--; | ||
274 | run_time = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2); | ||
275 | restart_at = GNUNET_TIME_relative_min (run_time, restart_at); | ||
276 | } | ||
277 | break; | ||
278 | |||
279 | case GNUNET_FS_QUEUE_PRIORITY_NORMAL: | ||
280 | if ((num_downloads_change > 0) && | ||
281 | ((qe->blocks + h->active_blocks <= h->max_parallel_requests) || | ||
282 | ((qe->blocks > h->max_parallel_requests) && | ||
283 | (0 == h->active_downloads)))) | ||
284 | { | ||
285 | start_job (qe); | ||
286 | num_downloads_change--; | ||
287 | } | ||
288 | else if (num_downloads_change > 0) | ||
289 | block_limit_hit = GNUNET_YES; | ||
290 | break; | ||
291 | |||
292 | default: | ||
293 | GNUNET_break (0); | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | GNUNET_break ((0 == num_downloads_change) || (GNUNET_YES == block_limit_hit)); | ||
298 | GNUNET_break (0 == num_probes_change); | ||
299 | |||
300 | GNUNET_log ( | ||
301 | GNUNET_ERROR_TYPE_DEBUG, | ||
302 | "AD: %u, MP: %u; %d probes and %d downloads to start, will run again in %s\n", | ||
303 | h->active_downloads, | ||
304 | h->max_parallel_requests, | ||
305 | num_probes_change, | ||
306 | num_downloads_change, | ||
307 | GNUNET_STRINGS_relative_time_to_string (restart_at, GNUNET_YES)); | ||
308 | |||
309 | /* make sure we run again, callbacks might have | ||
310 | already re-scheduled the job, so cancel such | ||
311 | an operation (if it exists) */ | ||
312 | if (NULL != h->queue_job) | ||
313 | GNUNET_SCHEDULER_cancel (h->queue_job); | ||
314 | h->queue_job = | ||
315 | GNUNET_SCHEDULER_add_delayed (restart_at, &process_job_queue, h); | ||
316 | } | ||
317 | |||
318 | |||
319 | /** | ||
320 | * Add a job to the queue. | ||
321 | * | ||
322 | * @param h handle to the overall FS state | ||
323 | * @param start function to call to begin the job | ||
324 | * @param stop function to call to pause the job, or on dequeue (if the job was running) | ||
325 | * @param cls closure for start and stop | ||
326 | * @param blocks number of blocks this jobs uses | ||
327 | * @param priority how important is this download | ||
328 | * @return queue handle | ||
329 | */ | ||
330 | struct GNUNET_FS_QueueEntry * | ||
331 | GNUNET_FS_queue_ (struct GNUNET_FS_Handle *h, | ||
332 | GNUNET_SCHEDULER_TaskCallback start, | ||
333 | GNUNET_SCHEDULER_TaskCallback stop, | ||
334 | void *cls, | ||
335 | unsigned int blocks, | ||
336 | enum GNUNET_FS_QueuePriority priority) | ||
337 | { | ||
338 | struct GNUNET_FS_QueueEntry *qe; | ||
339 | |||
340 | qe = GNUNET_new (struct GNUNET_FS_QueueEntry); | ||
341 | qe->h = h; | ||
342 | qe->start = start; | ||
343 | qe->stop = stop; | ||
344 | qe->cls = cls; | ||
345 | qe->queue_time = GNUNET_TIME_absolute_get (); | ||
346 | qe->blocks = blocks; | ||
347 | qe->priority = priority; | ||
348 | GNUNET_CONTAINER_DLL_insert_after (h->pending_head, | ||
349 | h->pending_tail, | ||
350 | h->pending_tail, | ||
351 | qe); | ||
352 | if (NULL != h->queue_job) | ||
353 | GNUNET_SCHEDULER_cancel (h->queue_job); | ||
354 | h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h); | ||
355 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queueing job %p\n", qe); | ||
356 | return qe; | ||
357 | } | ||
358 | |||
359 | |||
360 | /** | ||
361 | * Dequeue a job from the queue. | ||
362 | * | ||
363 | * @param qe handle for the job | ||
364 | */ | ||
365 | void | ||
366 | GNUNET_FS_dequeue_ (struct GNUNET_FS_QueueEntry *qe) | ||
367 | { | ||
368 | struct GNUNET_FS_Handle *h; | ||
369 | |||
370 | h = qe->h; | ||
371 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Dequeueing job %p\n", qe); | ||
372 | if (GNUNET_YES == qe->active) | ||
373 | stop_job (qe); | ||
374 | GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, qe); | ||
375 | GNUNET_free (qe); | ||
376 | if (NULL != h->queue_job) | ||
377 | GNUNET_SCHEDULER_cancel (h->queue_job); | ||
378 | h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h); | ||
379 | } | ||
380 | |||
381 | |||
382 | /** | ||
383 | * Create a top-level activity entry. | ||
384 | * | ||
385 | * @param h global fs handle | ||
386 | * @param ssf suspend signal function to use | ||
387 | * @param ssf_cls closure for @a ssf | ||
388 | * @return fresh top-level activity handle | ||
389 | */ | ||
390 | struct TopLevelActivity * | ||
391 | GNUNET_FS_make_top (struct GNUNET_FS_Handle *h, | ||
392 | SuspendSignalFunction ssf, | ||
393 | void *ssf_cls) | ||
394 | { | ||
395 | struct TopLevelActivity *ret; | ||
396 | |||
397 | ret = GNUNET_new (struct TopLevelActivity); | ||
398 | ret->ssf = ssf; | ||
399 | ret->ssf_cls = ssf_cls; | ||
400 | GNUNET_CONTAINER_DLL_insert (h->top_head, h->top_tail, ret); | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | |||
405 | /** | ||
406 | * Destroy a top-level activity entry. | ||
407 | * | ||
408 | * @param h global fs handle | ||
409 | * @param top top level activity entry | ||
410 | */ | ||
411 | void | ||
412 | GNUNET_FS_end_top (struct GNUNET_FS_Handle *h, struct TopLevelActivity *top) | ||
413 | { | ||
414 | GNUNET_CONTAINER_DLL_remove (h->top_head, h->top_tail, top); | ||
415 | GNUNET_free (top); | ||
416 | } | ||
417 | |||
418 | |||
419 | /** | ||
420 | * Closure for #GNUNET_FS_data_reader_file_(). | ||
421 | */ | ||
422 | struct FileInfo | ||
423 | { | ||
424 | /** | ||
425 | * Name of the file to read. | ||
426 | */ | ||
427 | char *filename; | ||
428 | |||
429 | /** | ||
430 | * File descriptor, NULL if it has not yet been opened. | ||
431 | */ | ||
432 | struct GNUNET_DISK_FileHandle *fd; | ||
433 | }; | ||
434 | |||
435 | |||
436 | /** | ||
437 | * Function that provides data by reading from a file. | ||
438 | * | ||
439 | * @param cls closure with the `struct FileInfo *` | ||
440 | * @param offset offset to read from; it is possible | ||
441 | * that the caller might need to go backwards | ||
442 | * a bit at times; set to `UINT64_MAX` to tell | ||
443 | * the reader that we won't be reading for a while | ||
444 | * (used to close the file descriptor but NOT fully | ||
445 | * clean up the reader's state); in this case, | ||
446 | * a value of '0' for @a max should be ignored | ||
447 | * @param max maximum number of bytes that should be | ||
448 | * copied to @a buf; readers are not allowed | ||
449 | * to provide less data unless there is an error; | ||
450 | * a value of "0" will be used at the end to allow | ||
451 | * the reader to clean up its internal state | ||
452 | * @param buf where the reader should write the data | ||
453 | * @param emsg location for the reader to store an error message | ||
454 | * @return number of bytes written, usually @a max, 0 on error | ||
455 | */ | ||
456 | size_t | ||
457 | GNUNET_FS_data_reader_file_ (void *cls, | ||
458 | uint64_t offset, | ||
459 | size_t max, | ||
460 | void *buf, | ||
461 | char **emsg) | ||
462 | { | ||
463 | struct FileInfo *fi = cls; | ||
464 | ssize_t ret; | ||
465 | |||
466 | if (UINT64_MAX == offset) | ||
467 | { | ||
468 | if (NULL != fi->fd) | ||
469 | { | ||
470 | GNUNET_DISK_file_close (fi->fd); | ||
471 | fi->fd = NULL; | ||
472 | } | ||
473 | return 0; | ||
474 | } | ||
475 | if (0 == max) | ||
476 | { | ||
477 | if (NULL != fi->fd) | ||
478 | GNUNET_DISK_file_close (fi->fd); | ||
479 | GNUNET_free (fi->filename); | ||
480 | GNUNET_free (fi); | ||
481 | return 0; | ||
482 | } | ||
483 | if (NULL == fi->fd) | ||
484 | { | ||
485 | fi->fd = GNUNET_DISK_file_open (fi->filename, | ||
486 | GNUNET_DISK_OPEN_READ, | ||
487 | GNUNET_DISK_PERM_NONE); | ||
488 | if (NULL == fi->fd) | ||
489 | { | ||
490 | GNUNET_asprintf (emsg, | ||
491 | _ ("Could not open file `%s': %s"), | ||
492 | fi->filename, | ||
493 | strerror (errno)); | ||
494 | return 0; | ||
495 | } | ||
496 | } | ||
497 | if ((GNUNET_SYSERR == | ||
498 | GNUNET_DISK_file_seek (fi->fd, offset, GNUNET_DISK_SEEK_SET)) || | ||
499 | (-1 == (ret = GNUNET_DISK_file_read (fi->fd, buf, max)))) | ||
500 | { | ||
501 | GNUNET_asprintf (emsg, | ||
502 | _ ("Could not read file `%s': %s"), | ||
503 | fi->filename, | ||
504 | strerror (errno)); | ||
505 | return 0; | ||
506 | } | ||
507 | if (ret != max) | ||
508 | { | ||
509 | GNUNET_asprintf (emsg, | ||
510 | _ ("Short read reading from file `%s'!"), | ||
511 | fi->filename); | ||
512 | return 0; | ||
513 | } | ||
514 | return max; | ||
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * Create the closure for the #GNUNET_FS_data_reader_file_() callback. | ||
520 | * | ||
521 | * @param filename file to read | ||
522 | * @return closure to use, NULL on error | ||
523 | */ | ||
524 | void * | ||
525 | GNUNET_FS_make_file_reader_context_ (const char *filename) | ||
526 | { | ||
527 | struct FileInfo *fi; | ||
528 | |||
529 | fi = GNUNET_new (struct FileInfo); | ||
530 | fi->filename = GNUNET_STRINGS_filename_expand (filename); | ||
531 | if (NULL == fi->filename) | ||
532 | { | ||
533 | GNUNET_free (fi); | ||
534 | return NULL; | ||
535 | } | ||
536 | return fi; | ||
537 | } | ||
538 | |||
539 | |||
540 | /** | ||
541 | * Function that provides data by copying from a buffer. | ||
542 | * | ||
543 | * @param cls closure (points to the buffer) | ||
544 | * @param offset offset to read from; it is possible | ||
545 | * that the caller might need to go backwards | ||
546 | * a bit at times; set to `UINT64_MAX` to tell | ||
547 | * the reader that we won't be reading for a while | ||
548 | * (used to close the file descriptor but NOT fully | ||
549 | * clean up the reader's state); in this case, | ||
550 | * a value of '0' for @a max should be ignored | ||
551 | * @param max maximum number of bytes that should be | ||
552 | * copied to @a buf; readers are not allowed | ||
553 | * to provide less data unless there is an error; | ||
554 | * a value of "0" will be used at the end to allow | ||
555 | * the reader to clean up its internal state | ||
556 | * @param buf where the reader should write the data | ||
557 | * @param emsg location for the reader to store an error message | ||
558 | * @return number of bytes written, usually @a max, 0 on error | ||
559 | */ | ||
560 | size_t | ||
561 | GNUNET_FS_data_reader_copy_ (void *cls, | ||
562 | uint64_t offset, | ||
563 | size_t max, | ||
564 | void *buf, | ||
565 | char **emsg) | ||
566 | { | ||
567 | char *data = cls; | ||
568 | |||
569 | if (UINT64_MAX == offset) | ||
570 | return 0; | ||
571 | if (0 == max) | ||
572 | { | ||
573 | GNUNET_free (data); | ||
574 | return 0; | ||
575 | } | ||
576 | GNUNET_memcpy (buf, &data[offset], max); | ||
577 | return max; | ||
578 | } | ||
579 | |||
580 | |||
581 | /** | ||
582 | * Return the full filename where we would store state information | ||
583 | * (for serialization/deserialization). | ||
584 | * | ||
585 | * @param h master context | ||
586 | * @param ext component of the path | ||
587 | * @param ent entity identifier (or empty string for the directory) | ||
588 | * @return NULL on error | ||
589 | */ | ||
590 | static char * | ||
591 | get_serialization_file_name (struct GNUNET_FS_Handle *h, | ||
592 | const char *ext, | ||
593 | const char *ent) | ||
594 | { | ||
595 | char *basename; | ||
596 | char *ret; | ||
597 | |||
598 | if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) | ||
599 | return NULL; /* persistence not requested */ | ||
600 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg, | ||
601 | "fs", | ||
602 | "STATE_DIR", | ||
603 | &basename)) | ||
604 | return NULL; | ||
605 | GNUNET_asprintf (&ret, | ||
606 | "%s%s%s%s%s%s%s", | ||
607 | basename, | ||
608 | DIR_SEPARATOR_STR, | ||
609 | h->client_name, | ||
610 | DIR_SEPARATOR_STR, | ||
611 | ext, | ||
612 | DIR_SEPARATOR_STR, | ||
613 | ent); | ||
614 | GNUNET_free (basename); | ||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | |||
619 | /** | ||
620 | * Return the full filename where we would store state information | ||
621 | * (for serialization/deserialization) that is associated with a | ||
622 | * parent operation. | ||
623 | * | ||
624 | * @param h master context | ||
625 | * @param ext component of the path | ||
626 | * @param uni name of the parent operation | ||
627 | * @param ent entity identifier (or empty string for the directory) | ||
628 | * @return NULL on error | ||
629 | */ | ||
630 | static char * | ||
631 | get_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h, | ||
632 | const char *ext, | ||
633 | const char *uni, | ||
634 | const char *ent) | ||
635 | { | ||
636 | char *basename; | ||
637 | char *ret; | ||
638 | |||
639 | if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) | ||
640 | return NULL; /* persistence not requested */ | ||
641 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg, | ||
642 | "fs", | ||
643 | "STATE_DIR", | ||
644 | &basename)) | ||
645 | return NULL; | ||
646 | GNUNET_asprintf (&ret, | ||
647 | "%s%s%s%s%s%s%s.dir%s%s", | ||
648 | basename, | ||
649 | DIR_SEPARATOR_STR, | ||
650 | h->client_name, | ||
651 | DIR_SEPARATOR_STR, | ||
652 | ext, | ||
653 | DIR_SEPARATOR_STR, | ||
654 | uni, | ||
655 | DIR_SEPARATOR_STR, | ||
656 | ent); | ||
657 | GNUNET_free (basename); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | |||
662 | /** | ||
663 | * Return a read handle for deserialization. | ||
664 | * | ||
665 | * @param h master context | ||
666 | * @param ext component of the path | ||
667 | * @param ent entity identifier (or empty string for the directory) | ||
668 | * @return NULL on error | ||
669 | */ | ||
670 | static struct GNUNET_BIO_ReadHandle * | ||
671 | get_read_handle (struct GNUNET_FS_Handle *h, const char *ext, const char *ent) | ||
672 | { | ||
673 | char *fn; | ||
674 | struct GNUNET_BIO_ReadHandle *ret; | ||
675 | |||
676 | fn = get_serialization_file_name (h, ext, ent); | ||
677 | if (NULL == fn) | ||
678 | return NULL; | ||
679 | ret = GNUNET_BIO_read_open_file (fn); | ||
680 | GNUNET_free (fn); | ||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | |||
685 | /** | ||
686 | * Return a write handle for serialization. | ||
687 | * | ||
688 | * @param h master context | ||
689 | * @param ext component of the path | ||
690 | * @param ent entity identifier (or empty string for the directory) | ||
691 | * @return NULL on error | ||
692 | */ | ||
693 | static struct GNUNET_BIO_WriteHandle * | ||
694 | get_write_handle (struct GNUNET_FS_Handle *h, const char *ext, const char *ent) | ||
695 | { | ||
696 | char *fn; | ||
697 | struct GNUNET_BIO_WriteHandle *ret; | ||
698 | |||
699 | fn = get_serialization_file_name (h, ext, ent); | ||
700 | if (NULL == fn) | ||
701 | return NULL; | ||
702 | ret = GNUNET_BIO_write_open_file (fn); | ||
703 | GNUNET_break (NULL != ret); | ||
704 | GNUNET_free (fn); | ||
705 | return ret; | ||
706 | } | ||
707 | |||
708 | |||
709 | /** | ||
710 | * Return a write handle for serialization. | ||
711 | * | ||
712 | * @param h master context | ||
713 | * @param ext component of the path | ||
714 | * @param uni name of parent | ||
715 | * @param ent entity identifier (or empty string for the directory) | ||
716 | * @return NULL on error | ||
717 | */ | ||
718 | static struct GNUNET_BIO_WriteHandle * | ||
719 | get_write_handle_in_dir (struct GNUNET_FS_Handle *h, | ||
720 | const char *ext, | ||
721 | const char *uni, | ||
722 | const char *ent) | ||
723 | { | ||
724 | char *fn; | ||
725 | struct GNUNET_BIO_WriteHandle *ret; | ||
726 | |||
727 | fn = get_serialization_file_name_in_dir (h, ext, uni, ent); | ||
728 | if (NULL == fn) | ||
729 | return NULL; | ||
730 | ret = GNUNET_BIO_write_open_file (fn); | ||
731 | GNUNET_free (fn); | ||
732 | return ret; | ||
733 | } | ||
734 | |||
735 | |||
736 | /** | ||
737 | * Remove serialization/deserialization file from disk. | ||
738 | * | ||
739 | * @param h master context | ||
740 | * @param ext component of the path | ||
741 | * @param ent entity identifier | ||
742 | */ | ||
743 | void | ||
744 | GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h, | ||
745 | const char *ext, | ||
746 | const char *ent) | ||
747 | { | ||
748 | char *filename; | ||
749 | |||
750 | if ((NULL == ent) || (0 == strlen (ent))) | ||
751 | { | ||
752 | GNUNET_break (0); | ||
753 | return; | ||
754 | } | ||
755 | filename = get_serialization_file_name (h, ext, ent); | ||
756 | if (NULL != filename) | ||
757 | { | ||
758 | if ((0 != unlink (filename)) && (ENOENT != errno)) | ||
759 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); | ||
760 | GNUNET_free (filename); | ||
761 | } | ||
762 | } | ||
763 | |||
764 | |||
765 | /** | ||
766 | * Remove serialization/deserialization file from disk. | ||
767 | * | ||
768 | * @param h master context | ||
769 | * @param ext component of the path | ||
770 | * @param uni parent name | ||
771 | * @param ent entity identifier | ||
772 | */ | ||
773 | static void | ||
774 | remove_sync_file_in_dir (struct GNUNET_FS_Handle *h, | ||
775 | const char *ext, | ||
776 | const char *uni, | ||
777 | const char *ent) | ||
778 | { | ||
779 | char *filename; | ||
780 | |||
781 | if ((NULL == ent) || (0 == strlen (ent))) | ||
782 | { | ||
783 | GNUNET_break (0); | ||
784 | return; | ||
785 | } | ||
786 | filename = get_serialization_file_name_in_dir (h, ext, uni, ent); | ||
787 | if (NULL == filename) | ||
788 | return; | ||
789 | if (0 != unlink (filename)) | ||
790 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); | ||
791 | GNUNET_free (filename); | ||
792 | } | ||
793 | |||
794 | |||
795 | /** | ||
796 | * Remove serialization/deserialization directory from disk. | ||
797 | * | ||
798 | * @param h master context | ||
799 | * @param ext component of the path | ||
800 | * @param uni unique name of parent | ||
801 | */ | ||
802 | void | ||
803 | GNUNET_FS_remove_sync_dir_ (struct GNUNET_FS_Handle *h, | ||
804 | const char *ext, | ||
805 | const char *uni) | ||
806 | { | ||
807 | char *dn; | ||
808 | |||
809 | if (NULL == uni) | ||
810 | return; | ||
811 | dn = get_serialization_file_name_in_dir (h, ext, uni, ""); | ||
812 | if (NULL == dn) | ||
813 | return; | ||
814 | if ((GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES)) && | ||
815 | (GNUNET_OK != GNUNET_DISK_directory_remove (dn))) | ||
816 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dn); | ||
817 | GNUNET_free (dn); | ||
818 | } | ||
819 | |||
820 | |||
821 | /** | ||
822 | * Serialize a start-time. Since we use start-times to | ||
823 | * calculate the duration of some operation, we actually | ||
824 | * do not serialize the absolute time but the (relative) | ||
825 | * duration since the start time. When we then | ||
826 | * deserialize the start time, we take the current time and | ||
827 | * subtract that duration so that we get again an absolute | ||
828 | * time stamp that will result in correct performance | ||
829 | * calculations. | ||
830 | * | ||
831 | * @param wh handle for writing | ||
832 | * @param timestamp time to serialize | ||
833 | * @return #GNUNET_OK on success | ||
834 | */ | ||
835 | static int | ||
836 | write_start_time (struct GNUNET_BIO_WriteHandle *wh, | ||
837 | struct GNUNET_TIME_Absolute timestamp) | ||
838 | { | ||
839 | struct GNUNET_TIME_Relative dur; | ||
840 | |||
841 | dur = GNUNET_TIME_absolute_get_duration (timestamp); | ||
842 | return GNUNET_BIO_write_int64 (wh, "start time", dur.rel_value_us); | ||
843 | } | ||
844 | |||
845 | |||
846 | /** | ||
847 | * Deserialize a start-time. Since we use start-times to | ||
848 | * calculate the duration of some operation, we actually | ||
849 | * do not serialize the absolute time but the (relative) | ||
850 | * duration since the start time. Thus, when we then | ||
851 | * deserialize the start time, we take the current time and | ||
852 | * subtract that duration so that we get again an absolute | ||
853 | * time stamp that will result in correct performance | ||
854 | * calculations. | ||
855 | * | ||
856 | * @param rh handle for reading | ||
857 | * @param timestamp where to write the deserialized timestamp | ||
858 | * @return #GNUNET_OK on success | ||
859 | */ | ||
860 | static int | ||
861 | read_start_time (struct GNUNET_BIO_ReadHandle *rh, | ||
862 | struct GNUNET_TIME_Absolute *timestamp) | ||
863 | { | ||
864 | struct GNUNET_TIME_Relative dur; | ||
865 | |||
866 | if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, "start time", | ||
867 | (int64_t *) &dur.rel_value_us)) | ||
868 | return GNUNET_SYSERR; | ||
869 | *timestamp = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (), dur); | ||
870 | return GNUNET_OK; | ||
871 | } | ||
872 | |||
873 | |||
874 | /** | ||
875 | * Using the given serialization filename, try to deserialize | ||
876 | * the file-information tree associated with it. | ||
877 | * | ||
878 | * @param h master context | ||
879 | * @param filename name of the file (without directory) with | ||
880 | * the information | ||
881 | * @return NULL on error | ||
882 | */ | ||
883 | static struct GNUNET_FS_FileInformation * | ||
884 | deserialize_file_information (struct GNUNET_FS_Handle *h, const char *filename); | ||
885 | |||
886 | |||
887 | /** | ||
888 | * Using the given serialization filename, try to deserialize | ||
889 | * the file-information tree associated with it. | ||
890 | * | ||
891 | * @param h master context | ||
892 | * @param fn name of the file (without directory) with | ||
893 | * the information | ||
894 | * @param rh handle for reading | ||
895 | * @return NULL on error | ||
896 | */ | ||
897 | static struct GNUNET_FS_FileInformation * | ||
898 | deserialize_fi_node (struct GNUNET_FS_Handle *h, | ||
899 | const char *fn, | ||
900 | struct GNUNET_BIO_ReadHandle *rh) | ||
901 | { | ||
902 | struct GNUNET_FS_FileInformation *ret; | ||
903 | struct GNUNET_FS_FileInformation *nxt; | ||
904 | char b; | ||
905 | char *ksks; | ||
906 | char *chks; | ||
907 | char *skss; | ||
908 | char *filename; | ||
909 | uint32_t dsize; | ||
910 | |||
911 | if (GNUNET_OK != GNUNET_BIO_read (rh, "status flag", &b, sizeof(b))) | ||
912 | { | ||
913 | GNUNET_break (0); | ||
914 | return NULL; | ||
915 | } | ||
916 | ret = GNUNET_new (struct GNUNET_FS_FileInformation); | ||
917 | ret->h = h; | ||
918 | ksks = NULL; | ||
919 | chks = NULL; | ||
920 | skss = NULL; | ||
921 | filename = NULL; | ||
922 | if ((GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "metadata", &ret->meta)) || | ||
923 | (GNUNET_OK != GNUNET_BIO_read_string (rh, "ksk-uri", &ksks, 32 * 1024)) || | ||
924 | ((NULL != ksks) && | ||
925 | ((NULL == (ret->keywords = GNUNET_FS_uri_parse (ksks, NULL))) || | ||
926 | (GNUNET_YES != GNUNET_FS_uri_test_ksk (ret->keywords)))) || | ||
927 | (GNUNET_OK != GNUNET_BIO_read_string (rh, "chk-uri", &chks, 1024)) || | ||
928 | ((NULL != chks) && | ||
929 | ((NULL == (ret->chk_uri = GNUNET_FS_uri_parse (chks, NULL))) || | ||
930 | (GNUNET_YES != GNUNET_FS_uri_test_chk (ret->chk_uri)))) || | ||
931 | (GNUNET_OK != GNUNET_BIO_read_string (rh, "sks-uri", &skss, 1024)) || | ||
932 | ((NULL != skss) && | ||
933 | ((NULL == (ret->sks_uri = GNUNET_FS_uri_parse (skss, NULL))) || | ||
934 | (GNUNET_YES != GNUNET_FS_uri_test_sks (ret->sks_uri)))) || | ||
935 | (GNUNET_OK != read_start_time (rh, &ret->start_time)) || | ||
936 | (GNUNET_OK != | ||
937 | GNUNET_BIO_read_string (rh, "emsg", &ret->emsg, 16 * 1024)) || | ||
938 | (GNUNET_OK != | ||
939 | GNUNET_BIO_read_string (rh, "fn", &ret->filename, 16 * 1024)) || | ||
940 | (GNUNET_OK != | ||
941 | GNUNET_BIO_read_int64 ( | ||
942 | rh, | ||
943 | "expiration time", | ||
944 | (int64_t *) &ret->bo.expiration_time.abs_value_us)) || | ||
945 | (GNUNET_OK != GNUNET_BIO_read_int32 ( | ||
946 | rh, | ||
947 | "anonymity level", | ||
948 | (int32_t *) &ret->bo.anonymity_level)) || | ||
949 | (GNUNET_OK != GNUNET_BIO_read_int32 ( | ||
950 | rh, | ||
951 | "content priority", | ||
952 | (int32_t *) &ret->bo.content_priority)) || | ||
953 | (GNUNET_OK != GNUNET_BIO_read_int32 ( | ||
954 | rh, | ||
955 | "replication level", | ||
956 | (int32_t *) &ret->bo.replication_level))) | ||
957 | { | ||
958 | GNUNET_break (0); | ||
959 | goto cleanup; | ||
960 | } | ||
961 | switch (b) | ||
962 | { | ||
963 | case 0: /* file-insert */ | ||
964 | if (GNUNET_OK != GNUNET_BIO_read_int64 ( | ||
965 | rh, | ||
966 | "file size", | ||
967 | (int64_t *) &ret->data.file.file_size)) | ||
968 | { | ||
969 | GNUNET_break (0); | ||
970 | goto cleanup; | ||
971 | } | ||
972 | ret->is_directory = GNUNET_NO; | ||
973 | ret->data.file.do_index = GNUNET_NO; | ||
974 | ret->data.file.have_hash = GNUNET_NO; | ||
975 | ret->data.file.index_start_confirmed = GNUNET_NO; | ||
976 | if (GNUNET_NO == ret->is_published) | ||
977 | { | ||
978 | if (NULL == ret->filename) | ||
979 | { | ||
980 | ret->data.file.reader = &GNUNET_FS_data_reader_copy_; | ||
981 | ret->data.file.reader_cls = | ||
982 | GNUNET_malloc_large (ret->data.file.file_size); | ||
983 | if (ret->data.file.reader_cls == NULL) | ||
984 | goto cleanup; | ||
985 | if (GNUNET_OK != GNUNET_BIO_read (rh, | ||
986 | "file-data", | ||
987 | ret->data.file.reader_cls, | ||
988 | ret->data.file.file_size)) | ||
989 | { | ||
990 | GNUNET_break (0); | ||
991 | goto cleanup; | ||
992 | } | ||
993 | } | ||
994 | else | ||
995 | { | ||
996 | ret->data.file.reader = &GNUNET_FS_data_reader_file_; | ||
997 | ret->data.file.reader_cls = | ||
998 | GNUNET_FS_make_file_reader_context_ (ret->filename); | ||
999 | } | ||
1000 | } | ||
1001 | break; | ||
1002 | |||
1003 | case 1: /* file-index, no hash */ | ||
1004 | if (NULL == ret->filename) | ||
1005 | { | ||
1006 | GNUNET_break (0); | ||
1007 | goto cleanup; | ||
1008 | } | ||
1009 | if (GNUNET_OK != GNUNET_BIO_read_int64 ( | ||
1010 | rh, | ||
1011 | "file size", | ||
1012 | (int64_t *) &ret->data.file.file_size)) | ||
1013 | { | ||
1014 | GNUNET_break (0); | ||
1015 | goto cleanup; | ||
1016 | } | ||
1017 | ret->is_directory = GNUNET_NO; | ||
1018 | ret->data.file.do_index = GNUNET_YES; | ||
1019 | ret->data.file.have_hash = GNUNET_NO; | ||
1020 | ret->data.file.index_start_confirmed = GNUNET_NO; | ||
1021 | ret->data.file.reader = &GNUNET_FS_data_reader_file_; | ||
1022 | ret->data.file.reader_cls = | ||
1023 | GNUNET_FS_make_file_reader_context_ (ret->filename); | ||
1024 | break; | ||
1025 | |||
1026 | case 2: /* file-index-with-hash */ | ||
1027 | if (NULL == ret->filename) | ||
1028 | { | ||
1029 | GNUNET_break (0); | ||
1030 | goto cleanup; | ||
1031 | } | ||
1032 | if ((GNUNET_OK != GNUNET_BIO_read_int64 ( | ||
1033 | rh, | ||
1034 | "file size", | ||
1035 | (int64_t *) &ret->data.file.file_size)) || | ||
1036 | (GNUNET_OK != GNUNET_BIO_read (rh, | ||
1037 | "fileid", | ||
1038 | &ret->data.file.file_id, | ||
1039 | sizeof(struct GNUNET_HashCode)))) | ||
1040 | { | ||
1041 | GNUNET_break (0); | ||
1042 | goto cleanup; | ||
1043 | } | ||
1044 | ret->is_directory = GNUNET_NO; | ||
1045 | ret->data.file.do_index = GNUNET_YES; | ||
1046 | ret->data.file.have_hash = GNUNET_YES; | ||
1047 | ret->data.file.index_start_confirmed = GNUNET_NO; | ||
1048 | ret->data.file.reader = &GNUNET_FS_data_reader_file_; | ||
1049 | ret->data.file.reader_cls = | ||
1050 | GNUNET_FS_make_file_reader_context_ (ret->filename); | ||
1051 | break; | ||
1052 | |||
1053 | case 3: /* file-index-with-hash-confirmed */ | ||
1054 | if (NULL == ret->filename) | ||
1055 | { | ||
1056 | GNUNET_break (0); | ||
1057 | goto cleanup; | ||
1058 | } | ||
1059 | if ((GNUNET_OK != GNUNET_BIO_read_int64 ( | ||
1060 | rh, | ||
1061 | "file size", | ||
1062 | (int64_t *) &ret->data.file.file_size)) || | ||
1063 | (GNUNET_OK != GNUNET_BIO_read (rh, | ||
1064 | "fileid", | ||
1065 | &ret->data.file.file_id, | ||
1066 | sizeof(struct GNUNET_HashCode)))) | ||
1067 | { | ||
1068 | GNUNET_break (0); | ||
1069 | goto cleanup; | ||
1070 | } | ||
1071 | ret->is_directory = GNUNET_NO; | ||
1072 | ret->data.file.do_index = GNUNET_YES; | ||
1073 | ret->data.file.have_hash = GNUNET_YES; | ||
1074 | ret->data.file.index_start_confirmed = GNUNET_YES; | ||
1075 | ret->data.file.reader = &GNUNET_FS_data_reader_file_; | ||
1076 | ret->data.file.reader_cls = | ||
1077 | GNUNET_FS_make_file_reader_context_ (ret->filename); | ||
1078 | break; | ||
1079 | |||
1080 | case 4: /* directory */ | ||
1081 | ret->is_directory = GNUNET_YES; | ||
1082 | if ((GNUNET_OK != GNUNET_BIO_read_int32 (rh, "dsize", | ||
1083 | (int32_t *) &dsize)) || | ||
1084 | (GNUNET_OK != | ||
1085 | GNUNET_BIO_read_int64 ( | ||
1086 | rh, | ||
1087 | "contents completed", | ||
1088 | (int64_t *) &ret->data.dir.contents_completed)) || | ||
1089 | (GNUNET_OK != | ||
1090 | GNUNET_BIO_read_int64 ( | ||
1091 | rh, | ||
1092 | "contents size", | ||
1093 | (int64_t *) &ret->data.dir.contents_size)) || | ||
1094 | (NULL == (ret->data.dir.dir_data = GNUNET_malloc_large (dsize))) || | ||
1095 | (GNUNET_OK != | ||
1096 | GNUNET_BIO_read (rh, "dir-data", ret->data.dir.dir_data, dsize)) || | ||
1097 | (GNUNET_OK != | ||
1098 | GNUNET_BIO_read_string (rh, "ent-filename", &filename, 16 * 1024))) | ||
1099 | { | ||
1100 | GNUNET_break (0); | ||
1101 | goto cleanup; | ||
1102 | } | ||
1103 | ret->data.dir.dir_size = (uint32_t) dsize; | ||
1104 | if (NULL != filename) | ||
1105 | { | ||
1106 | ret->data.dir.entries = deserialize_file_information (h, filename); | ||
1107 | GNUNET_free (filename); | ||
1108 | filename = NULL; | ||
1109 | nxt = ret->data.dir.entries; | ||
1110 | while (NULL != nxt) | ||
1111 | { | ||
1112 | nxt->dir = ret; | ||
1113 | nxt = nxt->next; | ||
1114 | } | ||
1115 | } | ||
1116 | break; | ||
1117 | |||
1118 | default: | ||
1119 | GNUNET_break (0); | ||
1120 | goto cleanup; | ||
1121 | } | ||
1122 | ret->serialization = GNUNET_strdup (fn); | ||
1123 | if (GNUNET_OK != | ||
1124 | GNUNET_BIO_read_string (rh, "nxt-filename", &filename, 16 * 1024)) | ||
1125 | { | ||
1126 | GNUNET_break (0); | ||
1127 | goto cleanup; | ||
1128 | } | ||
1129 | if (NULL != filename) | ||
1130 | { | ||
1131 | ret->next = deserialize_file_information (h, filename); | ||
1132 | GNUNET_free (filename); | ||
1133 | filename = NULL; | ||
1134 | } | ||
1135 | GNUNET_free (ksks); | ||
1136 | GNUNET_free (skss); | ||
1137 | GNUNET_free (chks); | ||
1138 | return ret; | ||
1139 | cleanup: | ||
1140 | GNUNET_free (ksks); | ||
1141 | GNUNET_free (chks); | ||
1142 | GNUNET_free (skss); | ||
1143 | GNUNET_free (filename); | ||
1144 | GNUNET_FS_file_information_destroy (ret, NULL, NULL); | ||
1145 | return NULL; | ||
1146 | } | ||
1147 | |||
1148 | |||
1149 | /** | ||
1150 | * Using the given serialization filename, try to deserialize | ||
1151 | * the file-information tree associated with it. | ||
1152 | * | ||
1153 | * @param h master context | ||
1154 | * @param filename name of the file (without directory) with | ||
1155 | * the information | ||
1156 | * @return NULL on error | ||
1157 | */ | ||
1158 | static struct GNUNET_FS_FileInformation * | ||
1159 | deserialize_file_information (struct GNUNET_FS_Handle *h, const char *filename) | ||
1160 | { | ||
1161 | struct GNUNET_FS_FileInformation *ret; | ||
1162 | struct GNUNET_BIO_ReadHandle *rh; | ||
1163 | char *emsg; | ||
1164 | char *fn; | ||
1165 | |||
1166 | rh = get_read_handle (h, GNUNET_FS_SYNC_PATH_FILE_INFO, filename); | ||
1167 | if (NULL == rh) | ||
1168 | return NULL; | ||
1169 | ret = deserialize_fi_node (h, filename, rh); | ||
1170 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
1171 | { | ||
1172 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1173 | _ ("Failed to resume publishing information `%s': %s\n"), | ||
1174 | filename, | ||
1175 | emsg); | ||
1176 | GNUNET_free (emsg); | ||
1177 | } | ||
1178 | if (NULL == ret) | ||
1179 | { | ||
1180 | fn = | ||
1181 | get_serialization_file_name (h, GNUNET_FS_SYNC_PATH_FILE_INFO, filename); | ||
1182 | if (NULL != fn) | ||
1183 | { | ||
1184 | if (0 != unlink (fn)) | ||
1185 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); | ||
1186 | GNUNET_free (fn); | ||
1187 | } | ||
1188 | } | ||
1189 | return ret; | ||
1190 | } | ||
1191 | |||
1192 | |||
1193 | /** | ||
1194 | * Given a serialization name (full absolute path), return the | ||
1195 | * basename of the file (without the path), which must only | ||
1196 | * consist of the 6 random characters. | ||
1197 | * | ||
1198 | * @param fullname name to extract the basename from | ||
1199 | * @return copy of the basename, NULL on error | ||
1200 | */ | ||
1201 | static char * | ||
1202 | get_serialization_short_name (const char *fullname) | ||
1203 | { | ||
1204 | const char *end; | ||
1205 | const char *nxt; | ||
1206 | |||
1207 | end = NULL; | ||
1208 | nxt = fullname; | ||
1209 | /* FIXME: we could do this faster since we know | ||
1210 | * the length of 'end'... */ | ||
1211 | while ('\0' != *nxt) | ||
1212 | { | ||
1213 | if (DIR_SEPARATOR == *nxt) | ||
1214 | end = nxt + 1; | ||
1215 | nxt++; | ||
1216 | } | ||
1217 | if ((NULL == end) || (0 == strlen (end))) | ||
1218 | { | ||
1219 | GNUNET_break (0); | ||
1220 | return NULL; | ||
1221 | } | ||
1222 | GNUNET_break (6 == strlen (end)); | ||
1223 | return GNUNET_strdup (end); | ||
1224 | } | ||
1225 | |||
1226 | |||
1227 | /** | ||
1228 | * Create a new random name for serialization. Also checks if persistence | ||
1229 | * is enabled and returns NULL if not. | ||
1230 | * | ||
1231 | * @param h master context | ||
1232 | * @param ext component of the path | ||
1233 | * @return NULL on error | ||
1234 | */ | ||
1235 | static char * | ||
1236 | make_serialization_file_name (struct GNUNET_FS_Handle *h, const char *ext) | ||
1237 | { | ||
1238 | char *fn; | ||
1239 | char *dn; | ||
1240 | char *ret; | ||
1241 | |||
1242 | if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) | ||
1243 | return NULL; /* persistence not requested */ | ||
1244 | dn = get_serialization_file_name (h, ext, ""); | ||
1245 | if (NULL == dn) | ||
1246 | return NULL; | ||
1247 | if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn)) | ||
1248 | { | ||
1249 | GNUNET_free (dn); | ||
1250 | return NULL; | ||
1251 | } | ||
1252 | fn = GNUNET_DISK_mktemp (dn); | ||
1253 | GNUNET_free (dn); | ||
1254 | if (NULL == fn) | ||
1255 | return NULL; /* epic fail */ | ||
1256 | ret = get_serialization_short_name (fn); | ||
1257 | GNUNET_free (fn); | ||
1258 | return ret; | ||
1259 | } | ||
1260 | |||
1261 | |||
1262 | /** | ||
1263 | * Create a new random name for serialization. Also checks if persistence | ||
1264 | * is enabled and returns NULL if not. | ||
1265 | * | ||
1266 | * @param h master context | ||
1267 | * @param ext component of the path | ||
1268 | * @param uni name of parent | ||
1269 | * @return NULL on error | ||
1270 | */ | ||
1271 | static char * | ||
1272 | make_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h, | ||
1273 | const char *ext, | ||
1274 | const char *uni) | ||
1275 | { | ||
1276 | char *fn; | ||
1277 | char *dn; | ||
1278 | char *ret; | ||
1279 | |||
1280 | if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) | ||
1281 | return NULL; /* persistence not requested */ | ||
1282 | dn = get_serialization_file_name_in_dir (h, ext, uni, ""); | ||
1283 | if (NULL == dn) | ||
1284 | return NULL; | ||
1285 | if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn)) | ||
1286 | { | ||
1287 | GNUNET_free (dn); | ||
1288 | return NULL; | ||
1289 | } | ||
1290 | fn = GNUNET_DISK_mktemp (dn); | ||
1291 | GNUNET_free (dn); | ||
1292 | if (NULL == fn) | ||
1293 | return NULL; /* epic fail */ | ||
1294 | ret = get_serialization_short_name (fn); | ||
1295 | GNUNET_free (fn); | ||
1296 | return ret; | ||
1297 | } | ||
1298 | |||
1299 | |||
1300 | /** | ||
1301 | * Copy all of the data from the reader to the write handle. | ||
1302 | * | ||
1303 | * @param wh write handle | ||
1304 | * @param fi file with reader | ||
1305 | * @return #GNUNET_OK on success | ||
1306 | */ | ||
1307 | static int | ||
1308 | copy_from_reader (struct GNUNET_BIO_WriteHandle *wh, | ||
1309 | struct GNUNET_FS_FileInformation *fi) | ||
1310 | { | ||
1311 | char buf[32 * 1024]; | ||
1312 | uint64_t off; | ||
1313 | size_t ret; | ||
1314 | size_t left; | ||
1315 | char *emsg; | ||
1316 | |||
1317 | emsg = NULL; | ||
1318 | off = 0; | ||
1319 | while (off < fi->data.file.file_size) | ||
1320 | { | ||
1321 | left = GNUNET_MIN (sizeof(buf), fi->data.file.file_size - off); | ||
1322 | ret = | ||
1323 | fi->data.file.reader (fi->data.file.reader_cls, off, left, buf, &emsg); | ||
1324 | if (0 == ret) | ||
1325 | { | ||
1326 | GNUNET_free (emsg); | ||
1327 | return GNUNET_SYSERR; | ||
1328 | } | ||
1329 | if (GNUNET_OK != GNUNET_BIO_write (wh, "copied from reader", buf, ret)) | ||
1330 | return GNUNET_SYSERR; | ||
1331 | off += ret; | ||
1332 | } | ||
1333 | return GNUNET_OK; | ||
1334 | } | ||
1335 | |||
1336 | |||
1337 | /** | ||
1338 | * Create a temporary file on disk to store the current | ||
1339 | * state of @a fi in. | ||
1340 | * | ||
1341 | * @param fi file information to sync with disk | ||
1342 | */ | ||
1343 | void | ||
1344 | GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *fi) | ||
1345 | { | ||
1346 | char *fn; | ||
1347 | struct GNUNET_BIO_WriteHandle *wh; | ||
1348 | char b; | ||
1349 | char *ksks; | ||
1350 | char *chks; | ||
1351 | char *skss; | ||
1352 | |||
1353 | if (NULL == fi->serialization) | ||
1354 | fi->serialization = | ||
1355 | make_serialization_file_name (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO); | ||
1356 | if (NULL == fi->serialization) | ||
1357 | return; | ||
1358 | wh = | ||
1359 | get_write_handle (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO, fi->serialization); | ||
1360 | if (NULL == wh) | ||
1361 | { | ||
1362 | GNUNET_free (fi->serialization); | ||
1363 | fi->serialization = NULL; | ||
1364 | return; | ||
1365 | } | ||
1366 | if (GNUNET_YES == fi->is_directory) | ||
1367 | b = 4; | ||
1368 | else if (GNUNET_YES == fi->data.file.index_start_confirmed) | ||
1369 | b = 3; | ||
1370 | else if (GNUNET_YES == fi->data.file.have_hash) | ||
1371 | b = 2; | ||
1372 | else if (GNUNET_YES == fi->data.file.do_index) | ||
1373 | b = 1; | ||
1374 | else | ||
1375 | b = 0; | ||
1376 | if (NULL != fi->keywords) | ||
1377 | ksks = GNUNET_FS_uri_to_string (fi->keywords); | ||
1378 | else | ||
1379 | ksks = NULL; | ||
1380 | if (NULL != fi->chk_uri) | ||
1381 | chks = GNUNET_FS_uri_to_string (fi->chk_uri); | ||
1382 | else | ||
1383 | chks = NULL; | ||
1384 | if (NULL != fi->sks_uri) | ||
1385 | skss = GNUNET_FS_uri_to_string (fi->sks_uri); | ||
1386 | else | ||
1387 | skss = NULL; | ||
1388 | struct GNUNET_BIO_WriteSpec ws1[] = { | ||
1389 | GNUNET_BIO_write_spec_object ("b", &b, sizeof (b)), | ||
1390 | GNUNET_BIO_write_spec_meta_data ("meta", fi->meta), | ||
1391 | GNUNET_BIO_write_spec_string ("ksks", ksks), | ||
1392 | GNUNET_BIO_write_spec_string ("chks", chks), | ||
1393 | GNUNET_BIO_write_spec_string ("skss", skss), | ||
1394 | GNUNET_BIO_write_spec_end (), | ||
1395 | }; | ||
1396 | struct GNUNET_BIO_WriteSpec ws2[] = { | ||
1397 | GNUNET_BIO_write_spec_string ("emsg", fi->emsg), | ||
1398 | GNUNET_BIO_write_spec_string ("filename", fi->filename), | ||
1399 | GNUNET_BIO_write_spec_int64 ( | ||
1400 | "expiration time", | ||
1401 | (int64_t *) &fi->bo.expiration_time.abs_value_us), | ||
1402 | GNUNET_BIO_write_spec_int32 ( | ||
1403 | "anonymity level", | ||
1404 | (int32_t *) &fi->bo.anonymity_level), | ||
1405 | GNUNET_BIO_write_spec_int32 ( | ||
1406 | "content priority", | ||
1407 | (int32_t *) &fi->bo.content_priority), | ||
1408 | GNUNET_BIO_write_spec_int32 ( | ||
1409 | "replication level", | ||
1410 | (int32_t *) &fi->bo.replication_level), | ||
1411 | GNUNET_BIO_write_spec_end (), | ||
1412 | }; | ||
1413 | if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws1)) || | ||
1414 | (GNUNET_OK != write_start_time (wh, fi->start_time)) || | ||
1415 | (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws2))) | ||
1416 | { | ||
1417 | GNUNET_break (0); | ||
1418 | goto cleanup; | ||
1419 | } | ||
1420 | GNUNET_free (chks); | ||
1421 | chks = NULL; | ||
1422 | GNUNET_free (ksks); | ||
1423 | ksks = NULL; | ||
1424 | GNUNET_free (skss); | ||
1425 | skss = NULL; | ||
1426 | |||
1427 | switch (b) | ||
1428 | { | ||
1429 | case 0: /* file-insert */ | ||
1430 | if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, "file size", | ||
1431 | fi->data.file.file_size)) | ||
1432 | { | ||
1433 | GNUNET_break (0); | ||
1434 | goto cleanup; | ||
1435 | } | ||
1436 | if ((GNUNET_NO == fi->is_published) && (NULL == fi->filename)) | ||
1437 | if (GNUNET_OK != copy_from_reader (wh, fi)) | ||
1438 | { | ||
1439 | GNUNET_break (0); | ||
1440 | goto cleanup; | ||
1441 | } | ||
1442 | break; | ||
1443 | |||
1444 | case 1: /* file-index, no hash */ | ||
1445 | if (NULL == fi->filename) | ||
1446 | { | ||
1447 | GNUNET_break (0); | ||
1448 | goto cleanup; | ||
1449 | } | ||
1450 | if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, "file size", | ||
1451 | fi->data.file.file_size)) | ||
1452 | { | ||
1453 | GNUNET_break (0); | ||
1454 | goto cleanup; | ||
1455 | } | ||
1456 | break; | ||
1457 | |||
1458 | case 2: /* file-index-with-hash */ | ||
1459 | case 3: /* file-index-with-hash-confirmed */ | ||
1460 | if (NULL == fi->filename) | ||
1461 | { | ||
1462 | GNUNET_break (0); | ||
1463 | goto cleanup; | ||
1464 | } | ||
1465 | if ((GNUNET_OK != GNUNET_BIO_write_int64 (wh, "file size", | ||
1466 | fi->data.file.file_size)) || | ||
1467 | (GNUNET_OK != GNUNET_BIO_write (wh, | ||
1468 | "file id", | ||
1469 | &fi->data.file.file_id, | ||
1470 | sizeof(struct GNUNET_HashCode)))) | ||
1471 | { | ||
1472 | GNUNET_break (0); | ||
1473 | goto cleanup; | ||
1474 | } | ||
1475 | break; | ||
1476 | |||
1477 | case 4: /* directory */ | ||
1478 | if ((NULL != fi->data.dir.entries) && | ||
1479 | (NULL == fi->data.dir.entries->serialization)) | ||
1480 | GNUNET_FS_file_information_sync_ (fi->data.dir.entries); | ||
1481 | struct GNUNET_BIO_WriteSpec ws[] = { | ||
1482 | GNUNET_BIO_write_spec_int32 ("dir size", | ||
1483 | (int32_t *) &fi->data.dir.dir_size), | ||
1484 | GNUNET_BIO_write_spec_int64 ( | ||
1485 | "contents completed", | ||
1486 | (int64_t *) &fi->data.dir.contents_completed), | ||
1487 | GNUNET_BIO_write_spec_int64 ("contents size", | ||
1488 | (int64_t *) &fi->data.dir.contents_size), | ||
1489 | GNUNET_BIO_write_spec_object ("dir data", | ||
1490 | fi->data.dir.dir_data, | ||
1491 | (uint32_t) fi->data.dir.dir_size), | ||
1492 | GNUNET_BIO_write_spec_string ("dir entries", | ||
1493 | (fi->data.dir.entries == NULL) | ||
1494 | ? NULL | ||
1495 | : fi->data.dir.entries->serialization), | ||
1496 | GNUNET_BIO_write_spec_end (), | ||
1497 | }; | ||
1498 | if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws))) | ||
1499 | { | ||
1500 | GNUNET_break (0); | ||
1501 | goto cleanup; | ||
1502 | } | ||
1503 | break; | ||
1504 | |||
1505 | default: | ||
1506 | GNUNET_assert (0); | ||
1507 | goto cleanup; | ||
1508 | } | ||
1509 | if ((NULL != fi->next) && (NULL == fi->next->serialization)) | ||
1510 | GNUNET_FS_file_information_sync_ (fi->next); | ||
1511 | if (GNUNET_OK != GNUNET_BIO_write_string (wh, | ||
1512 | "serialization", | ||
1513 | (fi->next != NULL) | ||
1514 | ? fi->next->serialization | ||
1515 | : NULL)) | ||
1516 | { | ||
1517 | GNUNET_break (0); | ||
1518 | goto cleanup; | ||
1519 | } | ||
1520 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
1521 | { | ||
1522 | wh = NULL; | ||
1523 | GNUNET_break (0); | ||
1524 | goto cleanup; | ||
1525 | } | ||
1526 | return; /* done! */ | ||
1527 | cleanup: | ||
1528 | if (NULL != wh) | ||
1529 | (void) GNUNET_BIO_write_close (wh, NULL); | ||
1530 | GNUNET_free (chks); | ||
1531 | GNUNET_free (ksks); | ||
1532 | GNUNET_free (skss); | ||
1533 | fn = get_serialization_file_name (fi->h, | ||
1534 | GNUNET_FS_SYNC_PATH_FILE_INFO, | ||
1535 | fi->serialization); | ||
1536 | if (NULL != fn) | ||
1537 | { | ||
1538 | if (0 != unlink (fn)) | ||
1539 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); | ||
1540 | GNUNET_free (fn); | ||
1541 | } | ||
1542 | GNUNET_free (fi->serialization); | ||
1543 | fi->serialization = NULL; | ||
1544 | } | ||
1545 | |||
1546 | |||
1547 | /** | ||
1548 | * Find the entry in the file information struct where the | ||
1549 | * serialization filename matches the given name. | ||
1550 | * | ||
1551 | * @param pos file information to search | ||
1552 | * @param srch filename to search for | ||
1553 | * @return NULL if srch was not found in this subtree | ||
1554 | */ | ||
1555 | static struct GNUNET_FS_FileInformation * | ||
1556 | find_file_position (struct GNUNET_FS_FileInformation *pos, const char *srch) | ||
1557 | { | ||
1558 | struct GNUNET_FS_FileInformation *r; | ||
1559 | |||
1560 | while (NULL != pos) | ||
1561 | { | ||
1562 | if (0 == strcmp (srch, pos->serialization)) | ||
1563 | return pos; | ||
1564 | if ((GNUNET_YES == pos->is_directory) && | ||
1565 | (NULL != (r = find_file_position (pos->data.dir.entries, srch)))) | ||
1566 | return r; | ||
1567 | pos = pos->next; | ||
1568 | } | ||
1569 | return NULL; | ||
1570 | } | ||
1571 | |||
1572 | |||
1573 | /** | ||
1574 | * Signal the FS's progress function that we are resuming | ||
1575 | * an upload. | ||
1576 | * | ||
1577 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`, for the parent (!)) | ||
1578 | * @param fi the entry in the publish-structure | ||
1579 | * @param length length of the file or directory | ||
1580 | * @param meta metadata for the file or directory (can be modified) | ||
1581 | * @param uri pointer to the keywords that will be used for this entry (can be modified) | ||
1582 | * @param bo block options (can be modified) | ||
1583 | * @param do_index should we index? | ||
1584 | * @param client_info pointer to client context set upon creation (can be modified) | ||
1585 | * @return #GNUNET_OK to continue (always) | ||
1586 | */ | ||
1587 | static int | ||
1588 | fip_signal_resume (void *cls, | ||
1589 | struct GNUNET_FS_FileInformation *fi, | ||
1590 | uint64_t length, | ||
1591 | struct GNUNET_CONTAINER_MetaData *meta, | ||
1592 | struct GNUNET_FS_Uri **uri, | ||
1593 | struct GNUNET_FS_BlockOptions *bo, | ||
1594 | int *do_index, | ||
1595 | void **client_info) | ||
1596 | { | ||
1597 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1598 | struct GNUNET_FS_ProgressInfo pi; | ||
1599 | |||
1600 | if (GNUNET_YES == pc->skip_next_fi_callback) | ||
1601 | { | ||
1602 | pc->skip_next_fi_callback = GNUNET_NO; | ||
1603 | return GNUNET_OK; | ||
1604 | } | ||
1605 | pi.status = GNUNET_FS_STATUS_PUBLISH_RESUME; | ||
1606 | pi.value.publish.specifics.resume.message = fi->emsg; | ||
1607 | pi.value.publish.specifics.resume.chk_uri = fi->chk_uri; | ||
1608 | *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0); | ||
1609 | if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) | ||
1610 | { | ||
1611 | /* process entries in directory */ | ||
1612 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1613 | GNUNET_FS_file_information_inspect (fi, &fip_signal_resume, pc); | ||
1614 | } | ||
1615 | return GNUNET_OK; | ||
1616 | } | ||
1617 | |||
1618 | |||
1619 | /** | ||
1620 | * Function called with a filename of serialized publishing operation | ||
1621 | * to deserialize. | ||
1622 | * | ||
1623 | * @param cls the `struct GNUNET_FS_Handle *` | ||
1624 | * @param filename complete filename (absolute path) | ||
1625 | * @return #GNUNET_OK (continue to iterate) | ||
1626 | */ | ||
1627 | static int | ||
1628 | deserialize_publish_file (void *cls, const char *filename) | ||
1629 | { | ||
1630 | struct GNUNET_FS_Handle *h = cls; | ||
1631 | struct GNUNET_BIO_ReadHandle *rh; | ||
1632 | struct GNUNET_FS_PublishContext *pc; | ||
1633 | int32_t options; | ||
1634 | int32_t all_done; | ||
1635 | int32_t have_ns; | ||
1636 | char *fi_root; | ||
1637 | struct GNUNET_CRYPTO_EcdsaPrivateKey ns; | ||
1638 | char *fi_pos; | ||
1639 | char *emsg; | ||
1640 | |||
1641 | pc = GNUNET_new (struct GNUNET_FS_PublishContext); | ||
1642 | pc->h = h; | ||
1643 | pc->serialization = get_serialization_short_name (filename); | ||
1644 | fi_root = NULL; | ||
1645 | fi_pos = NULL; | ||
1646 | rh = GNUNET_BIO_read_open_file (filename); | ||
1647 | if (NULL == rh) | ||
1648 | { | ||
1649 | GNUNET_break (0); | ||
1650 | goto cleanup; | ||
1651 | } | ||
1652 | struct GNUNET_BIO_ReadSpec rs[] = { | ||
1653 | GNUNET_BIO_read_spec_string ("publish-nid", &pc->nid, 1024), | ||
1654 | GNUNET_BIO_read_spec_string ("publish-nuid", &pc->nuid, 1024), | ||
1655 | GNUNET_BIO_read_spec_int32 ("options", &options), | ||
1656 | GNUNET_BIO_read_spec_int32 ("all done", &all_done), | ||
1657 | GNUNET_BIO_read_spec_int32 ("have ns", &have_ns), | ||
1658 | GNUNET_BIO_read_spec_string ("publish-firoot", &fi_root, 128), | ||
1659 | GNUNET_BIO_read_spec_string ("publish-fipos", &fi_pos, 128), | ||
1660 | GNUNET_BIO_read_spec_end (), | ||
1661 | }; | ||
1662 | if ((GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs)) || | ||
1663 | ((GNUNET_YES == have_ns) && | ||
1664 | (GNUNET_OK != GNUNET_BIO_read (rh, "publish-ns", &ns, sizeof(ns))))) | ||
1665 | { | ||
1666 | GNUNET_break (0); | ||
1667 | goto cleanup; | ||
1668 | } | ||
1669 | pc->options = options; | ||
1670 | pc->all_done = all_done; | ||
1671 | if (NULL == fi_root) | ||
1672 | { | ||
1673 | GNUNET_break (0); | ||
1674 | goto cleanup; | ||
1675 | } | ||
1676 | pc->fi = deserialize_file_information (h, fi_root); | ||
1677 | if (NULL == pc->fi) | ||
1678 | { | ||
1679 | GNUNET_break (0); | ||
1680 | goto cleanup; | ||
1681 | } | ||
1682 | if (GNUNET_YES == have_ns) | ||
1683 | { | ||
1684 | pc->ns = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey); | ||
1685 | *pc->ns = ns; | ||
1686 | } | ||
1687 | if ((0 == (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) && | ||
1688 | (GNUNET_YES != pc->all_done)) | ||
1689 | { | ||
1690 | pc->dsh = GNUNET_DATASTORE_connect (h->cfg); | ||
1691 | if (NULL == pc->dsh) | ||
1692 | goto cleanup; | ||
1693 | } | ||
1694 | if (NULL != fi_pos) | ||
1695 | { | ||
1696 | pc->fi_pos = find_file_position (pc->fi, fi_pos); | ||
1697 | GNUNET_free (fi_pos); | ||
1698 | fi_pos = NULL; | ||
1699 | if (NULL == pc->fi_pos) | ||
1700 | { | ||
1701 | /* failed to find position for resuming, outch! Will start from root! */ | ||
1702 | GNUNET_break (0); | ||
1703 | if (GNUNET_YES != pc->all_done) | ||
1704 | pc->fi_pos = pc->fi; | ||
1705 | } | ||
1706 | } | ||
1707 | GNUNET_free (fi_root); | ||
1708 | fi_root = NULL; | ||
1709 | /* generate RESUME event(s) */ | ||
1710 | GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_resume, pc); | ||
1711 | |||
1712 | /* re-start publishing (if needed)... */ | ||
1713 | if (GNUNET_YES != pc->all_done) | ||
1714 | { | ||
1715 | GNUNET_assert (NULL == pc->upload_task); | ||
1716 | pc->upload_task = | ||
1717 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
1718 | &GNUNET_FS_publish_main_, | ||
1719 | pc); | ||
1720 | } | ||
1721 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
1722 | { | ||
1723 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1724 | _ ("Failure while resuming publishing operation `%s': %s\n"), | ||
1725 | filename, | ||
1726 | emsg); | ||
1727 | GNUNET_free (emsg); | ||
1728 | } | ||
1729 | pc->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, pc); | ||
1730 | return GNUNET_OK; | ||
1731 | cleanup: | ||
1732 | GNUNET_free (pc->nid); | ||
1733 | GNUNET_free (pc->nuid); | ||
1734 | GNUNET_free (fi_root); | ||
1735 | GNUNET_free (fi_pos); | ||
1736 | if ((NULL != rh) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))) | ||
1737 | { | ||
1738 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1739 | _ ("Failed to resume publishing operation `%s': %s\n"), | ||
1740 | filename, | ||
1741 | emsg); | ||
1742 | GNUNET_free (emsg); | ||
1743 | } | ||
1744 | if (NULL != pc->fi) | ||
1745 | GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL); | ||
1746 | if (0 != unlink (filename)) | ||
1747 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); | ||
1748 | GNUNET_free (pc->serialization); | ||
1749 | GNUNET_free (pc); | ||
1750 | return GNUNET_OK; | ||
1751 | } | ||
1752 | |||
1753 | |||
1754 | /** | ||
1755 | * Synchronize this publishing struct with its mirror | ||
1756 | * on disk. Note that all internal FS-operations that change | ||
1757 | * publishing structs should already call "sync" internally, | ||
1758 | * so this function is likely not useful for clients. | ||
1759 | * | ||
1760 | * @param pc the struct to sync | ||
1761 | */ | ||
1762 | void | ||
1763 | GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc) | ||
1764 | { | ||
1765 | struct GNUNET_BIO_WriteHandle *wh; | ||
1766 | int32_t have_ns; | ||
1767 | |||
1768 | if (NULL == pc->serialization) | ||
1769 | pc->serialization = | ||
1770 | make_serialization_file_name (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH); | ||
1771 | if (NULL == pc->serialization) | ||
1772 | return; | ||
1773 | if (NULL == pc->fi) | ||
1774 | return; | ||
1775 | if (NULL == pc->fi->serialization) | ||
1776 | { | ||
1777 | GNUNET_break (0); | ||
1778 | return; | ||
1779 | } | ||
1780 | wh = get_write_handle (pc->h, | ||
1781 | GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, | ||
1782 | pc->serialization); | ||
1783 | if (NULL == wh) | ||
1784 | { | ||
1785 | GNUNET_break (0); | ||
1786 | goto cleanup; | ||
1787 | } | ||
1788 | have_ns = (NULL != pc->ns) ? GNUNET_YES : GNUNET_NO; | ||
1789 | struct GNUNET_BIO_WriteSpec ws[] = { | ||
1790 | GNUNET_BIO_write_spec_string ("nid", pc->nid), | ||
1791 | GNUNET_BIO_write_spec_string ("nuid", pc->nuid), | ||
1792 | GNUNET_BIO_write_spec_int32 ("options", (int32_t *) &pc->options), | ||
1793 | GNUNET_BIO_write_spec_int32 ("all done", &pc->all_done), | ||
1794 | GNUNET_BIO_write_spec_int32 ("have ns", &have_ns), | ||
1795 | GNUNET_BIO_write_spec_string ("serialization", pc->fi->serialization), | ||
1796 | GNUNET_BIO_write_spec_string ("pos serialization", (NULL == pc->fi_pos) | ||
1797 | ? NULL | ||
1798 | : pc->fi_pos->serialization), | ||
1799 | GNUNET_BIO_read_spec_end () | ||
1800 | }; | ||
1801 | if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws)) || | ||
1802 | ((NULL != pc->ns) && | ||
1803 | (GNUNET_OK != | ||
1804 | GNUNET_BIO_write (wh, | ||
1805 | "ns", | ||
1806 | pc->ns, | ||
1807 | sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey))))) | ||
1808 | { | ||
1809 | GNUNET_break (0); | ||
1810 | goto cleanup; | ||
1811 | } | ||
1812 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
1813 | { | ||
1814 | wh = NULL; | ||
1815 | GNUNET_break (0); | ||
1816 | goto cleanup; | ||
1817 | } | ||
1818 | return; | ||
1819 | cleanup: | ||
1820 | if (NULL != wh) | ||
1821 | (void) GNUNET_BIO_write_close (wh, NULL); | ||
1822 | GNUNET_FS_remove_sync_file_ (pc->h, | ||
1823 | GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, | ||
1824 | pc->serialization); | ||
1825 | GNUNET_free (pc->serialization); | ||
1826 | pc->serialization = NULL; | ||
1827 | } | ||
1828 | |||
1829 | |||
1830 | /** | ||
1831 | * Synchronize this unindex struct with its mirror | ||
1832 | * on disk. Note that all internal FS-operations that change | ||
1833 | * publishing structs should already call "sync" internally, | ||
1834 | * so this function is likely not useful for clients. | ||
1835 | * | ||
1836 | * @param uc the struct to sync | ||
1837 | */ | ||
1838 | void | ||
1839 | GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc) | ||
1840 | { | ||
1841 | struct GNUNET_BIO_WriteHandle *wh; | ||
1842 | char *uris; | ||
1843 | |||
1844 | if (NULL == uc->serialization) | ||
1845 | uc->serialization = | ||
1846 | make_serialization_file_name (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX); | ||
1847 | if (NULL == uc->serialization) | ||
1848 | return; | ||
1849 | wh = get_write_handle (uc->h, | ||
1850 | GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, | ||
1851 | uc->serialization); | ||
1852 | if (NULL == wh) | ||
1853 | { | ||
1854 | GNUNET_break (0); | ||
1855 | goto cleanup; | ||
1856 | } | ||
1857 | if (NULL != uc->ksk_uri) | ||
1858 | uris = GNUNET_FS_uri_to_string (uc->ksk_uri); | ||
1859 | else | ||
1860 | uris = NULL; | ||
1861 | struct GNUNET_BIO_WriteSpec ws1[] = { | ||
1862 | GNUNET_BIO_write_spec_string ("filename", uc->filename), | ||
1863 | GNUNET_BIO_write_spec_int64 ("file size", (int64_t *) &uc->file_size), | ||
1864 | GNUNET_BIO_write_spec_end (), | ||
1865 | }; | ||
1866 | struct GNUNET_BIO_WriteSpec ws2[] = { | ||
1867 | GNUNET_BIO_write_spec_int32 ("state", (int32_t *) &uc->state), | ||
1868 | GNUNET_BIO_write_spec_object ("hashkey", &uc->chk, | ||
1869 | sizeof (struct ContentHashKey)), | ||
1870 | GNUNET_BIO_write_spec_string ("uris", uris), | ||
1871 | GNUNET_BIO_write_spec_int32 ("ksk offset", (int32_t *) &uc->ksk_offset), | ||
1872 | GNUNET_BIO_write_spec_end (), | ||
1873 | }; | ||
1874 | if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws1)) || | ||
1875 | (GNUNET_OK != write_start_time (wh, uc->start_time)) || | ||
1876 | (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws2)) || | ||
1877 | ((uc->state == UNINDEX_STATE_FS_NOTIFY) && | ||
1878 | (GNUNET_OK != GNUNET_BIO_write (wh, | ||
1879 | "file id", | ||
1880 | &uc->file_id, | ||
1881 | sizeof(struct GNUNET_HashCode)))) || | ||
1882 | ((uc->state == UNINDEX_STATE_ERROR) && | ||
1883 | (GNUNET_OK != GNUNET_BIO_write_string (wh, "emsg", uc->emsg)))) | ||
1884 | { | ||
1885 | GNUNET_break (0); | ||
1886 | goto cleanup; | ||
1887 | } | ||
1888 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
1889 | { | ||
1890 | wh = NULL; | ||
1891 | GNUNET_break (0); | ||
1892 | goto cleanup; | ||
1893 | } | ||
1894 | return; | ||
1895 | cleanup: | ||
1896 | if (NULL != wh) | ||
1897 | (void) GNUNET_BIO_write_close (wh, NULL); | ||
1898 | GNUNET_FS_remove_sync_file_ (uc->h, | ||
1899 | GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, | ||
1900 | uc->serialization); | ||
1901 | GNUNET_free (uc->serialization); | ||
1902 | uc->serialization = NULL; | ||
1903 | } | ||
1904 | |||
1905 | |||
1906 | /** | ||
1907 | * Serialize a download request. | ||
1908 | * | ||
1909 | * @param wh handle for writing the download request to disk | ||
1910 | * @param dr the the request to write to disk | ||
1911 | * @return #GNUNET_YES on success, #GNUNET_NO on error | ||
1912 | */ | ||
1913 | static int | ||
1914 | write_download_request (struct GNUNET_BIO_WriteHandle *wh, | ||
1915 | struct DownloadRequest *dr) | ||
1916 | { | ||
1917 | unsigned int i; | ||
1918 | struct GNUNET_BIO_WriteSpec ws[] = { | ||
1919 | GNUNET_BIO_write_spec_int32 ("state", (int32_t *) &dr->state), | ||
1920 | GNUNET_BIO_write_spec_int64 ("offset", (int64_t *) &dr->offset), | ||
1921 | GNUNET_BIO_write_spec_int32 ("num children", (int32_t *) &dr->num_children), | ||
1922 | GNUNET_BIO_write_spec_int32 ("depth", (int32_t *) &dr->depth), | ||
1923 | GNUNET_BIO_write_spec_end (), | ||
1924 | }; | ||
1925 | |||
1926 | if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws))) | ||
1927 | return GNUNET_NO; | ||
1928 | if ((BRS_CHK_SET == dr->state) && | ||
1929 | (GNUNET_OK != | ||
1930 | GNUNET_BIO_write (wh, "hashkey", | ||
1931 | &dr->chk, sizeof(struct ContentHashKey)))) | ||
1932 | return GNUNET_NO; | ||
1933 | for (i = 0; i < dr->num_children; i++) | ||
1934 | if (GNUNET_NO == write_download_request (wh, dr->children[i])) | ||
1935 | return GNUNET_NO; | ||
1936 | return GNUNET_YES; | ||
1937 | } | ||
1938 | |||
1939 | |||
1940 | /** | ||
1941 | * Read a download request tree. | ||
1942 | * | ||
1943 | * @param rh cadet to read from | ||
1944 | * @return value the download request read from disk, NULL on error | ||
1945 | */ | ||
1946 | static struct DownloadRequest * | ||
1947 | read_download_request (struct GNUNET_BIO_ReadHandle *rh) | ||
1948 | { | ||
1949 | struct DownloadRequest *dr; | ||
1950 | unsigned int i; | ||
1951 | |||
1952 | dr = GNUNET_new (struct DownloadRequest); | ||
1953 | struct GNUNET_BIO_ReadSpec rs[] = { | ||
1954 | GNUNET_BIO_read_spec_int32 ("state", (int32_t *) &dr->state), | ||
1955 | GNUNET_BIO_read_spec_int64 ("offset", (int64_t *) &dr->offset), | ||
1956 | GNUNET_BIO_read_spec_int32 ("num children", (int32_t *) &dr->num_children), | ||
1957 | GNUNET_BIO_read_spec_end (), | ||
1958 | }; | ||
1959 | if ((GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs)) || | ||
1960 | (dr->num_children > CHK_PER_INODE) || | ||
1961 | (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "depth", | ||
1962 | (int32_t *) &dr->depth)) || | ||
1963 | ((0 == dr->depth) && (dr->num_children > 0)) || | ||
1964 | ((dr->depth > 0) && (0 == dr->num_children))) | ||
1965 | { | ||
1966 | GNUNET_break (0); | ||
1967 | dr->num_children = 0; | ||
1968 | goto cleanup; | ||
1969 | } | ||
1970 | if (dr->num_children > 0) | ||
1971 | dr->children = | ||
1972 | GNUNET_malloc (dr->num_children * sizeof(struct DownloadRequest *)); | ||
1973 | switch (dr->state) | ||
1974 | { | ||
1975 | case BRS_INIT: | ||
1976 | case BRS_RECONSTRUCT_DOWN: | ||
1977 | case BRS_RECONSTRUCT_META_UP: | ||
1978 | case BRS_RECONSTRUCT_UP: | ||
1979 | break; | ||
1980 | |||
1981 | case BRS_CHK_SET: | ||
1982 | if (GNUNET_OK != | ||
1983 | GNUNET_BIO_read (rh, "chk", &dr->chk, sizeof(struct ContentHashKey))) | ||
1984 | goto cleanup; | ||
1985 | break; | ||
1986 | |||
1987 | case BRS_DOWNLOAD_DOWN: | ||
1988 | case BRS_DOWNLOAD_UP: | ||
1989 | case BRS_ERROR: | ||
1990 | break; | ||
1991 | |||
1992 | default: | ||
1993 | GNUNET_break (0); | ||
1994 | goto cleanup; | ||
1995 | } | ||
1996 | for (i = 0; i < dr->num_children; i++) | ||
1997 | { | ||
1998 | if (NULL == (dr->children[i] = read_download_request (rh))) | ||
1999 | goto cleanup; | ||
2000 | dr->children[i]->parent = dr; | ||
2001 | } | ||
2002 | return dr; | ||
2003 | cleanup: | ||
2004 | GNUNET_FS_free_download_request_ (dr); | ||
2005 | return NULL; | ||
2006 | } | ||
2007 | |||
2008 | |||
2009 | /** | ||
2010 | * Compute the name of the sync file (or directory) for the given download | ||
2011 | * context. | ||
2012 | * | ||
2013 | * @param dc download context to compute for | ||
2014 | * @param uni unique filename to use, use "" for the directory name | ||
2015 | * @param ext extension to use, use ".dir" for our own subdirectory | ||
2016 | * @return the expanded file name, NULL for none | ||
2017 | */ | ||
2018 | static char * | ||
2019 | get_download_sync_filename (struct GNUNET_FS_DownloadContext *dc, | ||
2020 | const char *uni, | ||
2021 | const char *ext) | ||
2022 | { | ||
2023 | char *par; | ||
2024 | char *epar; | ||
2025 | |||
2026 | if (dc->parent == NULL) | ||
2027 | return get_serialization_file_name (dc->h, | ||
2028 | (dc->search != NULL) | ||
2029 | ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD | ||
2030 | : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, | ||
2031 | uni); | ||
2032 | if (NULL == dc->parent->serialization) | ||
2033 | return NULL; | ||
2034 | par = get_download_sync_filename (dc->parent, dc->parent->serialization, ""); | ||
2035 | if (NULL == par) | ||
2036 | return NULL; | ||
2037 | GNUNET_asprintf (&epar, "%s.dir%s%s%s", par, DIR_SEPARATOR_STR, uni, ext); | ||
2038 | GNUNET_free (par); | ||
2039 | return epar; | ||
2040 | } | ||
2041 | |||
2042 | |||
2043 | /** | ||
2044 | * Synchronize this download struct with its mirror | ||
2045 | * on disk. Note that all internal FS-operations that change | ||
2046 | * publishing structs should already call "sync" internally, | ||
2047 | * so this function is likely not useful for clients. | ||
2048 | * | ||
2049 | * @param dc the struct to sync | ||
2050 | */ | ||
2051 | void | ||
2052 | GNUNET_FS_download_sync_ (struct GNUNET_FS_DownloadContext *dc) | ||
2053 | { | ||
2054 | struct GNUNET_BIO_WriteHandle *wh; | ||
2055 | char *uris; | ||
2056 | char *fn; | ||
2057 | char *dir; | ||
2058 | |||
2059 | if (0 != (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) | ||
2060 | return; /* we don't sync probes */ | ||
2061 | if (NULL == dc->serialization) | ||
2062 | { | ||
2063 | dir = get_download_sync_filename (dc, "", ""); | ||
2064 | if (NULL == dir) | ||
2065 | return; | ||
2066 | if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dir)) | ||
2067 | { | ||
2068 | GNUNET_free (dir); | ||
2069 | return; | ||
2070 | } | ||
2071 | fn = GNUNET_DISK_mktemp (dir); | ||
2072 | GNUNET_free (dir); | ||
2073 | if (NULL == fn) | ||
2074 | return; | ||
2075 | dc->serialization = get_serialization_short_name (fn); | ||
2076 | } | ||
2077 | else | ||
2078 | { | ||
2079 | fn = get_download_sync_filename (dc, dc->serialization, ""); | ||
2080 | if (NULL == fn) | ||
2081 | { | ||
2082 | GNUNET_free (dc->serialization); | ||
2083 | dc->serialization = NULL; | ||
2084 | GNUNET_free (fn); | ||
2085 | return; | ||
2086 | } | ||
2087 | } | ||
2088 | wh = GNUNET_BIO_write_open_file (fn); | ||
2089 | if (NULL == wh) | ||
2090 | { | ||
2091 | GNUNET_free (dc->serialization); | ||
2092 | dc->serialization = NULL; | ||
2093 | GNUNET_free (fn); | ||
2094 | return; | ||
2095 | } | ||
2096 | GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_chk (dc->uri)) || | ||
2097 | (GNUNET_YES == GNUNET_FS_uri_test_loc (dc->uri))); | ||
2098 | uris = GNUNET_FS_uri_to_string (dc->uri); | ||
2099 | struct GNUNET_BIO_WriteSpec ws1[] = { | ||
2100 | GNUNET_BIO_write_spec_string ("uris", uris), | ||
2101 | GNUNET_BIO_write_spec_meta_data ("metadata", dc->meta), | ||
2102 | GNUNET_BIO_write_spec_string ("emsg", dc->emsg), | ||
2103 | GNUNET_BIO_write_spec_string ("filename", dc->filename), | ||
2104 | GNUNET_BIO_write_spec_string ("temp filename", dc->temp_filename), | ||
2105 | GNUNET_BIO_write_spec_int64 ("old file size", | ||
2106 | (int64_t *) &dc->old_file_size), | ||
2107 | GNUNET_BIO_write_spec_int64 ("offset", (int64_t *) &dc->offset), | ||
2108 | GNUNET_BIO_write_spec_int64 ("length", (int64_t *) &dc->length), | ||
2109 | GNUNET_BIO_write_spec_int64 ("completed", (int64_t *) &dc->completed), | ||
2110 | GNUNET_BIO_write_spec_end (), | ||
2111 | }; | ||
2112 | struct GNUNET_BIO_WriteSpec ws2[] = { | ||
2113 | GNUNET_BIO_write_spec_int32 ("anonymity", (int32_t *) &dc->anonymity), | ||
2114 | GNUNET_BIO_write_spec_int32 ("options", (int32_t *) &dc->options), | ||
2115 | GNUNET_BIO_write_spec_int32 ("has finished", (int32_t *) &dc->has_finished), | ||
2116 | GNUNET_BIO_write_spec_end (), | ||
2117 | }; | ||
2118 | if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws1)) || | ||
2119 | (GNUNET_OK != write_start_time (wh, dc->start_time)) || | ||
2120 | (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws2))) | ||
2121 | { | ||
2122 | GNUNET_break (0); | ||
2123 | goto cleanup; | ||
2124 | } | ||
2125 | if (NULL == dc->emsg) | ||
2126 | { | ||
2127 | GNUNET_assert (dc->top_request != NULL); | ||
2128 | if (GNUNET_YES != write_download_request (wh, dc->top_request)) | ||
2129 | { | ||
2130 | GNUNET_break (0); | ||
2131 | goto cleanup; | ||
2132 | } | ||
2133 | } | ||
2134 | GNUNET_free (uris); | ||
2135 | uris = NULL; | ||
2136 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
2137 | { | ||
2138 | wh = NULL; | ||
2139 | GNUNET_break (0); | ||
2140 | goto cleanup; | ||
2141 | } | ||
2142 | GNUNET_free (fn); | ||
2143 | return; | ||
2144 | cleanup: | ||
2145 | if (NULL != wh) | ||
2146 | (void) GNUNET_BIO_write_close (wh, NULL); | ||
2147 | GNUNET_free (uris); | ||
2148 | if (0 != unlink (fn)) | ||
2149 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); | ||
2150 | GNUNET_free (fn); | ||
2151 | GNUNET_free (dc->serialization); | ||
2152 | dc->serialization = NULL; | ||
2153 | } | ||
2154 | |||
2155 | |||
2156 | /** | ||
2157 | * Synchronize this search result with its mirror | ||
2158 | * on disk. Note that all internal FS-operations that change | ||
2159 | * publishing structs should already call "sync" internally, | ||
2160 | * so this function is likely not useful for clients. | ||
2161 | * | ||
2162 | * @param sr the struct to sync | ||
2163 | */ | ||
2164 | void | ||
2165 | GNUNET_FS_search_result_sync_ (struct GNUNET_FS_SearchResult *sr) | ||
2166 | { | ||
2167 | struct GNUNET_BIO_WriteHandle *wh; | ||
2168 | char *uris; | ||
2169 | |||
2170 | if (NULL == sr->sc) | ||
2171 | return; | ||
2172 | uris = NULL; | ||
2173 | if (NULL == sr->serialization) | ||
2174 | sr->serialization = | ||
2175 | make_serialization_file_name_in_dir (sr->h, | ||
2176 | (sr->sc->psearch_result == NULL) | ||
2177 | ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH | ||
2178 | : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, | ||
2179 | sr->sc->serialization); | ||
2180 | if (NULL == sr->serialization) | ||
2181 | return; | ||
2182 | wh = get_write_handle_in_dir (sr->h, | ||
2183 | (sr->sc->psearch_result == NULL) | ||
2184 | ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH | ||
2185 | : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, | ||
2186 | sr->sc->serialization, | ||
2187 | sr->serialization); | ||
2188 | if (NULL == wh) | ||
2189 | { | ||
2190 | GNUNET_break (0); | ||
2191 | goto cleanup; | ||
2192 | } | ||
2193 | uris = GNUNET_FS_uri_to_string (sr->uri); | ||
2194 | struct GNUNET_BIO_WriteSpec ws[] = { | ||
2195 | GNUNET_BIO_write_spec_string ("uris", uris), | ||
2196 | GNUNET_BIO_write_spec_string ("download serialization", | ||
2197 | (sr->download != NULL) | ||
2198 | ? sr->download->serialization | ||
2199 | : NULL), | ||
2200 | GNUNET_BIO_write_spec_string ("update search serialization", | ||
2201 | (sr->update_search != NULL) | ||
2202 | ? sr->update_search->serialization | ||
2203 | : NULL), | ||
2204 | GNUNET_BIO_write_spec_meta_data ("metadata", sr->meta), | ||
2205 | GNUNET_BIO_write_spec_object ("key", &sr->key, | ||
2206 | sizeof(struct GNUNET_HashCode)), | ||
2207 | GNUNET_BIO_write_spec_int32 ("mandatory missing", | ||
2208 | (int32_t *) &sr->mandatory_missing), | ||
2209 | GNUNET_BIO_write_spec_int32 ("optional support", | ||
2210 | (int32_t *) &sr->optional_support), | ||
2211 | GNUNET_BIO_write_spec_int32 ("availability success", | ||
2212 | (int32_t *) &sr->availability_success), | ||
2213 | GNUNET_BIO_write_spec_int32 ("availability trials", | ||
2214 | (int32_t *) &sr->availability_trials), | ||
2215 | GNUNET_BIO_write_spec_end (), | ||
2216 | }; | ||
2217 | if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws))) | ||
2218 | { | ||
2219 | GNUNET_break (0); | ||
2220 | goto cleanup; | ||
2221 | } | ||
2222 | if ((NULL != sr->uri) && (GNUNET_FS_URI_KSK == sr->sc->uri->type) && | ||
2223 | (GNUNET_OK != | ||
2224 | GNUNET_BIO_write (wh, | ||
2225 | "keyword bitmap", | ||
2226 | sr->keyword_bitmap, | ||
2227 | (sr->sc->uri->data.ksk.keywordCount + 7) / 8))) | ||
2228 | { | ||
2229 | GNUNET_break (0); | ||
2230 | goto cleanup; | ||
2231 | } | ||
2232 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
2233 | { | ||
2234 | wh = NULL; | ||
2235 | GNUNET_break (0); | ||
2236 | goto cleanup; | ||
2237 | } | ||
2238 | GNUNET_free (uris); | ||
2239 | return; | ||
2240 | cleanup: | ||
2241 | GNUNET_free (uris); | ||
2242 | if (NULL != wh) | ||
2243 | (void) GNUNET_BIO_write_close (wh, NULL); | ||
2244 | remove_sync_file_in_dir (sr->h, | ||
2245 | (NULL == sr->sc->psearch_result) | ||
2246 | ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH | ||
2247 | : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, | ||
2248 | sr->sc->serialization, | ||
2249 | sr->serialization); | ||
2250 | GNUNET_free (sr->serialization); | ||
2251 | sr->serialization = NULL; | ||
2252 | } | ||
2253 | |||
2254 | |||
2255 | /** | ||
2256 | * Synchronize this search struct with its mirror | ||
2257 | * on disk. Note that all internal FS-operations that change | ||
2258 | * publishing structs should already call "sync" internally, | ||
2259 | * so this function is likely not useful for clients. | ||
2260 | * | ||
2261 | * @param sc the struct to sync | ||
2262 | */ | ||
2263 | void | ||
2264 | GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc) | ||
2265 | { | ||
2266 | struct GNUNET_BIO_WriteHandle *wh; | ||
2267 | char *uris; | ||
2268 | char in_pause; | ||
2269 | const char *category; | ||
2270 | |||
2271 | category = (NULL == sc->psearch_result) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH | ||
2272 | : GNUNET_FS_SYNC_PATH_CHILD_SEARCH; | ||
2273 | if (NULL == sc->serialization) | ||
2274 | sc->serialization = make_serialization_file_name (sc->h, category); | ||
2275 | if (NULL == sc->serialization) | ||
2276 | return; | ||
2277 | uris = NULL; | ||
2278 | wh = get_write_handle (sc->h, category, sc->serialization); | ||
2279 | if (NULL == wh) | ||
2280 | { | ||
2281 | GNUNET_break (0); | ||
2282 | goto cleanup; | ||
2283 | } | ||
2284 | GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_ksk (sc->uri)) || | ||
2285 | (GNUNET_YES == GNUNET_FS_uri_test_sks (sc->uri))); | ||
2286 | uris = GNUNET_FS_uri_to_string (sc->uri); | ||
2287 | in_pause = (sc->task != NULL) ? 'r' : '\0'; | ||
2288 | if ((GNUNET_OK != GNUNET_BIO_write_string (wh, "uris", uris)) || | ||
2289 | (GNUNET_OK != write_start_time (wh, sc->start_time)) || | ||
2290 | (GNUNET_OK != GNUNET_BIO_write_string (wh, "emsg", sc->emsg)) || | ||
2291 | (GNUNET_OK != GNUNET_BIO_write_int32 (wh, "options", | ||
2292 | (uint32_t) sc->options)) || | ||
2293 | (GNUNET_OK != GNUNET_BIO_write (wh, "in pause", | ||
2294 | &in_pause, sizeof(in_pause))) || | ||
2295 | (GNUNET_OK != GNUNET_BIO_write_int32 (wh, "anonymity", sc->anonymity))) | ||
2296 | { | ||
2297 | GNUNET_break (0); | ||
2298 | goto cleanup; | ||
2299 | } | ||
2300 | GNUNET_free (uris); | ||
2301 | uris = NULL; | ||
2302 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
2303 | { | ||
2304 | wh = NULL; | ||
2305 | GNUNET_break (0); | ||
2306 | goto cleanup; | ||
2307 | } | ||
2308 | return; | ||
2309 | cleanup: | ||
2310 | if (NULL != wh) | ||
2311 | (void) GNUNET_BIO_write_close (wh, NULL); | ||
2312 | GNUNET_free (uris); | ||
2313 | GNUNET_FS_remove_sync_file_ (sc->h, category, sc->serialization); | ||
2314 | GNUNET_free (sc->serialization); | ||
2315 | sc->serialization = NULL; | ||
2316 | } | ||
2317 | |||
2318 | |||
2319 | /** | ||
2320 | * Function called with a filename of serialized unindexing operation | ||
2321 | * to deserialize. | ||
2322 | * | ||
2323 | * @param cls the `struct GNUNET_FS_Handle *` | ||
2324 | * @param filename complete filename (absolute path) | ||
2325 | * @return #GNUNET_OK (continue to iterate) | ||
2326 | */ | ||
2327 | static int | ||
2328 | deserialize_unindex_file (void *cls, const char *filename) | ||
2329 | { | ||
2330 | struct GNUNET_FS_Handle *h = cls; | ||
2331 | struct GNUNET_BIO_ReadHandle *rh; | ||
2332 | struct GNUNET_FS_UnindexContext *uc; | ||
2333 | struct GNUNET_FS_ProgressInfo pi; | ||
2334 | char *emsg; | ||
2335 | char *uris; | ||
2336 | uint32_t state; | ||
2337 | |||
2338 | uc = GNUNET_new (struct GNUNET_FS_UnindexContext); | ||
2339 | uc->h = h; | ||
2340 | uc->serialization = get_serialization_short_name (filename); | ||
2341 | rh = GNUNET_BIO_read_open_file (filename); | ||
2342 | if (NULL == rh) | ||
2343 | { | ||
2344 | GNUNET_break (0); | ||
2345 | goto cleanup; | ||
2346 | } | ||
2347 | uris = NULL; | ||
2348 | if ((GNUNET_OK != | ||
2349 | GNUNET_BIO_read_string (rh, "unindex-fn", &uc->filename, 10 * 1024)) || | ||
2350 | (GNUNET_OK != GNUNET_BIO_read_int64 (rh, "file size", | ||
2351 | (int64_t *) &uc->file_size)) || | ||
2352 | (GNUNET_OK != read_start_time (rh, &uc->start_time)) || | ||
2353 | (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "state", | ||
2354 | (int32_t *) &state)) || | ||
2355 | (GNUNET_OK != | ||
2356 | GNUNET_BIO_read (rh, "uri", &uc->chk, sizeof(struct ContentHashKey))) || | ||
2357 | (GNUNET_OK != | ||
2358 | GNUNET_BIO_read_string (rh, "unindex-kskuri", &uris, 10 * 1024)) || | ||
2359 | (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "ksk offset", | ||
2360 | (int32_t *) &uc->ksk_offset))) | ||
2361 | { | ||
2362 | GNUNET_free (uris); | ||
2363 | GNUNET_break (0); | ||
2364 | goto cleanup; | ||
2365 | } | ||
2366 | if (NULL != uris) | ||
2367 | { | ||
2368 | uc->ksk_uri = GNUNET_FS_uri_parse (uris, &emsg); | ||
2369 | GNUNET_free (uris); | ||
2370 | if (NULL == uc->ksk_uri) | ||
2371 | { | ||
2372 | GNUNET_break (0); | ||
2373 | GNUNET_free (emsg); | ||
2374 | goto cleanup; | ||
2375 | } | ||
2376 | } | ||
2377 | if ((uc->ksk_offset > 0) && | ||
2378 | ((NULL == uc->ksk_uri) || | ||
2379 | (uc->ksk_offset > uc->ksk_uri->data.ksk.keywordCount))) | ||
2380 | { | ||
2381 | GNUNET_break (0); | ||
2382 | goto cleanup; | ||
2383 | } | ||
2384 | uc->state = (enum UnindexState) state; | ||
2385 | switch (state) | ||
2386 | { | ||
2387 | case UNINDEX_STATE_HASHING: | ||
2388 | break; | ||
2389 | |||
2390 | case UNINDEX_STATE_FS_NOTIFY: | ||
2391 | if (GNUNET_OK != GNUNET_BIO_read (rh, | ||
2392 | "unindex-hash", | ||
2393 | &uc->file_id, | ||
2394 | sizeof(struct GNUNET_HashCode))) | ||
2395 | { | ||
2396 | GNUNET_break (0); | ||
2397 | goto cleanup; | ||
2398 | } | ||
2399 | break; | ||
2400 | |||
2401 | case UNINDEX_STATE_DS_REMOVE: | ||
2402 | case UNINDEX_STATE_EXTRACT_KEYWORDS: | ||
2403 | case UNINDEX_STATE_DS_REMOVE_KBLOCKS: | ||
2404 | break; | ||
2405 | |||
2406 | case UNINDEX_STATE_COMPLETE: | ||
2407 | break; | ||
2408 | |||
2409 | case UNINDEX_STATE_ERROR: | ||
2410 | if (GNUNET_OK != | ||
2411 | GNUNET_BIO_read_string (rh, "unindex-emsg", &uc->emsg, 10 * 1024)) | ||
2412 | { | ||
2413 | GNUNET_break (0); | ||
2414 | goto cleanup; | ||
2415 | } | ||
2416 | break; | ||
2417 | |||
2418 | default: | ||
2419 | GNUNET_break (0); | ||
2420 | goto cleanup; | ||
2421 | } | ||
2422 | uc->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, uc); | ||
2423 | pi.status = GNUNET_FS_STATUS_UNINDEX_RESUME; | ||
2424 | pi.value.unindex.specifics.resume.message = uc->emsg; | ||
2425 | GNUNET_FS_unindex_make_status_ (&pi, | ||
2426 | uc, | ||
2427 | (uc->state == UNINDEX_STATE_COMPLETE) | ||
2428 | ? uc->file_size | ||
2429 | : 0); | ||
2430 | switch (uc->state) | ||
2431 | { | ||
2432 | case UNINDEX_STATE_HASHING: | ||
2433 | uc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
2434 | uc->filename, | ||
2435 | HASHING_BLOCKSIZE, | ||
2436 | &GNUNET_FS_unindex_process_hash_, | ||
2437 | uc); | ||
2438 | break; | ||
2439 | |||
2440 | case UNINDEX_STATE_FS_NOTIFY: | ||
2441 | uc->state = UNINDEX_STATE_HASHING; | ||
2442 | GNUNET_FS_unindex_process_hash_ (uc, &uc->file_id); | ||
2443 | break; | ||
2444 | |||
2445 | case UNINDEX_STATE_DS_REMOVE: | ||
2446 | GNUNET_FS_unindex_do_remove_ (uc); | ||
2447 | break; | ||
2448 | |||
2449 | case UNINDEX_STATE_EXTRACT_KEYWORDS: | ||
2450 | GNUNET_FS_unindex_do_extract_keywords_ (uc); | ||
2451 | break; | ||
2452 | |||
2453 | case UNINDEX_STATE_DS_REMOVE_KBLOCKS: | ||
2454 | GNUNET_FS_unindex_do_remove_kblocks_ (uc); | ||
2455 | break; | ||
2456 | |||
2457 | case UNINDEX_STATE_COMPLETE: | ||
2458 | case UNINDEX_STATE_ERROR: | ||
2459 | /* no need to resume any operation, we were done */ | ||
2460 | break; | ||
2461 | |||
2462 | default: | ||
2463 | break; | ||
2464 | } | ||
2465 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
2466 | { | ||
2467 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2468 | _ ("Failure while resuming unindexing operation `%s': %s\n"), | ||
2469 | filename, | ||
2470 | emsg); | ||
2471 | GNUNET_free (emsg); | ||
2472 | } | ||
2473 | return GNUNET_OK; | ||
2474 | cleanup: | ||
2475 | GNUNET_free (uc->filename); | ||
2476 | if ((NULL != rh) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))) | ||
2477 | { | ||
2478 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2479 | _ ("Failed to resume unindexing operation `%s': %s\n"), | ||
2480 | filename, | ||
2481 | emsg); | ||
2482 | GNUNET_free (emsg); | ||
2483 | } | ||
2484 | if (NULL != uc->serialization) | ||
2485 | GNUNET_FS_remove_sync_file_ (h, | ||
2486 | GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, | ||
2487 | uc->serialization); | ||
2488 | GNUNET_free (uc->serialization); | ||
2489 | GNUNET_free (uc); | ||
2490 | return GNUNET_OK; | ||
2491 | } | ||
2492 | |||
2493 | |||
2494 | /** | ||
2495 | * Deserialize a download. | ||
2496 | * | ||
2497 | * @param h overall context | ||
2498 | * @param rh file to deserialize from | ||
2499 | * @param parent parent download | ||
2500 | * @param search associated search | ||
2501 | * @param serialization name under which the search was serialized | ||
2502 | */ | ||
2503 | static void | ||
2504 | deserialize_download (struct GNUNET_FS_Handle *h, | ||
2505 | struct GNUNET_BIO_ReadHandle *rh, | ||
2506 | struct GNUNET_FS_DownloadContext *parent, | ||
2507 | struct GNUNET_FS_SearchResult *search, | ||
2508 | const char *serialization); | ||
2509 | |||
2510 | |||
2511 | /** | ||
2512 | * Deserialize a search. | ||
2513 | * | ||
2514 | * @param h overall context | ||
2515 | * @param rh file to deserialize from | ||
2516 | * @param psearch_result parent search result | ||
2517 | * @param serialization name under which the search was serialized | ||
2518 | */ | ||
2519 | static struct GNUNET_FS_SearchContext * | ||
2520 | deserialize_search (struct GNUNET_FS_Handle *h, | ||
2521 | struct GNUNET_BIO_ReadHandle *rh, | ||
2522 | struct GNUNET_FS_SearchResult *psearch_result, | ||
2523 | const char *serialization); | ||
2524 | |||
2525 | |||
2526 | /** | ||
2527 | * Function called with a filename of serialized search result | ||
2528 | * to deserialize. | ||
2529 | * | ||
2530 | * @param cls the `struct GNUNET_FS_SearchContext *` | ||
2531 | * @param filename complete filename (absolute path) | ||
2532 | * @return #GNUNET_OK (continue to iterate) | ||
2533 | */ | ||
2534 | static int | ||
2535 | deserialize_search_result (void *cls, const char *filename) | ||
2536 | { | ||
2537 | struct GNUNET_FS_SearchContext *sc = cls; | ||
2538 | char *serialized; | ||
2539 | char *uris; | ||
2540 | char *emsg; | ||
2541 | char *download; | ||
2542 | char *update_srch; | ||
2543 | struct GNUNET_BIO_ReadHandle *rh; | ||
2544 | struct GNUNET_BIO_ReadHandle *drh; | ||
2545 | struct GNUNET_FS_SearchResult *sr; | ||
2546 | |||
2547 | serialized = get_serialization_short_name (filename); | ||
2548 | rh = GNUNET_BIO_read_open_file (filename); | ||
2549 | if (NULL == rh) | ||
2550 | { | ||
2551 | if (NULL != serialized) | ||
2552 | { | ||
2553 | remove_sync_file_in_dir (sc->h, | ||
2554 | (NULL == sc->psearch_result) | ||
2555 | ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH | ||
2556 | : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, | ||
2557 | sc->serialization, | ||
2558 | serialized); | ||
2559 | GNUNET_free (serialized); | ||
2560 | } | ||
2561 | return GNUNET_OK; | ||
2562 | } | ||
2563 | emsg = NULL; | ||
2564 | uris = NULL; | ||
2565 | download = NULL; | ||
2566 | update_srch = NULL; | ||
2567 | sr = GNUNET_new (struct GNUNET_FS_SearchResult); | ||
2568 | sr->h = sc->h; | ||
2569 | sr->sc = sc; | ||
2570 | sr->serialization = serialized; | ||
2571 | if ((GNUNET_OK != | ||
2572 | GNUNET_BIO_read_string (rh, "result-uri", &uris, 10 * 1024)) || | ||
2573 | (NULL == (sr->uri = GNUNET_FS_uri_parse (uris, &emsg))) || | ||
2574 | (GNUNET_OK != | ||
2575 | GNUNET_BIO_read_string (rh, "download-lnk", &download, 16)) || | ||
2576 | (GNUNET_OK != | ||
2577 | GNUNET_BIO_read_string (rh, "search-lnk", &update_srch, 16)) || | ||
2578 | (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "result-meta", &sr->meta)) || | ||
2579 | (GNUNET_OK != GNUNET_BIO_read (rh, | ||
2580 | "result-key", | ||
2581 | &sr->key, | ||
2582 | sizeof(struct GNUNET_HashCode))) || | ||
2583 | (GNUNET_OK != GNUNET_BIO_read_int32 ( | ||
2584 | rh, | ||
2585 | "mandatory missing", | ||
2586 | (int32_t *) &sr->mandatory_missing)) || | ||
2587 | (GNUNET_OK != GNUNET_BIO_read_int32 ( | ||
2588 | rh, | ||
2589 | "optional support", | ||
2590 | (int32_t *) &sr->optional_support)) || | ||
2591 | (GNUNET_OK != GNUNET_BIO_read_int32 ( | ||
2592 | rh, | ||
2593 | "availability success", | ||
2594 | (int32_t *) &sr->availability_success)) || | ||
2595 | (GNUNET_OK != GNUNET_BIO_read_int32 ( | ||
2596 | rh, | ||
2597 | "availability trials", | ||
2598 | (int32_t *) &sr->availability_trials))) | ||
2599 | { | ||
2600 | GNUNET_break (0); | ||
2601 | goto cleanup; | ||
2602 | } | ||
2603 | if (GNUNET_FS_URI_KSK == sr->sc->uri->type) | ||
2604 | { | ||
2605 | sr->keyword_bitmap = GNUNET_malloc ( | ||
2606 | (sr->sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */ | ||
2607 | if (GNUNET_OK != | ||
2608 | GNUNET_BIO_read (rh, | ||
2609 | "keyword-bitmap", | ||
2610 | sr->keyword_bitmap, | ||
2611 | (sr->sc->uri->data.ksk.keywordCount + 7) / 8)) | ||
2612 | { | ||
2613 | GNUNET_break (0); | ||
2614 | goto cleanup; | ||
2615 | } | ||
2616 | } | ||
2617 | GNUNET_free (uris); | ||
2618 | if (NULL != download) | ||
2619 | { | ||
2620 | drh = get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD, download); | ||
2621 | if (NULL != drh) | ||
2622 | { | ||
2623 | deserialize_download (sc->h, drh, NULL, sr, download); | ||
2624 | if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg)) | ||
2625 | { | ||
2626 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2627 | _ ("Failed to resume sub-download `%s': %s\n"), | ||
2628 | download, | ||
2629 | emsg); | ||
2630 | GNUNET_free (emsg); | ||
2631 | } | ||
2632 | } | ||
2633 | GNUNET_free (download); | ||
2634 | } | ||
2635 | if (NULL != update_srch) | ||
2636 | { | ||
2637 | drh = | ||
2638 | get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_SEARCH, update_srch); | ||
2639 | if (NULL != drh) | ||
2640 | { | ||
2641 | deserialize_search (sc->h, drh, sr, update_srch); | ||
2642 | if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg)) | ||
2643 | { | ||
2644 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2645 | _ ("Failed to resume sub-search `%s': %s\n"), | ||
2646 | update_srch, | ||
2647 | emsg); | ||
2648 | GNUNET_free (emsg); | ||
2649 | } | ||
2650 | } | ||
2651 | GNUNET_free (update_srch); | ||
2652 | } | ||
2653 | GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put ( | ||
2654 | sc->master_result_map, | ||
2655 | &sr->key, | ||
2656 | sr, | ||
2657 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
2658 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
2659 | { | ||
2660 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2661 | _ ("Failure while resuming search operation `%s': %s\n"), | ||
2662 | filename, | ||
2663 | emsg); | ||
2664 | GNUNET_free (emsg); | ||
2665 | } | ||
2666 | return GNUNET_OK; | ||
2667 | cleanup: | ||
2668 | GNUNET_free (download); | ||
2669 | GNUNET_free (emsg); | ||
2670 | GNUNET_free (uris); | ||
2671 | GNUNET_free (update_srch); | ||
2672 | if (NULL != sr->uri) | ||
2673 | GNUNET_FS_uri_destroy (sr->uri); | ||
2674 | if (NULL != sr->meta) | ||
2675 | GNUNET_CONTAINER_meta_data_destroy (sr->meta); | ||
2676 | GNUNET_free (sr->serialization); | ||
2677 | GNUNET_free (sr); | ||
2678 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
2679 | { | ||
2680 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2681 | _ ("Failure while resuming search operation `%s': %s\n"), | ||
2682 | filename, | ||
2683 | emsg); | ||
2684 | GNUNET_free (emsg); | ||
2685 | } | ||
2686 | return GNUNET_OK; | ||
2687 | } | ||
2688 | |||
2689 | |||
2690 | /** | ||
2691 | * Send the 'resume' signal to the callback; also actually | ||
2692 | * resume the download (put it in the queue). Does this | ||
2693 | * recursively for the top-level download and all child | ||
2694 | * downloads. | ||
2695 | * | ||
2696 | * @param dc download to resume | ||
2697 | */ | ||
2698 | static void | ||
2699 | signal_download_resume (struct GNUNET_FS_DownloadContext *dc) | ||
2700 | { | ||
2701 | struct GNUNET_FS_DownloadContext *dcc; | ||
2702 | struct GNUNET_FS_ProgressInfo pi; | ||
2703 | |||
2704 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_RESUME; | ||
2705 | pi.value.download.specifics.resume.meta = dc->meta; | ||
2706 | pi.value.download.specifics.resume.message = dc->emsg; | ||
2707 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
2708 | dcc = dc->child_head; | ||
2709 | while (NULL != dcc) | ||
2710 | { | ||
2711 | signal_download_resume (dcc); | ||
2712 | dcc = dcc->next; | ||
2713 | } | ||
2714 | } | ||
2715 | |||
2716 | |||
2717 | /** | ||
2718 | * Signal resuming of a search to our clients (for the | ||
2719 | * top level search and all sub-searches). | ||
2720 | * | ||
2721 | * @param sc search being resumed | ||
2722 | */ | ||
2723 | static void | ||
2724 | signal_search_resume (struct GNUNET_FS_SearchContext *sc); | ||
2725 | |||
2726 | |||
2727 | /** | ||
2728 | * Iterator over search results signaling resume to the client for | ||
2729 | * each result. | ||
2730 | * | ||
2731 | * @param cls closure, the `struct GNUNET_FS_SearchContext *` | ||
2732 | * @param key current key code | ||
2733 | * @param value value in the hash map, the `struct GNUNET_FS_SearchResult *` | ||
2734 | * @return #GNUNET_YES (we should continue to iterate) | ||
2735 | */ | ||
2736 | static int | ||
2737 | signal_result_resume (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
2738 | { | ||
2739 | struct GNUNET_FS_SearchContext *sc = cls; | ||
2740 | struct GNUNET_FS_ProgressInfo pi; | ||
2741 | struct GNUNET_FS_SearchResult *sr = value; | ||
2742 | |||
2743 | if (0 == sr->mandatory_missing) | ||
2744 | { | ||
2745 | pi.status = GNUNET_FS_STATUS_SEARCH_RESUME_RESULT; | ||
2746 | pi.value.search.specifics.resume_result.meta = sr->meta; | ||
2747 | pi.value.search.specifics.resume_result.uri = sr->uri; | ||
2748 | pi.value.search.specifics.resume_result.result = sr; | ||
2749 | pi.value.search.specifics.resume_result.availability_rank = | ||
2750 | 2 * sr->availability_success - sr->availability_trials; | ||
2751 | pi.value.search.specifics.resume_result.availability_certainty = | ||
2752 | sr->availability_trials; | ||
2753 | pi.value.search.specifics.resume_result.applicability_rank = | ||
2754 | sr->optional_support; | ||
2755 | sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); | ||
2756 | } | ||
2757 | if (NULL != sr->download) | ||
2758 | { | ||
2759 | signal_download_resume (sr->download); | ||
2760 | } | ||
2761 | else | ||
2762 | { | ||
2763 | GNUNET_FS_search_start_probe_ (sr); | ||
2764 | } | ||
2765 | if (NULL != sr->update_search) | ||
2766 | signal_search_resume (sr->update_search); | ||
2767 | return GNUNET_YES; | ||
2768 | } | ||
2769 | |||
2770 | |||
2771 | /** | ||
2772 | * Free memory allocated by the search context and its children | ||
2773 | * | ||
2774 | * @param sc search context to free | ||
2775 | */ | ||
2776 | static void | ||
2777 | free_search_context (struct GNUNET_FS_SearchContext *sc); | ||
2778 | |||
2779 | |||
2780 | /** | ||
2781 | * Iterator over search results freeing each. | ||
2782 | * | ||
2783 | * @param cls closure, the `struct GNUNET_FS_SearchContext *` | ||
2784 | * @param key current key code | ||
2785 | * @param value value in the hash map, the `struct GNUNET_FS_SearchResult *` | ||
2786 | * @return #GNUNET_YES (we should continue to iterate) | ||
2787 | */ | ||
2788 | static int | ||
2789 | free_result (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
2790 | { | ||
2791 | struct GNUNET_FS_SearchResult *sr = value; | ||
2792 | |||
2793 | if (NULL != sr->update_search) | ||
2794 | { | ||
2795 | free_search_context (sr->update_search); | ||
2796 | GNUNET_assert (NULL == sr->update_search); | ||
2797 | } | ||
2798 | GNUNET_CONTAINER_meta_data_destroy (sr->meta); | ||
2799 | GNUNET_FS_uri_destroy (sr->uri); | ||
2800 | GNUNET_free (sr); | ||
2801 | return GNUNET_YES; | ||
2802 | } | ||
2803 | |||
2804 | |||
2805 | /** | ||
2806 | * Free memory allocated by the search context and its children | ||
2807 | * | ||
2808 | * @param sc search context to free | ||
2809 | */ | ||
2810 | static void | ||
2811 | free_search_context (struct GNUNET_FS_SearchContext *sc) | ||
2812 | { | ||
2813 | if (NULL != sc->serialization) | ||
2814 | { | ||
2815 | GNUNET_FS_remove_sync_file_ (sc->h, | ||
2816 | (sc->psearch_result == NULL) | ||
2817 | ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH | ||
2818 | : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, | ||
2819 | sc->serialization); | ||
2820 | GNUNET_FS_remove_sync_dir_ (sc->h, | ||
2821 | (sc->psearch_result == NULL) | ||
2822 | ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH | ||
2823 | : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, | ||
2824 | sc->serialization); | ||
2825 | } | ||
2826 | GNUNET_free (sc->serialization); | ||
2827 | GNUNET_free (sc->emsg); | ||
2828 | if (NULL != sc->uri) | ||
2829 | GNUNET_FS_uri_destroy (sc->uri); | ||
2830 | if (NULL != sc->master_result_map) | ||
2831 | { | ||
2832 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
2833 | &free_result, | ||
2834 | sc); | ||
2835 | GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); | ||
2836 | } | ||
2837 | GNUNET_free (sc); | ||
2838 | } | ||
2839 | |||
2840 | |||
2841 | /** | ||
2842 | * Function called with a filename of serialized sub-download | ||
2843 | * to deserialize. | ||
2844 | * | ||
2845 | * @param cls the `struct GNUNET_FS_DownloadContext *` (parent) | ||
2846 | * @param filename complete filename (absolute path) | ||
2847 | * @return #GNUNET_OK (continue to iterate) | ||
2848 | */ | ||
2849 | static int | ||
2850 | deserialize_subdownload (void *cls, const char *filename) | ||
2851 | { | ||
2852 | struct GNUNET_FS_DownloadContext *parent = cls; | ||
2853 | char *serialized; | ||
2854 | char *emsg; | ||
2855 | struct GNUNET_BIO_ReadHandle *rh; | ||
2856 | |||
2857 | serialized = get_serialization_short_name (filename); | ||
2858 | rh = GNUNET_BIO_read_open_file (filename); | ||
2859 | if (NULL == rh) | ||
2860 | { | ||
2861 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2862 | _ ( | ||
2863 | "Failed to resume sub-download `%s': could not open file `%s'\n"), | ||
2864 | serialized, | ||
2865 | filename); | ||
2866 | GNUNET_free (serialized); | ||
2867 | return GNUNET_OK; | ||
2868 | } | ||
2869 | deserialize_download (parent->h, rh, parent, NULL, serialized); | ||
2870 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
2871 | { | ||
2872 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2873 | _ ("Failed to resume sub-download `%s': %s\n"), | ||
2874 | serialized, | ||
2875 | emsg); | ||
2876 | GNUNET_free (emsg); | ||
2877 | } | ||
2878 | GNUNET_free (serialized); | ||
2879 | return GNUNET_OK; | ||
2880 | } | ||
2881 | |||
2882 | |||
2883 | /** | ||
2884 | * Free this download context and all of its descendants. | ||
2885 | * (only works during deserialization since not all possible | ||
2886 | * state it taken care of). | ||
2887 | * | ||
2888 | * @param dc context to free | ||
2889 | */ | ||
2890 | static void | ||
2891 | free_download_context (struct GNUNET_FS_DownloadContext *dc) | ||
2892 | { | ||
2893 | struct GNUNET_FS_DownloadContext *dcc; | ||
2894 | |||
2895 | if (NULL != dc->meta) | ||
2896 | GNUNET_CONTAINER_meta_data_destroy (dc->meta); | ||
2897 | if (NULL != dc->uri) | ||
2898 | GNUNET_FS_uri_destroy (dc->uri); | ||
2899 | GNUNET_free (dc->temp_filename); | ||
2900 | GNUNET_free (dc->emsg); | ||
2901 | GNUNET_free (dc->filename); | ||
2902 | GNUNET_free (dc->serialization); | ||
2903 | while (NULL != (dcc = dc->child_head)) | ||
2904 | { | ||
2905 | GNUNET_CONTAINER_DLL_remove (dc->child_head, dc->child_tail, dcc); | ||
2906 | free_download_context (dcc); | ||
2907 | } | ||
2908 | GNUNET_FS_free_download_request_ (dc->top_request); | ||
2909 | if (NULL != dc->active) | ||
2910 | GNUNET_CONTAINER_multihashmap_destroy (dc->active); | ||
2911 | GNUNET_free (dc); | ||
2912 | } | ||
2913 | |||
2914 | |||
2915 | /** | ||
2916 | * Deserialize a download. | ||
2917 | * | ||
2918 | * @param h overall context | ||
2919 | * @param rh file to deserialize from | ||
2920 | * @param parent parent download | ||
2921 | * @param search associated search | ||
2922 | * @param serialization name under which the search was serialized | ||
2923 | */ | ||
2924 | static void | ||
2925 | deserialize_download (struct GNUNET_FS_Handle *h, | ||
2926 | struct GNUNET_BIO_ReadHandle *rh, | ||
2927 | struct GNUNET_FS_DownloadContext *parent, | ||
2928 | struct GNUNET_FS_SearchResult *search, | ||
2929 | const char *serialization) | ||
2930 | { | ||
2931 | struct GNUNET_FS_DownloadContext *dc; | ||
2932 | char *emsg; | ||
2933 | char *uris; | ||
2934 | char *dn; | ||
2935 | uint32_t options; | ||
2936 | uint32_t status; | ||
2937 | |||
2938 | uris = NULL; | ||
2939 | emsg = NULL; | ||
2940 | dc = GNUNET_new (struct GNUNET_FS_DownloadContext); | ||
2941 | dc->parent = parent; | ||
2942 | dc->h = h; | ||
2943 | dc->serialization = GNUNET_strdup (serialization); | ||
2944 | struct GNUNET_BIO_ReadSpec rs[] = { | ||
2945 | GNUNET_BIO_read_spec_meta_data ("download-meta", &dc->meta), | ||
2946 | GNUNET_BIO_read_spec_string ("download-emsg", &dc->emsg, 10 * 1024), | ||
2947 | GNUNET_BIO_read_spec_string ("download-fn", &dc->filename, 10 * 1024), | ||
2948 | GNUNET_BIO_read_spec_string ("download-tfn", | ||
2949 | &dc->temp_filename, 10 * 1024), | ||
2950 | GNUNET_BIO_read_spec_int64 ("old file size", | ||
2951 | (int64_t *) &dc->old_file_size), | ||
2952 | GNUNET_BIO_read_spec_int64 ("offset", | ||
2953 | (int64_t *) &dc->offset), | ||
2954 | GNUNET_BIO_read_spec_int64 ("length", | ||
2955 | (int64_t *) &dc->length), | ||
2956 | GNUNET_BIO_read_spec_int64 ("completed", | ||
2957 | (int64_t *) &dc->completed), | ||
2958 | GNUNET_BIO_read_spec_end (), | ||
2959 | }; | ||
2960 | if ((GNUNET_OK != | ||
2961 | GNUNET_BIO_read_string (rh, "download-uri", &uris, 10 * 1024)) || | ||
2962 | (NULL == (dc->uri = GNUNET_FS_uri_parse (uris, &emsg))) || | ||
2963 | ((GNUNET_YES != GNUNET_FS_uri_test_chk (dc->uri)) && | ||
2964 | (GNUNET_YES != GNUNET_FS_uri_test_loc (dc->uri))) || | ||
2965 | (GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs)) || | ||
2966 | (GNUNET_OK != read_start_time (rh, &dc->start_time)) || | ||
2967 | (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "anonymity", | ||
2968 | (int32_t *) &dc->anonymity)) || | ||
2969 | (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "options", | ||
2970 | (int32_t *) &options)) || | ||
2971 | (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "status", | ||
2972 | (int32_t *) &status))) | ||
2973 | { | ||
2974 | GNUNET_break (0); | ||
2975 | goto cleanup; | ||
2976 | } | ||
2977 | dc->options = (enum GNUNET_FS_DownloadOptions) options; | ||
2978 | dc->active = | ||
2979 | GNUNET_CONTAINER_multihashmap_create (1 + 2 * (dc->length / DBLOCK_SIZE), | ||
2980 | GNUNET_NO); | ||
2981 | dc->has_finished = (int) status; | ||
2982 | dc->treedepth = | ||
2983 | GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri)); | ||
2984 | if (GNUNET_FS_uri_test_loc (dc->uri)) | ||
2985 | GNUNET_assert (GNUNET_OK == | ||
2986 | GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target)); | ||
2987 | if (NULL == dc->emsg) | ||
2988 | { | ||
2989 | dc->top_request = read_download_request (rh); | ||
2990 | if (NULL == dc->top_request) | ||
2991 | { | ||
2992 | GNUNET_break (0); | ||
2993 | goto cleanup; | ||
2994 | } | ||
2995 | } | ||
2996 | dn = get_download_sync_filename (dc, dc->serialization, ".dir"); | ||
2997 | if (NULL != dn) | ||
2998 | { | ||
2999 | if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES)) | ||
3000 | GNUNET_DISK_directory_scan (dn, &deserialize_subdownload, dc); | ||
3001 | GNUNET_free (dn); | ||
3002 | } | ||
3003 | if (NULL != parent) | ||
3004 | { | ||
3005 | GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc); | ||
3006 | } | ||
3007 | if (NULL != search) | ||
3008 | { | ||
3009 | dc->search = search; | ||
3010 | search->download = dc; | ||
3011 | } | ||
3012 | if ((NULL == parent) && (NULL == search)) | ||
3013 | { | ||
3014 | dc->top = | ||
3015 | GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc); | ||
3016 | signal_download_resume (dc); | ||
3017 | } | ||
3018 | GNUNET_free (uris); | ||
3019 | GNUNET_assert (NULL == dc->job_queue); | ||
3020 | dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc); | ||
3021 | return; | ||
3022 | cleanup: | ||
3023 | GNUNET_free (uris); | ||
3024 | GNUNET_free (emsg); | ||
3025 | free_download_context (dc); | ||
3026 | } | ||
3027 | |||
3028 | |||
3029 | /** | ||
3030 | * Signal resuming of a search to our clients (for the | ||
3031 | * top level search and all sub-searches). | ||
3032 | * | ||
3033 | * @param sc search being resumed | ||
3034 | */ | ||
3035 | static void | ||
3036 | signal_search_resume (struct GNUNET_FS_SearchContext *sc) | ||
3037 | { | ||
3038 | struct GNUNET_FS_ProgressInfo pi; | ||
3039 | |||
3040 | pi.status = GNUNET_FS_STATUS_SEARCH_RESUME; | ||
3041 | pi.value.search.specifics.resume.message = sc->emsg; | ||
3042 | pi.value.search.specifics.resume.is_paused = | ||
3043 | (NULL == sc->mq) ? GNUNET_YES : GNUNET_NO; | ||
3044 | sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); | ||
3045 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
3046 | &signal_result_resume, | ||
3047 | sc); | ||
3048 | } | ||
3049 | |||
3050 | |||
3051 | /** | ||
3052 | * Deserialize a search. | ||
3053 | * | ||
3054 | * @param h overall context | ||
3055 | * @param rh file to deserialize from | ||
3056 | * @param psearch_result parent search result | ||
3057 | * @param serialization name under which the search was serialized | ||
3058 | */ | ||
3059 | static struct GNUNET_FS_SearchContext * | ||
3060 | deserialize_search (struct GNUNET_FS_Handle *h, | ||
3061 | struct GNUNET_BIO_ReadHandle *rh, | ||
3062 | struct GNUNET_FS_SearchResult *psearch_result, | ||
3063 | const char *serialization) | ||
3064 | { | ||
3065 | struct GNUNET_FS_SearchContext *sc; | ||
3066 | char *emsg; | ||
3067 | char *uris; | ||
3068 | char *dn; | ||
3069 | uint32_t options; | ||
3070 | char in_pause; | ||
3071 | |||
3072 | if ((NULL != psearch_result) && (NULL != psearch_result->update_search)) | ||
3073 | { | ||
3074 | GNUNET_break (0); | ||
3075 | return NULL; | ||
3076 | } | ||
3077 | uris = NULL; | ||
3078 | emsg = NULL; | ||
3079 | sc = GNUNET_new (struct GNUNET_FS_SearchContext); | ||
3080 | if (NULL != psearch_result) | ||
3081 | { | ||
3082 | sc->psearch_result = psearch_result; | ||
3083 | psearch_result->update_search = sc; | ||
3084 | } | ||
3085 | sc->h = h; | ||
3086 | sc->serialization = GNUNET_strdup (serialization); | ||
3087 | if ((GNUNET_OK != | ||
3088 | GNUNET_BIO_read_string (rh, "search-uri", &uris, 10 * 1024)) || | ||
3089 | (NULL == (sc->uri = GNUNET_FS_uri_parse (uris, &emsg))) || | ||
3090 | ((GNUNET_YES != GNUNET_FS_uri_test_ksk (sc->uri)) && | ||
3091 | (GNUNET_YES != GNUNET_FS_uri_test_sks (sc->uri))) || | ||
3092 | (GNUNET_OK != read_start_time (rh, &sc->start_time)) || | ||
3093 | (GNUNET_OK != | ||
3094 | GNUNET_BIO_read_string (rh, "search-emsg", &sc->emsg, 10 * 1024)) || | ||
3095 | (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "options", | ||
3096 | (int32_t *) &options)) || | ||
3097 | (GNUNET_OK != | ||
3098 | GNUNET_BIO_read (rh, "search-pause", &in_pause, sizeof(in_pause))) || | ||
3099 | (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "anonymity", | ||
3100 | (int32_t *) &sc->anonymity))) | ||
3101 | { | ||
3102 | GNUNET_break (0); | ||
3103 | goto cleanup; | ||
3104 | } | ||
3105 | sc->options = (enum GNUNET_FS_SearchOptions) options; | ||
3106 | sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO); | ||
3107 | dn = get_serialization_file_name_in_dir (h, | ||
3108 | (NULL == sc->psearch_result) | ||
3109 | ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH | ||
3110 | : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, | ||
3111 | sc->serialization, | ||
3112 | ""); | ||
3113 | if (NULL != dn) | ||
3114 | { | ||
3115 | if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES)) | ||
3116 | GNUNET_DISK_directory_scan (dn, &deserialize_search_result, sc); | ||
3117 | GNUNET_free (dn); | ||
3118 | } | ||
3119 | if (('\0' == in_pause) && | ||
3120 | (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc))) | ||
3121 | { | ||
3122 | GNUNET_log ( | ||
3123 | GNUNET_ERROR_TYPE_WARNING, | ||
3124 | _ ("Could not resume running search, will resume as paused search\n")); | ||
3125 | } | ||
3126 | signal_search_resume (sc); | ||
3127 | GNUNET_free (uris); | ||
3128 | return sc; | ||
3129 | cleanup: | ||
3130 | GNUNET_free (emsg); | ||
3131 | free_search_context (sc); | ||
3132 | GNUNET_free (uris); | ||
3133 | return NULL; | ||
3134 | } | ||
3135 | |||
3136 | |||
3137 | /** | ||
3138 | * Function called with a filename of serialized search operation | ||
3139 | * to deserialize. | ||
3140 | * | ||
3141 | * @param cls the `struct GNUNET_FS_Handle *` | ||
3142 | * @param filename complete filename (absolute path) | ||
3143 | * @return #GNUNET_OK (continue to iterate) | ||
3144 | */ | ||
3145 | static int | ||
3146 | deserialize_search_file (void *cls, const char *filename) | ||
3147 | { | ||
3148 | struct GNUNET_FS_Handle *h = cls; | ||
3149 | char *set; | ||
3150 | char *emsg; | ||
3151 | struct GNUNET_BIO_ReadHandle *rh; | ||
3152 | struct GNUNET_FS_SearchContext *sc; | ||
3153 | struct stat buf; | ||
3154 | |||
3155 | if (0 != stat (filename, &buf)) | ||
3156 | { | ||
3157 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename); | ||
3158 | return GNUNET_OK; | ||
3159 | } | ||
3160 | if (S_ISDIR (buf.st_mode)) | ||
3161 | return GNUNET_OK; /* skip directories */ | ||
3162 | set = get_serialization_short_name (filename); | ||
3163 | rh = GNUNET_BIO_read_open_file (filename); | ||
3164 | if (NULL == rh) | ||
3165 | { | ||
3166 | if (NULL != set) | ||
3167 | { | ||
3168 | GNUNET_FS_remove_sync_file_ (h, GNUNET_FS_SYNC_PATH_MASTER_SEARCH, set); | ||
3169 | GNUNET_free (set); | ||
3170 | } | ||
3171 | return GNUNET_OK; | ||
3172 | } | ||
3173 | sc = deserialize_search (h, rh, NULL, set); | ||
3174 | if (NULL != sc) | ||
3175 | sc->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, sc); | ||
3176 | GNUNET_free (set); | ||
3177 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
3178 | { | ||
3179 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
3180 | _ ("Failure while resuming search operation `%s': %s\n"), | ||
3181 | filename, | ||
3182 | emsg); | ||
3183 | GNUNET_free (emsg); | ||
3184 | } | ||
3185 | return GNUNET_OK; | ||
3186 | } | ||
3187 | |||
3188 | |||
3189 | /** | ||
3190 | * Function called with a filename of serialized download operation | ||
3191 | * to deserialize. | ||
3192 | * | ||
3193 | * @param cls the `struct GNUNET_FS_Handle *` | ||
3194 | * @param filename complete filename (absolute path) | ||
3195 | * @return #GNUNET_OK (continue to iterate) | ||
3196 | */ | ||
3197 | static int | ||
3198 | deserialize_download_file (void *cls, const char *filename) | ||
3199 | { | ||
3200 | struct GNUNET_FS_Handle *h = cls; | ||
3201 | char *set; | ||
3202 | char *emsg; | ||
3203 | struct GNUNET_BIO_ReadHandle *rh; | ||
3204 | |||
3205 | set = get_serialization_short_name (filename); | ||
3206 | rh = GNUNET_BIO_read_open_file (filename); | ||
3207 | if (NULL == rh) | ||
3208 | { | ||
3209 | if (0 != unlink (filename)) | ||
3210 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); | ||
3211 | GNUNET_free (set); | ||
3212 | return GNUNET_OK; | ||
3213 | } | ||
3214 | deserialize_download (h, rh, NULL, NULL, set); | ||
3215 | GNUNET_free (set); | ||
3216 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
3217 | { | ||
3218 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
3219 | _ ("Failure while resuming download operation `%s': %s\n"), | ||
3220 | filename, | ||
3221 | emsg); | ||
3222 | GNUNET_free (emsg); | ||
3223 | } | ||
3224 | return GNUNET_OK; | ||
3225 | } | ||
3226 | |||
3227 | |||
3228 | /** | ||
3229 | * Deserialize information about pending operations. | ||
3230 | * | ||
3231 | * @param master_path which master directory should be scanned | ||
3232 | * @param proc function to call for each entry (will get @a h for 'cls') | ||
3233 | * @param h the `struct GNUNET_FS_Handle *` | ||
3234 | */ | ||
3235 | static void | ||
3236 | deserialization_master (const char *master_path, | ||
3237 | GNUNET_FileNameCallback proc, | ||
3238 | struct GNUNET_FS_Handle *h) | ||
3239 | { | ||
3240 | char *dn; | ||
3241 | |||
3242 | dn = get_serialization_file_name (h, master_path, ""); | ||
3243 | if (NULL == dn) | ||
3244 | return; | ||
3245 | if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES)) | ||
3246 | GNUNET_DISK_directory_scan (dn, proc, h); | ||
3247 | GNUNET_free (dn); | ||
3248 | } | ||
3249 | |||
3250 | |||
3251 | /** | ||
3252 | * Setup a connection to the file-sharing service. | ||
3253 | * | ||
3254 | * @param cfg configuration to use | ||
3255 | * @param client_name unique identifier for this client | ||
3256 | * @param upcb function to call to notify about FS actions | ||
3257 | * @param upcb_cls closure for @a upcb | ||
3258 | * @param flags specific attributes for fs-operations | ||
3259 | * @param ... list of optional options, terminated with #GNUNET_FS_OPTIONS_END | ||
3260 | * @return NULL on error | ||
3261 | */ | ||
3262 | struct GNUNET_FS_Handle * | ||
3263 | GNUNET_FS_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
3264 | const char *client_name, | ||
3265 | GNUNET_FS_ProgressCallback upcb, | ||
3266 | void *upcb_cls, | ||
3267 | enum GNUNET_FS_Flags flags, | ||
3268 | ...) | ||
3269 | { | ||
3270 | struct GNUNET_FS_Handle *ret; | ||
3271 | enum GNUNET_FS_OPTIONS opt; | ||
3272 | va_list ap; | ||
3273 | |||
3274 | ret = GNUNET_new (struct GNUNET_FS_Handle); | ||
3275 | ret->cfg = cfg; | ||
3276 | ret->client_name = GNUNET_strdup (client_name); | ||
3277 | ret->upcb = upcb; | ||
3278 | ret->upcb_cls = upcb_cls; | ||
3279 | ret->flags = flags; | ||
3280 | ret->max_parallel_downloads = DEFAULT_MAX_PARALLEL_DOWNLOADS; | ||
3281 | ret->max_parallel_requests = DEFAULT_MAX_PARALLEL_REQUESTS; | ||
3282 | ret->avg_block_latency = | ||
3283 | GNUNET_TIME_UNIT_MINUTES; /* conservative starting point */ | ||
3284 | va_start (ap, flags); | ||
3285 | while (GNUNET_FS_OPTIONS_END != | ||
3286 | (opt = GNUNET_VA_ARG_ENUM (ap, GNUNET_FS_OPTIONS))) | ||
3287 | { | ||
3288 | switch (opt) | ||
3289 | { | ||
3290 | case GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM: | ||
3291 | ret->max_parallel_downloads = va_arg (ap, unsigned int); | ||
3292 | |||
3293 | break; | ||
3294 | |||
3295 | case GNUNET_FS_OPTIONS_REQUEST_PARALLELISM: | ||
3296 | ret->max_parallel_requests = va_arg (ap, unsigned int); | ||
3297 | |||
3298 | break; | ||
3299 | |||
3300 | default: | ||
3301 | GNUNET_break (0); | ||
3302 | GNUNET_free (ret->client_name); | ||
3303 | GNUNET_free (ret); | ||
3304 | va_end (ap); | ||
3305 | return NULL; | ||
3306 | } | ||
3307 | } | ||
3308 | va_end (ap); | ||
3309 | if (0 != (GNUNET_FS_FLAGS_PERSISTENCE & flags)) | ||
3310 | { | ||
3311 | deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, | ||
3312 | &deserialize_publish_file, | ||
3313 | ret); | ||
3314 | deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_SEARCH, | ||
3315 | &deserialize_search_file, | ||
3316 | ret); | ||
3317 | deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, | ||
3318 | &deserialize_download_file, | ||
3319 | ret); | ||
3320 | deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, | ||
3321 | &deserialize_unindex_file, | ||
3322 | ret); | ||
3323 | } | ||
3324 | return ret; | ||
3325 | } | ||
3326 | |||
3327 | |||
3328 | /** | ||
3329 | * Close our connection with the file-sharing service. | ||
3330 | * The callback given to #GNUNET_FS_start() will no longer be | ||
3331 | * called after this function returns. | ||
3332 | * This function MUST NOT be called from within the | ||
3333 | * callback itself. | ||
3334 | * | ||
3335 | * @param h handle that was returned from #GNUNET_FS_start() | ||
3336 | */ | ||
3337 | void | ||
3338 | GNUNET_FS_stop (struct GNUNET_FS_Handle *h) | ||
3339 | { | ||
3340 | while (NULL != h->top_head) | ||
3341 | h->top_head->ssf (h->top_head->ssf_cls); | ||
3342 | if (NULL != h->queue_job) | ||
3343 | GNUNET_SCHEDULER_cancel (h->queue_job); | ||
3344 | GNUNET_free (h->client_name); | ||
3345 | GNUNET_free (h); | ||
3346 | } | ||
3347 | |||
3348 | |||
3349 | /* end of fs_api.c */ | ||
diff --git a/src/fs/fs_api.h b/src/fs/fs_api.h deleted file mode 100644 index 050d5f46c..000000000 --- a/src/fs/fs_api.h +++ /dev/null | |||
@@ -1,1940 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_api.h | ||
23 | * @brief shared definitions for the FS library | ||
24 | * @author Igor Wronsky, Christian Grothoff | ||
25 | */ | ||
26 | #ifndef FS_API_H | ||
27 | #define FS_API_H | ||
28 | |||
29 | #include "gnunet_constants.h" | ||
30 | #include "gnunet_datastore_service.h" | ||
31 | #include "gnunet_dht_service.h" | ||
32 | #include "gnunet_fs_service.h" | ||
33 | #include "gnunet_block_lib.h" | ||
34 | #include "block_fs.h" | ||
35 | #include "fs.h" | ||
36 | |||
37 | /** | ||
38 | * Pick a multiple of 2 here to achieve 8-byte alignment! We also | ||
39 | * probably want DBlocks to have (roughly) the same size as IBlocks. | ||
40 | * With SHA-512, the optimal value is 32768 byte / 128 byte = 256 (128 | ||
41 | * byte = 2 * 512 bits). DO NOT CHANGE! | ||
42 | */ | ||
43 | #define CHK_PER_INODE 256 | ||
44 | |||
45 | /** | ||
46 | * Maximum size for a file to be considered for inlining in a | ||
47 | * directory. | ||
48 | */ | ||
49 | #define MAX_INLINE_SIZE 65536 | ||
50 | |||
51 | /** | ||
52 | * Name of the directory with top-level searches. | ||
53 | */ | ||
54 | #define GNUNET_FS_SYNC_PATH_MASTER_SEARCH "search" | ||
55 | |||
56 | /** | ||
57 | * Name of the directory with sub-searches (namespace-updates). | ||
58 | */ | ||
59 | #define GNUNET_FS_SYNC_PATH_CHILD_SEARCH "search-child" | ||
60 | |||
61 | /** | ||
62 | * Name of the directory with master downloads (not associated | ||
63 | * with search or part of another download). | ||
64 | */ | ||
65 | #define GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD "download" | ||
66 | |||
67 | /** | ||
68 | * Name of the directory with downloads that are part of another | ||
69 | * download or a search. | ||
70 | */ | ||
71 | #define GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD "download-child" | ||
72 | |||
73 | /** | ||
74 | * Name of the directory with publishing operations. | ||
75 | */ | ||
76 | #define GNUNET_FS_SYNC_PATH_MASTER_PUBLISH "publish" | ||
77 | |||
78 | /** | ||
79 | * Name of the directory with files that are being published | ||
80 | */ | ||
81 | #define GNUNET_FS_SYNC_PATH_FILE_INFO "publish-file" | ||
82 | |||
83 | /** | ||
84 | * Name of the directory with unindex operations. | ||
85 | */ | ||
86 | #define GNUNET_FS_SYNC_PATH_MASTER_UNINDEX "unindex" | ||
87 | |||
88 | |||
89 | /** | ||
90 | * @brief complete information needed | ||
91 | * to download a file. | ||
92 | */ | ||
93 | struct FileIdentifier | ||
94 | { | ||
95 | /** | ||
96 | * Total size of the file in bytes. (network byte order (!)) | ||
97 | */ | ||
98 | uint64_t file_length; | ||
99 | |||
100 | /** | ||
101 | * Query and key of the top GNUNET_EC_IBlock. | ||
102 | */ | ||
103 | struct ContentHashKey chk; | ||
104 | }; | ||
105 | |||
106 | |||
107 | /** | ||
108 | * Information about a file and its location | ||
109 | * (peer claiming to share the file). | ||
110 | */ | ||
111 | struct Location | ||
112 | { | ||
113 | /** | ||
114 | * Information about the shared file. | ||
115 | */ | ||
116 | struct FileIdentifier fi; | ||
117 | |||
118 | /** | ||
119 | * Identity of the peer sharing the file. | ||
120 | */ | ||
121 | struct GNUNET_PeerIdentity peer; | ||
122 | |||
123 | /** | ||
124 | * Time when this location URI expires. | ||
125 | */ | ||
126 | struct GNUNET_TIME_Absolute expirationTime; | ||
127 | |||
128 | /** | ||
129 | * Signature over the GNUNET_EC_FileIdentifier, | ||
130 | * peer identity and expiration time. | ||
131 | */ | ||
132 | struct GNUNET_CRYPTO_EddsaSignature contentSignature; | ||
133 | }; | ||
134 | |||
135 | /** | ||
136 | * Types of URIs. | ||
137 | */ | ||
138 | enum GNUNET_FS_UriType | ||
139 | { | ||
140 | /** | ||
141 | * Content-hash-key (simple file). | ||
142 | */ | ||
143 | GNUNET_FS_URI_CHK, | ||
144 | |||
145 | /** | ||
146 | * Signed key space (file in namespace). | ||
147 | */ | ||
148 | GNUNET_FS_URI_SKS, | ||
149 | |||
150 | /** | ||
151 | * Keyword search key (query with keywords). | ||
152 | */ | ||
153 | GNUNET_FS_URI_KSK, | ||
154 | |||
155 | /** | ||
156 | * Location (chk with identity of hosting peer). | ||
157 | */ | ||
158 | GNUNET_FS_URI_LOC | ||
159 | }; | ||
160 | |||
161 | |||
162 | /** | ||
163 | * A Universal Resource Identifier (URI), opaque. | ||
164 | */ | ||
165 | struct GNUNET_FS_Uri | ||
166 | { | ||
167 | /** | ||
168 | * Type of the URI. | ||
169 | */ | ||
170 | enum GNUNET_FS_UriType type; | ||
171 | |||
172 | union | ||
173 | { | ||
174 | struct | ||
175 | { | ||
176 | /** | ||
177 | * Keywords start with a '+' if they are mandatory (in which | ||
178 | * case the '+' is NOT part of the keyword) and with a simple | ||
179 | * space if they are optional (in which case the space is ALSO | ||
180 | * not part of the actual keyword). | ||
181 | * | ||
182 | * Double-quotes to protect spaces and %-encoding are NOT used | ||
183 | * internally (only in URI-strings). | ||
184 | */ | ||
185 | char **keywords; | ||
186 | |||
187 | /** | ||
188 | * Size of the keywords array. | ||
189 | */ | ||
190 | unsigned int keywordCount; | ||
191 | } ksk; | ||
192 | |||
193 | struct | ||
194 | { | ||
195 | /** | ||
196 | * Identifier of the namespace. | ||
197 | */ | ||
198 | struct GNUNET_CRYPTO_EcdsaPublicKey ns; | ||
199 | |||
200 | /** | ||
201 | * Human-readable identifier chosen for this entry in the | ||
202 | * namespace. | ||
203 | */ | ||
204 | char *identifier; | ||
205 | } sks; | ||
206 | |||
207 | /** | ||
208 | * Information needed to retrieve a file (content-hash-key | ||
209 | * plus file size). | ||
210 | */ | ||
211 | struct FileIdentifier chk; | ||
212 | |||
213 | /** | ||
214 | * Information needed to retrieve a file including signed | ||
215 | * location (identity of a peer) of the content. | ||
216 | */ | ||
217 | struct Location loc; | ||
218 | } data; | ||
219 | }; | ||
220 | |||
221 | |||
222 | /** | ||
223 | * Information for a file or directory that is | ||
224 | * about to be published. | ||
225 | */ | ||
226 | struct GNUNET_FS_FileInformation | ||
227 | { | ||
228 | /** | ||
229 | * Files in a directory are kept as a linked list. | ||
230 | */ | ||
231 | struct GNUNET_FS_FileInformation *next; | ||
232 | |||
233 | /** | ||
234 | * If this is a file in a directory, "dir" refers to | ||
235 | * the directory; otherwise NULL. | ||
236 | */ | ||
237 | struct GNUNET_FS_FileInformation *dir; | ||
238 | |||
239 | /** | ||
240 | * Handle to the master context. | ||
241 | */ | ||
242 | struct GNUNET_FS_Handle *h; | ||
243 | |||
244 | /** | ||
245 | * Pointer kept for the client. | ||
246 | */ | ||
247 | void *client_info; | ||
248 | |||
249 | /** | ||
250 | * Metadata to use for the file. | ||
251 | */ | ||
252 | struct GNUNET_CONTAINER_MetaData *meta; | ||
253 | |||
254 | /** | ||
255 | * Keywords to use for KBlocks. | ||
256 | */ | ||
257 | struct GNUNET_FS_Uri *keywords; | ||
258 | |||
259 | /** | ||
260 | * CHK for this file or directory. NULL if | ||
261 | * we have not yet computed it. | ||
262 | */ | ||
263 | struct GNUNET_FS_Uri *chk_uri; | ||
264 | |||
265 | /** | ||
266 | * SKS URI for this file or directory. NULL if | ||
267 | * we have not yet computed it. | ||
268 | */ | ||
269 | struct GNUNET_FS_Uri *sks_uri; | ||
270 | |||
271 | /** | ||
272 | * Block options for the file. | ||
273 | */ | ||
274 | struct GNUNET_FS_BlockOptions bo; | ||
275 | |||
276 | /** | ||
277 | * At what time did we start this upload? | ||
278 | */ | ||
279 | struct GNUNET_TIME_Absolute start_time; | ||
280 | |||
281 | /** | ||
282 | * Under what filename is this struct serialized | ||
283 | * (for operational persistence). Should be determined | ||
284 | * using 'mktemp'. | ||
285 | */ | ||
286 | char *serialization; | ||
287 | |||
288 | /** | ||
289 | * Encoder being used to publish this file. | ||
290 | */ | ||
291 | struct GNUNET_FS_TreeEncoder *te; | ||
292 | |||
293 | /** | ||
294 | * Error message (non-NULL if this operation failed). | ||
295 | */ | ||
296 | char *emsg; | ||
297 | |||
298 | /** | ||
299 | * Name of the file or directory (must be an absolute path). | ||
300 | */ | ||
301 | char *filename; | ||
302 | |||
303 | /** | ||
304 | * Data describing either the file or the directory. | ||
305 | */ | ||
306 | union | ||
307 | { | ||
308 | /** | ||
309 | * Data for a file. | ||
310 | */ | ||
311 | struct | ||
312 | { | ||
313 | /** | ||
314 | * Function that can be used to read the data for the file. | ||
315 | */ | ||
316 | GNUNET_FS_DataReader reader; | ||
317 | |||
318 | /** | ||
319 | * Closure for reader. | ||
320 | */ | ||
321 | void *reader_cls; | ||
322 | |||
323 | /** | ||
324 | * If this file is being indexed, this value is set to the hash | ||
325 | * over the entire file (when the indexing process is started). | ||
326 | * Otherwise this field is not used. | ||
327 | */ | ||
328 | struct GNUNET_HashCode file_id; | ||
329 | |||
330 | /** | ||
331 | * Size of the file (in bytes). | ||
332 | */ | ||
333 | uint64_t file_size; | ||
334 | |||
335 | /** | ||
336 | * Should the file be indexed or inserted? | ||
337 | */ | ||
338 | int do_index; | ||
339 | |||
340 | /** | ||
341 | * Is "file_id" already valid? Set to #GNUNET_YES once the hash | ||
342 | * has been calculated. | ||
343 | */ | ||
344 | int have_hash; | ||
345 | |||
346 | /** | ||
347 | * Has the service confirmed our INDEX_START request? | ||
348 | * #GNUNET_YES if this step has been completed. | ||
349 | */ | ||
350 | int index_start_confirmed; | ||
351 | } file; | ||
352 | |||
353 | /** | ||
354 | * Data for a directory. | ||
355 | */ | ||
356 | struct | ||
357 | { | ||
358 | /** | ||
359 | * Linked list of entries in the directory. | ||
360 | */ | ||
361 | struct GNUNET_FS_FileInformation *entries; | ||
362 | |||
363 | /** | ||
364 | * Size of the directory itself (in bytes); 0 if the | ||
365 | * size has not yet been calculated. | ||
366 | */ | ||
367 | size_t dir_size; | ||
368 | |||
369 | /** | ||
370 | * Pointer to the data for the directory (or NULL if not | ||
371 | * available). | ||
372 | */ | ||
373 | void *dir_data; | ||
374 | |||
375 | /** | ||
376 | * How much of the directory have we published (relative to @e contents_size). | ||
377 | */ | ||
378 | uint64_t contents_completed; | ||
379 | |||
380 | /** | ||
381 | * Sum of all of the sizes of all of the files in the directory. | ||
382 | */ | ||
383 | uint64_t contents_size; | ||
384 | } dir; | ||
385 | } data; | ||
386 | |||
387 | /** | ||
388 | * Is this struct for a file or directory? | ||
389 | */ | ||
390 | int is_directory; | ||
391 | |||
392 | /** | ||
393 | * Are we done publishing this file? | ||
394 | */ | ||
395 | int is_published; | ||
396 | }; | ||
397 | |||
398 | |||
399 | /** | ||
400 | * Priorities for the queue. | ||
401 | */ | ||
402 | enum GNUNET_FS_QueuePriority | ||
403 | { | ||
404 | /** | ||
405 | * This is a probe (low priority). | ||
406 | */ | ||
407 | GNUNET_FS_QUEUE_PRIORITY_PROBE, | ||
408 | |||
409 | /** | ||
410 | * Default priority. | ||
411 | */ | ||
412 | GNUNET_FS_QUEUE_PRIORITY_NORMAL | ||
413 | }; | ||
414 | |||
415 | |||
416 | /** | ||
417 | * Entry in the job queue. | ||
418 | */ | ||
419 | struct GNUNET_FS_QueueEntry | ||
420 | { | ||
421 | /** | ||
422 | * This is a linked list. | ||
423 | */ | ||
424 | struct GNUNET_FS_QueueEntry *next; | ||
425 | |||
426 | /** | ||
427 | * This is a linked list. | ||
428 | */ | ||
429 | struct GNUNET_FS_QueueEntry *prev; | ||
430 | |||
431 | /** | ||
432 | * Function to call when the job is started. | ||
433 | */ | ||
434 | GNUNET_SCHEDULER_TaskCallback start; | ||
435 | |||
436 | /** | ||
437 | * Function to call when the job needs to stop (or is done / dequeued). | ||
438 | */ | ||
439 | GNUNET_SCHEDULER_TaskCallback stop; | ||
440 | |||
441 | /** | ||
442 | * Closure for start and stop. | ||
443 | */ | ||
444 | void *cls; | ||
445 | |||
446 | /** | ||
447 | * Handle to FS primary context. | ||
448 | */ | ||
449 | struct GNUNET_FS_Handle *h; | ||
450 | |||
451 | /** | ||
452 | * Message queue handle, or NULL if job is not running. | ||
453 | */ | ||
454 | struct GNUNET_MQ_Handle *mq; | ||
455 | |||
456 | /** | ||
457 | * Time the job was originally queued. | ||
458 | */ | ||
459 | struct GNUNET_TIME_Absolute queue_time; | ||
460 | |||
461 | /** | ||
462 | * Time the job was started last. | ||
463 | */ | ||
464 | struct GNUNET_TIME_Absolute start_time; | ||
465 | |||
466 | /** | ||
467 | * Total amount of time the job has been running (except for the | ||
468 | * current run). | ||
469 | */ | ||
470 | struct GNUNET_TIME_Relative run_time; | ||
471 | |||
472 | /** | ||
473 | * How many blocks do the active downloads have? | ||
474 | */ | ||
475 | unsigned int blocks; | ||
476 | |||
477 | /** | ||
478 | * How important is this download? | ||
479 | */ | ||
480 | enum GNUNET_FS_QueuePriority priority; | ||
481 | |||
482 | /** | ||
483 | * How often have we (re)started this download? | ||
484 | */ | ||
485 | unsigned int start_times; | ||
486 | |||
487 | /** | ||
488 | * #GNUNET_YES if the job is active now. | ||
489 | */ | ||
490 | int active; | ||
491 | }; | ||
492 | |||
493 | |||
494 | /** | ||
495 | * Information we store for each search result. | ||
496 | */ | ||
497 | struct GNUNET_FS_SearchResult | ||
498 | { | ||
499 | /** | ||
500 | * File-sharing context this result belongs to. | ||
501 | */ | ||
502 | struct GNUNET_FS_Handle *h; | ||
503 | |||
504 | /** | ||
505 | * Kept in a DLL while probing. | ||
506 | */ | ||
507 | struct GNUNET_FS_SearchResult *next; | ||
508 | |||
509 | /** | ||
510 | * Kept in a DLL while probing. | ||
511 | */ | ||
512 | struct GNUNET_FS_SearchResult *prev; | ||
513 | |||
514 | /** | ||
515 | * Search context this result belongs to; can be NULL | ||
516 | * for probes that come from a directory result. | ||
517 | */ | ||
518 | struct GNUNET_FS_SearchContext *sc; | ||
519 | |||
520 | /** | ||
521 | * URI to which this search result refers to. | ||
522 | */ | ||
523 | struct GNUNET_FS_Uri *uri; | ||
524 | |||
525 | /** | ||
526 | * Metadata for the search result. | ||
527 | */ | ||
528 | struct GNUNET_CONTAINER_MetaData *meta; | ||
529 | |||
530 | /** | ||
531 | * Client info for this search result. | ||
532 | */ | ||
533 | void *client_info; | ||
534 | |||
535 | /** | ||
536 | * ID of a job that is currently probing this results' availability | ||
537 | * (NULL if we are not currently probing). | ||
538 | */ | ||
539 | struct GNUNET_FS_DownloadContext *probe_ctx; | ||
540 | |||
541 | /** | ||
542 | * ID of an associated download based on this search result (or | ||
543 | * NULL for none). | ||
544 | */ | ||
545 | struct GNUNET_FS_DownloadContext *download; | ||
546 | |||
547 | /** | ||
548 | * If this search result triggered an update search, this field | ||
549 | * links to the update search. | ||
550 | */ | ||
551 | struct GNUNET_FS_SearchContext *update_search; | ||
552 | |||
553 | /** | ||
554 | * Name under which this search result is stored on disk. | ||
555 | */ | ||
556 | char *serialization; | ||
557 | |||
558 | /** | ||
559 | * Bitmap that specifies precisely which keywords have been matched already. | ||
560 | */ | ||
561 | uint8_t *keyword_bitmap; | ||
562 | |||
563 | /** | ||
564 | * Key for the search result based on the URI. | ||
565 | */ | ||
566 | struct GNUNET_HashCode key; | ||
567 | |||
568 | /** | ||
569 | * ID of the task that will clean up the probe_ctx should it not | ||
570 | * complete on time (and that will need to be cancelled if we clean | ||
571 | * up the search result before then). | ||
572 | */ | ||
573 | struct GNUNET_SCHEDULER_Task *probe_cancel_task; | ||
574 | |||
575 | /** | ||
576 | * When did the current probe become active? | ||
577 | */ | ||
578 | struct GNUNET_TIME_Absolute probe_active_time; | ||
579 | |||
580 | /** | ||
581 | * How much longer should we run the current probe before giving up? | ||
582 | */ | ||
583 | struct GNUNET_TIME_Relative remaining_probe_time; | ||
584 | |||
585 | /** | ||
586 | * Anonymity level to use for probes using this search result. | ||
587 | */ | ||
588 | uint32_t anonymity; | ||
589 | |||
590 | /** | ||
591 | * Number of mandatory keywords for which we have NOT yet found the | ||
592 | * search result; when this value hits zero, the search result is | ||
593 | * given to the callback. | ||
594 | */ | ||
595 | uint32_t mandatory_missing; | ||
596 | |||
597 | /** | ||
598 | * Number of optional keywords under which this result was also | ||
599 | * found. | ||
600 | */ | ||
601 | uint32_t optional_support; | ||
602 | |||
603 | /** | ||
604 | * Number of availability tests that have succeeded for this result. | ||
605 | */ | ||
606 | uint32_t availability_success; | ||
607 | |||
608 | /** | ||
609 | * Number of availability trials that we have performed for this | ||
610 | * search result. | ||
611 | */ | ||
612 | uint32_t availability_trials; | ||
613 | }; | ||
614 | |||
615 | |||
616 | /** | ||
617 | * Add a job to the queue. | ||
618 | * | ||
619 | * @param h handle to the overall FS state | ||
620 | * @param start function to call to begin the job | ||
621 | * @param stop function to call to pause the job, or on dequeue (if the job was running) | ||
622 | * @param cls closure for start and stop | ||
623 | * @param blocks number of blocks this download has | ||
624 | * @param priority how important is this download | ||
625 | * @return queue handle | ||
626 | */ | ||
627 | struct GNUNET_FS_QueueEntry * | ||
628 | GNUNET_FS_queue_ (struct GNUNET_FS_Handle *h, | ||
629 | GNUNET_SCHEDULER_TaskCallback start, | ||
630 | GNUNET_SCHEDULER_TaskCallback stop, | ||
631 | void *cls, | ||
632 | unsigned int blocks, | ||
633 | enum GNUNET_FS_QueuePriority priority); | ||
634 | |||
635 | |||
636 | /** | ||
637 | * Dequeue a job from the queue. | ||
638 | * | ||
639 | * @param qe handle for the job | ||
640 | */ | ||
641 | void | ||
642 | GNUNET_FS_dequeue_ (struct GNUNET_FS_QueueEntry *qe); | ||
643 | |||
644 | |||
645 | /** | ||
646 | * Function that provides data by reading from a file. | ||
647 | * | ||
648 | * @param cls closure (points to the file information) | ||
649 | * @param offset offset to read from; it is possible | ||
650 | * that the caller might need to go backwards | ||
651 | * a bit at times | ||
652 | * @param max maximum number of bytes that should be | ||
653 | * copied to @a buf; readers are not allowed | ||
654 | * to provide less data unless there is an error; | ||
655 | * a value of "0" will be used at the end to allow | ||
656 | * the reader to clean up its internal state | ||
657 | * @param buf where the reader should write the data | ||
658 | * @param emsg location for the reader to store an error message | ||
659 | * @return number of bytes written, usually "max", 0 on error | ||
660 | */ | ||
661 | size_t | ||
662 | GNUNET_FS_data_reader_file_ (void *cls, | ||
663 | uint64_t offset, | ||
664 | size_t max, | ||
665 | void *buf, | ||
666 | char **emsg); | ||
667 | |||
668 | |||
669 | /** | ||
670 | * Create the closure for the #GNUNET_FS_data_reader_file_() callback. | ||
671 | * | ||
672 | * @param filename file to read | ||
673 | * @return closure to use | ||
674 | */ | ||
675 | void * | ||
676 | GNUNET_FS_make_file_reader_context_ (const char *filename); | ||
677 | |||
678 | |||
679 | /** | ||
680 | * Function that provides data by copying from a buffer. | ||
681 | * | ||
682 | * @param cls closure (points to the buffer) | ||
683 | * @param offset offset to read from; it is possible | ||
684 | * that the caller might need to go backwards | ||
685 | * a bit at times | ||
686 | * @param max maximum number of bytes that should be | ||
687 | * copied to @a buf; readers are not allowed | ||
688 | * to provide less data unless there is an error; | ||
689 | * a value of "0" will be used at the end to allow | ||
690 | * the reader to clean up its internal state | ||
691 | * @param buf where the reader should write the data | ||
692 | * @param emsg location for the reader to store an error message | ||
693 | * @return number of bytes written, usually @a max, 0 on error | ||
694 | */ | ||
695 | size_t | ||
696 | GNUNET_FS_data_reader_copy_ (void *cls, | ||
697 | uint64_t offset, | ||
698 | size_t max, | ||
699 | void *buf, | ||
700 | char **emsg); | ||
701 | |||
702 | |||
703 | /** | ||
704 | * Notification of FS that a search probe has made progress. | ||
705 | * This function is used INSTEAD of the client's event handler | ||
706 | * for downloads where the #GNUNET_FS_DOWNLOAD_IS_PROBE flag is set. | ||
707 | * | ||
708 | * @param cls closure, always NULL (!), actual closure | ||
709 | * is in the client-context of the info struct | ||
710 | * @param info details about the event, specifying the event type | ||
711 | * and various bits about the event | ||
712 | * @return client-context (for the next progress call | ||
713 | * for this operation; should be set to NULL for | ||
714 | * SUSPEND and STOPPED events). The value returned | ||
715 | * will be passed to future callbacks in the respective | ||
716 | * field in the `struct GNUNET_FS_ProgressInfo`. | ||
717 | */ | ||
718 | void * | ||
719 | GNUNET_FS_search_probe_progress_ (void *cls, | ||
720 | const struct GNUNET_FS_ProgressInfo *info); | ||
721 | |||
722 | |||
723 | /** | ||
724 | * Main function that performs the upload. | ||
725 | * | ||
726 | * @param cls `struct GNUNET_FS_PublishContext` identifies the upload | ||
727 | */ | ||
728 | void | ||
729 | GNUNET_FS_publish_main_ (void *cls); | ||
730 | |||
731 | |||
732 | /** | ||
733 | * Function called once the hash of the file | ||
734 | * that is being unindexed has been computed. | ||
735 | * | ||
736 | * @param cls closure, unindex context | ||
737 | * @param file_id computed hash, NULL on error | ||
738 | */ | ||
739 | void | ||
740 | GNUNET_FS_unindex_process_hash_ (void *cls, | ||
741 | const struct GNUNET_HashCode *file_id); | ||
742 | |||
743 | |||
744 | /** | ||
745 | * Extract the keywords for KBlock removal | ||
746 | * | ||
747 | * @param uc context for the unindex operation. | ||
748 | */ | ||
749 | void | ||
750 | GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc); | ||
751 | |||
752 | |||
753 | /** | ||
754 | * If necessary, connect to the datastore and remove the KBlocks. | ||
755 | * | ||
756 | * @param uc context for the unindex operation. | ||
757 | */ | ||
758 | void | ||
759 | GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc); | ||
760 | |||
761 | |||
762 | /** | ||
763 | * Fill in all of the generic fields for a publish event and call the | ||
764 | * callback. | ||
765 | * | ||
766 | * @param pi structure to fill in | ||
767 | * @param pc overall publishing context | ||
768 | * @param p file information for the file being published | ||
769 | * @param offset where in the file are we so far | ||
770 | * @return value returned from callback | ||
771 | */ | ||
772 | void * | ||
773 | GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
774 | struct GNUNET_FS_PublishContext *pc, | ||
775 | const struct GNUNET_FS_FileInformation *p, | ||
776 | uint64_t offset); | ||
777 | |||
778 | |||
779 | /** | ||
780 | * Fill in all of the generic fields for a download event and call the | ||
781 | * callback. | ||
782 | * | ||
783 | * @param pi structure to fill in | ||
784 | * @param dc overall download context | ||
785 | */ | ||
786 | void | ||
787 | GNUNET_FS_download_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
788 | struct GNUNET_FS_DownloadContext *dc); | ||
789 | |||
790 | |||
791 | /** | ||
792 | * Task that creates the initial (top-level) download | ||
793 | * request for the file. | ||
794 | * | ||
795 | * @param cls the 'struct GNUNET_FS_DownloadContext' | ||
796 | */ | ||
797 | void | ||
798 | GNUNET_FS_download_start_task_ (void *cls); | ||
799 | |||
800 | |||
801 | /** | ||
802 | * Fill in all of the generic fields for | ||
803 | * an unindex event and call the callback. | ||
804 | * | ||
805 | * @param pi structure to fill in | ||
806 | * @param uc overall unindex context | ||
807 | * @param offset where we are in the file (for progress) | ||
808 | */ | ||
809 | void | ||
810 | GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
811 | struct GNUNET_FS_UnindexContext *uc, | ||
812 | uint64_t offset); | ||
813 | |||
814 | /** | ||
815 | * Fill in all of the generic fields for a search event and | ||
816 | * call the callback. | ||
817 | * | ||
818 | * @param pi structure to fill in | ||
819 | * @param h file-sharing handle | ||
820 | * @param sc overall search context | ||
821 | * @return value returned by the callback | ||
822 | */ | ||
823 | void * | ||
824 | GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
825 | struct GNUNET_FS_Handle *h, | ||
826 | struct GNUNET_FS_SearchContext *sc); | ||
827 | |||
828 | |||
829 | /** | ||
830 | * Connect to the datastore and remove the blocks. | ||
831 | * | ||
832 | * @param uc context for the unindex operation. | ||
833 | */ | ||
834 | void | ||
835 | GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc); | ||
836 | |||
837 | /** | ||
838 | * Build the request and actually initiate the search using the | ||
839 | * GNUnet FS service. | ||
840 | * | ||
841 | * @param sc search context | ||
842 | * @return GNUNET_OK on success, GNUNET_SYSERR on error | ||
843 | */ | ||
844 | int | ||
845 | GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc); | ||
846 | |||
847 | /** | ||
848 | * Start the downloading process (by entering the queue). | ||
849 | * | ||
850 | * @param dc our download context | ||
851 | */ | ||
852 | void | ||
853 | GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc); | ||
854 | |||
855 | |||
856 | /** | ||
857 | * Start download probes for the given search result. | ||
858 | * | ||
859 | * @param sr the search result | ||
860 | */ | ||
861 | void | ||
862 | GNUNET_FS_search_start_probe_ (struct GNUNET_FS_SearchResult *sr); | ||
863 | |||
864 | |||
865 | /** | ||
866 | * Remove serialization/deserialization file from disk. | ||
867 | * | ||
868 | * @param h master context | ||
869 | * @param ext component of the path | ||
870 | * @param ent entity identifier | ||
871 | */ | ||
872 | void | ||
873 | GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h, | ||
874 | const char *ext, | ||
875 | const char *ent); | ||
876 | |||
877 | |||
878 | /** | ||
879 | * Remove serialization/deserialization directory from disk. | ||
880 | * | ||
881 | * @param h master context | ||
882 | * @param ext component of the path | ||
883 | * @param uni unique name of parent | ||
884 | */ | ||
885 | void | ||
886 | GNUNET_FS_remove_sync_dir_ (struct GNUNET_FS_Handle *h, | ||
887 | const char *ext, | ||
888 | const char *uni); | ||
889 | |||
890 | |||
891 | /** | ||
892 | * Synchronize this file-information struct with its mirror | ||
893 | * on disk. Note that all internal FS-operations that change | ||
894 | * file information data should already call "sync" internally, | ||
895 | * so this function is likely not useful for clients. | ||
896 | * | ||
897 | * @param fi the struct to sync | ||
898 | */ | ||
899 | void | ||
900 | GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *f); | ||
901 | |||
902 | |||
903 | /** | ||
904 | * Synchronize this publishing struct with its mirror | ||
905 | * on disk. Note that all internal FS-operations that change | ||
906 | * publishing structs should already call "sync" internally, | ||
907 | * so this function is likely not useful for clients. | ||
908 | * | ||
909 | * @param pc the struct to sync | ||
910 | */ | ||
911 | void | ||
912 | GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc); | ||
913 | |||
914 | |||
915 | /** | ||
916 | * Synchronize this unindex struct with its mirror | ||
917 | * on disk. Note that all internal FS-operations that change | ||
918 | * publishing structs should already call "sync" internally, | ||
919 | * so this function is likely not useful for clients. | ||
920 | * | ||
921 | * @param uc the struct to sync | ||
922 | */ | ||
923 | void | ||
924 | GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc); | ||
925 | |||
926 | |||
927 | /** | ||
928 | * Synchronize this search struct with its mirror | ||
929 | * on disk. Note that all internal FS-operations that change | ||
930 | * publishing structs should already call "sync" internally, | ||
931 | * so this function is likely not useful for clients. | ||
932 | * | ||
933 | * @param sc the struct to sync | ||
934 | */ | ||
935 | void | ||
936 | GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc); | ||
937 | |||
938 | |||
939 | /** | ||
940 | * Synchronize this search result with its mirror | ||
941 | * on disk. Note that all internal FS-operations that change | ||
942 | * publishing structs should already call "sync" internally, | ||
943 | * so this function is likely not useful for clients. | ||
944 | * | ||
945 | * @param sr the struct to sync | ||
946 | */ | ||
947 | void | ||
948 | GNUNET_FS_search_result_sync_ (struct GNUNET_FS_SearchResult *sr); | ||
949 | |||
950 | |||
951 | /** | ||
952 | * Synchronize this download struct with its mirror | ||
953 | * on disk. Note that all internal FS-operations that change | ||
954 | * publishing structs should already call "sync" internally, | ||
955 | * so this function is likely not useful for clients. | ||
956 | * | ||
957 | * @param dc the struct to sync | ||
958 | */ | ||
959 | void | ||
960 | GNUNET_FS_download_sync_ (struct GNUNET_FS_DownloadContext *dc); | ||
961 | |||
962 | |||
963 | /** | ||
964 | * Create SUSPEND event for the given publish operation | ||
965 | * and then clean up our state (without stop signal). | ||
966 | * | ||
967 | * @param cls the `struct GNUNET_FS_PublishContext` to signal for | ||
968 | */ | ||
969 | void | ||
970 | GNUNET_FS_publish_signal_suspend_ (void *cls); | ||
971 | |||
972 | |||
973 | /** | ||
974 | * Create SUSPEND event for the given search operation | ||
975 | * and then clean up our state (without stop signal). | ||
976 | * | ||
977 | * @param cls the 'struct GNUNET_FS_SearchContext' to signal for | ||
978 | */ | ||
979 | void | ||
980 | GNUNET_FS_search_signal_suspend_ (void *cls); | ||
981 | |||
982 | |||
983 | /** | ||
984 | * Create SUSPEND event for the given download operation | ||
985 | * and then clean up our state (without stop signal). | ||
986 | * | ||
987 | * @param cls the `struct GNUNET_FS_DownloadContext` to signal for | ||
988 | */ | ||
989 | void | ||
990 | GNUNET_FS_download_signal_suspend_ (void *cls); | ||
991 | |||
992 | |||
993 | /** | ||
994 | * Create SUSPEND event for the given unindex operation | ||
995 | * and then clean up our state (without stop signal). | ||
996 | * | ||
997 | * @param cls the `struct GNUNET_FS_UnindexContext` to signal for | ||
998 | */ | ||
999 | void | ||
1000 | GNUNET_FS_unindex_signal_suspend_ (void *cls); | ||
1001 | |||
1002 | |||
1003 | /** | ||
1004 | * Function signature of the functions that can be called | ||
1005 | * to trigger suspend signals and clean-up for top-level | ||
1006 | * activities. | ||
1007 | * | ||
1008 | * @param cls closure | ||
1009 | */ | ||
1010 | typedef void (*SuspendSignalFunction) (void *cls); | ||
1011 | |||
1012 | /** | ||
1013 | * We track all of the top-level activities of FS | ||
1014 | * so that we can signal 'suspend' on shutdown. | ||
1015 | */ | ||
1016 | struct TopLevelActivity | ||
1017 | { | ||
1018 | /** | ||
1019 | * This is a doubly-linked list. | ||
1020 | */ | ||
1021 | struct TopLevelActivity *next; | ||
1022 | |||
1023 | /** | ||
1024 | * This is a doubly-linked list. | ||
1025 | */ | ||
1026 | struct TopLevelActivity *prev; | ||
1027 | |||
1028 | /** | ||
1029 | * Function to call for suspend-signalling and clean up. | ||
1030 | */ | ||
1031 | SuspendSignalFunction ssf; | ||
1032 | |||
1033 | /** | ||
1034 | * Closure for 'ssf' (some struct GNUNET_FS_XXXHandle*) | ||
1035 | */ | ||
1036 | void *ssf_cls; | ||
1037 | }; | ||
1038 | |||
1039 | |||
1040 | /** | ||
1041 | * Create a top-level activity entry. | ||
1042 | * | ||
1043 | * @param h global fs handle | ||
1044 | * @param ssf suspend signal function to use | ||
1045 | * @param ssf_cls closure for @a ssf | ||
1046 | * @return fresh top-level activity handle | ||
1047 | */ | ||
1048 | struct TopLevelActivity * | ||
1049 | GNUNET_FS_make_top (struct GNUNET_FS_Handle *h, | ||
1050 | SuspendSignalFunction ssf, | ||
1051 | void *ssf_cls); | ||
1052 | |||
1053 | |||
1054 | /** | ||
1055 | * Destroy a top-level activity entry. | ||
1056 | * | ||
1057 | * @param h global fs handle | ||
1058 | * @param top top level activity entry | ||
1059 | */ | ||
1060 | void | ||
1061 | GNUNET_FS_end_top (struct GNUNET_FS_Handle *h, | ||
1062 | struct TopLevelActivity *top); | ||
1063 | |||
1064 | |||
1065 | /** | ||
1066 | * Master context for most FS operations. | ||
1067 | */ | ||
1068 | struct GNUNET_FS_Handle | ||
1069 | { | ||
1070 | /** | ||
1071 | * Configuration to use. | ||
1072 | */ | ||
1073 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
1074 | |||
1075 | /** | ||
1076 | * Name of our client. | ||
1077 | */ | ||
1078 | char *client_name; | ||
1079 | |||
1080 | /** | ||
1081 | * Function to call with updates on our progress. | ||
1082 | */ | ||
1083 | GNUNET_FS_ProgressCallback upcb; | ||
1084 | |||
1085 | /** | ||
1086 | * Closure for upcb. | ||
1087 | */ | ||
1088 | void *upcb_cls; | ||
1089 | |||
1090 | /** | ||
1091 | * Head of DLL of top-level activities. | ||
1092 | */ | ||
1093 | struct TopLevelActivity *top_head; | ||
1094 | |||
1095 | /** | ||
1096 | * Tail of DLL of top-level activities. | ||
1097 | */ | ||
1098 | struct TopLevelActivity *top_tail; | ||
1099 | |||
1100 | /** | ||
1101 | * Head of DLL of running jobs. | ||
1102 | */ | ||
1103 | struct GNUNET_FS_QueueEntry *running_head; | ||
1104 | |||
1105 | /** | ||
1106 | * Tail of DLL of running jobs. | ||
1107 | */ | ||
1108 | struct GNUNET_FS_QueueEntry *running_tail; | ||
1109 | |||
1110 | /** | ||
1111 | * Head of DLL of pending jobs. | ||
1112 | */ | ||
1113 | struct GNUNET_FS_QueueEntry *pending_head; | ||
1114 | |||
1115 | /** | ||
1116 | * Tail of DLL of pending jobs. | ||
1117 | */ | ||
1118 | struct GNUNET_FS_QueueEntry *pending_tail; | ||
1119 | |||
1120 | /** | ||
1121 | * Head of active probes. | ||
1122 | */ | ||
1123 | struct GNUNET_FS_SearchResult *probes_head; | ||
1124 | |||
1125 | /** | ||
1126 | * Tail of active probes. | ||
1127 | */ | ||
1128 | struct GNUNET_FS_SearchResult *probes_tail; | ||
1129 | |||
1130 | /** | ||
1131 | * Task that processes the jobs in the running and pending queues | ||
1132 | * (and moves jobs around as needed). | ||
1133 | */ | ||
1134 | struct GNUNET_SCHEDULER_Task *queue_job; | ||
1135 | |||
1136 | /** | ||
1137 | * Task we use to report periodically to the application that | ||
1138 | * certain search probes (from @e probes_head) are still running. | ||
1139 | */ | ||
1140 | struct GNUNET_SCHEDULER_Task *probe_ping_task; | ||
1141 | |||
1142 | /** | ||
1143 | * Average time we take for a single request to be satisfied. | ||
1144 | * FIXME: not yet calculated properly... | ||
1145 | */ | ||
1146 | struct GNUNET_TIME_Relative avg_block_latency; | ||
1147 | |||
1148 | /** | ||
1149 | * How many actual downloads do we have running right now? | ||
1150 | */ | ||
1151 | unsigned int active_downloads; | ||
1152 | |||
1153 | /** | ||
1154 | * How many blocks do the active downloads have? | ||
1155 | */ | ||
1156 | unsigned int active_blocks; | ||
1157 | |||
1158 | /** | ||
1159 | * General flags. | ||
1160 | */ | ||
1161 | enum GNUNET_FS_Flags flags; | ||
1162 | |||
1163 | /** | ||
1164 | * Maximum number of parallel downloads. | ||
1165 | */ | ||
1166 | unsigned int max_parallel_downloads; | ||
1167 | |||
1168 | /** | ||
1169 | * Maximum number of parallel requests. | ||
1170 | */ | ||
1171 | unsigned int max_parallel_requests; | ||
1172 | }; | ||
1173 | |||
1174 | |||
1175 | /** | ||
1176 | * Handle for controlling a publication process. | ||
1177 | */ | ||
1178 | struct GNUNET_FS_PublishContext | ||
1179 | { | ||
1180 | /** | ||
1181 | * Handle to the global fs context. | ||
1182 | */ | ||
1183 | struct GNUNET_FS_Handle *h; | ||
1184 | |||
1185 | /** | ||
1186 | * Our top-level activity entry (if we are top-level, otherwise NULL). | ||
1187 | */ | ||
1188 | struct TopLevelActivity *top; | ||
1189 | |||
1190 | /** | ||
1191 | * File-structure that is being shared. | ||
1192 | */ | ||
1193 | struct GNUNET_FS_FileInformation *fi; | ||
1194 | |||
1195 | /** | ||
1196 | * Namespace that we are publishing in, NULL if we have no namespace. | ||
1197 | */ | ||
1198 | struct GNUNET_CRYPTO_EcdsaPrivateKey *ns; | ||
1199 | |||
1200 | /** | ||
1201 | * ID of the content in the namespace, NULL if we have no namespace. | ||
1202 | */ | ||
1203 | char *nid; | ||
1204 | |||
1205 | /** | ||
1206 | * ID for future updates, NULL if we have no namespace or no updates. | ||
1207 | */ | ||
1208 | char *nuid; | ||
1209 | |||
1210 | /** | ||
1211 | * Filename used for serializing information about this operation | ||
1212 | * (should be determined using 'mktemp'). | ||
1213 | */ | ||
1214 | char *serialization; | ||
1215 | |||
1216 | /** | ||
1217 | * Our own message queue for the FS service; only briefly used when | ||
1218 | * we start to index a file, otherwise NULL. | ||
1219 | */ | ||
1220 | struct GNUNET_MQ_Handle *mq; | ||
1221 | |||
1222 | /** | ||
1223 | * Current position in the file-tree for the upload. | ||
1224 | */ | ||
1225 | struct GNUNET_FS_FileInformation *fi_pos; | ||
1226 | |||
1227 | /** | ||
1228 | * Non-null if we are currently hashing a file. | ||
1229 | */ | ||
1230 | struct GNUNET_CRYPTO_FileHashContext *fhc; | ||
1231 | |||
1232 | /** | ||
1233 | * Connection to the datastore service. | ||
1234 | */ | ||
1235 | struct GNUNET_DATASTORE_Handle *dsh; | ||
1236 | |||
1237 | /** | ||
1238 | * Queue entry for reservation/unreservation. | ||
1239 | */ | ||
1240 | struct GNUNET_DATASTORE_QueueEntry *qre; | ||
1241 | |||
1242 | /** | ||
1243 | * Context for SKS publishing operation that is part of this publishing operation | ||
1244 | * (NULL if not active). | ||
1245 | */ | ||
1246 | struct GNUNET_FS_PublishSksContext *sks_pc; | ||
1247 | |||
1248 | /** | ||
1249 | * Context for KSK publishing operation that is part of this publishing operation | ||
1250 | * (NULL if not active). | ||
1251 | */ | ||
1252 | struct GNUNET_FS_PublishKskContext *ksk_pc; | ||
1253 | |||
1254 | /** | ||
1255 | * ID of the task performing the upload. NO_TASK if the upload has | ||
1256 | * completed. | ||
1257 | */ | ||
1258 | struct GNUNET_SCHEDULER_Task *upload_task; | ||
1259 | |||
1260 | /** | ||
1261 | * Storage space to reserve for the operation. | ||
1262 | */ | ||
1263 | uint64_t reserve_space; | ||
1264 | |||
1265 | /** | ||
1266 | * Overall number of entries to reserve for the | ||
1267 | * publish operation. | ||
1268 | */ | ||
1269 | uint32_t reserve_entries; | ||
1270 | |||
1271 | /** | ||
1272 | * Options for publishing. | ||
1273 | */ | ||
1274 | enum GNUNET_FS_PublishOptions options; | ||
1275 | |||
1276 | /** | ||
1277 | * Space reservation ID with datastore service | ||
1278 | * for this upload. | ||
1279 | */ | ||
1280 | int rid; | ||
1281 | |||
1282 | /** | ||
1283 | * Set to #GNUNET_YES if we were able to publish any block. | ||
1284 | * (and thus unindexing on error might make sense). | ||
1285 | */ | ||
1286 | int any_done; | ||
1287 | |||
1288 | /** | ||
1289 | * Set to #GNUNET_YES if all processing has completed. | ||
1290 | */ | ||
1291 | int all_done; | ||
1292 | |||
1293 | /** | ||
1294 | * Flag set to #GNUNET_YES if the next callback from | ||
1295 | * #GNUNET_FS_file_information_inspect should be skipped because it | ||
1296 | * is for the directory which was already processed with the parent. | ||
1297 | */ | ||
1298 | int skip_next_fi_callback; | ||
1299 | }; | ||
1300 | |||
1301 | |||
1302 | /** | ||
1303 | * Phases of unindex processing (state machine). | ||
1304 | */ | ||
1305 | enum UnindexState | ||
1306 | { | ||
1307 | /** | ||
1308 | * We're currently hashing the file. | ||
1309 | */ | ||
1310 | UNINDEX_STATE_HASHING = 0, | ||
1311 | |||
1312 | /** | ||
1313 | * We're telling the datastore to delete | ||
1314 | * the respective DBlocks and IBlocks. | ||
1315 | */ | ||
1316 | UNINDEX_STATE_DS_REMOVE = 1, | ||
1317 | |||
1318 | /** | ||
1319 | * Find out which keywords apply. | ||
1320 | */ | ||
1321 | UNINDEX_STATE_EXTRACT_KEYWORDS = 2, | ||
1322 | |||
1323 | /** | ||
1324 | * We're telling the datastore to remove KBlocks. | ||
1325 | */ | ||
1326 | UNINDEX_STATE_DS_REMOVE_KBLOCKS = 3, | ||
1327 | |||
1328 | /** | ||
1329 | * We're notifying the FS service about | ||
1330 | * the unindexing. | ||
1331 | */ | ||
1332 | UNINDEX_STATE_FS_NOTIFY = 4, | ||
1333 | |||
1334 | /** | ||
1335 | * We're done. | ||
1336 | */ | ||
1337 | UNINDEX_STATE_COMPLETE = 5, | ||
1338 | |||
1339 | /** | ||
1340 | * We've encountered a fatal error. | ||
1341 | */ | ||
1342 | UNINDEX_STATE_ERROR = 6 | ||
1343 | }; | ||
1344 | |||
1345 | |||
1346 | /** | ||
1347 | * Handle for controlling an unindexing operation. | ||
1348 | */ | ||
1349 | struct GNUNET_FS_UnindexContext | ||
1350 | { | ||
1351 | /** | ||
1352 | * The content hash key of the last block we processed, will in the | ||
1353 | * end be set to the CHK from the URI. Used to remove the KBlocks. | ||
1354 | */ | ||
1355 | struct ContentHashKey chk; | ||
1356 | |||
1357 | /** | ||
1358 | * Global FS context. | ||
1359 | */ | ||
1360 | struct GNUNET_FS_Handle *h; | ||
1361 | |||
1362 | /** | ||
1363 | * Our top-level activity entry. | ||
1364 | */ | ||
1365 | struct TopLevelActivity *top; | ||
1366 | |||
1367 | /** | ||
1368 | * Directory scanner to find keywords (KBlock removal). | ||
1369 | */ | ||
1370 | struct GNUNET_FS_DirScanner *dscan; | ||
1371 | |||
1372 | /** | ||
1373 | * Keywords found (telling us which KBlocks to remove). | ||
1374 | */ | ||
1375 | struct GNUNET_FS_Uri *ksk_uri; | ||
1376 | |||
1377 | /** | ||
1378 | * Current offset in KSK removal. | ||
1379 | */ | ||
1380 | uint32_t ksk_offset; | ||
1381 | |||
1382 | /** | ||
1383 | * Name of the file that we are unindexing. | ||
1384 | */ | ||
1385 | char *filename; | ||
1386 | |||
1387 | /** | ||
1388 | * Short name under which we are serializing the state of this operation. | ||
1389 | */ | ||
1390 | char *serialization; | ||
1391 | |||
1392 | /** | ||
1393 | * Connection to the FS service, only valid during the | ||
1394 | * #UNINDEX_STATE_FS_NOTIFY phase. | ||
1395 | */ | ||
1396 | struct GNUNET_MQ_Handle *mq; | ||
1397 | |||
1398 | /** | ||
1399 | * Connection to the datastore service, only valid during the | ||
1400 | * UNINDEX_STATE_DS_NOTIFY phase. | ||
1401 | */ | ||
1402 | struct GNUNET_DATASTORE_Handle *dsh; | ||
1403 | |||
1404 | /** | ||
1405 | * Pointer kept for the client. | ||
1406 | */ | ||
1407 | void *client_info; | ||
1408 | |||
1409 | /** | ||
1410 | * Merkle-ish tree encoder context. | ||
1411 | */ | ||
1412 | struct GNUNET_FS_TreeEncoder *tc; | ||
1413 | |||
1414 | /** | ||
1415 | * Handle used to read the file. | ||
1416 | */ | ||
1417 | struct GNUNET_DISK_FileHandle *fh; | ||
1418 | |||
1419 | /** | ||
1420 | * Handle to datastore 'get_key' operation issued for | ||
1421 | * obtaining KBlocks. | ||
1422 | */ | ||
1423 | struct GNUNET_DATASTORE_QueueEntry *dqe; | ||
1424 | |||
1425 | /** | ||
1426 | * Current key for decrypting UBLocks from 'get_key' operation. | ||
1427 | */ | ||
1428 | struct GNUNET_HashCode ukey; | ||
1429 | |||
1430 | /** | ||
1431 | * Current query of 'get_key' operation. | ||
1432 | */ | ||
1433 | struct GNUNET_HashCode uquery; | ||
1434 | |||
1435 | /** | ||
1436 | * Error message, NULL on success. | ||
1437 | */ | ||
1438 | char *emsg; | ||
1439 | |||
1440 | /** | ||
1441 | * Context for hashing of the file. | ||
1442 | */ | ||
1443 | struct GNUNET_CRYPTO_FileHashContext *fhc; | ||
1444 | |||
1445 | /** | ||
1446 | * Overall size of the file. | ||
1447 | */ | ||
1448 | uint64_t file_size; | ||
1449 | |||
1450 | /** | ||
1451 | * When did we start? | ||
1452 | */ | ||
1453 | struct GNUNET_TIME_Absolute start_time; | ||
1454 | |||
1455 | /** | ||
1456 | * Hash of the file's contents (once computed). | ||
1457 | */ | ||
1458 | struct GNUNET_HashCode file_id; | ||
1459 | |||
1460 | /** | ||
1461 | * Current operatinonal phase. | ||
1462 | */ | ||
1463 | enum UnindexState state; | ||
1464 | }; | ||
1465 | |||
1466 | |||
1467 | /** | ||
1468 | * Information we keep for each keyword in a keyword search. | ||
1469 | */ | ||
1470 | struct SearchRequestEntry | ||
1471 | { | ||
1472 | /** | ||
1473 | * Hash of the public key, also known as the query. | ||
1474 | */ | ||
1475 | struct GNUNET_HashCode uquery; | ||
1476 | |||
1477 | /** | ||
1478 | * Derived public key, hashes to 'uquery'. | ||
1479 | */ | ||
1480 | struct GNUNET_CRYPTO_EcdsaPublicKey dpub; | ||
1481 | |||
1482 | /** | ||
1483 | * The original keyword, used to derive the | ||
1484 | * key (for decrypting the UBlock). | ||
1485 | */ | ||
1486 | char *keyword; | ||
1487 | |||
1488 | /** | ||
1489 | * Map that contains a "struct GNUNET_FS_SearchResult" for each result that | ||
1490 | * was found under this keyword. Note that the entries will point | ||
1491 | * to the same locations as those in the master result map (in | ||
1492 | * "struct GNUNET_FS_SearchContext"), so they should not be freed. | ||
1493 | * The key for each entry is the XOR of the key and query in the CHK | ||
1494 | * URI (as a unique identifier for the search result). | ||
1495 | */ | ||
1496 | struct GNUNET_CONTAINER_MultiHashMap *results; | ||
1497 | |||
1498 | /** | ||
1499 | * Is this keyword a mandatory keyword | ||
1500 | * (started with '+')? | ||
1501 | */ | ||
1502 | int mandatory; | ||
1503 | }; | ||
1504 | |||
1505 | |||
1506 | /** | ||
1507 | * Handle for controlling a search. | ||
1508 | */ | ||
1509 | struct GNUNET_FS_SearchContext | ||
1510 | { | ||
1511 | /** | ||
1512 | * Handle to the global FS context. | ||
1513 | */ | ||
1514 | struct GNUNET_FS_Handle *h; | ||
1515 | |||
1516 | /** | ||
1517 | * Our top-level activity entry (if we are top-level, otherwise NULL). | ||
1518 | */ | ||
1519 | struct TopLevelActivity *top; | ||
1520 | |||
1521 | /** | ||
1522 | * List of keywords that we're looking for. | ||
1523 | */ | ||
1524 | struct GNUNET_FS_Uri *uri; | ||
1525 | |||
1526 | /** | ||
1527 | * For update-searches, link to the search result that triggered | ||
1528 | * the update search; otherwise NULL. | ||
1529 | */ | ||
1530 | struct GNUNET_FS_SearchResult *psearch_result; | ||
1531 | |||
1532 | /** | ||
1533 | * Connection to the FS service. | ||
1534 | */ | ||
1535 | struct GNUNET_MQ_Handle *mq; | ||
1536 | |||
1537 | /** | ||
1538 | * Pointer we keep for the client. | ||
1539 | */ | ||
1540 | void *client_info; | ||
1541 | |||
1542 | /** | ||
1543 | * Name of the file on disk we use for persistence. | ||
1544 | */ | ||
1545 | char *serialization; | ||
1546 | |||
1547 | /** | ||
1548 | * Error message (non-NULL if this operation failed). | ||
1549 | */ | ||
1550 | char *emsg; | ||
1551 | |||
1552 | /** | ||
1553 | * Map that contains a `struct GNUNET_FS_SearchResult` for each result that | ||
1554 | * was found in the search. The key for each entry is the XOR of | ||
1555 | * the key and query in the CHK URI (as a unique identifier for the | ||
1556 | * search result). | ||
1557 | */ | ||
1558 | struct GNUNET_CONTAINER_MultiHashMap *master_result_map; | ||
1559 | |||
1560 | /** | ||
1561 | * Per-keyword information for a keyword search. This array will | ||
1562 | * have exactly as many entries as there were keywords. | ||
1563 | */ | ||
1564 | struct SearchRequestEntry *requests; | ||
1565 | |||
1566 | /** | ||
1567 | * When did we start? | ||
1568 | */ | ||
1569 | struct GNUNET_TIME_Absolute start_time; | ||
1570 | |||
1571 | /** | ||
1572 | * How long to wait before we try to reconnect to FS service? | ||
1573 | */ | ||
1574 | struct GNUNET_TIME_Relative reconnect_backoff; | ||
1575 | |||
1576 | /** | ||
1577 | * ID of a task that is using this struct and that must be cancelled | ||
1578 | * when the search is being stopped (if not | ||
1579 | * NULL). Used for the task that adds some | ||
1580 | * artificial delay when trying to reconnect to the FS service. | ||
1581 | */ | ||
1582 | struct GNUNET_SCHEDULER_Task *task; | ||
1583 | |||
1584 | /** | ||
1585 | * Anonymity level for the search. | ||
1586 | */ | ||
1587 | uint32_t anonymity; | ||
1588 | |||
1589 | /** | ||
1590 | * Number of mandatory keywords in this query. | ||
1591 | */ | ||
1592 | uint32_t mandatory_count; | ||
1593 | |||
1594 | /** | ||
1595 | * Options for the search. | ||
1596 | */ | ||
1597 | enum GNUNET_FS_SearchOptions options; | ||
1598 | }; | ||
1599 | |||
1600 | |||
1601 | /** | ||
1602 | * FSM for possible states a block can go through. The typical | ||
1603 | * order of progression is linear through the states, alternatives | ||
1604 | * are documented in the comments. | ||
1605 | */ | ||
1606 | enum BlockRequestState | ||
1607 | { | ||
1608 | /** | ||
1609 | * Initial state, block has only been allocated (since it is | ||
1610 | * relevant to the overall download request). | ||
1611 | */ | ||
1612 | BRS_INIT = 0, | ||
1613 | |||
1614 | /** | ||
1615 | * We've checked the block on the path down the tree, and the | ||
1616 | * content on disk did match the desired CHK, but not all | ||
1617 | * the way down, so at the bottom some blocks will still | ||
1618 | * need to be reconstructed). | ||
1619 | */ | ||
1620 | BRS_RECONSTRUCT_DOWN = 1, | ||
1621 | |||
1622 | /** | ||
1623 | * We've calculated the CHK bottom-up based on the meta data. | ||
1624 | * This may work, but if it did we have to write the meta data to | ||
1625 | * disk at the end (and we still need to check against the | ||
1626 | * CHK set on top). | ||
1627 | */ | ||
1628 | BRS_RECONSTRUCT_META_UP = 2, | ||
1629 | |||
1630 | /** | ||
1631 | * We've calculated the CHK bottom-up based on what we have on | ||
1632 | * disk, which may not be what the desired CHK is. If the | ||
1633 | * reconstructed CHKs match whatever comes from above, we're | ||
1634 | * done with the respective subtree. | ||
1635 | */ | ||
1636 | BRS_RECONSTRUCT_UP = 3, | ||
1637 | |||
1638 | /** | ||
1639 | * We've determined the real, desired CHK for this block | ||
1640 | * (full tree reconstruction failed), request is now pending. | ||
1641 | * If the CHK that bubbled up through reconstruction did match | ||
1642 | * the top-level request, the state machine for the subtree | ||
1643 | * would have moved to BRS_DOWNLOAD_UP. | ||
1644 | */ | ||
1645 | BRS_CHK_SET = 4, | ||
1646 | |||
1647 | /** | ||
1648 | * We've successfully downloaded this block, but the children | ||
1649 | * still need to be either downloaded or verified (download | ||
1650 | * request propagates down). If the download fails, the | ||
1651 | * state machine for this block may move to | ||
1652 | * BRS_DOWNLOAD_ERROR instead. | ||
1653 | */ | ||
1654 | BRS_DOWNLOAD_DOWN = 5, | ||
1655 | |||
1656 | /** | ||
1657 | * This block and all of its children have been downloaded | ||
1658 | * successfully (full completion propagates up). | ||
1659 | */ | ||
1660 | BRS_DOWNLOAD_UP = 6, | ||
1661 | |||
1662 | /** | ||
1663 | * We got a block back that matched the query but did not hash to | ||
1664 | * the key (malicious publisher or hash collision); this block | ||
1665 | * can never be downloaded (error propagates up). | ||
1666 | */ | ||
1667 | BRS_ERROR = 7 | ||
1668 | }; | ||
1669 | |||
1670 | |||
1671 | /** | ||
1672 | * Information about an active download request. | ||
1673 | */ | ||
1674 | struct DownloadRequest | ||
1675 | { | ||
1676 | /** | ||
1677 | * Parent in the CHK-tree. | ||
1678 | */ | ||
1679 | struct DownloadRequest *parent; | ||
1680 | |||
1681 | /** | ||
1682 | * Array (!) of child-requests, or NULL for the bottom of the tree. | ||
1683 | */ | ||
1684 | struct DownloadRequest **children; | ||
1685 | |||
1686 | /** | ||
1687 | * CHK for the request for this block (set during reconstruction | ||
1688 | * to what we have on disk, later to what we want to have). | ||
1689 | */ | ||
1690 | struct ContentHashKey chk; | ||
1691 | |||
1692 | /** | ||
1693 | * Offset of the corresponding block. Specifically, first (!) byte of | ||
1694 | * the first DBLOCK in the subtree induced by block represented by | ||
1695 | * this request. | ||
1696 | */ | ||
1697 | uint64_t offset; | ||
1698 | |||
1699 | /** | ||
1700 | * Number of entries in @e children array. | ||
1701 | */ | ||
1702 | unsigned int num_children; | ||
1703 | |||
1704 | /** | ||
1705 | * Depth of the corresponding block in the tree. 0==DBLOCKs. | ||
1706 | */ | ||
1707 | unsigned int depth; | ||
1708 | |||
1709 | /** | ||
1710 | * Offset of the CHK for this block in the parent block | ||
1711 | */ | ||
1712 | unsigned int chk_idx; | ||
1713 | |||
1714 | /** | ||
1715 | * State in the FSM. | ||
1716 | */ | ||
1717 | enum BlockRequestState state; | ||
1718 | }; | ||
1719 | |||
1720 | |||
1721 | /** | ||
1722 | * (recursively) free download request structure | ||
1723 | * | ||
1724 | * @param dr request to free | ||
1725 | */ | ||
1726 | void | ||
1727 | GNUNET_FS_free_download_request_ (struct DownloadRequest *dr); | ||
1728 | |||
1729 | |||
1730 | /** | ||
1731 | * Stop the ping task for this search result. | ||
1732 | * | ||
1733 | * @param sr result to start pinging for. | ||
1734 | */ | ||
1735 | void | ||
1736 | GNUNET_FS_stop_probe_ping_task_ (struct GNUNET_FS_SearchResult *sr); | ||
1737 | |||
1738 | |||
1739 | /** | ||
1740 | * Context for controlling a download. | ||
1741 | */ | ||
1742 | struct GNUNET_FS_DownloadContext | ||
1743 | { | ||
1744 | /** | ||
1745 | * Global FS context. | ||
1746 | */ | ||
1747 | struct GNUNET_FS_Handle *h; | ||
1748 | |||
1749 | /** | ||
1750 | * Our top-level activity entry (if we are top-level, otherwise NULL). | ||
1751 | */ | ||
1752 | struct TopLevelActivity *top; | ||
1753 | |||
1754 | /** | ||
1755 | * Connection to the FS service. | ||
1756 | */ | ||
1757 | struct GNUNET_MQ_Handle *mq; | ||
1758 | |||
1759 | /** | ||
1760 | * Parent download (used when downloading files | ||
1761 | * in directories). | ||
1762 | */ | ||
1763 | struct GNUNET_FS_DownloadContext *parent; | ||
1764 | |||
1765 | /** | ||
1766 | * Associated search (used when downloading files | ||
1767 | * based on search results), or NULL for none. | ||
1768 | */ | ||
1769 | struct GNUNET_FS_SearchResult *search; | ||
1770 | |||
1771 | /** | ||
1772 | * Head of list of child downloads. | ||
1773 | */ | ||
1774 | struct GNUNET_FS_DownloadContext *child_head; | ||
1775 | |||
1776 | /** | ||
1777 | * Tail of list of child downloads. | ||
1778 | */ | ||
1779 | struct GNUNET_FS_DownloadContext *child_tail; | ||
1780 | |||
1781 | /** | ||
1782 | * Previous download belonging to the same parent. | ||
1783 | */ | ||
1784 | struct GNUNET_FS_DownloadContext *prev; | ||
1785 | |||
1786 | /** | ||
1787 | * Next download belonging to the same parent. | ||
1788 | */ | ||
1789 | struct GNUNET_FS_DownloadContext *next; | ||
1790 | |||
1791 | /** | ||
1792 | * Context kept for the client. | ||
1793 | */ | ||
1794 | void *client_info; | ||
1795 | |||
1796 | /** | ||
1797 | * URI that identifies the file that we are downloading. | ||
1798 | */ | ||
1799 | struct GNUNET_FS_Uri *uri; | ||
1800 | |||
1801 | /** | ||
1802 | * Known meta-data for the file (can be NULL). | ||
1803 | */ | ||
1804 | struct GNUNET_CONTAINER_MetaData *meta; | ||
1805 | |||
1806 | /** | ||
1807 | * Error message, NULL if we're doing OK. | ||
1808 | */ | ||
1809 | char *emsg; | ||
1810 | |||
1811 | /** | ||
1812 | * Random portion of filename we use for syncing state of this | ||
1813 | * download. | ||
1814 | */ | ||
1815 | char *serialization; | ||
1816 | |||
1817 | /** | ||
1818 | * Where are we writing the data (name of the | ||
1819 | * file, can be NULL!). | ||
1820 | */ | ||
1821 | char *filename; | ||
1822 | |||
1823 | /** | ||
1824 | * Where are we writing the data temporarily (name of the | ||
1825 | * file, can be NULL!); used if we do not have a permanent | ||
1826 | * name and we are a directory and we do a recursive download. | ||
1827 | */ | ||
1828 | char *temp_filename; | ||
1829 | |||
1830 | /** | ||
1831 | * Our entry in the job queue. | ||
1832 | */ | ||
1833 | struct GNUNET_FS_QueueEntry *job_queue; | ||
1834 | |||
1835 | /** | ||
1836 | * Tree encoder used for the reconstruction. | ||
1837 | */ | ||
1838 | struct GNUNET_FS_TreeEncoder *te; | ||
1839 | |||
1840 | /** | ||
1841 | * File handle for reading data from an existing file | ||
1842 | * (to pass to tree encoder). | ||
1843 | */ | ||
1844 | struct GNUNET_DISK_FileHandle *rfh; | ||
1845 | |||
1846 | /** | ||
1847 | * Map of active requests (those waiting for a response). The key | ||
1848 | * is the hash of the encryped block (aka query). | ||
1849 | */ | ||
1850 | struct GNUNET_CONTAINER_MultiHashMap *active; | ||
1851 | |||
1852 | /** | ||
1853 | * Top-level download request. | ||
1854 | */ | ||
1855 | struct DownloadRequest *top_request; | ||
1856 | |||
1857 | /** | ||
1858 | * Identity of the peer having the content, or all-zeros | ||
1859 | * if we don't know of such a peer. | ||
1860 | */ | ||
1861 | struct GNUNET_PeerIdentity target; | ||
1862 | |||
1863 | /** | ||
1864 | * ID of a task that is using this struct and that must be cancelled | ||
1865 | * when the download is being stopped (if not | ||
1866 | * NULL). Used for the task that adds some | ||
1867 | * artificial delay when trying to reconnect to the FS service or | ||
1868 | * the task processing incrementally the data on disk, or the | ||
1869 | * task requesting blocks, etc. | ||
1870 | */ | ||
1871 | struct GNUNET_SCHEDULER_Task *task; | ||
1872 | |||
1873 | /** | ||
1874 | * What is the first offset that we're interested | ||
1875 | * in? | ||
1876 | */ | ||
1877 | uint64_t offset; | ||
1878 | |||
1879 | /** | ||
1880 | * How many bytes starting from offset are desired? | ||
1881 | * This is NOT the overall length of the file! | ||
1882 | */ | ||
1883 | uint64_t length; | ||
1884 | |||
1885 | /** | ||
1886 | * How many bytes have we already received within | ||
1887 | * the specified range (DBlocks only). | ||
1888 | */ | ||
1889 | uint64_t completed; | ||
1890 | |||
1891 | /** | ||
1892 | * What was the size of the file on disk that we're downloading | ||
1893 | * before we started? Used to detect if there is a point in | ||
1894 | * checking an existing block on disk for matching the desired | ||
1895 | * content. 0 if the file did not exist already. | ||
1896 | */ | ||
1897 | uint64_t old_file_size; | ||
1898 | |||
1899 | /** | ||
1900 | * Time download was started. | ||
1901 | */ | ||
1902 | struct GNUNET_TIME_Absolute start_time; | ||
1903 | |||
1904 | /** | ||
1905 | * How long to wait before we try to reconnect to FS service? | ||
1906 | */ | ||
1907 | struct GNUNET_TIME_Relative reconnect_backoff; | ||
1908 | |||
1909 | /** | ||
1910 | * Desired level of anonymity. | ||
1911 | */ | ||
1912 | uint32_t anonymity; | ||
1913 | |||
1914 | /** | ||
1915 | * The depth of the file-tree. | ||
1916 | */ | ||
1917 | unsigned int treedepth; | ||
1918 | |||
1919 | /** | ||
1920 | * Options for the download. | ||
1921 | */ | ||
1922 | enum GNUNET_FS_DownloadOptions options; | ||
1923 | |||
1924 | /** | ||
1925 | * Flag set upon transitive completion (includes child downloads). | ||
1926 | * This flag is only set to #GNUNET_YES for directories where all | ||
1927 | * child-downloads have also completed (and signalled completion). | ||
1928 | */ | ||
1929 | int has_finished; | ||
1930 | |||
1931 | /** | ||
1932 | * Are we ready to issue requests (reconstructions are finished)? | ||
1933 | */ | ||
1934 | int issue_requests; | ||
1935 | }; | ||
1936 | |||
1937 | |||
1938 | #endif | ||
1939 | |||
1940 | /* end of fs_api.h */ | ||
diff --git a/src/fs/fs_directory.c b/src/fs/fs_directory.c deleted file mode 100644 index eb7aac5bb..000000000 --- a/src/fs/fs_directory.c +++ /dev/null | |||
@@ -1,675 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003, 2004, 2006, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_directory.c | ||
23 | * @brief Helper functions for building directories. | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - modify directory builder API to support incremental | ||
28 | * generation of directories (to allow directories that | ||
29 | * would not fit into memory to be created) | ||
30 | * - modify directory processor API to support incremental | ||
31 | * iteration over FULL directories (without missing entries) | ||
32 | * to allow access to directories that do not fit entirely | ||
33 | * into memory | ||
34 | */ | ||
35 | #include "platform.h" | ||
36 | #include "gnunet_fs_service.h" | ||
37 | #include "fs_api.h" | ||
38 | |||
39 | /** | ||
40 | * String that is used to indicate that a file | ||
41 | * is a GNUnet directory. | ||
42 | */ | ||
43 | #define GNUNET_DIRECTORY_MAGIC "\211GND\r\n\032\n" | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Does the meta-data claim that this is a directory? | ||
48 | * Checks if the mime-type is that of a GNUnet directory. | ||
49 | * | ||
50 | * @return #GNUNET_YES if it is, #GNUNET_NO if it is not, #GNUNET_SYSERR if | ||
51 | * we have no mime-type information (treat as #GNUNET_NO) | ||
52 | */ | ||
53 | int | ||
54 | GNUNET_FS_meta_data_test_for_directory (const struct | ||
55 | GNUNET_CONTAINER_MetaData *md) | ||
56 | { | ||
57 | char *mime; | ||
58 | int ret; | ||
59 | |||
60 | if (NULL == md) | ||
61 | return GNUNET_SYSERR; | ||
62 | mime = GNUNET_CONTAINER_meta_data_get_by_type (md, | ||
63 | EXTRACTOR_METATYPE_MIMETYPE); | ||
64 | if (NULL == mime) | ||
65 | return GNUNET_SYSERR; | ||
66 | ret = (0 == strcasecmp (mime, GNUNET_FS_DIRECTORY_MIME)) ? GNUNET_YES : | ||
67 | GNUNET_NO; | ||
68 | GNUNET_free (mime); | ||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | |||
73 | /** | ||
74 | * Set the MIMETYPE information for the given | ||
75 | * metadata to "application/gnunet-directory". | ||
76 | * | ||
77 | * @param md metadata to add mimetype to | ||
78 | */ | ||
79 | void | ||
80 | GNUNET_FS_meta_data_make_directory (struct GNUNET_CONTAINER_MetaData *md) | ||
81 | { | ||
82 | char *mime; | ||
83 | |||
84 | mime = | ||
85 | GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); | ||
86 | if (mime != NULL) | ||
87 | { | ||
88 | GNUNET_break (0 == strcmp (mime, GNUNET_FS_DIRECTORY_MIME)); | ||
89 | GNUNET_free (mime); | ||
90 | return; | ||
91 | } | ||
92 | GNUNET_CONTAINER_meta_data_insert (md, "<gnunet>", | ||
93 | EXTRACTOR_METATYPE_MIMETYPE, | ||
94 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
95 | GNUNET_FS_DIRECTORY_MIME, | ||
96 | strlen (GNUNET_FS_DIRECTORY_MIME) + 1); | ||
97 | } | ||
98 | |||
99 | |||
100 | /** | ||
101 | * Closure for 'find_full_data'. | ||
102 | */ | ||
103 | struct GetFullDataClosure | ||
104 | { | ||
105 | /** | ||
106 | * Extracted binary meta data. | ||
107 | */ | ||
108 | void *data; | ||
109 | |||
110 | /** | ||
111 | * Number of bytes stored in data. | ||
112 | */ | ||
113 | size_t size; | ||
114 | }; | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Type of a function that libextractor calls for each | ||
119 | * meta data item found. | ||
120 | * | ||
121 | * @param cls closure (user-defined) | ||
122 | * @param plugin_name name of the plugin that produced this value; | ||
123 | * special values can be used (e.g. '<zlib>' for zlib being | ||
124 | * used in the main libextractor library and yielding | ||
125 | * meta data). | ||
126 | * @param type libextractor-type describing the meta data | ||
127 | * @param format basic format information about data | ||
128 | * @param data_mime_type mime-type of data (not of the original file); | ||
129 | * can be NULL (if mime-type is not known) | ||
130 | * @param data actual meta-data found | ||
131 | * @param data_len number of bytes in data | ||
132 | * @return 0 to continue extracting, 1 to abort | ||
133 | */ | ||
134 | static int | ||
135 | find_full_data (void *cls, const char *plugin_name, | ||
136 | enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, | ||
137 | const char *data_mime_type, const char *data, size_t data_len) | ||
138 | { | ||
139 | struct GetFullDataClosure *gfdc = cls; | ||
140 | |||
141 | if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA) | ||
142 | { | ||
143 | gfdc->size = data_len; | ||
144 | if (data_len > 0) | ||
145 | { | ||
146 | gfdc->data = GNUNET_malloc (data_len); | ||
147 | GNUNET_memcpy (gfdc->data, data, data_len); | ||
148 | } | ||
149 | return 1; | ||
150 | } | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | |||
155 | /** | ||
156 | * Iterate over all entries in a directory. Note that directories | ||
157 | * are structured such that it is possible to iterate over the | ||
158 | * individual blocks as well as over the entire directory. Thus | ||
159 | * a client can call this function on the buffer in the | ||
160 | * GNUNET_FS_ProgressCallback. Also, directories can optionally | ||
161 | * include the contents of (small) files embedded in the directory | ||
162 | * itself; for those files, the processor may be given the | ||
163 | * contents of the file directly by this function. | ||
164 | * <p> | ||
165 | * | ||
166 | * Note that this function maybe called on parts of directories. Thus | ||
167 | * parser errors should not be reported _at all_ (with GNUNET_break). | ||
168 | * Still, if some entries can be recovered despite these parsing | ||
169 | * errors, the function should try to do this. | ||
170 | * | ||
171 | * @param size number of bytes in data | ||
172 | * @param data pointer to the beginning of the directory | ||
173 | * @param offset offset of data in the directory | ||
174 | * @param dep function to call on each entry | ||
175 | * @param dep_cls closure for @a dep | ||
176 | * @return #GNUNET_OK if this could be a block in a directory, | ||
177 | * #GNUNET_NO if this could be part of a directory (but not 100% OK) | ||
178 | * #GNUNET_SYSERR if @a data does not represent a directory | ||
179 | */ | ||
180 | int | ||
181 | GNUNET_FS_directory_list_contents (size_t size, | ||
182 | const void *data, | ||
183 | uint64_t offset, | ||
184 | GNUNET_FS_DirectoryEntryProcessor dep, | ||
185 | void *dep_cls) | ||
186 | { | ||
187 | struct GetFullDataClosure full_data; | ||
188 | const char *cdata = data; | ||
189 | char *emsg; | ||
190 | uint64_t pos; | ||
191 | uint64_t align; | ||
192 | uint32_t mdSize; | ||
193 | uint64_t epos; | ||
194 | struct GNUNET_FS_Uri *uri; | ||
195 | struct GNUNET_CONTAINER_MetaData *md; | ||
196 | char *filename; | ||
197 | |||
198 | if ((offset == 0) && | ||
199 | ((size < 8 + sizeof(uint32_t)) || | ||
200 | (0 != memcmp (cdata, | ||
201 | GNUNET_FS_DIRECTORY_MAGIC, | ||
202 | 8)))) | ||
203 | return GNUNET_SYSERR; | ||
204 | pos = offset; | ||
205 | if (offset == 0) | ||
206 | { | ||
207 | GNUNET_memcpy (&mdSize, | ||
208 | &cdata[8], | ||
209 | sizeof(uint32_t)); | ||
210 | mdSize = ntohl (mdSize); | ||
211 | if (mdSize > size - 8 - sizeof(uint32_t)) | ||
212 | { | ||
213 | /* invalid size */ | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
215 | _ ("MAGIC mismatch. This is not a GNUnet directory.\n")); | ||
216 | return GNUNET_SYSERR; | ||
217 | } | ||
218 | md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[8 + sizeof(uint32_t)], | ||
219 | mdSize); | ||
220 | if (md == NULL) | ||
221 | { | ||
222 | GNUNET_break (0); | ||
223 | return GNUNET_SYSERR; /* malformed ! */ | ||
224 | } | ||
225 | dep (dep_cls, | ||
226 | NULL, | ||
227 | NULL, | ||
228 | md, | ||
229 | 0, | ||
230 | NULL); | ||
231 | GNUNET_CONTAINER_meta_data_destroy (md); | ||
232 | pos = 8 + sizeof(uint32_t) + mdSize; | ||
233 | } | ||
234 | while (pos < size) | ||
235 | { | ||
236 | /* find end of URI */ | ||
237 | if (cdata[pos] == '\0') | ||
238 | { | ||
239 | /* URI is never empty, must be end of block, | ||
240 | * skip to next alignment */ | ||
241 | align = ((pos / DBLOCK_SIZE) + 1) * DBLOCK_SIZE; | ||
242 | if (align == pos) | ||
243 | { | ||
244 | /* if we were already aligned, still skip a block! */ | ||
245 | align += DBLOCK_SIZE; | ||
246 | } | ||
247 | pos = align; | ||
248 | if (pos >= size) | ||
249 | { | ||
250 | /* malformed - or partial download... */ | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | epos = pos; | ||
255 | while ((epos < size) && (cdata[epos] != '\0')) | ||
256 | epos++; | ||
257 | if (epos >= size) | ||
258 | return GNUNET_NO; /* malformed - or partial download */ | ||
259 | |||
260 | uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg); | ||
261 | pos = epos + 1; | ||
262 | if (NULL == uri) | ||
263 | { | ||
264 | GNUNET_free (emsg); | ||
265 | pos--; /* go back to '\0' to force going to next alignment */ | ||
266 | continue; | ||
267 | } | ||
268 | if (GNUNET_FS_uri_test_ksk (uri)) | ||
269 | { | ||
270 | GNUNET_FS_uri_destroy (uri); | ||
271 | GNUNET_break (0); | ||
272 | return GNUNET_NO; /* illegal in directory! */ | ||
273 | } | ||
274 | |||
275 | GNUNET_memcpy (&mdSize, | ||
276 | &cdata[pos], | ||
277 | sizeof(uint32_t)); | ||
278 | mdSize = ntohl (mdSize); | ||
279 | pos += sizeof(uint32_t); | ||
280 | if (pos + mdSize > size) | ||
281 | { | ||
282 | GNUNET_FS_uri_destroy (uri); | ||
283 | return GNUNET_NO; /* malformed - or partial download */ | ||
284 | } | ||
285 | |||
286 | md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], | ||
287 | mdSize); | ||
288 | if (NULL == md) | ||
289 | { | ||
290 | GNUNET_FS_uri_destroy (uri); | ||
291 | GNUNET_break (0); | ||
292 | return GNUNET_NO; /* malformed ! */ | ||
293 | } | ||
294 | pos += mdSize; | ||
295 | filename = | ||
296 | GNUNET_CONTAINER_meta_data_get_by_type (md, | ||
297 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); | ||
298 | full_data.size = 0; | ||
299 | full_data.data = NULL; | ||
300 | GNUNET_CONTAINER_meta_data_iterate (md, | ||
301 | &find_full_data, | ||
302 | &full_data); | ||
303 | if (NULL != dep) | ||
304 | { | ||
305 | dep (dep_cls, | ||
306 | filename, | ||
307 | uri, | ||
308 | md, | ||
309 | full_data.size, | ||
310 | full_data.data); | ||
311 | } | ||
312 | GNUNET_free (full_data.data); | ||
313 | GNUNET_free (filename); | ||
314 | GNUNET_CONTAINER_meta_data_destroy (md); | ||
315 | GNUNET_FS_uri_destroy (uri); | ||
316 | } | ||
317 | return GNUNET_OK; | ||
318 | } | ||
319 | |||
320 | |||
321 | /** | ||
322 | * Entries in the directory (builder). | ||
323 | */ | ||
324 | struct BuilderEntry | ||
325 | { | ||
326 | /** | ||
327 | * This is a linked list. | ||
328 | */ | ||
329 | struct BuilderEntry *next; | ||
330 | |||
331 | /** | ||
332 | * Length of this entry. | ||
333 | */ | ||
334 | size_t len; | ||
335 | }; | ||
336 | |||
337 | /** | ||
338 | * Internal state of a directory builder. | ||
339 | */ | ||
340 | struct GNUNET_FS_DirectoryBuilder | ||
341 | { | ||
342 | /** | ||
343 | * Meta-data for the directory itself. | ||
344 | */ | ||
345 | struct GNUNET_CONTAINER_MetaData *meta; | ||
346 | |||
347 | /** | ||
348 | * Head of linked list of entries. | ||
349 | */ | ||
350 | struct BuilderEntry *head; | ||
351 | |||
352 | /** | ||
353 | * Number of entries in the directory. | ||
354 | */ | ||
355 | unsigned int count; | ||
356 | }; | ||
357 | |||
358 | |||
359 | /** | ||
360 | * Create a directory builder. | ||
361 | * | ||
362 | * @param mdir metadata for the directory | ||
363 | */ | ||
364 | struct GNUNET_FS_DirectoryBuilder * | ||
365 | GNUNET_FS_directory_builder_create (const struct GNUNET_CONTAINER_MetaData | ||
366 | *mdir) | ||
367 | { | ||
368 | struct GNUNET_FS_DirectoryBuilder *ret; | ||
369 | |||
370 | ret = GNUNET_new (struct GNUNET_FS_DirectoryBuilder); | ||
371 | if (mdir != NULL) | ||
372 | ret->meta = GNUNET_CONTAINER_meta_data_duplicate (mdir); | ||
373 | else | ||
374 | ret->meta = GNUNET_CONTAINER_meta_data_create (); | ||
375 | GNUNET_FS_meta_data_make_directory (ret->meta); | ||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | |||
380 | /** | ||
381 | * Add an entry to a directory. | ||
382 | * | ||
383 | * @param bld directory to extend | ||
384 | * @param uri uri of the entry (must not be a KSK) | ||
385 | * @param md metadata of the entry | ||
386 | * @param data raw data of the entry, can be NULL, otherwise | ||
387 | * data must point to exactly the number of bytes specified | ||
388 | * by the uri which must be of type LOC or CHK | ||
389 | */ | ||
390 | void | ||
391 | GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld, | ||
392 | const struct GNUNET_FS_Uri *uri, | ||
393 | const struct GNUNET_CONTAINER_MetaData *md, | ||
394 | const void *data) | ||
395 | { | ||
396 | struct GNUNET_FS_Uri *curi; | ||
397 | struct BuilderEntry *e; | ||
398 | uint64_t fsize; | ||
399 | uint32_t big; | ||
400 | ssize_t ret; | ||
401 | size_t mds; | ||
402 | size_t mdxs; | ||
403 | char *uris; | ||
404 | char *serialized; | ||
405 | char *sptr; | ||
406 | size_t slen; | ||
407 | struct GNUNET_CONTAINER_MetaData *meta; | ||
408 | const struct GNUNET_CONTAINER_MetaData *meta_use; | ||
409 | |||
410 | GNUNET_assert (! GNUNET_FS_uri_test_ksk (uri)); | ||
411 | if (NULL != data) | ||
412 | { | ||
413 | GNUNET_assert (! GNUNET_FS_uri_test_sks (uri)); | ||
414 | if (GNUNET_FS_uri_test_chk (uri)) | ||
415 | { | ||
416 | fsize = GNUNET_FS_uri_chk_get_file_size (uri); | ||
417 | } | ||
418 | else | ||
419 | { | ||
420 | curi = GNUNET_FS_uri_loc_get_uri (uri); | ||
421 | GNUNET_assert (NULL != curi); | ||
422 | fsize = GNUNET_FS_uri_chk_get_file_size (curi); | ||
423 | GNUNET_FS_uri_destroy (curi); | ||
424 | } | ||
425 | } | ||
426 | else | ||
427 | { | ||
428 | fsize = 0; /* not given */ | ||
429 | } | ||
430 | if (fsize > MAX_INLINE_SIZE) | ||
431 | fsize = 0; /* too large */ | ||
432 | uris = GNUNET_FS_uri_to_string (uri); | ||
433 | slen = strlen (uris) + 1; | ||
434 | mds = GNUNET_CONTAINER_meta_data_get_serialized_size (md); | ||
435 | meta_use = md; | ||
436 | meta = NULL; | ||
437 | if (fsize > 0) | ||
438 | { | ||
439 | meta = GNUNET_CONTAINER_meta_data_duplicate (md); | ||
440 | GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", | ||
441 | EXTRACTOR_METATYPE_GNUNET_FULL_DATA, | ||
442 | EXTRACTOR_METAFORMAT_BINARY, NULL, data, | ||
443 | fsize); | ||
444 | mdxs = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); | ||
445 | if ((slen + sizeof(uint32_t) + mdxs - 1) / DBLOCK_SIZE == | ||
446 | (slen + sizeof(uint32_t) + mds - 1) / DBLOCK_SIZE) | ||
447 | { | ||
448 | /* adding full data would not cause us to cross | ||
449 | * additional blocks, so add it! */ | ||
450 | meta_use = meta; | ||
451 | mds = mdxs; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | if (mds > GNUNET_MAX_MALLOC_CHECKED / 2) | ||
456 | mds = GNUNET_MAX_MALLOC_CHECKED / 2; | ||
457 | e = GNUNET_malloc (sizeof(struct BuilderEntry) + slen + mds | ||
458 | + sizeof(uint32_t)); | ||
459 | serialized = (char *) &e[1]; | ||
460 | GNUNET_memcpy (serialized, uris, slen); | ||
461 | GNUNET_free (uris); | ||
462 | sptr = &serialized[slen + sizeof(uint32_t)]; | ||
463 | ret = | ||
464 | GNUNET_CONTAINER_meta_data_serialize (meta_use, &sptr, mds, | ||
465 | GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); | ||
466 | if (NULL != meta) | ||
467 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
468 | if (ret == -1) | ||
469 | mds = 0; | ||
470 | else | ||
471 | mds = ret; | ||
472 | big = htonl (mds); | ||
473 | GNUNET_memcpy (&serialized[slen], &big, sizeof(uint32_t)); | ||
474 | e->len = slen + sizeof(uint32_t) + mds; | ||
475 | e->next = bld->head; | ||
476 | bld->head = e; | ||
477 | bld->count++; | ||
478 | } | ||
479 | |||
480 | |||
481 | /** | ||
482 | * Given the start and end position of a block of | ||
483 | * data, return the end position of that data | ||
484 | * after alignment to the DBLOCK_SIZE. | ||
485 | */ | ||
486 | static size_t | ||
487 | do_align (size_t start_position, size_t end_position) | ||
488 | { | ||
489 | size_t align; | ||
490 | |||
491 | align = (end_position / DBLOCK_SIZE) * DBLOCK_SIZE; | ||
492 | if ((start_position < align) && (end_position > align)) | ||
493 | return align + end_position - start_position; | ||
494 | return end_position; | ||
495 | } | ||
496 | |||
497 | |||
498 | /** | ||
499 | * Compute a permutation of the blocks to | ||
500 | * minimize the cost of alignment. Greedy packer. | ||
501 | * | ||
502 | * @param start starting position for the first block | ||
503 | * @param count size of the two arrays | ||
504 | * @param sizes the sizes of the individual blocks | ||
505 | * @param perm the permutation of the blocks (updated) | ||
506 | */ | ||
507 | static void | ||
508 | block_align (size_t start, unsigned int count, const size_t *sizes, | ||
509 | unsigned int *perm) | ||
510 | { | ||
511 | unsigned int i; | ||
512 | unsigned int j; | ||
513 | unsigned int tmp; | ||
514 | unsigned int best; | ||
515 | ssize_t badness; | ||
516 | size_t cpos; | ||
517 | size_t cend; | ||
518 | ssize_t cbad; | ||
519 | unsigned int cval; | ||
520 | |||
521 | cpos = start; | ||
522 | for (i = 0; i < count; i++) | ||
523 | { | ||
524 | start = cpos; | ||
525 | badness = 0x7FFFFFFF; | ||
526 | best = -1; | ||
527 | for (j = i; j < count; j++) | ||
528 | { | ||
529 | cval = perm[j]; | ||
530 | cend = cpos + sizes[cval]; | ||
531 | if (cpos % DBLOCK_SIZE == 0) | ||
532 | { | ||
533 | /* prefer placing the largest blocks first */ | ||
534 | cbad = -(cend % DBLOCK_SIZE); | ||
535 | } | ||
536 | else | ||
537 | { | ||
538 | if (cpos / DBLOCK_SIZE == cend / DBLOCK_SIZE) | ||
539 | { | ||
540 | /* Data fits into the same block! Prefer small left-overs! */ | ||
541 | cbad = DBLOCK_SIZE - cend % DBLOCK_SIZE; | ||
542 | } | ||
543 | else | ||
544 | { | ||
545 | /* Would have to waste space to re-align, add big factor, this | ||
546 | * case is a real loss (proportional to space wasted)! */ | ||
547 | cbad = DBLOCK_SIZE * (DBLOCK_SIZE - cpos % DBLOCK_SIZE); | ||
548 | } | ||
549 | } | ||
550 | if (cbad < badness) | ||
551 | { | ||
552 | best = j; | ||
553 | badness = cbad; | ||
554 | } | ||
555 | } | ||
556 | GNUNET_assert (best != -1); | ||
557 | tmp = perm[i]; | ||
558 | perm[i] = perm[best]; | ||
559 | perm[best] = tmp; | ||
560 | cpos += sizes[perm[i]]; | ||
561 | cpos = do_align (start, cpos); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | |||
566 | /** | ||
567 | * Finish building the directory. Frees the | ||
568 | * builder context and returns the directory | ||
569 | * in-memory. | ||
570 | * | ||
571 | * @param bld directory to finish | ||
572 | * @param rsize set to the number of bytes needed | ||
573 | * @param rdata set to the encoded directory | ||
574 | * @return #GNUNET_OK on success | ||
575 | */ | ||
576 | int | ||
577 | GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld, | ||
578 | size_t *rsize, | ||
579 | void **rdata) | ||
580 | { | ||
581 | char *data; | ||
582 | char *sptr; | ||
583 | size_t *sizes; | ||
584 | unsigned int *perm; | ||
585 | unsigned int i; | ||
586 | unsigned int j; | ||
587 | struct BuilderEntry *pos; | ||
588 | struct BuilderEntry **bes; | ||
589 | size_t size; | ||
590 | size_t psize; | ||
591 | size_t off; | ||
592 | ssize_t ret; | ||
593 | uint32_t big; | ||
594 | |||
595 | size = strlen (GNUNET_DIRECTORY_MAGIC) + sizeof(uint32_t); | ||
596 | size += GNUNET_CONTAINER_meta_data_get_serialized_size (bld->meta); | ||
597 | sizes = NULL; | ||
598 | perm = NULL; | ||
599 | bes = NULL; | ||
600 | if (0 < bld->count) | ||
601 | { | ||
602 | sizes = GNUNET_new_array (bld->count, | ||
603 | size_t); | ||
604 | perm = GNUNET_new_array (bld->count, | ||
605 | unsigned int); | ||
606 | bes = GNUNET_new_array (bld->count, | ||
607 | struct BuilderEntry *); | ||
608 | pos = bld->head; | ||
609 | for (i = 0; i < bld->count; i++) | ||
610 | { | ||
611 | perm[i] = i; | ||
612 | bes[i] = pos; | ||
613 | sizes[i] = pos->len; | ||
614 | pos = pos->next; | ||
615 | } | ||
616 | block_align (size, bld->count, sizes, perm); | ||
617 | /* compute final size with alignment */ | ||
618 | for (i = 0; i < bld->count; i++) | ||
619 | { | ||
620 | psize = size; | ||
621 | size += sizes[perm[i]]; | ||
622 | size = do_align (psize, size); | ||
623 | } | ||
624 | } | ||
625 | *rsize = size; | ||
626 | data = GNUNET_malloc_large (size); | ||
627 | if (data == NULL) | ||
628 | { | ||
629 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, | ||
630 | "malloc"); | ||
631 | *rsize = 0; | ||
632 | *rdata = NULL; | ||
633 | GNUNET_free (sizes); | ||
634 | GNUNET_free (perm); | ||
635 | GNUNET_free (bes); | ||
636 | return GNUNET_SYSERR; | ||
637 | } | ||
638 | *rdata = data; | ||
639 | GNUNET_memcpy (data, | ||
640 | GNUNET_DIRECTORY_MAGIC, | ||
641 | strlen (GNUNET_DIRECTORY_MAGIC)); | ||
642 | off = strlen (GNUNET_DIRECTORY_MAGIC); | ||
643 | |||
644 | sptr = &data[off + sizeof(uint32_t)]; | ||
645 | ret = | ||
646 | GNUNET_CONTAINER_meta_data_serialize (bld->meta, | ||
647 | &sptr, | ||
648 | size - off - sizeof(uint32_t), | ||
649 | GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); | ||
650 | GNUNET_assert (ret != -1); | ||
651 | big = htonl (ret); | ||
652 | GNUNET_memcpy (&data[off], | ||
653 | &big, | ||
654 | sizeof(uint32_t)); | ||
655 | off += sizeof(uint32_t) + ret; | ||
656 | for (j = 0; j < bld->count; j++) | ||
657 | { | ||
658 | i = perm[j]; | ||
659 | psize = off; | ||
660 | off += sizes[i]; | ||
661 | off = do_align (psize, off); | ||
662 | GNUNET_memcpy (&data[off - sizes[i]], &(bes[i])[1], sizes[i]); | ||
663 | GNUNET_free (bes[i]); | ||
664 | } | ||
665 | GNUNET_free (sizes); | ||
666 | GNUNET_free (perm); | ||
667 | GNUNET_free (bes); | ||
668 | GNUNET_assert (off == size); | ||
669 | GNUNET_CONTAINER_meta_data_destroy (bld->meta); | ||
670 | GNUNET_free (bld); | ||
671 | return GNUNET_OK; | ||
672 | } | ||
673 | |||
674 | |||
675 | /* end of fs_directory.c */ | ||
diff --git a/src/fs/fs_dirmetascan.c b/src/fs/fs_dirmetascan.c deleted file mode 100644 index cb50182f9..000000000 --- a/src/fs/fs_dirmetascan.c +++ /dev/null | |||
@@ -1,503 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2005-2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_dirmetascan.c | ||
23 | * @brief code to asynchronously build a 'struct GNUNET_FS_ShareTreeItem' | ||
24 | * from an on-disk directory for publishing; use the 'gnunet-helper-fs-publish'. | ||
25 | * @author LRN | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | #include "gnunet_scheduler_lib.h" | ||
31 | #include <pthread.h> | ||
32 | |||
33 | |||
34 | /** | ||
35 | * An opaque structure a pointer to which is returned to the | ||
36 | * caller to be used to control the scanner. | ||
37 | */ | ||
38 | struct GNUNET_FS_DirScanner | ||
39 | { | ||
40 | /** | ||
41 | * Helper process. | ||
42 | */ | ||
43 | struct GNUNET_HELPER_Handle *helper; | ||
44 | |||
45 | /** | ||
46 | * Expanded filename (as given by the scan initiator). | ||
47 | * The scanner thread stores a copy here, and frees it when it finishes. | ||
48 | */ | ||
49 | char *filename_expanded; | ||
50 | |||
51 | /** | ||
52 | * Second argument to helper process. | ||
53 | */ | ||
54 | char *ex_arg; | ||
55 | |||
56 | /** | ||
57 | * The function that will be called every time there's a progress | ||
58 | * message. | ||
59 | */ | ||
60 | GNUNET_FS_DirScannerProgressCallback progress_callback; | ||
61 | |||
62 | /** | ||
63 | * A closure for progress_callback. | ||
64 | */ | ||
65 | void *progress_callback_cls; | ||
66 | |||
67 | /** | ||
68 | * After the scan is finished, it will contain a pointer to the | ||
69 | * top-level directory entry in the directory tree built by the | ||
70 | * scanner. | ||
71 | */ | ||
72 | struct GNUNET_FS_ShareTreeItem *toplevel; | ||
73 | |||
74 | /** | ||
75 | * Current position during processing. | ||
76 | */ | ||
77 | struct GNUNET_FS_ShareTreeItem *pos; | ||
78 | |||
79 | /** | ||
80 | * Task scheduled when we are done. | ||
81 | */ | ||
82 | struct GNUNET_SCHEDULER_Task *stop_task; | ||
83 | |||
84 | /** | ||
85 | * Arguments for helper. | ||
86 | */ | ||
87 | char *args[4]; | ||
88 | }; | ||
89 | |||
90 | |||
91 | /** | ||
92 | * Abort the scan. Must not be called from within the progress_callback | ||
93 | * function. | ||
94 | * | ||
95 | * @param ds directory scanner structure | ||
96 | */ | ||
97 | void | ||
98 | GNUNET_FS_directory_scan_abort (struct GNUNET_FS_DirScanner *ds) | ||
99 | { | ||
100 | /* terminate helper */ | ||
101 | if (NULL != ds->helper) | ||
102 | GNUNET_HELPER_stop (ds->helper, GNUNET_NO); | ||
103 | |||
104 | /* free resources */ | ||
105 | if (NULL != ds->toplevel) | ||
106 | GNUNET_FS_share_tree_free (ds->toplevel); | ||
107 | if (NULL != ds->stop_task) | ||
108 | GNUNET_SCHEDULER_cancel (ds->stop_task); | ||
109 | GNUNET_free (ds->ex_arg); | ||
110 | GNUNET_free (ds->filename_expanded); | ||
111 | GNUNET_free (ds); | ||
112 | } | ||
113 | |||
114 | |||
115 | /** | ||
116 | * Obtain the result of the scan after the scan has signalled | ||
117 | * completion. Must not be called prior to completion. The 'ds' is | ||
118 | * freed as part of this call. | ||
119 | * | ||
120 | * @param ds directory scanner structure | ||
121 | * @return the results of the scan (a directory tree) | ||
122 | */ | ||
123 | struct GNUNET_FS_ShareTreeItem * | ||
124 | GNUNET_FS_directory_scan_get_result (struct GNUNET_FS_DirScanner *ds) | ||
125 | { | ||
126 | struct GNUNET_FS_ShareTreeItem *result; | ||
127 | |||
128 | /* check that we're actually done */ | ||
129 | GNUNET_assert (NULL == ds->helper); | ||
130 | /* preserve result */ | ||
131 | result = ds->toplevel; | ||
132 | ds->toplevel = NULL; | ||
133 | GNUNET_FS_directory_scan_abort (ds); | ||
134 | return result; | ||
135 | } | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Move in the directory from the given position to the next file | ||
140 | * in DFS traversal. | ||
141 | * | ||
142 | * @param pos current position | ||
143 | * @return next file, NULL for none | ||
144 | */ | ||
145 | static struct GNUNET_FS_ShareTreeItem * | ||
146 | advance (struct GNUNET_FS_ShareTreeItem *pos) | ||
147 | { | ||
148 | int moved; | ||
149 | |||
150 | GNUNET_assert (NULL != pos); | ||
151 | moved = 0; /* must not terminate, even on file, otherwise "normal" */ | ||
152 | while ((pos->is_directory == GNUNET_YES) || (0 == moved)) | ||
153 | { | ||
154 | if ((moved != -1) && (NULL != pos->children_head)) | ||
155 | { | ||
156 | pos = pos->children_head; | ||
157 | moved = 1; /* can terminate if file */ | ||
158 | continue; | ||
159 | } | ||
160 | if (NULL != pos->next) | ||
161 | { | ||
162 | pos = pos->next; | ||
163 | moved = 1; /* can terminate if file */ | ||
164 | continue; | ||
165 | } | ||
166 | if (NULL != pos->parent) | ||
167 | { | ||
168 | pos = pos->parent; | ||
169 | moved = -1; /* force move to 'next' or 'parent' */ | ||
170 | continue; | ||
171 | } | ||
172 | /* no more options, end of traversal */ | ||
173 | return NULL; | ||
174 | } | ||
175 | return pos; | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Add another child node to the tree. | ||
181 | * | ||
182 | * @param parent parent of the child, NULL for top level | ||
183 | * @param filename name of the file or directory | ||
184 | * @param is_directory GNUNET_YES for directories | ||
185 | * @return new entry that was just created | ||
186 | */ | ||
187 | static struct GNUNET_FS_ShareTreeItem * | ||
188 | expand_tree (struct GNUNET_FS_ShareTreeItem *parent, | ||
189 | const char *filename, | ||
190 | int is_directory) | ||
191 | { | ||
192 | struct GNUNET_FS_ShareTreeItem *chld; | ||
193 | size_t slen; | ||
194 | |||
195 | chld = GNUNET_new (struct GNUNET_FS_ShareTreeItem); | ||
196 | chld->parent = parent; | ||
197 | chld->filename = GNUNET_strdup (filename); | ||
198 | GNUNET_asprintf (&chld->short_filename, | ||
199 | "%s%s", | ||
200 | GNUNET_STRINGS_get_short_name (filename), | ||
201 | is_directory == GNUNET_YES ? "/" : ""); | ||
202 | /* make sure we do not end with '//' */ | ||
203 | slen = strlen (chld->short_filename); | ||
204 | if ((slen >= 2) && (chld->short_filename[slen - 1] == '/') && | ||
205 | (chld->short_filename[slen - 2] == '/')) | ||
206 | chld->short_filename[slen - 1] = '\0'; | ||
207 | chld->is_directory = is_directory; | ||
208 | if (NULL != parent) | ||
209 | GNUNET_CONTAINER_DLL_insert (parent->children_head, | ||
210 | parent->children_tail, | ||
211 | chld); | ||
212 | return chld; | ||
213 | } | ||
214 | |||
215 | |||
216 | /** | ||
217 | * Task run last to shut everything down. | ||
218 | * | ||
219 | * @param cls the 'struct GNUNET_FS_DirScanner' | ||
220 | */ | ||
221 | static void | ||
222 | finish_scan (void *cls) | ||
223 | { | ||
224 | struct GNUNET_FS_DirScanner *ds = cls; | ||
225 | |||
226 | ds->stop_task = NULL; | ||
227 | if (NULL != ds->helper) | ||
228 | { | ||
229 | GNUNET_HELPER_stop (ds->helper, GNUNET_NO); | ||
230 | ds->helper = NULL; | ||
231 | } | ||
232 | ds->progress_callback (ds->progress_callback_cls, | ||
233 | NULL, | ||
234 | GNUNET_SYSERR, | ||
235 | GNUNET_FS_DIRSCANNER_FINISHED); | ||
236 | } | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Called every time there is data to read from the scanner. | ||
241 | * Calls the scanner progress handler. | ||
242 | * | ||
243 | * @param cls the closure (directory scanner object) | ||
244 | * @param msg message from the helper process | ||
245 | * @return #GNUNET_OK on success, | ||
246 | * #GNUNET_NO to stop further processing (no error) | ||
247 | * #GNUNET_SYSERR to stop further processing with error | ||
248 | */ | ||
249 | static int | ||
250 | process_helper_msgs (void *cls, const struct GNUNET_MessageHeader *msg) | ||
251 | { | ||
252 | struct GNUNET_FS_DirScanner *ds = cls; | ||
253 | const char *filename; | ||
254 | size_t left; | ||
255 | |||
256 | #if 0 | ||
257 | fprintf (stderr, | ||
258 | "DMS parses %u-byte message of type %u\n", | ||
259 | (unsigned int) ntohs (msg->size), | ||
260 | (unsigned int) ntohs (msg->type)); | ||
261 | #endif | ||
262 | left = ntohs (msg->size) - sizeof(struct GNUNET_MessageHeader); | ||
263 | filename = (const char *) &msg[1]; | ||
264 | switch (ntohs (msg->type)) | ||
265 | { | ||
266 | case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE: | ||
267 | if (filename[left - 1] != '\0') | ||
268 | { | ||
269 | GNUNET_break (0); | ||
270 | break; | ||
271 | } | ||
272 | ds->progress_callback (ds->progress_callback_cls, | ||
273 | filename, | ||
274 | GNUNET_NO, | ||
275 | GNUNET_FS_DIRSCANNER_FILE_START); | ||
276 | if (NULL == ds->toplevel) | ||
277 | { | ||
278 | ds->toplevel = expand_tree (ds->pos, filename, GNUNET_NO); | ||
279 | } | ||
280 | else | ||
281 | { | ||
282 | GNUNET_assert (NULL != ds->pos); | ||
283 | (void) expand_tree (ds->pos, filename, GNUNET_NO); | ||
284 | } | ||
285 | return GNUNET_OK; | ||
286 | |||
287 | case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY: | ||
288 | if (filename[left - 1] != '\0') | ||
289 | { | ||
290 | GNUNET_break (0); | ||
291 | break; | ||
292 | } | ||
293 | if (0 == strcmp ("..", filename)) | ||
294 | { | ||
295 | if (NULL == ds->pos) | ||
296 | { | ||
297 | GNUNET_break (0); | ||
298 | break; | ||
299 | } | ||
300 | ds->pos = ds->pos->parent; | ||
301 | return GNUNET_OK; | ||
302 | } | ||
303 | ds->progress_callback (ds->progress_callback_cls, | ||
304 | filename, | ||
305 | GNUNET_YES, | ||
306 | GNUNET_FS_DIRSCANNER_FILE_START); | ||
307 | ds->pos = expand_tree (ds->pos, filename, GNUNET_YES); | ||
308 | if (NULL == ds->toplevel) | ||
309 | ds->toplevel = ds->pos; | ||
310 | return GNUNET_OK; | ||
311 | |||
312 | case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR: | ||
313 | break; | ||
314 | |||
315 | case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE: | ||
316 | if ('\0' != filename[left - 1]) | ||
317 | break; | ||
318 | ds->progress_callback (ds->progress_callback_cls, | ||
319 | filename, | ||
320 | GNUNET_SYSERR, | ||
321 | GNUNET_FS_DIRSCANNER_FILE_IGNORED); | ||
322 | return GNUNET_OK; | ||
323 | |||
324 | case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE: | ||
325 | if (0 != left) | ||
326 | { | ||
327 | GNUNET_break (0); | ||
328 | break; | ||
329 | } | ||
330 | if (NULL == ds->toplevel) | ||
331 | break; | ||
332 | ds->progress_callback (ds->progress_callback_cls, | ||
333 | NULL, | ||
334 | GNUNET_SYSERR, | ||
335 | GNUNET_FS_DIRSCANNER_ALL_COUNTED); | ||
336 | ds->pos = ds->toplevel; | ||
337 | if (GNUNET_YES == ds->pos->is_directory) | ||
338 | ds->pos = advance (ds->pos); | ||
339 | return GNUNET_OK; | ||
340 | |||
341 | case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA: { | ||
342 | size_t nlen; | ||
343 | const char *end; | ||
344 | |||
345 | if (NULL == ds->pos) | ||
346 | { | ||
347 | GNUNET_break (0); | ||
348 | break; | ||
349 | } | ||
350 | end = memchr (filename, 0, left); | ||
351 | if (NULL == end) | ||
352 | { | ||
353 | GNUNET_break (0); | ||
354 | break; | ||
355 | } | ||
356 | end++; | ||
357 | nlen = end - filename; | ||
358 | left -= nlen; | ||
359 | if (0 != strcmp (filename, ds->pos->filename)) | ||
360 | { | ||
361 | GNUNET_break (0); | ||
362 | break; | ||
363 | } | ||
364 | ds->progress_callback (ds->progress_callback_cls, | ||
365 | filename, | ||
366 | GNUNET_YES, | ||
367 | GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED); | ||
368 | if (0 < left) | ||
369 | { | ||
370 | ds->pos->meta = GNUNET_CONTAINER_meta_data_deserialize (end, left); | ||
371 | if (NULL == ds->pos->meta) | ||
372 | { | ||
373 | GNUNET_break (0); | ||
374 | break; | ||
375 | } | ||
376 | /* having full filenames is too dangerous; always make sure we clean them up */ | ||
377 | GNUNET_CONTAINER_meta_data_delete (ds->pos->meta, | ||
378 | EXTRACTOR_METATYPE_FILENAME, | ||
379 | NULL, | ||
380 | 0); | ||
381 | /* instead, put in our 'safer' original filename */ | ||
382 | GNUNET_CONTAINER_meta_data_insert (ds->pos->meta, | ||
383 | "<libgnunetfs>", | ||
384 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, | ||
385 | EXTRACTOR_METAFORMAT_UTF8, | ||
386 | "text/plain", | ||
387 | ds->pos->short_filename, | ||
388 | strlen (ds->pos->short_filename) | ||
389 | + 1); | ||
390 | } | ||
391 | ds->pos->ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data ( | ||
392 | ds->pos->meta); | ||
393 | ds->pos = advance (ds->pos); | ||
394 | return GNUNET_OK; | ||
395 | } | ||
396 | |||
397 | case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED: | ||
398 | if (NULL != ds->pos) | ||
399 | { | ||
400 | GNUNET_break (0); | ||
401 | break; | ||
402 | } | ||
403 | if (0 != left) | ||
404 | { | ||
405 | GNUNET_break (0); | ||
406 | break; | ||
407 | } | ||
408 | if (NULL == ds->toplevel) | ||
409 | break; | ||
410 | ds->stop_task = GNUNET_SCHEDULER_add_now (&finish_scan, ds); | ||
411 | return GNUNET_OK; | ||
412 | |||
413 | default: | ||
414 | GNUNET_break (0); | ||
415 | break; | ||
416 | } | ||
417 | ds->progress_callback (ds->progress_callback_cls, | ||
418 | NULL, | ||
419 | GNUNET_SYSERR, | ||
420 | GNUNET_FS_DIRSCANNER_INTERNAL_ERROR); | ||
421 | return GNUNET_OK; | ||
422 | } | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Function called if our helper process died. | ||
427 | * | ||
428 | * @param cls the 'struct GNUNET_FS_DirScanner' callback. | ||
429 | */ | ||
430 | static void | ||
431 | helper_died_cb (void *cls) | ||
432 | { | ||
433 | struct GNUNET_FS_DirScanner *ds = cls; | ||
434 | |||
435 | ds->helper = NULL; | ||
436 | if (NULL != ds->stop_task) | ||
437 | return; /* normal death, was finished */ | ||
438 | ds->progress_callback (ds->progress_callback_cls, | ||
439 | NULL, | ||
440 | GNUNET_SYSERR, | ||
441 | GNUNET_FS_DIRSCANNER_INTERNAL_ERROR); | ||
442 | } | ||
443 | |||
444 | |||
445 | /** | ||
446 | * Start a directory scanner thread. | ||
447 | * | ||
448 | * @param filename name of the directory to scan | ||
449 | * @param disable_extractor #GNUNET_YES to not run libextractor on files (only | ||
450 | * build a tree) | ||
451 | * @param ex if not NULL, must be a list of extra plugins for extractor | ||
452 | * @param cb the callback to call when there are scanning progress messages | ||
453 | * @param cb_cls closure for 'cb' | ||
454 | * @return directory scanner object to be used for controlling the scanner | ||
455 | */ | ||
456 | struct GNUNET_FS_DirScanner * | ||
457 | GNUNET_FS_directory_scan_start (const char *filename, | ||
458 | int disable_extractor, | ||
459 | const char *ex, | ||
460 | GNUNET_FS_DirScannerProgressCallback cb, | ||
461 | void *cb_cls) | ||
462 | { | ||
463 | struct stat sbuf; | ||
464 | char *filename_expanded; | ||
465 | struct GNUNET_FS_DirScanner *ds; | ||
466 | |||
467 | if (0 != stat (filename, &sbuf)) | ||
468 | return NULL; | ||
469 | filename_expanded = GNUNET_STRINGS_filename_expand (filename); | ||
470 | if (NULL == filename_expanded) | ||
471 | return NULL; | ||
472 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
473 | "Starting to scan directory `%s'\n", | ||
474 | filename_expanded); | ||
475 | ds = GNUNET_new (struct GNUNET_FS_DirScanner); | ||
476 | ds->progress_callback = cb; | ||
477 | ds->progress_callback_cls = cb_cls; | ||
478 | ds->filename_expanded = filename_expanded; | ||
479 | if (disable_extractor) | ||
480 | ds->ex_arg = GNUNET_strdup ("-"); | ||
481 | else | ||
482 | ds->ex_arg = (NULL != ex) ? GNUNET_strdup (ex) : NULL; | ||
483 | ds->args[0] = "gnunet-helper-fs-publish"; | ||
484 | ds->args[1] = ds->filename_expanded; | ||
485 | ds->args[2] = ds->ex_arg; | ||
486 | ds->args[3] = NULL; | ||
487 | ds->helper = GNUNET_HELPER_start (GNUNET_NO, | ||
488 | "gnunet-helper-fs-publish", | ||
489 | ds->args, | ||
490 | &process_helper_msgs, | ||
491 | &helper_died_cb, | ||
492 | ds); | ||
493 | if (NULL == ds->helper) | ||
494 | { | ||
495 | GNUNET_free (filename_expanded); | ||
496 | GNUNET_free (ds); | ||
497 | return NULL; | ||
498 | } | ||
499 | return ds; | ||
500 | } | ||
501 | |||
502 | |||
503 | /* end of fs_dirmetascan.c */ | ||
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c deleted file mode 100644 index 5c98d224a..000000000 --- a/src/fs/fs_download.c +++ /dev/null | |||
@@ -1,2418 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001-2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/fs_download.c | ||
22 | * @brief download methods | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_constants.h" | ||
27 | #include "gnunet_fs_service.h" | ||
28 | #include "fs_api.h" | ||
29 | #include "fs_tree.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Determine if the given download (options and meta data) should cause | ||
34 | * use to try to do a recursive download. | ||
35 | */ | ||
36 | static int | ||
37 | is_recursive_download (struct GNUNET_FS_DownloadContext *dc) | ||
38 | { | ||
39 | return (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) && | ||
40 | ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) || | ||
41 | ((NULL == dc->meta) && | ||
42 | ((NULL == dc->filename) || | ||
43 | ((strlen (dc->filename) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && | ||
44 | (NULL != strstr (dc->filename + strlen (dc->filename) | ||
45 | - strlen (GNUNET_FS_DIRECTORY_EXT), | ||
46 | GNUNET_FS_DIRECTORY_EXT)))))); | ||
47 | } | ||
48 | |||
49 | |||
50 | /** | ||
51 | * We're storing the IBLOCKS after the DBLOCKS on disk (so that we | ||
52 | * only have to truncate the file once we're done). | ||
53 | * | ||
54 | * Given the offset of a block (with respect to the DBLOCKS) and its | ||
55 | * depth, return the offset where we would store this block in the | ||
56 | * file. | ||
57 | * | ||
58 | * @param fsize overall file size | ||
59 | * @param off offset of the block in the file | ||
60 | * @param depth depth of the block in the tree, 0 for DBLOCK | ||
61 | * @return off for DBLOCKS (depth == treedepth), | ||
62 | * otherwise an offset past the end | ||
63 | * of the file that does not overlap | ||
64 | * with the range for any other block | ||
65 | */ | ||
66 | static uint64_t | ||
67 | compute_disk_offset (uint64_t fsize, uint64_t off, unsigned int depth) | ||
68 | { | ||
69 | unsigned int i; | ||
70 | uint64_t lsize; /* what is the size of all IBlocks for depth "i"? */ | ||
71 | uint64_t loff; /* where do IBlocks for depth "i" start? */ | ||
72 | unsigned int ioff; /* which IBlock corresponds to "off" at depth "i"? */ | ||
73 | |||
74 | if (0 == depth) | ||
75 | return off; | ||
76 | /* first IBlocks start at the end of file, rounded up | ||
77 | * to full DBLOCK_SIZE */ | ||
78 | loff = ((fsize + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * DBLOCK_SIZE; | ||
79 | lsize = | ||
80 | ((fsize + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * sizeof(struct ContentHashKey); | ||
81 | GNUNET_assert (0 == (off % DBLOCK_SIZE)); | ||
82 | ioff = (off / DBLOCK_SIZE); | ||
83 | for (i = 1; i < depth; i++) | ||
84 | { | ||
85 | loff += lsize; | ||
86 | lsize = (lsize + CHK_PER_INODE - 1) / CHK_PER_INODE; | ||
87 | GNUNET_assert (lsize > 0); | ||
88 | GNUNET_assert (0 == (ioff % CHK_PER_INODE)); | ||
89 | ioff /= CHK_PER_INODE; | ||
90 | } | ||
91 | return loff + ioff * sizeof(struct ContentHashKey); | ||
92 | } | ||
93 | |||
94 | |||
95 | /** | ||
96 | * Fill in all of the generic fields for a download event and call the | ||
97 | * callback. | ||
98 | * | ||
99 | * @param pi structure to fill in | ||
100 | * @param dc overall download context | ||
101 | */ | ||
102 | void | ||
103 | GNUNET_FS_download_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
104 | struct GNUNET_FS_DownloadContext *dc) | ||
105 | { | ||
106 | pi->value.download.dc = dc; | ||
107 | pi->value.download.cctx = dc->client_info; | ||
108 | pi->value.download.pctx = | ||
109 | (NULL == dc->parent) ? NULL : dc->parent->client_info; | ||
110 | pi->value.download.sctx = | ||
111 | (NULL == dc->search) ? NULL : dc->search->client_info; | ||
112 | pi->value.download.uri = dc->uri; | ||
113 | pi->value.download.filename = dc->filename; | ||
114 | pi->value.download.size = dc->length; | ||
115 | /* FIXME: Fix duration calculation to account for pauses */ | ||
116 | pi->value.download.duration = | ||
117 | GNUNET_TIME_absolute_get_duration (dc->start_time); | ||
118 | pi->value.download.completed = dc->completed; | ||
119 | pi->value.download.anonymity = dc->anonymity; | ||
120 | pi->value.download.eta = | ||
121 | GNUNET_TIME_calculate_eta (dc->start_time, dc->completed, dc->length); | ||
122 | pi->value.download.is_active = (NULL == dc->mq) ? GNUNET_NO : GNUNET_YES; | ||
123 | pi->fsh = dc->h; | ||
124 | if (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) | ||
125 | dc->client_info = dc->h->upcb (dc->h->upcb_cls, pi); | ||
126 | else | ||
127 | dc->client_info = GNUNET_FS_search_probe_progress_ (NULL, pi); | ||
128 | } | ||
129 | |||
130 | |||
131 | /** | ||
132 | * Closure for iterator processing results. | ||
133 | */ | ||
134 | struct ProcessResultClosure | ||
135 | { | ||
136 | /** | ||
137 | * Hash of data. | ||
138 | */ | ||
139 | struct GNUNET_HashCode query; | ||
140 | |||
141 | /** | ||
142 | * Data found in P2P network. | ||
143 | */ | ||
144 | const void *data; | ||
145 | |||
146 | /** | ||
147 | * Our download context. | ||
148 | */ | ||
149 | struct GNUNET_FS_DownloadContext *dc; | ||
150 | |||
151 | /** | ||
152 | * When did we last transmit the request? | ||
153 | */ | ||
154 | struct GNUNET_TIME_Absolute last_transmission; | ||
155 | |||
156 | /** | ||
157 | * Number of bytes in data. | ||
158 | */ | ||
159 | size_t size; | ||
160 | |||
161 | /** | ||
162 | * Type of data. | ||
163 | */ | ||
164 | enum GNUNET_BLOCK_Type type; | ||
165 | |||
166 | /** | ||
167 | * Flag to indicate if this block should be stored on disk. | ||
168 | */ | ||
169 | int do_store; | ||
170 | |||
171 | /** | ||
172 | * how much respect did we offer to get this reply? | ||
173 | */ | ||
174 | uint32_t respect_offered; | ||
175 | |||
176 | /** | ||
177 | * how often did we transmit the query? | ||
178 | */ | ||
179 | uint32_t num_transmissions; | ||
180 | }; | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Iterator over entries in the pending requests in the 'active' map for the | ||
185 | * reply that we just got. | ||
186 | * | ||
187 | * @param cls closure (our 'struct ProcessResultClosure') | ||
188 | * @param key query for the given value / request | ||
189 | * @param value value in the hash map (a 'struct DownloadRequest') | ||
190 | * @return #GNUNET_YES (we should continue to iterate); unless serious error | ||
191 | */ | ||
192 | static int | ||
193 | process_result_with_request (void *cls, | ||
194 | const struct GNUNET_HashCode *key, | ||
195 | void *value); | ||
196 | |||
197 | |||
198 | /** | ||
199 | * We've found a matching block without downloading it. | ||
200 | * Encrypt it and pass it to our "receive" function as | ||
201 | * if we had received it from the network. | ||
202 | * | ||
203 | * @param dc download in question | ||
204 | * @param chk request this relates to | ||
205 | * @param dr request details | ||
206 | * @param block plaintext data matching request | ||
207 | * @param len number of bytes in block | ||
208 | * @param do_store should we still store the block on disk? | ||
209 | * @return GNUNET_OK on success | ||
210 | */ | ||
211 | static int | ||
212 | encrypt_existing_match (struct GNUNET_FS_DownloadContext *dc, | ||
213 | const struct ContentHashKey *chk, | ||
214 | struct DownloadRequest *dr, | ||
215 | const char *block, | ||
216 | size_t len, | ||
217 | int do_store) | ||
218 | { | ||
219 | struct ProcessResultClosure prc; | ||
220 | char enc[len]; | ||
221 | struct GNUNET_CRYPTO_SymmetricSessionKey sk; | ||
222 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
223 | struct GNUNET_HashCode query; | ||
224 | |||
225 | GNUNET_CRYPTO_hash_to_aes_key (&chk->key, &sk, &iv); | ||
226 | if (-1 == GNUNET_CRYPTO_symmetric_encrypt (block, len, &sk, &iv, enc)) | ||
227 | { | ||
228 | GNUNET_break (0); | ||
229 | return GNUNET_SYSERR; | ||
230 | } | ||
231 | GNUNET_CRYPTO_hash (enc, len, &query); | ||
232 | if (0 != memcmp (&query, &chk->query, sizeof(struct GNUNET_HashCode))) | ||
233 | { | ||
234 | GNUNET_break_op (0); | ||
235 | return GNUNET_SYSERR; | ||
236 | } | ||
237 | GNUNET_log ( | ||
238 | GNUNET_ERROR_TYPE_DEBUG, | ||
239 | "Matching %u byte block for `%s' at offset %llu already present, no need for download!\n", | ||
240 | (unsigned int) len, | ||
241 | dc->filename, | ||
242 | (unsigned long long) dr->offset); | ||
243 | /* already got it! */ | ||
244 | prc.dc = dc; | ||
245 | prc.data = enc; | ||
246 | prc.size = len; | ||
247 | prc.type = (0 == dr->depth) ? GNUNET_BLOCK_TYPE_FS_DBLOCK | ||
248 | : GNUNET_BLOCK_TYPE_FS_IBLOCK; | ||
249 | prc.query = chk->query; | ||
250 | prc.do_store = do_store; | ||
251 | prc.last_transmission = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
252 | process_result_with_request (&prc, &chk->key, dr); | ||
253 | return GNUNET_OK; | ||
254 | } | ||
255 | |||
256 | |||
257 | /** | ||
258 | * We've lost our connection with the FS service. | ||
259 | * Re-establish it and re-transmit all of our | ||
260 | * pending requests. | ||
261 | * | ||
262 | * @param dc download context that is having trouble | ||
263 | */ | ||
264 | static void | ||
265 | try_reconnect (struct GNUNET_FS_DownloadContext *dc); | ||
266 | |||
267 | |||
268 | /** | ||
269 | * We found an entry in a directory. Check if the respective child | ||
270 | * already exists and if not create the respective child download. | ||
271 | * | ||
272 | * @param cls the parent download | ||
273 | * @param filename name of the file in the directory | ||
274 | * @param uri URI of the file (CHK or LOC) | ||
275 | * @param meta meta data of the file | ||
276 | * @param length number of bytes in data | ||
277 | * @param data contents of the file (or NULL if they were not inlined) | ||
278 | */ | ||
279 | static void | ||
280 | trigger_recursive_download (void *cls, | ||
281 | const char *filename, | ||
282 | const struct GNUNET_FS_Uri *uri, | ||
283 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
284 | size_t length, | ||
285 | const void *data); | ||
286 | |||
287 | |||
288 | /** | ||
289 | * We're done downloading a directory. Open the file and | ||
290 | * trigger all of the (remaining) child downloads. | ||
291 | * | ||
292 | * @param dc context of download that just completed | ||
293 | */ | ||
294 | static void | ||
295 | full_recursive_download (struct GNUNET_FS_DownloadContext *dc) | ||
296 | { | ||
297 | size_t size; | ||
298 | uint64_t size64; | ||
299 | void *data; | ||
300 | struct GNUNET_DISK_FileHandle *h; | ||
301 | struct GNUNET_DISK_MapHandle *m; | ||
302 | |||
303 | size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri); | ||
304 | size = (size_t) size64; | ||
305 | if (size64 != (uint64_t) size) | ||
306 | { | ||
307 | GNUNET_log ( | ||
308 | GNUNET_ERROR_TYPE_ERROR, | ||
309 | _ ( | ||
310 | "Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n")); | ||
311 | return; | ||
312 | } | ||
313 | if (NULL != dc->filename) | ||
314 | { | ||
315 | h = GNUNET_DISK_file_open (dc->filename, | ||
316 | GNUNET_DISK_OPEN_READ, | ||
317 | GNUNET_DISK_PERM_NONE); | ||
318 | } | ||
319 | else | ||
320 | { | ||
321 | GNUNET_assert (NULL != dc->temp_filename); | ||
322 | h = GNUNET_DISK_file_open (dc->temp_filename, | ||
323 | GNUNET_DISK_OPEN_READ, | ||
324 | GNUNET_DISK_PERM_NONE); | ||
325 | } | ||
326 | if (NULL == h) | ||
327 | return; /* oops */ | ||
328 | data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size); | ||
329 | if (NULL == data) | ||
330 | { | ||
331 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
332 | _ ("Directory too large for system address space\n")); | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | if (GNUNET_OK != | ||
337 | GNUNET_FS_directory_list_contents (size, | ||
338 | data, | ||
339 | 0, | ||
340 | &trigger_recursive_download, | ||
341 | dc)) | ||
342 | { | ||
343 | GNUNET_log ( | ||
344 | GNUNET_ERROR_TYPE_WARNING, | ||
345 | _ ( | ||
346 | "Failed to access full directory contents of `%s' for recursive download\n"), | ||
347 | dc->filename); | ||
348 | } | ||
349 | GNUNET_DISK_file_unmap (m); | ||
350 | } | ||
351 | GNUNET_DISK_file_close (h); | ||
352 | if (NULL == dc->filename) | ||
353 | { | ||
354 | if (0 != unlink (dc->temp_filename)) | ||
355 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
356 | "unlink", | ||
357 | dc->temp_filename); | ||
358 | GNUNET_free (dc->temp_filename); | ||
359 | dc->temp_filename = NULL; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | |||
364 | /** | ||
365 | * Check if all child-downloads have completed (or trigger them if | ||
366 | * necessary) and once we're completely done, signal completion (and | ||
367 | * possibly recurse to parent). This function MUST be called when the | ||
368 | * download of a file itself is done or when the download of a file is | ||
369 | * done and then later a direct child download has completed (and | ||
370 | * hence this download may complete itself). | ||
371 | * | ||
372 | * @param dc download to check for completion of children | ||
373 | */ | ||
374 | static void | ||
375 | check_completed (struct GNUNET_FS_DownloadContext *dc) | ||
376 | { | ||
377 | struct GNUNET_FS_ProgressInfo pi; | ||
378 | struct GNUNET_FS_DownloadContext *pos; | ||
379 | |||
380 | /* first, check if we need to download children */ | ||
381 | if (is_recursive_download (dc)) | ||
382 | full_recursive_download (dc); | ||
383 | /* then, check if children are done already */ | ||
384 | for (pos = dc->child_head; NULL != pos; pos = pos->next) | ||
385 | { | ||
386 | if ((NULL == pos->emsg) && (pos->completed < pos->length)) | ||
387 | return; /* not done yet */ | ||
388 | if ((NULL != pos->child_head) && (pos->has_finished != GNUNET_YES)) | ||
389 | return; /* not transitively done yet */ | ||
390 | } | ||
391 | /* All of our children are done, so mark this download done */ | ||
392 | dc->has_finished = GNUNET_YES; | ||
393 | if (NULL != dc->job_queue) | ||
394 | { | ||
395 | GNUNET_FS_dequeue_ (dc->job_queue); | ||
396 | dc->job_queue = NULL; | ||
397 | } | ||
398 | if (NULL != dc->task) | ||
399 | { | ||
400 | GNUNET_SCHEDULER_cancel (dc->task); | ||
401 | dc->task = NULL; | ||
402 | } | ||
403 | if (NULL != dc->rfh) | ||
404 | { | ||
405 | GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (dc->rfh)); | ||
406 | dc->rfh = NULL; | ||
407 | } | ||
408 | GNUNET_FS_download_sync_ (dc); | ||
409 | |||
410 | /* signal completion */ | ||
411 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED; | ||
412 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
413 | |||
414 | /* let parent know */ | ||
415 | if (NULL != dc->parent) | ||
416 | check_completed (dc->parent); | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
421 | * We got a block of plaintext data (from the meta data). | ||
422 | * Try it for upward reconstruction of the data. On success, | ||
423 | * the top-level block will move to state BRS_DOWNLOAD_UP. | ||
424 | * | ||
425 | * @param dc context for the download | ||
426 | * @param dr download request to match against | ||
427 | * @param data plaintext data, starting from the beginning of the file | ||
428 | * @param data_len number of bytes in data | ||
429 | */ | ||
430 | static void | ||
431 | try_match_block (struct GNUNET_FS_DownloadContext *dc, | ||
432 | struct DownloadRequest *dr, | ||
433 | const char *data, | ||
434 | size_t data_len) | ||
435 | { | ||
436 | struct GNUNET_FS_ProgressInfo pi; | ||
437 | unsigned int i; | ||
438 | char enc[DBLOCK_SIZE]; | ||
439 | struct ContentHashKey chks[CHK_PER_INODE]; | ||
440 | struct ContentHashKey in_chk; | ||
441 | struct GNUNET_CRYPTO_SymmetricSessionKey sk; | ||
442 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
443 | size_t dlen; | ||
444 | struct DownloadRequest *drc; | ||
445 | struct GNUNET_DISK_FileHandle *fh; | ||
446 | int complete; | ||
447 | const char *fn; | ||
448 | const char *odata; | ||
449 | size_t odata_len; | ||
450 | |||
451 | odata = data; | ||
452 | odata_len = data_len; | ||
453 | if (BRS_DOWNLOAD_UP == dr->state) | ||
454 | return; | ||
455 | if (dr->depth > 0) | ||
456 | { | ||
457 | if ((dc->offset > 0) || | ||
458 | (dc->length < GNUNET_ntohll (dc->uri->data.chk.file_length))) | ||
459 | { | ||
460 | /* NOTE: this test is not tight, but should suffice; the issue | ||
461 | here is that 'dr->num_children' may inherently only specify a | ||
462 | smaller range than what is in the original file; | ||
463 | thus, reconstruction of (some) inner blocks will fail. | ||
464 | FIXME: we might eventually want to write a tighter test to | ||
465 | maximize the circumstances under which we do succeed with | ||
466 | IBlock reconstruction. (need good tests though). */return; | ||
467 | } | ||
468 | complete = GNUNET_YES; | ||
469 | for (i = 0; i < dr->num_children; i++) | ||
470 | { | ||
471 | drc = dr->children[i]; | ||
472 | try_match_block (dc, drc, data, data_len); | ||
473 | if (drc->state != BRS_RECONSTRUCT_META_UP) | ||
474 | complete = GNUNET_NO; | ||
475 | else | ||
476 | chks[i] = drc->chk; | ||
477 | } | ||
478 | if (GNUNET_YES != complete) | ||
479 | return; | ||
480 | data = (const char *) chks; | ||
481 | dlen = dr->num_children * sizeof(struct ContentHashKey); | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | if (dr->offset > data_len) | ||
486 | return; /* oops */ | ||
487 | dlen = GNUNET_MIN (data_len - dr->offset, DBLOCK_SIZE); | ||
488 | } | ||
489 | GNUNET_CRYPTO_hash (&data[dr->offset], dlen, &in_chk.key); | ||
490 | GNUNET_CRYPTO_hash_to_aes_key (&in_chk.key, &sk, &iv); | ||
491 | if (-1 == | ||
492 | GNUNET_CRYPTO_symmetric_encrypt (&data[dr->offset], dlen, &sk, &iv, enc)) | ||
493 | { | ||
494 | GNUNET_break (0); | ||
495 | return; | ||
496 | } | ||
497 | GNUNET_CRYPTO_hash (enc, dlen, &in_chk.query); | ||
498 | switch (dr->state) | ||
499 | { | ||
500 | case BRS_INIT: | ||
501 | dr->chk = in_chk; | ||
502 | dr->state = BRS_RECONSTRUCT_META_UP; | ||
503 | break; | ||
504 | |||
505 | case BRS_CHK_SET: | ||
506 | if (0 != memcmp (&in_chk, &dr->chk, sizeof(struct ContentHashKey))) | ||
507 | { | ||
508 | /* other peer provided bogus meta data */ | ||
509 | GNUNET_break_op (0); | ||
510 | break; | ||
511 | } | ||
512 | /* write block to disk */ | ||
513 | fn = (NULL != dc->filename) ? dc->filename : dc->temp_filename; | ||
514 | if (NULL != fn) | ||
515 | { | ||
516 | fh = GNUNET_DISK_file_open (fn, | ||
517 | GNUNET_DISK_OPEN_READWRITE | ||
518 | | GNUNET_DISK_OPEN_CREATE | ||
519 | | GNUNET_DISK_OPEN_TRUNCATE, | ||
520 | GNUNET_DISK_PERM_USER_READ | ||
521 | | GNUNET_DISK_PERM_USER_WRITE | ||
522 | | GNUNET_DISK_PERM_GROUP_READ | ||
523 | | GNUNET_DISK_PERM_OTHER_READ); | ||
524 | if (NULL == fh) | ||
525 | { | ||
526 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); | ||
527 | GNUNET_asprintf (&dc->emsg, | ||
528 | _ ("Failed to open file `%s' for writing"), | ||
529 | fn); | ||
530 | GNUNET_DISK_file_close (fh); | ||
531 | dr->state = BRS_ERROR; | ||
532 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; | ||
533 | pi.value.download.specifics.error.message = dc->emsg; | ||
534 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
535 | return; | ||
536 | } | ||
537 | if (data_len != GNUNET_DISK_file_write (fh, odata, odata_len)) | ||
538 | { | ||
539 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn); | ||
540 | GNUNET_asprintf (&dc->emsg, | ||
541 | _ ("Failed to open file `%s' for writing"), | ||
542 | fn); | ||
543 | GNUNET_DISK_file_close (fh); | ||
544 | dr->state = BRS_ERROR; | ||
545 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; | ||
546 | pi.value.download.specifics.error.message = dc->emsg; | ||
547 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
548 | return; | ||
549 | } | ||
550 | GNUNET_DISK_file_close (fh); | ||
551 | } | ||
552 | /* signal success */ | ||
553 | dr->state = BRS_DOWNLOAD_UP; | ||
554 | dc->completed = dc->length; | ||
555 | GNUNET_FS_download_sync_ (dc); | ||
556 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; | ||
557 | pi.value.download.specifics.progress.data = data; | ||
558 | pi.value.download.specifics.progress.offset = 0; | ||
559 | pi.value.download.specifics.progress.data_len = dlen; | ||
560 | pi.value.download.specifics.progress.depth = 0; | ||
561 | pi.value.download.specifics.progress.respect_offered = 0; | ||
562 | pi.value.download.specifics.progress.block_download_duration = | ||
563 | GNUNET_TIME_UNIT_ZERO; | ||
564 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
565 | if ((NULL != dc->filename) && | ||
566 | (0 != truncate (dc->filename, | ||
567 | GNUNET_ntohll (dc->uri->data.chk.file_length)))) | ||
568 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
569 | "truncate", | ||
570 | dc->filename); | ||
571 | check_completed (dc); | ||
572 | break; | ||
573 | |||
574 | default: | ||
575 | /* how did we get here? */ | ||
576 | GNUNET_break (0); | ||
577 | break; | ||
578 | } | ||
579 | } | ||
580 | |||
581 | |||
582 | /** | ||
583 | * Type of a function that libextractor calls for each | ||
584 | * meta data item found. If we find full data meta data, | ||
585 | * call 'try_match_block' on it. | ||
586 | * | ||
587 | * @param cls our 'struct GNUNET_FS_DownloadContext*' | ||
588 | * @param plugin_name name of the plugin that produced this value; | ||
589 | * special values can be used (e.g. '<zlib>' for zlib being | ||
590 | * used in the main libextractor library and yielding | ||
591 | * meta data). | ||
592 | * @param type libextractor-type describing the meta data | ||
593 | * @param format basic format information about data | ||
594 | * @param data_mime_type mime-type of data (not of the original file); | ||
595 | * can be NULL (if mime-type is not known) | ||
596 | * @param data actual meta-data found | ||
597 | * @param data_len number of bytes in data | ||
598 | * @return 0 to continue extracting, 1 to abort | ||
599 | */ | ||
600 | static int | ||
601 | match_full_data (void *cls, | ||
602 | const char *plugin_name, | ||
603 | enum EXTRACTOR_MetaType type, | ||
604 | enum EXTRACTOR_MetaFormat format, | ||
605 | const char *data_mime_type, | ||
606 | const char *data, | ||
607 | size_t data_len) | ||
608 | { | ||
609 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
610 | |||
611 | if (EXTRACTOR_METATYPE_GNUNET_FULL_DATA != type) | ||
612 | return 0; | ||
613 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
614 | "Found %u bytes of FD!\n", | ||
615 | (unsigned int) data_len); | ||
616 | if (GNUNET_FS_uri_chk_get_file_size (dc->uri) != data_len) | ||
617 | { | ||
618 | GNUNET_break_op (0); | ||
619 | return 1; /* bogus meta data */ | ||
620 | } | ||
621 | try_match_block (dc, dc->top_request, data, data_len); | ||
622 | return 1; | ||
623 | } | ||
624 | |||
625 | |||
626 | /** | ||
627 | * Set the state of the given download request to | ||
628 | * BRS_DOWNLOAD_UP and propagate it up the tree. | ||
629 | * | ||
630 | * @param dr download request that is done | ||
631 | */ | ||
632 | static void | ||
633 | propagate_up (struct DownloadRequest *dr) | ||
634 | { | ||
635 | unsigned int i; | ||
636 | |||
637 | do | ||
638 | { | ||
639 | dr->state = BRS_DOWNLOAD_UP; | ||
640 | dr = dr->parent; | ||
641 | if (NULL == dr) | ||
642 | break; | ||
643 | for (i = 0; i < dr->num_children; i++) | ||
644 | if (dr->children[i]->state != BRS_DOWNLOAD_UP) | ||
645 | break; | ||
646 | } | ||
647 | while (i == dr->num_children); | ||
648 | } | ||
649 | |||
650 | |||
651 | /** | ||
652 | * Try top-down reconstruction. Before, the given request node | ||
653 | * must have the state BRS_CHK_SET. Afterwards, more nodes may | ||
654 | * have that state or advanced to BRS_DOWNLOAD_DOWN or even | ||
655 | * BRS_DOWNLOAD_UP. It is also possible to get BRS_ERROR on the | ||
656 | * top level. | ||
657 | * | ||
658 | * @param dc overall download this block belongs to | ||
659 | * @param dr block to reconstruct | ||
660 | */ | ||
661 | static void | ||
662 | try_top_down_reconstruction (struct GNUNET_FS_DownloadContext *dc, | ||
663 | struct DownloadRequest *dr) | ||
664 | { | ||
665 | uint64_t off; | ||
666 | char block[DBLOCK_SIZE]; | ||
667 | struct GNUNET_HashCode key; | ||
668 | uint64_t total; | ||
669 | size_t len; | ||
670 | unsigned int i; | ||
671 | struct DownloadRequest *drc; | ||
672 | uint64_t child_block_size; | ||
673 | const struct ContentHashKey *chks; | ||
674 | int up_done; | ||
675 | |||
676 | GNUNET_assert (NULL != dc->rfh); | ||
677 | GNUNET_assert (BRS_CHK_SET == dr->state); | ||
678 | total = GNUNET_FS_uri_chk_get_file_size (dc->uri); | ||
679 | GNUNET_assert (dr->depth < dc->treedepth); | ||
680 | len = GNUNET_FS_tree_calculate_block_size (total, dr->offset, dr->depth); | ||
681 | GNUNET_assert (len <= DBLOCK_SIZE); | ||
682 | off = compute_disk_offset (total, dr->offset, dr->depth); | ||
683 | if (dc->old_file_size < off + len) | ||
684 | return; /* failure */ | ||
685 | if (off != GNUNET_DISK_file_seek (dc->rfh, off, GNUNET_DISK_SEEK_SET)) | ||
686 | { | ||
687 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "seek", dc->filename); | ||
688 | return; /* failure */ | ||
689 | } | ||
690 | if (len != GNUNET_DISK_file_read (dc->rfh, block, len)) | ||
691 | { | ||
692 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", dc->filename); | ||
693 | return; /* failure */ | ||
694 | } | ||
695 | GNUNET_CRYPTO_hash (block, len, &key); | ||
696 | if (0 != memcmp (&key, &dr->chk.key, sizeof(struct GNUNET_HashCode))) | ||
697 | return; /* mismatch */ | ||
698 | if (GNUNET_OK != | ||
699 | encrypt_existing_match (dc, &dr->chk, dr, block, len, GNUNET_NO)) | ||
700 | { | ||
701 | /* hash matches but encrypted block does not, really bad */ | ||
702 | dr->state = BRS_ERROR; | ||
703 | /* propagate up */ | ||
704 | while (NULL != dr->parent) | ||
705 | { | ||
706 | dr = dr->parent; | ||
707 | dr->state = BRS_ERROR; | ||
708 | } | ||
709 | return; | ||
710 | } | ||
711 | /* block matches */ | ||
712 | dr->state = BRS_DOWNLOAD_DOWN; | ||
713 | |||
714 | /* set CHKs for children */ | ||
715 | up_done = GNUNET_YES; | ||
716 | chks = (const struct ContentHashKey *) block; | ||
717 | for (i = 0; i < dr->num_children; i++) | ||
718 | { | ||
719 | drc = dr->children[i]; | ||
720 | GNUNET_assert (drc->offset >= dr->offset); | ||
721 | child_block_size = GNUNET_FS_tree_compute_tree_size (drc->depth); | ||
722 | GNUNET_assert (0 == (drc->offset - dr->offset) % child_block_size); | ||
723 | if (BRS_INIT == drc->state) | ||
724 | { | ||
725 | drc->state = BRS_CHK_SET; | ||
726 | drc->chk = chks[drc->chk_idx]; | ||
727 | try_top_down_reconstruction (dc, drc); | ||
728 | } | ||
729 | if (BRS_DOWNLOAD_UP != drc->state) | ||
730 | up_done = GNUNET_NO; /* children not all done */ | ||
731 | } | ||
732 | if (GNUNET_YES == up_done) | ||
733 | propagate_up (dr); /* children all done (or no children...) */ | ||
734 | } | ||
735 | |||
736 | |||
737 | /** | ||
738 | * Add entries to the message queue. | ||
739 | * | ||
740 | * @param cls our download context | ||
741 | * @param key unused | ||
742 | * @param entry entry of type `struct DownloadRequest` | ||
743 | * @return #GNUNET_OK | ||
744 | */ | ||
745 | static int | ||
746 | retry_entry (void *cls, const struct GNUNET_HashCode *key, void *entry) | ||
747 | { | ||
748 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
749 | struct DownloadRequest *dr = entry; | ||
750 | struct SearchMessage *sm; | ||
751 | struct GNUNET_MQ_Envelope *env; | ||
752 | |||
753 | env = GNUNET_MQ_msg (sm, GNUNET_MESSAGE_TYPE_FS_START_SEARCH); | ||
754 | if (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY)) | ||
755 | sm->options = htonl (GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY); | ||
756 | else | ||
757 | sm->options = htonl (GNUNET_FS_SEARCH_OPTION_NONE); | ||
758 | if (0 == dr->depth) | ||
759 | sm->type = htonl (GNUNET_BLOCK_TYPE_FS_DBLOCK); | ||
760 | else | ||
761 | sm->type = htonl (GNUNET_BLOCK_TYPE_FS_IBLOCK); | ||
762 | sm->anonymity_level = htonl (dc->anonymity); | ||
763 | sm->target = dc->target; | ||
764 | sm->query = dr->chk.query; | ||
765 | GNUNET_MQ_send (dc->mq, env); | ||
766 | return GNUNET_OK; | ||
767 | } | ||
768 | |||
769 | |||
770 | /** | ||
771 | * Schedule the download of the specified block in the tree. | ||
772 | * | ||
773 | * @param dc overall download this block belongs to | ||
774 | * @param dr request to schedule | ||
775 | */ | ||
776 | static void | ||
777 | schedule_block_download (struct GNUNET_FS_DownloadContext *dc, | ||
778 | struct DownloadRequest *dr) | ||
779 | { | ||
780 | unsigned int i; | ||
781 | |||
782 | switch (dr->state) | ||
783 | { | ||
784 | case BRS_INIT: | ||
785 | GNUNET_assert (0); | ||
786 | break; | ||
787 | |||
788 | case BRS_RECONSTRUCT_DOWN: | ||
789 | GNUNET_assert (0); | ||
790 | break; | ||
791 | |||
792 | case BRS_RECONSTRUCT_META_UP: | ||
793 | GNUNET_assert (0); | ||
794 | break; | ||
795 | |||
796 | case BRS_RECONSTRUCT_UP: | ||
797 | GNUNET_assert (0); | ||
798 | break; | ||
799 | |||
800 | case BRS_CHK_SET: | ||
801 | /* normal case, start download */ | ||
802 | break; | ||
803 | |||
804 | case BRS_DOWNLOAD_DOWN: | ||
805 | for (i = 0; i < dr->num_children; i++) | ||
806 | schedule_block_download (dc, dr->children[i]); | ||
807 | return; | ||
808 | |||
809 | case BRS_DOWNLOAD_UP: | ||
810 | /* We're done! */ | ||
811 | return; | ||
812 | |||
813 | case BRS_ERROR: | ||
814 | GNUNET_break (0); | ||
815 | return; | ||
816 | } | ||
817 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
818 | "Scheduling download at offset %llu and depth %u for `%s'\n", | ||
819 | (unsigned long long) dr->offset, | ||
820 | dr->depth, | ||
821 | GNUNET_h2s (&dr->chk.query)); | ||
822 | if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains_value (dc->active, | ||
823 | &dr->chk.query, | ||
824 | dr)) | ||
825 | return; /* already active */ | ||
826 | GNUNET_CONTAINER_multihashmap_put (dc->active, | ||
827 | &dr->chk.query, | ||
828 | dr, | ||
829 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
830 | if (NULL == dc->mq) | ||
831 | return; /* download not active */ | ||
832 | retry_entry (dc, &dr->chk.query, dr); | ||
833 | } | ||
834 | |||
835 | |||
836 | #define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX | ||
837 | |||
838 | /** | ||
839 | * We found an entry in a directory. Check if the respective child | ||
840 | * already exists and if not create the respective child download. | ||
841 | * | ||
842 | * @param cls the parent download | ||
843 | * @param filename name of the file in the directory | ||
844 | * @param uri URI of the file (CHK or LOC) | ||
845 | * @param meta meta data of the file | ||
846 | * @param length number of bytes in data | ||
847 | * @param data contents of the file (or NULL if they were not inlined) | ||
848 | */ | ||
849 | static void | ||
850 | trigger_recursive_download (void *cls, | ||
851 | const char *filename, | ||
852 | const struct GNUNET_FS_Uri *uri, | ||
853 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
854 | size_t length, | ||
855 | const void *data) | ||
856 | { | ||
857 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
858 | struct GNUNET_FS_DownloadContext *cpos; | ||
859 | char *temp_name; | ||
860 | char *fn; | ||
861 | char *us; | ||
862 | char *ext; | ||
863 | char *dn; | ||
864 | char *pos; | ||
865 | char *full_name; | ||
866 | char *sfn; | ||
867 | |||
868 | if (NULL == uri) | ||
869 | return; /* entry for the directory itself */ | ||
870 | cpos = dc->child_head; | ||
871 | while (NULL != cpos) | ||
872 | { | ||
873 | if ((GNUNET_FS_uri_test_equal (uri, cpos->uri)) || | ||
874 | ((NULL != filename) && (0 == strcmp (cpos->filename, filename)))) | ||
875 | break; | ||
876 | cpos = cpos->next; | ||
877 | } | ||
878 | if (NULL != cpos) | ||
879 | return; /* already exists */ | ||
880 | fn = NULL; | ||
881 | if (NULL == filename) | ||
882 | { | ||
883 | fn = GNUNET_FS_meta_data_suggest_filename (meta); | ||
884 | if (NULL == fn) | ||
885 | { | ||
886 | us = GNUNET_FS_uri_to_string (uri); | ||
887 | fn = GNUNET_strdup (&us[strlen (GNUNET_FS_URI_CHK_PREFIX)]); | ||
888 | GNUNET_free (us); | ||
889 | } | ||
890 | else if ('.' == fn[0]) | ||
891 | { | ||
892 | ext = fn; | ||
893 | us = GNUNET_FS_uri_to_string (uri); | ||
894 | GNUNET_asprintf (&fn, | ||
895 | "%s%s", | ||
896 | &us[strlen (GNUNET_FS_URI_CHK_PREFIX)], | ||
897 | ext); | ||
898 | GNUNET_free (ext); | ||
899 | GNUNET_free (us); | ||
900 | } | ||
901 | /* change '\' to '/' (this should have happened | ||
902 | * during insertion, but malicious peers may | ||
903 | * not have done this) */ | ||
904 | while (NULL != (pos = strstr (fn, "\\"))) | ||
905 | *pos = '/'; | ||
906 | /* remove '../' everywhere (again, well-behaved | ||
907 | * peers don't do this, but don't trust that | ||
908 | * we did not get something nasty) */ | ||
909 | while (NULL != (pos = strstr (fn, "../"))) | ||
910 | { | ||
911 | pos[0] = '_'; | ||
912 | pos[1] = '_'; | ||
913 | pos[2] = '_'; | ||
914 | } | ||
915 | filename = fn; | ||
916 | } | ||
917 | if (NULL == dc->filename) | ||
918 | { | ||
919 | full_name = NULL; | ||
920 | } | ||
921 | else | ||
922 | { | ||
923 | dn = GNUNET_strdup (dc->filename); | ||
924 | GNUNET_break ( | ||
925 | (strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && | ||
926 | (NULL != strstr (dn + strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT), | ||
927 | GNUNET_FS_DIRECTORY_EXT))); | ||
928 | sfn = GNUNET_strdup (filename); | ||
929 | while ((strlen (sfn) > 0) && ('/' == filename[strlen (sfn) - 1])) | ||
930 | sfn[strlen (sfn) - 1] = '\0'; | ||
931 | if ((strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && | ||
932 | (NULL != strstr (dn + strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT), | ||
933 | GNUNET_FS_DIRECTORY_EXT))) | ||
934 | dn[strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT)] = '\0'; | ||
935 | if ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) && | ||
936 | ((strlen (filename) < strlen (GNUNET_FS_DIRECTORY_EXT)) || | ||
937 | (NULL == strstr (filename + strlen (filename) | ||
938 | - strlen (GNUNET_FS_DIRECTORY_EXT), | ||
939 | GNUNET_FS_DIRECTORY_EXT)))) | ||
940 | { | ||
941 | GNUNET_asprintf (&full_name, | ||
942 | "%s%s%s%s", | ||
943 | dn, | ||
944 | DIR_SEPARATOR_STR, | ||
945 | sfn, | ||
946 | GNUNET_FS_DIRECTORY_EXT); | ||
947 | } | ||
948 | else | ||
949 | { | ||
950 | GNUNET_asprintf (&full_name, "%s%s%s", dn, DIR_SEPARATOR_STR, sfn); | ||
951 | } | ||
952 | GNUNET_free (sfn); | ||
953 | GNUNET_free (dn); | ||
954 | } | ||
955 | if ((NULL != full_name) && | ||
956 | (GNUNET_OK != GNUNET_DISK_directory_create_for_file (full_name))) | ||
957 | { | ||
958 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
959 | _ ( | ||
960 | "Failed to create directory for recursive download of `%s'\n"), | ||
961 | full_name); | ||
962 | GNUNET_free (full_name); | ||
963 | GNUNET_free (fn); | ||
964 | return; | ||
965 | } | ||
966 | |||
967 | temp_name = NULL; | ||
968 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
969 | "Triggering recursive download of size %llu with %u bytes MD\n", | ||
970 | (unsigned long long) GNUNET_FS_uri_chk_get_file_size (uri), | ||
971 | (unsigned int) GNUNET_CONTAINER_meta_data_get_serialized_size ( | ||
972 | meta)); | ||
973 | GNUNET_FS_download_start (dc->h, | ||
974 | uri, | ||
975 | meta, | ||
976 | full_name, | ||
977 | temp_name, | ||
978 | 0, | ||
979 | GNUNET_FS_uri_chk_get_file_size (uri), | ||
980 | dc->anonymity, | ||
981 | dc->options, | ||
982 | NULL, | ||
983 | dc); | ||
984 | GNUNET_free (full_name); | ||
985 | GNUNET_free (temp_name); | ||
986 | GNUNET_free (fn); | ||
987 | } | ||
988 | |||
989 | |||
990 | /** | ||
991 | * (recursively) free download request structure | ||
992 | * | ||
993 | * @param dr request to free | ||
994 | */ | ||
995 | void | ||
996 | GNUNET_FS_free_download_request_ (struct DownloadRequest *dr) | ||
997 | { | ||
998 | if (NULL == dr) | ||
999 | return; | ||
1000 | for (unsigned int i = 0; i < dr->num_children; i++) | ||
1001 | GNUNET_FS_free_download_request_ (dr->children[i]); | ||
1002 | GNUNET_free (dr->children); | ||
1003 | GNUNET_free (dr); | ||
1004 | } | ||
1005 | |||
1006 | |||
1007 | /** | ||
1008 | * Iterator over entries in the pending requests in the 'active' map for the | ||
1009 | * reply that we just got. | ||
1010 | * | ||
1011 | * @param cls closure (our `struct ProcessResultClosure`) | ||
1012 | * @param key query for the given value / request | ||
1013 | * @param value value in the hash map (a `struct DownloadRequest`) | ||
1014 | * @return #GNUNET_YES (we should continue to iterate); unless serious error | ||
1015 | */ | ||
1016 | static int | ||
1017 | process_result_with_request (void *cls, | ||
1018 | const struct GNUNET_HashCode *key, | ||
1019 | void *value) | ||
1020 | { | ||
1021 | struct ProcessResultClosure *prc = cls; | ||
1022 | struct DownloadRequest *dr = value; | ||
1023 | struct GNUNET_FS_DownloadContext *dc = prc->dc; | ||
1024 | struct DownloadRequest *drc; | ||
1025 | struct GNUNET_DISK_FileHandle *fh = NULL; | ||
1026 | struct GNUNET_CRYPTO_SymmetricSessionKey skey; | ||
1027 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
1028 | char pt[prc->size]; | ||
1029 | struct GNUNET_FS_ProgressInfo pi; | ||
1030 | uint64_t off; | ||
1031 | size_t bs; | ||
1032 | size_t app; | ||
1033 | int i; | ||
1034 | struct ContentHashKey *chkarr; | ||
1035 | |||
1036 | GNUNET_log ( | ||
1037 | GNUNET_ERROR_TYPE_DEBUG, | ||
1038 | "Received %u byte block `%s' matching pending request at depth %u and offset %llu/%llu\n", | ||
1039 | (unsigned int) prc->size, | ||
1040 | GNUNET_h2s (key), | ||
1041 | dr->depth, | ||
1042 | (unsigned long long) dr->offset, | ||
1043 | (unsigned long long) GNUNET_ntohll (dc->uri->data.chk.file_length)); | ||
1044 | bs = GNUNET_FS_tree_calculate_block_size (GNUNET_ntohll ( | ||
1045 | dc->uri->data.chk.file_length), | ||
1046 | dr->offset, | ||
1047 | dr->depth); | ||
1048 | if (prc->size != bs) | ||
1049 | { | ||
1050 | GNUNET_asprintf ( | ||
1051 | &dc->emsg, | ||
1052 | _ ( | ||
1053 | "Internal error or bogus download URI (expected %lu bytes at depth %u and offset %llu/%llu, got %lu bytes)"), | ||
1054 | bs, | ||
1055 | dr->depth, | ||
1056 | (unsigned long long) dr->offset, | ||
1057 | (unsigned long long) GNUNET_ntohll (dc->uri->data.chk.file_length), | ||
1058 | prc->size); | ||
1059 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s\n", dc->emsg); | ||
1060 | while (NULL != dr->parent) | ||
1061 | { | ||
1062 | dr->state = BRS_ERROR; | ||
1063 | dr = dr->parent; | ||
1064 | } | ||
1065 | dr->state = BRS_ERROR; | ||
1066 | goto signal_error; | ||
1067 | } | ||
1068 | |||
1069 | (void) GNUNET_CONTAINER_multihashmap_remove (dc->active, &prc->query, dr); | ||
1070 | GNUNET_CRYPTO_hash_to_aes_key (&dr->chk.key, &skey, &iv); | ||
1071 | if (-1 == | ||
1072 | GNUNET_CRYPTO_symmetric_decrypt (prc->data, prc->size, &skey, &iv, pt)) | ||
1073 | { | ||
1074 | GNUNET_break (0); | ||
1075 | dc->emsg = GNUNET_strdup (_ ("internal error decrypting content")); | ||
1076 | goto signal_error; | ||
1077 | } | ||
1078 | off = compute_disk_offset (GNUNET_ntohll (dc->uri->data.chk.file_length), | ||
1079 | dr->offset, | ||
1080 | dr->depth); | ||
1081 | /* save to disk */ | ||
1082 | if ((GNUNET_YES == prc->do_store) && | ||
1083 | ((NULL != dc->filename) || (is_recursive_download (dc))) && | ||
1084 | ((dr->depth == dc->treedepth) || | ||
1085 | (0 == (dc->options & GNUNET_FS_DOWNLOAD_NO_TEMPORARIES)))) | ||
1086 | { | ||
1087 | fh = GNUNET_DISK_file_open (NULL != dc->filename ? dc->filename | ||
1088 | : dc->temp_filename, | ||
1089 | GNUNET_DISK_OPEN_READWRITE | ||
1090 | | GNUNET_DISK_OPEN_CREATE, | ||
1091 | GNUNET_DISK_PERM_USER_READ | ||
1092 | | GNUNET_DISK_PERM_USER_WRITE | ||
1093 | | GNUNET_DISK_PERM_GROUP_READ | ||
1094 | | GNUNET_DISK_PERM_OTHER_READ); | ||
1095 | if (NULL == fh) | ||
1096 | { | ||
1097 | GNUNET_asprintf (&dc->emsg, | ||
1098 | _ ("Download failed: could not open file `%s': %s"), | ||
1099 | dc->filename, | ||
1100 | strerror (errno)); | ||
1101 | goto signal_error; | ||
1102 | } | ||
1103 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1104 | "Saving decrypted block to disk at offset %llu\n", | ||
1105 | (unsigned long long) off); | ||
1106 | if ((off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET))) | ||
1107 | { | ||
1108 | GNUNET_asprintf (&dc->emsg, | ||
1109 | _ ("Failed to seek to offset %llu in file `%s': %s"), | ||
1110 | (unsigned long long) off, | ||
1111 | dc->filename, | ||
1112 | strerror (errno)); | ||
1113 | goto signal_error; | ||
1114 | } | ||
1115 | if (prc->size != GNUNET_DISK_file_write (fh, pt, prc->size)) | ||
1116 | { | ||
1117 | GNUNET_asprintf ( | ||
1118 | &dc->emsg, | ||
1119 | _ ("Failed to write block of %u bytes at offset %llu in file `%s': %s"), | ||
1120 | (unsigned int) prc->size, | ||
1121 | (unsigned long long) off, | ||
1122 | dc->filename, | ||
1123 | strerror (errno)); | ||
1124 | goto signal_error; | ||
1125 | } | ||
1126 | GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh)); | ||
1127 | fh = NULL; | ||
1128 | } | ||
1129 | |||
1130 | if (0 == dr->depth) | ||
1131 | { | ||
1132 | /* DBLOCK, update progress and try recursion if applicable */ | ||
1133 | app = prc->size; | ||
1134 | if (dr->offset < dc->offset) | ||
1135 | { | ||
1136 | /* starting offset begins in the middle of pt, | ||
1137 | * do not count first bytes as progress */ | ||
1138 | GNUNET_assert (app > (dc->offset - dr->offset)); | ||
1139 | app -= (dc->offset - dr->offset); | ||
1140 | } | ||
1141 | if (dr->offset + prc->size > dc->offset + dc->length) | ||
1142 | { | ||
1143 | /* end of block is after relevant range, | ||
1144 | * do not count last bytes as progress */ | ||
1145 | GNUNET_assert (app > | ||
1146 | (dr->offset + prc->size) - (dc->offset + dc->length)); | ||
1147 | app -= (dr->offset + prc->size) - (dc->offset + dc->length); | ||
1148 | } | ||
1149 | dc->completed += app; | ||
1150 | |||
1151 | /* do recursive download if option is set and either meta data | ||
1152 | * says it is a directory or if no meta data is given AND filename | ||
1153 | * ends in '.gnd' (top-level case) */ | ||
1154 | if (is_recursive_download (dc)) | ||
1155 | GNUNET_FS_directory_list_contents (prc->size, | ||
1156 | pt, | ||
1157 | off, | ||
1158 | &trigger_recursive_download, | ||
1159 | dc); | ||
1160 | } | ||
1161 | GNUNET_assert (dc->completed <= dc->length); | ||
1162 | dr->state = BRS_DOWNLOAD_DOWN; | ||
1163 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; | ||
1164 | pi.value.download.specifics.progress.data = pt; | ||
1165 | pi.value.download.specifics.progress.offset = dr->offset; | ||
1166 | pi.value.download.specifics.progress.data_len = prc->size; | ||
1167 | pi.value.download.specifics.progress.depth = dr->depth; | ||
1168 | pi.value.download.specifics.progress.respect_offered = prc->respect_offered; | ||
1169 | pi.value.download.specifics.progress.num_transmissions = | ||
1170 | prc->num_transmissions; | ||
1171 | if (prc->last_transmission.abs_value_us != | ||
1172 | GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) | ||
1173 | pi.value.download.specifics.progress.block_download_duration = | ||
1174 | GNUNET_TIME_absolute_get_duration (prc->last_transmission); | ||
1175 | else | ||
1176 | pi.value.download.specifics.progress.block_download_duration = | ||
1177 | GNUNET_TIME_UNIT_ZERO; /* found locally */ | ||
1178 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1179 | if (0 == dr->depth) | ||
1180 | propagate_up (dr); | ||
1181 | |||
1182 | if (dc->completed == dc->length) | ||
1183 | { | ||
1184 | /* download completed, signal */ | ||
1185 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1186 | "Download completed, truncating file to desired length %llu\n", | ||
1187 | (unsigned long long) GNUNET_ntohll ( | ||
1188 | dc->uri->data.chk.file_length)); | ||
1189 | /* truncate file to size (since we store IBlocks at the end) */ | ||
1190 | if (NULL != dc->filename) | ||
1191 | { | ||
1192 | if (0 != truncate (dc->filename, | ||
1193 | GNUNET_ntohll (dc->uri->data.chk.file_length))) | ||
1194 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
1195 | "truncate", | ||
1196 | dc->filename); | ||
1197 | } | ||
1198 | GNUNET_assert (0 == dr->depth); | ||
1199 | check_completed (dc); | ||
1200 | } | ||
1201 | if (0 == dr->depth) | ||
1202 | { | ||
1203 | /* bottom of the tree, no child downloads possible, just sync */ | ||
1204 | GNUNET_FS_download_sync_ (dc); | ||
1205 | return GNUNET_YES; | ||
1206 | } | ||
1207 | |||
1208 | GNUNET_log ( | ||
1209 | GNUNET_ERROR_TYPE_DEBUG, | ||
1210 | "Triggering downloads of children (this block was at depth %u and offset %llu)\n", | ||
1211 | dr->depth, | ||
1212 | (unsigned long long) dr->offset); | ||
1213 | GNUNET_assert (0 == (prc->size % sizeof(struct ContentHashKey))); | ||
1214 | chkarr = (struct ContentHashKey *) pt; | ||
1215 | for (i = dr->num_children - 1; i >= 0; i--) | ||
1216 | { | ||
1217 | drc = dr->children[i]; | ||
1218 | switch (drc->state) | ||
1219 | { | ||
1220 | case BRS_INIT: | ||
1221 | if ((drc->chk_idx + 1) * sizeof(struct ContentHashKey) > prc->size) | ||
1222 | { | ||
1223 | /* 'chkarr' does not have enough space for this chk_idx; | ||
1224 | internal error! */ | ||
1225 | GNUNET_break (0); | ||
1226 | GNUNET_assert (0); | ||
1227 | dc->emsg = GNUNET_strdup (_ ("internal error decoding tree")); | ||
1228 | goto signal_error; | ||
1229 | } | ||
1230 | drc->chk = chkarr[drc->chk_idx]; | ||
1231 | drc->state = BRS_CHK_SET; | ||
1232 | if (GNUNET_YES == dc->issue_requests) | ||
1233 | schedule_block_download (dc, drc); | ||
1234 | break; | ||
1235 | |||
1236 | case BRS_RECONSTRUCT_DOWN: | ||
1237 | GNUNET_assert (0); | ||
1238 | break; | ||
1239 | |||
1240 | case BRS_RECONSTRUCT_META_UP: | ||
1241 | GNUNET_assert (0); | ||
1242 | break; | ||
1243 | |||
1244 | case BRS_RECONSTRUCT_UP: | ||
1245 | GNUNET_assert (0); | ||
1246 | break; | ||
1247 | |||
1248 | case BRS_CHK_SET: | ||
1249 | GNUNET_assert (0); | ||
1250 | break; | ||
1251 | |||
1252 | case BRS_DOWNLOAD_DOWN: | ||
1253 | GNUNET_assert (0); | ||
1254 | break; | ||
1255 | |||
1256 | case BRS_DOWNLOAD_UP: | ||
1257 | GNUNET_assert (0); | ||
1258 | break; | ||
1259 | |||
1260 | case BRS_ERROR: | ||
1261 | GNUNET_assert (0); | ||
1262 | break; | ||
1263 | |||
1264 | default: | ||
1265 | GNUNET_assert (0); | ||
1266 | break; | ||
1267 | } | ||
1268 | } | ||
1269 | GNUNET_FS_download_sync_ (dc); | ||
1270 | return GNUNET_YES; | ||
1271 | |||
1272 | signal_error: | ||
1273 | if (NULL != fh) | ||
1274 | GNUNET_DISK_file_close (fh); | ||
1275 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; | ||
1276 | pi.value.download.specifics.error.message = dc->emsg; | ||
1277 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1278 | GNUNET_MQ_destroy (dc->mq); | ||
1279 | dc->mq = NULL; | ||
1280 | GNUNET_FS_free_download_request_ (dc->top_request); | ||
1281 | dc->top_request = NULL; | ||
1282 | if (NULL != dc->job_queue) | ||
1283 | { | ||
1284 | GNUNET_FS_dequeue_ (dc->job_queue); | ||
1285 | dc->job_queue = NULL; | ||
1286 | } | ||
1287 | GNUNET_FS_download_sync_ (dc); | ||
1288 | return GNUNET_NO; | ||
1289 | } | ||
1290 | |||
1291 | |||
1292 | /** | ||
1293 | * Type of a function to call when we check the PUT message | ||
1294 | * from the service. | ||
1295 | * | ||
1296 | * @param cls closure | ||
1297 | * @param msg message received | ||
1298 | */ | ||
1299 | static int | ||
1300 | check_put (void *cls, const struct ClientPutMessage *cm) | ||
1301 | { | ||
1302 | /* any varsize length is OK */ | ||
1303 | return GNUNET_OK; | ||
1304 | } | ||
1305 | |||
1306 | |||
1307 | /** | ||
1308 | * Type of a function to call when we receive a message | ||
1309 | * from the service. | ||
1310 | * | ||
1311 | * @param cls closure | ||
1312 | * @param msg message received | ||
1313 | */ | ||
1314 | static void | ||
1315 | handle_put (void *cls, const struct ClientPutMessage *cm) | ||
1316 | { | ||
1317 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1318 | uint16_t msize = ntohs (cm->header.size) - sizeof(*cm); | ||
1319 | struct ProcessResultClosure prc; | ||
1320 | |||
1321 | prc.dc = dc; | ||
1322 | prc.data = &cm[1]; | ||
1323 | prc.last_transmission = GNUNET_TIME_absolute_ntoh (cm->last_transmission); | ||
1324 | prc.size = msize; | ||
1325 | prc.type = ntohl (cm->type); | ||
1326 | prc.do_store = GNUNET_YES; | ||
1327 | prc.respect_offered = ntohl (cm->respect_offered); | ||
1328 | prc.num_transmissions = ntohl (cm->num_transmissions); | ||
1329 | GNUNET_CRYPTO_hash (prc.data, msize, &prc.query); | ||
1330 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1331 | "Received result for query `%s' from FS service\n", | ||
1332 | GNUNET_h2s (&prc.query)); | ||
1333 | GNUNET_CONTAINER_multihashmap_get_multiple (dc->active, | ||
1334 | &prc.query, | ||
1335 | &process_result_with_request, | ||
1336 | &prc); | ||
1337 | } | ||
1338 | |||
1339 | |||
1340 | /** | ||
1341 | * Generic error handler, called with the appropriate error code and | ||
1342 | * the same closure specified at the creation of the message queue. | ||
1343 | * Not every message queue implementation supports an error handler. | ||
1344 | * | ||
1345 | * @param cls closure with the `struct GNUNET_FS_DownloadContext *` | ||
1346 | * @param error error code | ||
1347 | */ | ||
1348 | static void | ||
1349 | download_mq_error_handler (void *cls, enum GNUNET_MQ_Error error) | ||
1350 | { | ||
1351 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1352 | |||
1353 | if (NULL != dc->mq) | ||
1354 | { | ||
1355 | GNUNET_MQ_destroy (dc->mq); | ||
1356 | dc->mq = NULL; | ||
1357 | } | ||
1358 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1359 | "Transmitting download request failed, trying to reconnect\n"); | ||
1360 | try_reconnect (dc); | ||
1361 | } | ||
1362 | |||
1363 | |||
1364 | /** | ||
1365 | * Reconnect to the FS service and transmit our queries NOW. | ||
1366 | * | ||
1367 | * @param cls our download context | ||
1368 | */ | ||
1369 | static void | ||
1370 | do_reconnect (void *cls) | ||
1371 | { | ||
1372 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1373 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
1374 | { GNUNET_MQ_hd_var_size (put, | ||
1375 | GNUNET_MESSAGE_TYPE_FS_PUT, | ||
1376 | struct ClientPutMessage, | ||
1377 | dc), | ||
1378 | GNUNET_MQ_handler_end () }; | ||
1379 | |||
1380 | dc->task = NULL; | ||
1381 | dc->mq = GNUNET_CLIENT_connect (dc->h->cfg, | ||
1382 | "fs", | ||
1383 | handlers, | ||
1384 | &download_mq_error_handler, | ||
1385 | dc); | ||
1386 | if (NULL == dc->mq) | ||
1387 | { | ||
1388 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1389 | "Connecting to `%s'-service failed, will try again.\n", | ||
1390 | "FS"); | ||
1391 | try_reconnect (dc); | ||
1392 | return; | ||
1393 | } | ||
1394 | GNUNET_CONTAINER_multihashmap_iterate (dc->active, &retry_entry, dc); | ||
1395 | } | ||
1396 | |||
1397 | |||
1398 | /** | ||
1399 | * We've lost our connection with the FS service. | ||
1400 | * Re-establish it and re-transmit all of our | ||
1401 | * pending requests. | ||
1402 | * | ||
1403 | * @param dc download context that is having trouble | ||
1404 | */ | ||
1405 | static void | ||
1406 | try_reconnect (struct GNUNET_FS_DownloadContext *dc) | ||
1407 | { | ||
1408 | if (NULL != dc->mq) | ||
1409 | { | ||
1410 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1411 | "Moving all requests back to pending list\n"); | ||
1412 | GNUNET_MQ_destroy (dc->mq); | ||
1413 | dc->mq = NULL; | ||
1414 | } | ||
1415 | if (0 == dc->reconnect_backoff.rel_value_us) | ||
1416 | dc->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1417 | else | ||
1418 | dc->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (dc->reconnect_backoff); | ||
1419 | |||
1420 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1421 | "Will try to reconnect in %s\n", | ||
1422 | GNUNET_STRINGS_relative_time_to_string (dc->reconnect_backoff, | ||
1423 | GNUNET_YES)); | ||
1424 | GNUNET_break (NULL != dc->job_queue); | ||
1425 | dc->task = | ||
1426 | GNUNET_SCHEDULER_add_delayed (dc->reconnect_backoff, &do_reconnect, dc); | ||
1427 | } | ||
1428 | |||
1429 | |||
1430 | /** | ||
1431 | * We're allowed to ask the FS service for our blocks. Start the download. | ||
1432 | * | ||
1433 | * @param cls the 'struct GNUNET_FS_DownloadContext' | ||
1434 | * @param mq handle to use for communication with FS (we must destroy it!) | ||
1435 | */ | ||
1436 | static void | ||
1437 | activate_fs_download (void *cls) | ||
1438 | { | ||
1439 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1440 | struct GNUNET_FS_ProgressInfo pi; | ||
1441 | |||
1442 | GNUNET_assert (NULL == dc->mq); | ||
1443 | GNUNET_assert (NULL != dc->active); | ||
1444 | do_reconnect (dc); | ||
1445 | if (NULL != dc->mq) | ||
1446 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download activated\n"); | ||
1447 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE; | ||
1448 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1449 | } | ||
1450 | |||
1451 | |||
1452 | /** | ||
1453 | * We must stop to ask the FS service for our blocks. Pause the download. | ||
1454 | * | ||
1455 | * @param cls the `struct GNUNET_FS_DownloadContext` | ||
1456 | */ | ||
1457 | static void | ||
1458 | deactivate_fs_download (void *cls) | ||
1459 | { | ||
1460 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1461 | struct GNUNET_FS_ProgressInfo pi; | ||
1462 | |||
1463 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download deactivated\n"); | ||
1464 | if (NULL != dc->mq) | ||
1465 | { | ||
1466 | GNUNET_MQ_destroy (dc->mq); | ||
1467 | dc->mq = NULL; | ||
1468 | } | ||
1469 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_INACTIVE; | ||
1470 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1471 | } | ||
1472 | |||
1473 | |||
1474 | /** | ||
1475 | * (recursively) Create a download request structure. | ||
1476 | * | ||
1477 | * @param parent parent of the current entry | ||
1478 | * @param chk_idx index of the chk for this block in the parent block | ||
1479 | * @param depth depth of the current entry, 0 are the DBLOCKs, | ||
1480 | * top level block is 'dc->treedepth - 1' | ||
1481 | * @param dr_offset offset in the original file this block maps to | ||
1482 | * (as in, offset of the first byte of the first DBLOCK | ||
1483 | * in the subtree rooted in the returned download request tree) | ||
1484 | * @param file_start_offset desired starting offset for the download | ||
1485 | * in the original file; requesting tree should not contain | ||
1486 | * DBLOCKs prior to the file_start_offset | ||
1487 | * @param desired_length desired number of bytes the user wanted to access | ||
1488 | * (from file_start_offset). Resulting tree should not contain | ||
1489 | * DBLOCKs after file_start_offset + file_length. | ||
1490 | * @return download request tree for the given range of DBLOCKs at | ||
1491 | * the specified depth | ||
1492 | */ | ||
1493 | static struct DownloadRequest * | ||
1494 | create_download_request (struct DownloadRequest *parent, | ||
1495 | unsigned int chk_idx, | ||
1496 | unsigned int depth, | ||
1497 | uint64_t dr_offset, | ||
1498 | uint64_t file_start_offset, | ||
1499 | uint64_t desired_length) | ||
1500 | { | ||
1501 | struct DownloadRequest *dr; | ||
1502 | unsigned int i; | ||
1503 | unsigned int head_skip; | ||
1504 | uint64_t child_block_size; | ||
1505 | |||
1506 | dr = GNUNET_new (struct DownloadRequest); | ||
1507 | dr->parent = parent; | ||
1508 | dr->depth = depth; | ||
1509 | dr->offset = dr_offset; | ||
1510 | dr->chk_idx = chk_idx; | ||
1511 | if (0 == depth) | ||
1512 | return dr; | ||
1513 | child_block_size = GNUNET_FS_tree_compute_tree_size (depth - 1); | ||
1514 | |||
1515 | /* calculate how many blocks at this level are not interesting | ||
1516 | * from the start (rounded down), either because of the requested | ||
1517 | * file offset or because this IBlock is further along */ | ||
1518 | if (dr_offset < file_start_offset) | ||
1519 | { | ||
1520 | head_skip = (file_start_offset - dr_offset) / child_block_size; | ||
1521 | } | ||
1522 | else | ||
1523 | { | ||
1524 | head_skip = 0; | ||
1525 | } | ||
1526 | |||
1527 | /* calculate index of last block at this level that is interesting (rounded up) */ | ||
1528 | dr->num_children = | ||
1529 | (file_start_offset + desired_length - dr_offset) / child_block_size; | ||
1530 | if (dr->num_children * child_block_size < | ||
1531 | file_start_offset + desired_length - dr_offset) | ||
1532 | dr->num_children++; /* round up */ | ||
1533 | GNUNET_assert (dr->num_children > head_skip); | ||
1534 | dr->num_children -= head_skip; | ||
1535 | if (dr->num_children > CHK_PER_INODE) | ||
1536 | dr->num_children = CHK_PER_INODE; /* cap at max */ | ||
1537 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1538 | "Block at offset %llu and depth %u has %u children\n", | ||
1539 | (unsigned long long) dr_offset, | ||
1540 | depth, | ||
1541 | dr->num_children); | ||
1542 | |||
1543 | /* now we can get the total number of *interesting* children for this block */ | ||
1544 | |||
1545 | /* why else would we have gotten here to begin with? (that'd be a bad logic error) */ | ||
1546 | GNUNET_assert (dr->num_children > 0); | ||
1547 | |||
1548 | dr->children = GNUNET_new_array (dr->num_children, struct DownloadRequest *); | ||
1549 | for (i = 0; i < dr->num_children; i++) | ||
1550 | { | ||
1551 | dr->children[i] = | ||
1552 | create_download_request (dr, | ||
1553 | i + head_skip, | ||
1554 | depth - 1, | ||
1555 | dr_offset + (i + head_skip) * child_block_size, | ||
1556 | file_start_offset, | ||
1557 | desired_length); | ||
1558 | } | ||
1559 | return dr; | ||
1560 | } | ||
1561 | |||
1562 | |||
1563 | /** | ||
1564 | * Continuation after a possible attempt to reconstruct | ||
1565 | * the current IBlock from the existing file. | ||
1566 | * | ||
1567 | * @param cls the 'struct ReconstructContext' | ||
1568 | */ | ||
1569 | static void | ||
1570 | reconstruct_cont (void *cls) | ||
1571 | { | ||
1572 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1573 | |||
1574 | /* clean up state from tree encoder */ | ||
1575 | if (NULL != dc->task) | ||
1576 | { | ||
1577 | GNUNET_SCHEDULER_cancel (dc->task); | ||
1578 | dc->task = NULL; | ||
1579 | } | ||
1580 | if (NULL != dc->rfh) | ||
1581 | { | ||
1582 | GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (dc->rfh)); | ||
1583 | dc->rfh = NULL; | ||
1584 | } | ||
1585 | /* start "normal" download */ | ||
1586 | dc->issue_requests = GNUNET_YES; | ||
1587 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting normal download\n"); | ||
1588 | schedule_block_download (dc, dc->top_request); | ||
1589 | } | ||
1590 | |||
1591 | |||
1592 | /** | ||
1593 | * Task requesting the next block from the tree encoder. | ||
1594 | * | ||
1595 | * @param cls the 'struct GNUJNET_FS_DownloadContext' we're processing | ||
1596 | */ | ||
1597 | static void | ||
1598 | get_next_block (void *cls) | ||
1599 | { | ||
1600 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1601 | |||
1602 | dc->task = NULL; | ||
1603 | GNUNET_FS_tree_encoder_next (dc->te); | ||
1604 | } | ||
1605 | |||
1606 | |||
1607 | /** | ||
1608 | * Function called asking for the current (encoded) | ||
1609 | * block to be processed. After processing the | ||
1610 | * client should either call "GNUNET_FS_tree_encode_next" | ||
1611 | * or (on error) "GNUNET_FS_tree_encode_finish". | ||
1612 | * | ||
1613 | * This function checks if the content on disk matches | ||
1614 | * the expected content based on the URI. | ||
1615 | * | ||
1616 | * @param cls closure | ||
1617 | * @param chk content hash key for the block | ||
1618 | * @param offset offset of the block | ||
1619 | * @param depth depth of the block, 0 for DBLOCK | ||
1620 | * @param type type of the block (IBLOCK or DBLOCK) | ||
1621 | * @param block the (encrypted) block | ||
1622 | * @param block_size size of block (in bytes) | ||
1623 | */ | ||
1624 | static void | ||
1625 | reconstruct_cb (void *cls, | ||
1626 | const struct ContentHashKey *chk, | ||
1627 | uint64_t offset, | ||
1628 | unsigned int depth, | ||
1629 | enum GNUNET_BLOCK_Type type, | ||
1630 | const void *block, | ||
1631 | uint16_t block_size) | ||
1632 | { | ||
1633 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1634 | struct GNUNET_FS_ProgressInfo pi; | ||
1635 | struct DownloadRequest *dr; | ||
1636 | uint64_t blen; | ||
1637 | unsigned int chld; | ||
1638 | |||
1639 | /* find corresponding request entry */ | ||
1640 | dr = dc->top_request; | ||
1641 | while (dr->depth > depth) | ||
1642 | { | ||
1643 | GNUNET_assert (dr->num_children > 0); | ||
1644 | blen = GNUNET_FS_tree_compute_tree_size (dr->depth - 1); | ||
1645 | chld = (offset - dr->offset) / blen; | ||
1646 | if (chld < dr->children[0]->chk_idx) | ||
1647 | { | ||
1648 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1649 | "Block %u < %u irrelevant for our range\n", | ||
1650 | chld, | ||
1651 | dr->children[0]->chk_idx); | ||
1652 | dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); | ||
1653 | return; /* irrelevant block */ | ||
1654 | } | ||
1655 | if (chld > dr->children[dr->num_children - 1]->chk_idx) | ||
1656 | { | ||
1657 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1658 | "Block %u > %u irrelevant for our range\n", | ||
1659 | chld, | ||
1660 | dr->children[dr->num_children - 1]->chk_idx); | ||
1661 | dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); | ||
1662 | return; /* irrelevant block */ | ||
1663 | } | ||
1664 | dr = dr->children[chld - dr->children[0]->chk_idx]; | ||
1665 | } | ||
1666 | GNUNET_log ( | ||
1667 | GNUNET_ERROR_TYPE_DEBUG, | ||
1668 | "Matched TE block with request at offset %llu and depth %u in state %d\n", | ||
1669 | (unsigned long long) dr->offset, | ||
1670 | dr->depth, | ||
1671 | dr->state); | ||
1672 | /* FIXME: this code needs more testing and might | ||
1673 | need to handle more states... */ | ||
1674 | switch (dr->state) | ||
1675 | { | ||
1676 | case BRS_INIT: | ||
1677 | break; | ||
1678 | |||
1679 | case BRS_RECONSTRUCT_DOWN: | ||
1680 | break; | ||
1681 | |||
1682 | case BRS_RECONSTRUCT_META_UP: | ||
1683 | break; | ||
1684 | |||
1685 | case BRS_RECONSTRUCT_UP: | ||
1686 | break; | ||
1687 | |||
1688 | case BRS_CHK_SET: | ||
1689 | if (0 == memcmp (chk, &dr->chk, sizeof(struct ContentHashKey))) | ||
1690 | { | ||
1691 | GNUNET_log ( | ||
1692 | GNUNET_ERROR_TYPE_DEBUG, | ||
1693 | "Reconstruction succeeded, can use block at offset %llu, depth %u\n", | ||
1694 | (unsigned long long) offset, | ||
1695 | depth); | ||
1696 | /* block matches, hence tree below matches; | ||
1697 | * this request is done! */ | ||
1698 | dr->state = BRS_DOWNLOAD_UP; | ||
1699 | (void) GNUNET_CONTAINER_multihashmap_remove (dc->active, | ||
1700 | &dr->chk.query, | ||
1701 | dr); | ||
1702 | /* calculate how many bytes of payload this block | ||
1703 | * corresponds to */ | ||
1704 | blen = GNUNET_FS_tree_compute_tree_size (dr->depth); | ||
1705 | /* how many of those bytes are in the requested range? */ | ||
1706 | blen = GNUNET_MIN (blen, dc->length + dc->offset - dr->offset); | ||
1707 | /* signal progress */ | ||
1708 | dc->completed += blen; | ||
1709 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; | ||
1710 | pi.value.download.specifics.progress.data = NULL; | ||
1711 | pi.value.download.specifics.progress.offset = offset; | ||
1712 | pi.value.download.specifics.progress.data_len = 0; | ||
1713 | pi.value.download.specifics.progress.depth = 0; | ||
1714 | pi.value.download.specifics.progress.respect_offered = 0; | ||
1715 | pi.value.download.specifics.progress.block_download_duration = | ||
1716 | GNUNET_TIME_UNIT_ZERO; | ||
1717 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1718 | /* FIXME: duplicated code from 'process_result_with_request - refactor */ | ||
1719 | if (dc->completed == dc->length) | ||
1720 | { | ||
1721 | /* download completed, signal */ | ||
1722 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1723 | "Download completed, truncating file to desired length %llu\n", | ||
1724 | (unsigned long long) GNUNET_ntohll ( | ||
1725 | dc->uri->data.chk.file_length)); | ||
1726 | /* truncate file to size (since we store IBlocks at the end) */ | ||
1727 | if (NULL != dc->filename) | ||
1728 | { | ||
1729 | if (0 != truncate (dc->filename, | ||
1730 | GNUNET_ntohll (dc->uri->data.chk.file_length))) | ||
1731 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
1732 | "truncate", | ||
1733 | dc->filename); | ||
1734 | } | ||
1735 | } | ||
1736 | } | ||
1737 | else | ||
1738 | GNUNET_log ( | ||
1739 | GNUNET_ERROR_TYPE_DEBUG, | ||
1740 | "Reconstruction failed, need to download block at offset %llu, depth %u\n", | ||
1741 | (unsigned long long) offset, | ||
1742 | depth); | ||
1743 | break; | ||
1744 | |||
1745 | case BRS_DOWNLOAD_DOWN: | ||
1746 | break; | ||
1747 | |||
1748 | case BRS_DOWNLOAD_UP: | ||
1749 | break; | ||
1750 | |||
1751 | case BRS_ERROR: | ||
1752 | break; | ||
1753 | |||
1754 | default: | ||
1755 | GNUNET_assert (0); | ||
1756 | break; | ||
1757 | } | ||
1758 | dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); | ||
1759 | if ((dr == dc->top_request) && (dr->state == BRS_DOWNLOAD_UP)) | ||
1760 | check_completed (dc); | ||
1761 | } | ||
1762 | |||
1763 | |||
1764 | /** | ||
1765 | * Function called by the tree encoder to obtain a block of plaintext | ||
1766 | * data (for the lowest level of the tree). | ||
1767 | * | ||
1768 | * @param cls our 'struct ReconstructContext' | ||
1769 | * @param offset identifies which block to get | ||
1770 | * @param max (maximum) number of bytes to get; returning | ||
1771 | * fewer will also cause errors | ||
1772 | * @param buf where to copy the plaintext buffer | ||
1773 | * @param emsg location to store an error message (on error) | ||
1774 | * @return number of bytes copied to buf, 0 on error | ||
1775 | */ | ||
1776 | static size_t | ||
1777 | fh_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) | ||
1778 | { | ||
1779 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1780 | struct GNUNET_DISK_FileHandle *fh = dc->rfh; | ||
1781 | ssize_t ret; | ||
1782 | |||
1783 | if (NULL != emsg) | ||
1784 | *emsg = NULL; | ||
1785 | if (offset != GNUNET_DISK_file_seek (fh, offset, GNUNET_DISK_SEEK_SET)) | ||
1786 | { | ||
1787 | if (NULL != emsg) | ||
1788 | *emsg = GNUNET_strdup (strerror (errno)); | ||
1789 | return 0; | ||
1790 | } | ||
1791 | ret = GNUNET_DISK_file_read (fh, buf, max); | ||
1792 | if (ret < 0) | ||
1793 | { | ||
1794 | if (NULL != emsg) | ||
1795 | *emsg = GNUNET_strdup (strerror (errno)); | ||
1796 | return 0; | ||
1797 | } | ||
1798 | return ret; | ||
1799 | } | ||
1800 | |||
1801 | |||
1802 | /** | ||
1803 | * Task that creates the initial (top-level) download | ||
1804 | * request for the file. | ||
1805 | * | ||
1806 | * @param cls the 'struct GNUNET_FS_DownloadContext' | ||
1807 | */ | ||
1808 | void | ||
1809 | GNUNET_FS_download_start_task_ (void *cls) | ||
1810 | { | ||
1811 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1812 | struct GNUNET_FS_ProgressInfo pi; | ||
1813 | struct GNUNET_DISK_FileHandle *fh; | ||
1814 | |||
1815 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start task running...\n"); | ||
1816 | dc->task = NULL; | ||
1817 | if (0 == dc->length) | ||
1818 | { | ||
1819 | /* no bytes required! */ | ||
1820 | if (NULL != dc->filename) | ||
1821 | { | ||
1822 | fh = GNUNET_DISK_file_open (dc->filename, | ||
1823 | GNUNET_DISK_OPEN_READWRITE | ||
1824 | | GNUNET_DISK_OPEN_CREATE | ||
1825 | | ((0 == | ||
1826 | GNUNET_FS_uri_chk_get_file_size (dc->uri)) | ||
1827 | ? GNUNET_DISK_OPEN_TRUNCATE | ||
1828 | : 0), | ||
1829 | GNUNET_DISK_PERM_USER_READ | ||
1830 | | GNUNET_DISK_PERM_USER_WRITE | ||
1831 | | GNUNET_DISK_PERM_GROUP_READ | ||
1832 | | GNUNET_DISK_PERM_OTHER_READ); | ||
1833 | GNUNET_DISK_file_close (fh); | ||
1834 | } | ||
1835 | GNUNET_FS_download_sync_ (dc); | ||
1836 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_START; | ||
1837 | pi.value.download.specifics.start.meta = dc->meta; | ||
1838 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1839 | check_completed (dc); | ||
1840 | return; | ||
1841 | } | ||
1842 | if (NULL != dc->emsg) | ||
1843 | return; | ||
1844 | if (NULL == dc->top_request) | ||
1845 | { | ||
1846 | dc->top_request = create_download_request (NULL, | ||
1847 | 0, | ||
1848 | dc->treedepth - 1, | ||
1849 | 0, | ||
1850 | dc->offset, | ||
1851 | dc->length); | ||
1852 | dc->top_request->state = BRS_CHK_SET; | ||
1853 | dc->top_request->chk = (dc->uri->type == GNUNET_FS_URI_CHK) | ||
1854 | ? dc->uri->data.chk.chk | ||
1855 | : dc->uri->data.loc.fi.chk; | ||
1856 | /* signal start */ | ||
1857 | GNUNET_FS_download_sync_ (dc); | ||
1858 | if (NULL != dc->search) | ||
1859 | GNUNET_FS_search_result_sync_ (dc->search); | ||
1860 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_START; | ||
1861 | pi.value.download.specifics.start.meta = dc->meta; | ||
1862 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1863 | } | ||
1864 | GNUNET_FS_download_start_downloading_ (dc); | ||
1865 | /* attempt reconstruction from disk */ | ||
1866 | if (GNUNET_YES == GNUNET_DISK_file_test (dc->filename)) | ||
1867 | dc->rfh = GNUNET_DISK_file_open (dc->filename, | ||
1868 | GNUNET_DISK_OPEN_READ, | ||
1869 | GNUNET_DISK_PERM_NONE); | ||
1870 | if (dc->top_request->state == BRS_CHK_SET) | ||
1871 | { | ||
1872 | if (NULL != dc->rfh) | ||
1873 | { | ||
1874 | /* first, try top-down */ | ||
1875 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1876 | "Trying top-down reconstruction for `%s'\n", | ||
1877 | dc->filename); | ||
1878 | try_top_down_reconstruction (dc, dc->top_request); | ||
1879 | switch (dc->top_request->state) | ||
1880 | { | ||
1881 | case BRS_CHK_SET: | ||
1882 | break; /* normal */ | ||
1883 | |||
1884 | case BRS_DOWNLOAD_DOWN: | ||
1885 | break; /* normal, some blocks already down */ | ||
1886 | |||
1887 | case BRS_DOWNLOAD_UP: | ||
1888 | /* already done entirely, party! */ | ||
1889 | if (NULL != dc->rfh) | ||
1890 | { | ||
1891 | /* avoid hanging on to file handle longer than | ||
1892 | * necessary */ | ||
1893 | GNUNET_DISK_file_close (dc->rfh); | ||
1894 | dc->rfh = NULL; | ||
1895 | } | ||
1896 | return; | ||
1897 | |||
1898 | case BRS_ERROR: | ||
1899 | GNUNET_asprintf (&dc->emsg, _ ("Invalid URI")); | ||
1900 | GNUNET_FS_download_sync_ (dc); | ||
1901 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; | ||
1902 | pi.value.download.specifics.error.message = dc->emsg; | ||
1903 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1904 | return; | ||
1905 | |||
1906 | default: | ||
1907 | GNUNET_assert (0); | ||
1908 | break; | ||
1909 | } | ||
1910 | } | ||
1911 | } | ||
1912 | /* attempt reconstruction from meta data */ | ||
1913 | if ((GNUNET_FS_uri_chk_get_file_size (dc->uri) <= MAX_INLINE_SIZE) && | ||
1914 | (NULL != dc->meta)) | ||
1915 | { | ||
1916 | GNUNET_log ( | ||
1917 | GNUNET_ERROR_TYPE_DEBUG, | ||
1918 | "Trying to find embedded meta data for download of size %llu with %u bytes MD\n", | ||
1919 | (unsigned long long) GNUNET_FS_uri_chk_get_file_size (dc->uri), | ||
1920 | (unsigned int) GNUNET_CONTAINER_meta_data_get_serialized_size (dc->meta)); | ||
1921 | GNUNET_CONTAINER_meta_data_iterate (dc->meta, &match_full_data, dc); | ||
1922 | if (BRS_DOWNLOAD_UP == dc->top_request->state) | ||
1923 | { | ||
1924 | if (NULL != dc->rfh) | ||
1925 | { | ||
1926 | /* avoid hanging on to file handle longer than | ||
1927 | * necessary */ | ||
1928 | GNUNET_DISK_file_close (dc->rfh); | ||
1929 | dc->rfh = NULL; | ||
1930 | } | ||
1931 | return; /* finished, status update was already done for us */ | ||
1932 | } | ||
1933 | } | ||
1934 | if (NULL != dc->rfh) | ||
1935 | { | ||
1936 | /* finally, actually run bottom-up */ | ||
1937 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1938 | "Trying bottom-up reconstruction of file `%s'\n", | ||
1939 | dc->filename); | ||
1940 | dc->te = | ||
1941 | GNUNET_FS_tree_encoder_create (dc->h, | ||
1942 | GNUNET_FS_uri_chk_get_file_size (dc->uri), | ||
1943 | dc, | ||
1944 | &fh_reader, | ||
1945 | &reconstruct_cb, | ||
1946 | NULL, | ||
1947 | &reconstruct_cont); | ||
1948 | dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); | ||
1949 | } | ||
1950 | else | ||
1951 | { | ||
1952 | /* simple, top-level download */ | ||
1953 | dc->issue_requests = GNUNET_YES; | ||
1954 | schedule_block_download (dc, dc->top_request); | ||
1955 | } | ||
1956 | if (BRS_DOWNLOAD_UP == dc->top_request->state) | ||
1957 | check_completed (dc); | ||
1958 | } | ||
1959 | |||
1960 | |||
1961 | /** | ||
1962 | * Create SUSPEND event for the given download operation | ||
1963 | * and then clean up our state (without stop signal). | ||
1964 | * | ||
1965 | * @param cls the 'struct GNUNET_FS_DownloadContext' to signal for | ||
1966 | */ | ||
1967 | void | ||
1968 | GNUNET_FS_download_signal_suspend_ (void *cls) | ||
1969 | { | ||
1970 | struct GNUNET_FS_DownloadContext *dc = cls; | ||
1971 | struct GNUNET_FS_ProgressInfo pi; | ||
1972 | |||
1973 | if (NULL != dc->top) | ||
1974 | GNUNET_FS_end_top (dc->h, dc->top); | ||
1975 | while (NULL != dc->child_head) | ||
1976 | GNUNET_FS_download_signal_suspend_ (dc->child_head); | ||
1977 | if (NULL != dc->search) | ||
1978 | { | ||
1979 | dc->search->download = NULL; | ||
1980 | dc->search = NULL; | ||
1981 | } | ||
1982 | if (NULL != dc->job_queue) | ||
1983 | { | ||
1984 | GNUNET_FS_dequeue_ (dc->job_queue); | ||
1985 | dc->job_queue = NULL; | ||
1986 | } | ||
1987 | if (NULL != dc->parent) | ||
1988 | GNUNET_CONTAINER_DLL_remove (dc->parent->child_head, | ||
1989 | dc->parent->child_tail, | ||
1990 | dc); | ||
1991 | if (NULL != dc->task) | ||
1992 | { | ||
1993 | GNUNET_SCHEDULER_cancel (dc->task); | ||
1994 | dc->task = NULL; | ||
1995 | } | ||
1996 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_SUSPEND; | ||
1997 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
1998 | if (NULL != dc->te) | ||
1999 | { | ||
2000 | GNUNET_FS_tree_encoder_finish (dc->te, NULL); | ||
2001 | dc->te = NULL; | ||
2002 | } | ||
2003 | if (NULL != dc->rfh) | ||
2004 | { | ||
2005 | GNUNET_DISK_file_close (dc->rfh); | ||
2006 | dc->rfh = NULL; | ||
2007 | } | ||
2008 | GNUNET_FS_free_download_request_ (dc->top_request); | ||
2009 | if (NULL != dc->active) | ||
2010 | { | ||
2011 | GNUNET_CONTAINER_multihashmap_destroy (dc->active); | ||
2012 | dc->active = NULL; | ||
2013 | } | ||
2014 | GNUNET_free (dc->filename); | ||
2015 | GNUNET_CONTAINER_meta_data_destroy (dc->meta); | ||
2016 | GNUNET_FS_uri_destroy (dc->uri); | ||
2017 | GNUNET_free (dc->temp_filename); | ||
2018 | GNUNET_free (dc->serialization); | ||
2019 | GNUNET_assert (NULL == dc->job_queue); | ||
2020 | GNUNET_free (dc); | ||
2021 | } | ||
2022 | |||
2023 | |||
2024 | /** | ||
2025 | * Helper function to setup the download context. | ||
2026 | * | ||
2027 | * @param h handle to the file sharing subsystem | ||
2028 | * @param uri the URI of the file (determines what to download); CHK or LOC URI | ||
2029 | * @param meta known metadata for the file (can be NULL) | ||
2030 | * @param filename where to store the file, maybe NULL (then no file is | ||
2031 | * created on disk and data must be grabbed from the callbacks) | ||
2032 | * @param tempname where to store temporary file data, not used if filename is non-NULL; | ||
2033 | * can be NULL (in which case we will pick a name if needed); the temporary file | ||
2034 | * may already exist, in which case we will try to use the data that is there and | ||
2035 | * if it is not what is desired, will overwrite it | ||
2036 | * @param offset at what offset should we start the download (typically 0) | ||
2037 | * @param length how many bytes should be downloaded starting at offset | ||
2038 | * @param anonymity anonymity level to use for the download | ||
2039 | * @param options various options | ||
2040 | * @param cctx initial value for the client context for this download | ||
2041 | * @return context that can be used to control this download | ||
2042 | */ | ||
2043 | struct GNUNET_FS_DownloadContext * | ||
2044 | create_download_context (struct GNUNET_FS_Handle *h, | ||
2045 | const struct GNUNET_FS_Uri *uri, | ||
2046 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
2047 | const char *filename, | ||
2048 | const char *tempname, | ||
2049 | uint64_t offset, | ||
2050 | uint64_t length, | ||
2051 | uint32_t anonymity, | ||
2052 | enum GNUNET_FS_DownloadOptions options, | ||
2053 | void *cctx) | ||
2054 | { | ||
2055 | struct GNUNET_FS_DownloadContext *dc; | ||
2056 | |||
2057 | GNUNET_assert (GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)); | ||
2058 | if ((offset + length < offset) || | ||
2059 | (offset + length > GNUNET_FS_uri_chk_get_file_size (uri))) | ||
2060 | { | ||
2061 | GNUNET_break (0); | ||
2062 | return NULL; | ||
2063 | } | ||
2064 | dc = GNUNET_new (struct GNUNET_FS_DownloadContext); | ||
2065 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2066 | "Starting download %p, %u bytes at offset %llu\n", | ||
2067 | dc, | ||
2068 | (unsigned int) length, | ||
2069 | (unsigned long long) offset); | ||
2070 | dc->h = h; | ||
2071 | dc->uri = GNUNET_FS_uri_dup (uri); | ||
2072 | dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
2073 | dc->client_info = cctx; | ||
2074 | dc->start_time = GNUNET_TIME_absolute_get (); | ||
2075 | if (NULL != filename) | ||
2076 | { | ||
2077 | dc->filename = GNUNET_strdup (filename); | ||
2078 | if (GNUNET_YES == GNUNET_DISK_file_test (filename)) | ||
2079 | GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (filename, | ||
2080 | &dc->old_file_size, | ||
2081 | GNUNET_YES, | ||
2082 | GNUNET_YES)); | ||
2083 | } | ||
2084 | if (GNUNET_FS_uri_test_loc (dc->uri)) | ||
2085 | GNUNET_assert (GNUNET_OK == | ||
2086 | GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target)); | ||
2087 | dc->offset = offset; | ||
2088 | dc->length = length; | ||
2089 | dc->anonymity = anonymity; | ||
2090 | dc->options = options; | ||
2091 | dc->active = | ||
2092 | GNUNET_CONTAINER_multihashmap_create (1 + 2 * (length / DBLOCK_SIZE), | ||
2093 | GNUNET_NO); | ||
2094 | dc->treedepth = | ||
2095 | GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri)); | ||
2096 | if ((NULL == filename) && (is_recursive_download (dc))) | ||
2097 | { | ||
2098 | if (NULL != tempname) | ||
2099 | dc->temp_filename = GNUNET_strdup (tempname); | ||
2100 | else | ||
2101 | dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp"); | ||
2102 | } | ||
2103 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2104 | "Starting download `%s' of %llu bytes with tree depth %u\n", | ||
2105 | filename, | ||
2106 | (unsigned long long) length, | ||
2107 | dc->treedepth); | ||
2108 | GNUNET_assert (NULL == dc->job_queue); | ||
2109 | dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc); | ||
2110 | return dc; | ||
2111 | } | ||
2112 | |||
2113 | |||
2114 | /** | ||
2115 | * Download parts of a file. Note that this will store | ||
2116 | * the blocks at the respective offset in the given file. Also, the | ||
2117 | * download is still using the blocking of the underlying FS | ||
2118 | * encoding. As a result, the download may *write* outside of the | ||
2119 | * given boundaries (if offset and length do not match the 32k FS | ||
2120 | * block boundaries). <p> | ||
2121 | * | ||
2122 | * This function should be used to focus a download towards a | ||
2123 | * particular portion of the file (optimization), not to strictly | ||
2124 | * limit the download to exactly those bytes. | ||
2125 | * | ||
2126 | * @param h handle to the file sharing subsystem | ||
2127 | * @param uri the URI of the file (determines what to download); CHK or LOC URI | ||
2128 | * @param meta known metadata for the file (can be NULL) | ||
2129 | * @param filename where to store the file, maybe NULL (then no file is | ||
2130 | * created on disk and data must be grabbed from the callbacks) | ||
2131 | * @param tempname where to store temporary file data, not used if filename is non-NULL; | ||
2132 | * can be NULL (in which case we will pick a name if needed); the temporary file | ||
2133 | * may already exist, in which case we will try to use the data that is there and | ||
2134 | * if it is not what is desired, will overwrite it | ||
2135 | * @param offset at what offset should we start the download (typically 0) | ||
2136 | * @param length how many bytes should be downloaded starting at offset | ||
2137 | * @param anonymity anonymity level to use for the download | ||
2138 | * @param options various options | ||
2139 | * @param cctx initial value for the client context for this download | ||
2140 | * @param parent parent download to associate this download with (use NULL | ||
2141 | * for top-level downloads; useful for manually-triggered recursive downloads) | ||
2142 | * @return context that can be used to control this download | ||
2143 | */ | ||
2144 | struct GNUNET_FS_DownloadContext * | ||
2145 | GNUNET_FS_download_start (struct GNUNET_FS_Handle *h, | ||
2146 | const struct GNUNET_FS_Uri *uri, | ||
2147 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
2148 | const char *filename, | ||
2149 | const char *tempname, | ||
2150 | uint64_t offset, | ||
2151 | uint64_t length, | ||
2152 | uint32_t anonymity, | ||
2153 | enum GNUNET_FS_DownloadOptions options, | ||
2154 | void *cctx, | ||
2155 | struct GNUNET_FS_DownloadContext *parent) | ||
2156 | { | ||
2157 | struct GNUNET_FS_DownloadContext *dc; | ||
2158 | |||
2159 | dc = create_download_context (h, | ||
2160 | uri, | ||
2161 | meta, | ||
2162 | filename, | ||
2163 | tempname, | ||
2164 | offset, | ||
2165 | length, | ||
2166 | anonymity, | ||
2167 | options, | ||
2168 | cctx); | ||
2169 | if (NULL == dc) | ||
2170 | return NULL; | ||
2171 | dc->parent = parent; | ||
2172 | if (NULL != parent) | ||
2173 | GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc); | ||
2174 | else if (0 == (GNUNET_FS_DOWNLOAD_IS_PROBE & options)) | ||
2175 | dc->top = | ||
2176 | GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc); | ||
2177 | return dc; | ||
2178 | } | ||
2179 | |||
2180 | |||
2181 | /** | ||
2182 | * Download parts of a file based on a search result. The download | ||
2183 | * will be associated with the search result (and the association | ||
2184 | * will be preserved when serializing/deserializing the state). | ||
2185 | * If the search is stopped, the download will not be aborted but | ||
2186 | * be 'promoted' to a stand-alone download. | ||
2187 | * | ||
2188 | * As with the other download function, this will store | ||
2189 | * the blocks at the respective offset in the given file. Also, the | ||
2190 | * download is still using the blocking of the underlying FS | ||
2191 | * encoding. As a result, the download may *write* outside of the | ||
2192 | * given boundaries (if offset and length do not match the 32k FS | ||
2193 | * block boundaries). <p> | ||
2194 | * | ||
2195 | * The given range can be used to focus a download towards a | ||
2196 | * particular portion of the file (optimization), not to strictly | ||
2197 | * limit the download to exactly those bytes. | ||
2198 | * | ||
2199 | * @param h handle to the file sharing subsystem | ||
2200 | * @param sr the search result to use for the download (determines uri and | ||
2201 | * meta data and associations) | ||
2202 | * @param filename where to store the file, maybe NULL (then no file is | ||
2203 | * created on disk and data must be grabbed from the callbacks) | ||
2204 | * @param tempname where to store temporary file data, not used if filename is non-NULL; | ||
2205 | * can be NULL (in which case we will pick a name if needed); the temporary file | ||
2206 | * may already exist, in which case we will try to use the data that is there and | ||
2207 | * if it is not what is desired, will overwrite it | ||
2208 | * @param offset at what offset should we start the download (typically 0) | ||
2209 | * @param length how many bytes should be downloaded starting at offset | ||
2210 | * @param anonymity anonymity level to use for the download | ||
2211 | * @param options various download options | ||
2212 | * @param cctx initial value for the client context for this download | ||
2213 | * @return context that can be used to control this download | ||
2214 | */ | ||
2215 | struct GNUNET_FS_DownloadContext * | ||
2216 | GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h, | ||
2217 | struct GNUNET_FS_SearchResult *sr, | ||
2218 | const char *filename, | ||
2219 | const char *tempname, | ||
2220 | uint64_t offset, | ||
2221 | uint64_t length, | ||
2222 | uint32_t anonymity, | ||
2223 | enum GNUNET_FS_DownloadOptions options, | ||
2224 | void *cctx) | ||
2225 | { | ||
2226 | struct GNUNET_FS_DownloadContext *dc; | ||
2227 | |||
2228 | if ((NULL == sr) || (NULL != sr->download)) | ||
2229 | { | ||
2230 | GNUNET_break (0); | ||
2231 | return NULL; | ||
2232 | } | ||
2233 | dc = create_download_context (h, | ||
2234 | sr->uri, | ||
2235 | sr->meta, | ||
2236 | filename, | ||
2237 | tempname, | ||
2238 | offset, | ||
2239 | length, | ||
2240 | anonymity, | ||
2241 | options, | ||
2242 | cctx); | ||
2243 | if (NULL == dc) | ||
2244 | return NULL; | ||
2245 | dc->search = sr; | ||
2246 | sr->download = dc; | ||
2247 | if (NULL != sr->probe_ctx) | ||
2248 | { | ||
2249 | GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); | ||
2250 | sr->probe_ctx = NULL; | ||
2251 | GNUNET_FS_stop_probe_ping_task_ (sr); | ||
2252 | } | ||
2253 | return dc; | ||
2254 | } | ||
2255 | |||
2256 | |||
2257 | /** | ||
2258 | * Start the downloading process (by entering the queue). | ||
2259 | * | ||
2260 | * @param dc our download context | ||
2261 | */ | ||
2262 | void | ||
2263 | GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc) | ||
2264 | { | ||
2265 | if (dc->completed == dc->length) | ||
2266 | return; | ||
2267 | if (NULL != dc->mq) | ||
2268 | return; /* already running */ | ||
2269 | GNUNET_assert (NULL == dc->job_queue); | ||
2270 | GNUNET_assert (NULL == dc->task); | ||
2271 | GNUNET_assert (NULL != dc->active); | ||
2272 | dc->job_queue = | ||
2273 | GNUNET_FS_queue_ (dc->h, | ||
2274 | &activate_fs_download, | ||
2275 | &deactivate_fs_download, | ||
2276 | dc, | ||
2277 | (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE, | ||
2278 | (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) | ||
2279 | ? GNUNET_FS_QUEUE_PRIORITY_NORMAL | ||
2280 | : GNUNET_FS_QUEUE_PRIORITY_PROBE); | ||
2281 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2282 | "Download %p put into queue as job %p\n", | ||
2283 | dc, | ||
2284 | dc->job_queue); | ||
2285 | } | ||
2286 | |||
2287 | |||
2288 | /** | ||
2289 | * Suspend a download. | ||
2290 | * | ||
2291 | * @param dc handle for the download | ||
2292 | */ | ||
2293 | void | ||
2294 | GNUNET_FS_download_suspend (struct GNUNET_FS_DownloadContext *dc) | ||
2295 | { | ||
2296 | deactivate_fs_download (dc); | ||
2297 | } | ||
2298 | |||
2299 | |||
2300 | /** | ||
2301 | * Resume a suspended download. | ||
2302 | * | ||
2303 | * @param dc handle for the download | ||
2304 | */ | ||
2305 | void | ||
2306 | GNUNET_FS_download_resume (struct GNUNET_FS_DownloadContext *dc) | ||
2307 | { | ||
2308 | struct GNUNET_FS_ProgressInfo pi; | ||
2309 | |||
2310 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE; | ||
2311 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
2312 | |||
2313 | GNUNET_assert (NULL == dc->task); | ||
2314 | dc->job_queue = | ||
2315 | GNUNET_FS_queue_ (dc->h, | ||
2316 | &activate_fs_download, | ||
2317 | &deactivate_fs_download, | ||
2318 | dc, | ||
2319 | (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE, | ||
2320 | (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) | ||
2321 | ? GNUNET_FS_QUEUE_PRIORITY_NORMAL | ||
2322 | : GNUNET_FS_QUEUE_PRIORITY_PROBE); | ||
2323 | } | ||
2324 | |||
2325 | |||
2326 | /** | ||
2327 | * Stop a download (aborts if download is incomplete). | ||
2328 | * | ||
2329 | * @param dc handle for the download | ||
2330 | * @param do_delete delete files of incomplete downloads | ||
2331 | */ | ||
2332 | void | ||
2333 | GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc, int do_delete) | ||
2334 | { | ||
2335 | struct GNUNET_FS_ProgressInfo pi; | ||
2336 | int have_children; | ||
2337 | int search_was_null; | ||
2338 | |||
2339 | if (NULL != dc->top) | ||
2340 | GNUNET_FS_end_top (dc->h, dc->top); | ||
2341 | if (NULL != dc->task) | ||
2342 | { | ||
2343 | GNUNET_SCHEDULER_cancel (dc->task); | ||
2344 | dc->task = NULL; | ||
2345 | } | ||
2346 | search_was_null = (NULL == dc->search); | ||
2347 | if (NULL != dc->search) | ||
2348 | { | ||
2349 | dc->search->download = NULL; | ||
2350 | GNUNET_FS_search_result_sync_ (dc->search); | ||
2351 | dc->search = NULL; | ||
2352 | } | ||
2353 | if (NULL != dc->job_queue) | ||
2354 | { | ||
2355 | GNUNET_FS_dequeue_ (dc->job_queue); | ||
2356 | dc->job_queue = NULL; | ||
2357 | } | ||
2358 | if (NULL != dc->te) | ||
2359 | { | ||
2360 | GNUNET_FS_tree_encoder_finish (dc->te, NULL); | ||
2361 | dc->te = NULL; | ||
2362 | } | ||
2363 | have_children = (NULL != dc->child_head) ? GNUNET_YES : GNUNET_NO; | ||
2364 | while (NULL != dc->child_head) | ||
2365 | GNUNET_FS_download_stop (dc->child_head, do_delete); | ||
2366 | if (NULL != dc->parent) | ||
2367 | GNUNET_CONTAINER_DLL_remove (dc->parent->child_head, | ||
2368 | dc->parent->child_tail, | ||
2369 | dc); | ||
2370 | if (NULL != dc->serialization) | ||
2371 | GNUNET_FS_remove_sync_file_ (dc->h, | ||
2372 | ((NULL != dc->parent) || (! search_was_null)) | ||
2373 | ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD | ||
2374 | : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, | ||
2375 | dc->serialization); | ||
2376 | if ((GNUNET_YES == have_children) && (NULL == dc->parent)) | ||
2377 | GNUNET_FS_remove_sync_dir_ (dc->h, | ||
2378 | (! search_was_null) | ||
2379 | ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD | ||
2380 | : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, | ||
2381 | dc->serialization); | ||
2382 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_STOPPED; | ||
2383 | GNUNET_FS_download_make_status_ (&pi, dc); | ||
2384 | GNUNET_FS_free_download_request_ (dc->top_request); | ||
2385 | dc->top_request = NULL; | ||
2386 | if (NULL != dc->active) | ||
2387 | { | ||
2388 | GNUNET_CONTAINER_multihashmap_destroy (dc->active); | ||
2389 | dc->active = NULL; | ||
2390 | } | ||
2391 | if (NULL != dc->filename) | ||
2392 | { | ||
2393 | if ((dc->completed != dc->length) && (GNUNET_YES == do_delete)) | ||
2394 | { | ||
2395 | if ((0 != unlink (dc->filename)) && (ENOENT != errno)) | ||
2396 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
2397 | "unlink", | ||
2398 | dc->filename); | ||
2399 | } | ||
2400 | GNUNET_free (dc->filename); | ||
2401 | } | ||
2402 | GNUNET_CONTAINER_meta_data_destroy (dc->meta); | ||
2403 | GNUNET_FS_uri_destroy (dc->uri); | ||
2404 | if (NULL != dc->temp_filename) | ||
2405 | { | ||
2406 | if (0 != unlink (dc->temp_filename)) | ||
2407 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, | ||
2408 | "unlink", | ||
2409 | dc->temp_filename); | ||
2410 | GNUNET_free (dc->temp_filename); | ||
2411 | } | ||
2412 | GNUNET_free (dc->serialization); | ||
2413 | GNUNET_assert (NULL == dc->job_queue); | ||
2414 | GNUNET_free (dc); | ||
2415 | } | ||
2416 | |||
2417 | |||
2418 | /* end of fs_download.c */ | ||
diff --git a/src/fs/fs_file_information.c b/src/fs/fs_file_information.c deleted file mode 100644 index 3324abd58..000000000 --- a/src/fs/fs_file_information.c +++ /dev/null | |||
@@ -1,475 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_file_information.c | ||
23 | * @brief Manage information for publishing directory hierarchies | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #if HAVE_EXTRACTOR_H | ||
28 | #include <extractor.h> | ||
29 | #endif | ||
30 | #include "gnunet_fs_service.h" | ||
31 | #include "fs_api.h" | ||
32 | #include "fs_tree.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Obtain the name under which this file information | ||
37 | * structure is stored on disk. Only works for top-level | ||
38 | * file information structures. | ||
39 | * | ||
40 | * @param s structure to get the filename for | ||
41 | * @return NULL on error, otherwise filename that | ||
42 | * can be used to read this fi-struct from disk. | ||
43 | */ | ||
44 | const char * | ||
45 | GNUNET_FS_file_information_get_id (struct GNUNET_FS_FileInformation *s) | ||
46 | { | ||
47 | if (NULL != s->dir) | ||
48 | return NULL; | ||
49 | return s->serialization; | ||
50 | } | ||
51 | |||
52 | |||
53 | /** | ||
54 | * Obtain the filename from the file information structure. | ||
55 | * | ||
56 | * @param s structure to get the filename for | ||
57 | * @return "filename" field of the structure (can be NULL) | ||
58 | */ | ||
59 | const char * | ||
60 | GNUNET_FS_file_information_get_filename (struct GNUNET_FS_FileInformation *s) | ||
61 | { | ||
62 | return s->filename; | ||
63 | } | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Set the filename in the file information structure. | ||
68 | * If filename was already set, frees it before setting the new one. | ||
69 | * Makes a copy of the argument. | ||
70 | * | ||
71 | * @param s structure to get the filename for | ||
72 | * @param filename filename to set | ||
73 | */ | ||
74 | void | ||
75 | GNUNET_FS_file_information_set_filename (struct GNUNET_FS_FileInformation *s, | ||
76 | const char *filename) | ||
77 | { | ||
78 | GNUNET_free (s->filename); | ||
79 | if (filename) | ||
80 | s->filename = GNUNET_strdup (filename); | ||
81 | else | ||
82 | s->filename = NULL; | ||
83 | } | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Create an entry for a file in a publish-structure. | ||
88 | * | ||
89 | * @param h handle to the file sharing subsystem | ||
90 | * @param client_info initial value for the client-info value for this entry | ||
91 | * @param filename name of the file or directory to publish | ||
92 | * @param keywords under which keywords should this file be available | ||
93 | * directly; can be NULL | ||
94 | * @param meta metadata for the file | ||
95 | * @param do_index #GNUNET_YES for index, #GNUNET_NO for insertion, | ||
96 | * #GNUNET_SYSERR for simulation | ||
97 | * @param bo block options | ||
98 | * @return publish structure entry for the file | ||
99 | */ | ||
100 | struct GNUNET_FS_FileInformation * | ||
101 | GNUNET_FS_file_information_create_from_file ( | ||
102 | struct GNUNET_FS_Handle *h, | ||
103 | void *client_info, | ||
104 | const char *filename, | ||
105 | const struct GNUNET_FS_Uri *keywords, | ||
106 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
107 | int do_index, | ||
108 | const struct GNUNET_FS_BlockOptions *bo) | ||
109 | { | ||
110 | struct FileInfo *fi; | ||
111 | uint64_t fsize; | ||
112 | struct GNUNET_FS_FileInformation *ret; | ||
113 | const char *fn; | ||
114 | const char *ss; | ||
115 | |||
116 | /* FIXME: should include_symbolic_links be GNUNET_NO or GNUNET_YES here? */ | ||
117 | if (GNUNET_OK != | ||
118 | GNUNET_DISK_file_size (filename, &fsize, GNUNET_NO, GNUNET_YES)) | ||
119 | { | ||
120 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename); | ||
121 | return NULL; | ||
122 | } | ||
123 | fi = GNUNET_FS_make_file_reader_context_ (filename); | ||
124 | if (NULL == fi) | ||
125 | { | ||
126 | GNUNET_break (0); | ||
127 | return NULL; | ||
128 | } | ||
129 | ret = | ||
130 | GNUNET_FS_file_information_create_from_reader (h, | ||
131 | client_info, | ||
132 | fsize, | ||
133 | &GNUNET_FS_data_reader_file_, | ||
134 | fi, | ||
135 | keywords, | ||
136 | meta, | ||
137 | do_index, | ||
138 | bo); | ||
139 | if (ret == NULL) | ||
140 | return NULL; | ||
141 | ret->h = h; | ||
142 | ret->filename = GNUNET_strdup (filename); | ||
143 | fn = filename; | ||
144 | while (NULL != (ss = strstr (fn, DIR_SEPARATOR_STR))) | ||
145 | fn = ss + 1; | ||
146 | /* FIXME: If we assume that on other platforms CRT is UTF-8-aware, then | ||
147 | * this should be changed to EXTRACTOR_METAFORMAT_UTF8 | ||
148 | */ | ||
149 | GNUNET_CONTAINER_meta_data_insert (ret->meta, | ||
150 | "<gnunet>", | ||
151 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, | ||
152 | EXTRACTOR_METAFORMAT_C_STRING, | ||
153 | "text/plain", | ||
154 | fn, | ||
155 | strlen (fn) + 1); | ||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | |||
160 | /** | ||
161 | * Create an entry for a file in a publish-structure. | ||
162 | * | ||
163 | * @param h handle to the file sharing subsystem | ||
164 | * @param client_info initial value for the client-info value for this entry | ||
165 | * @param length length of the file | ||
166 | * @param data data for the file (should not be used afterwards by | ||
167 | * the caller; callee will "free") | ||
168 | * @param keywords under which keywords should this file be available | ||
169 | * directly; can be NULL | ||
170 | * @param meta metadata for the file | ||
171 | * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, | ||
172 | * GNUNET_SYSERR for simulation | ||
173 | * @param bo block options | ||
174 | * @return publish structure entry for the file | ||
175 | */ | ||
176 | struct GNUNET_FS_FileInformation * | ||
177 | GNUNET_FS_file_information_create_from_data ( | ||
178 | struct GNUNET_FS_Handle *h, | ||
179 | void *client_info, | ||
180 | uint64_t length, | ||
181 | void *data, | ||
182 | const struct GNUNET_FS_Uri *keywords, | ||
183 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
184 | int do_index, | ||
185 | const struct GNUNET_FS_BlockOptions *bo) | ||
186 | { | ||
187 | if (GNUNET_YES == do_index) | ||
188 | { | ||
189 | GNUNET_break (0); | ||
190 | return NULL; | ||
191 | } | ||
192 | return GNUNET_FS_file_information_create_from_reader (h, | ||
193 | client_info, | ||
194 | length, | ||
195 | & | ||
196 | GNUNET_FS_data_reader_copy_, | ||
197 | data, | ||
198 | keywords, | ||
199 | meta, | ||
200 | do_index, | ||
201 | bo); | ||
202 | } | ||
203 | |||
204 | |||
205 | /** | ||
206 | * Create an entry for a file in a publish-structure. | ||
207 | * | ||
208 | * @param h handle to the file sharing subsystem | ||
209 | * @param client_info initial value for the client-info value for this entry | ||
210 | * @param length length of the file | ||
211 | * @param reader function that can be used to obtain the data for the file | ||
212 | * @param reader_cls closure for "reader" | ||
213 | * @param keywords under which keywords should this file be available | ||
214 | * directly; can be NULL | ||
215 | * @param meta metadata for the file | ||
216 | * @param do_index #GNUNET_YES for index, #GNUNET_NO for insertion, | ||
217 | * #GNUNET_SYSERR for simulation | ||
218 | * @param bo block options | ||
219 | * @return publish structure entry for the file | ||
220 | */ | ||
221 | struct GNUNET_FS_FileInformation * | ||
222 | GNUNET_FS_file_information_create_from_reader ( | ||
223 | struct GNUNET_FS_Handle *h, | ||
224 | void *client_info, | ||
225 | uint64_t length, | ||
226 | GNUNET_FS_DataReader reader, | ||
227 | void *reader_cls, | ||
228 | const struct GNUNET_FS_Uri *keywords, | ||
229 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
230 | int do_index, | ||
231 | const struct GNUNET_FS_BlockOptions *bo) | ||
232 | { | ||
233 | struct GNUNET_FS_FileInformation *ret; | ||
234 | |||
235 | if ((GNUNET_YES == do_index) && (reader != &GNUNET_FS_data_reader_file_)) | ||
236 | { | ||
237 | GNUNET_break (0); | ||
238 | return NULL; | ||
239 | } | ||
240 | ret = GNUNET_new (struct GNUNET_FS_FileInformation); | ||
241 | ret->h = h; | ||
242 | ret->client_info = client_info; | ||
243 | ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
244 | if (ret->meta == NULL) | ||
245 | ret->meta = GNUNET_CONTAINER_meta_data_create (); | ||
246 | ret->keywords = (keywords == NULL) ? NULL : GNUNET_FS_uri_dup (keywords); | ||
247 | ret->data.file.reader = reader; | ||
248 | ret->data.file.reader_cls = reader_cls; | ||
249 | ret->data.file.do_index = do_index; | ||
250 | ret->data.file.file_size = length; | ||
251 | ret->bo = *bo; | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | |||
256 | /** | ||
257 | * Test if a given entry represents a directory. | ||
258 | * | ||
259 | * @param ent check if this FI represents a directory | ||
260 | * @return #GNUNET_YES if so, #GNUNET_NO if not | ||
261 | */ | ||
262 | int | ||
263 | GNUNET_FS_file_information_is_directory ( | ||
264 | const struct GNUNET_FS_FileInformation *ent) | ||
265 | { | ||
266 | return ent->is_directory; | ||
267 | } | ||
268 | |||
269 | |||
270 | /** | ||
271 | * Create an entry for an empty directory in a publish-structure. | ||
272 | * | ||
273 | * @param h handle to the file sharing subsystem | ||
274 | * @param client_info initial value for the client-info value for this entry | ||
275 | * @param meta metadata for the directory | ||
276 | * @param keywords under which keywords should this directory be available | ||
277 | * directly; can be NULL | ||
278 | * @param bo block options | ||
279 | * @param filename name of the directory; can be NULL | ||
280 | * @return publish structure entry for the directory , NULL on error | ||
281 | */ | ||
282 | struct GNUNET_FS_FileInformation * | ||
283 | GNUNET_FS_file_information_create_empty_directory ( | ||
284 | struct GNUNET_FS_Handle *h, | ||
285 | void *client_info, | ||
286 | const struct GNUNET_FS_Uri *keywords, | ||
287 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
288 | const struct GNUNET_FS_BlockOptions *bo, | ||
289 | const char *filename) | ||
290 | { | ||
291 | struct GNUNET_FS_FileInformation *ret; | ||
292 | |||
293 | ret = GNUNET_new (struct GNUNET_FS_FileInformation); | ||
294 | ret->h = h; | ||
295 | ret->client_info = client_info; | ||
296 | ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
297 | ret->keywords = GNUNET_FS_uri_dup (keywords); | ||
298 | ret->bo = *bo; | ||
299 | ret->is_directory = GNUNET_YES; | ||
300 | if (filename != NULL) | ||
301 | ret->filename = GNUNET_strdup (filename); | ||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | |||
306 | /** | ||
307 | * Add an entry to a directory in a publish-structure. Clients | ||
308 | * should never modify publish structures that were passed to | ||
309 | * #GNUNET_FS_publish_start already. | ||
310 | * | ||
311 | * @param dir the directory | ||
312 | * @param ent the entry to add; the entry must not have been | ||
313 | * added to any other directory at this point and | ||
314 | * must not include @a dir in its structure | ||
315 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
316 | */ | ||
317 | int | ||
318 | GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir, | ||
319 | struct GNUNET_FS_FileInformation *ent) | ||
320 | { | ||
321 | if ((ent->dir != NULL) || (ent->next != NULL) || | ||
322 | (dir->is_directory != GNUNET_YES)) | ||
323 | { | ||
324 | GNUNET_break (0); | ||
325 | return GNUNET_SYSERR; | ||
326 | } | ||
327 | ent->dir = dir; | ||
328 | ent->next = dir->data.dir.entries; | ||
329 | dir->data.dir.entries = ent; | ||
330 | dir->data.dir.dir_size = 0; | ||
331 | return GNUNET_OK; | ||
332 | } | ||
333 | |||
334 | |||
335 | /** | ||
336 | * Inspect a file or directory in a publish-structure. Clients | ||
337 | * should never modify publish structures that were passed to | ||
338 | * #GNUNET_FS_publish_start already. When called on a directory, | ||
339 | * this function will FIRST call @a proc with information about | ||
340 | * the directory itself and then for each of the files in the | ||
341 | * directory (but not for files in subdirectories). When called | ||
342 | * on a file, @a proc will be called exactly once (with information | ||
343 | * about the specific file). | ||
344 | * | ||
345 | * @param dir the directory | ||
346 | * @param proc function to call on each entry | ||
347 | * @param proc_cls closure for @a proc | ||
348 | */ | ||
349 | void | ||
350 | GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir, | ||
351 | GNUNET_FS_FileInformationProcessor proc, | ||
352 | void *proc_cls) | ||
353 | { | ||
354 | struct GNUNET_FS_FileInformation *pos; | ||
355 | int no; | ||
356 | |||
357 | no = GNUNET_NO; | ||
358 | if (GNUNET_OK != | ||
359 | proc (proc_cls, | ||
360 | dir, | ||
361 | (dir->is_directory == GNUNET_YES) ? dir->data.dir.dir_size | ||
362 | : dir->data.file.file_size, | ||
363 | dir->meta, | ||
364 | &dir->keywords, | ||
365 | &dir->bo, | ||
366 | (dir->is_directory == GNUNET_YES) ? &no : &dir->data.file.do_index, | ||
367 | &dir->client_info)) | ||
368 | return; | ||
369 | if (dir->is_directory != GNUNET_YES) | ||
370 | return; | ||
371 | pos = dir->data.dir.entries; | ||
372 | while (pos != NULL) | ||
373 | { | ||
374 | no = GNUNET_NO; | ||
375 | if (GNUNET_OK != | ||
376 | proc (proc_cls, | ||
377 | pos, | ||
378 | (pos->is_directory == GNUNET_YES) ? pos->data.dir.dir_size | ||
379 | : pos->data.file.file_size, | ||
380 | pos->meta, | ||
381 | &pos->keywords, | ||
382 | &pos->bo, | ||
383 | (pos->is_directory == GNUNET_YES) ? &no | ||
384 | : &pos->data.file.do_index, | ||
385 | &pos->client_info)) | ||
386 | break; | ||
387 | pos = pos->next; | ||
388 | } | ||
389 | } | ||
390 | |||
391 | |||
392 | /** | ||
393 | * Destroy publish-structure. Clients should never destroy publish | ||
394 | * structures that were passed to #GNUNET_FS_publish_start already. | ||
395 | * | ||
396 | * @param fi structure to destroy | ||
397 | * @param cleaner function to call on each entry in the structure | ||
398 | * (useful to clean up client_info); can be NULL; return | ||
399 | * values are ignored | ||
400 | * @param cleaner_cls closure for @a cleaner | ||
401 | */ | ||
402 | void | ||
403 | GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi, | ||
404 | GNUNET_FS_FileInformationProcessor cleaner, | ||
405 | void *cleaner_cls) | ||
406 | { | ||
407 | struct GNUNET_FS_FileInformation *pos; | ||
408 | int no; | ||
409 | |||
410 | no = GNUNET_NO; | ||
411 | if (GNUNET_YES == fi->is_directory) | ||
412 | { | ||
413 | /* clean up directory */ | ||
414 | while (NULL != (pos = fi->data.dir.entries)) | ||
415 | { | ||
416 | fi->data.dir.entries = pos->next; | ||
417 | GNUNET_FS_file_information_destroy (pos, cleaner, cleaner_cls); | ||
418 | } | ||
419 | /* clean up client-info */ | ||
420 | if (NULL != cleaner) | ||
421 | cleaner (cleaner_cls, | ||
422 | fi, | ||
423 | fi->data.dir.dir_size, | ||
424 | fi->meta, | ||
425 | &fi->keywords, | ||
426 | &fi->bo, | ||
427 | &no, | ||
428 | &fi->client_info); | ||
429 | GNUNET_free (fi->data.dir.dir_data); | ||
430 | } | ||
431 | else | ||
432 | { | ||
433 | /* call clean-up function of the reader */ | ||
434 | if (NULL != fi->data.file.reader) | ||
435 | { | ||
436 | (void) fi->data.file.reader (fi->data.file.reader_cls, 0, 0, NULL, NULL); | ||
437 | fi->data.file.reader = NULL; | ||
438 | } | ||
439 | /* clean up client-info */ | ||
440 | if (NULL != cleaner) | ||
441 | cleaner (cleaner_cls, | ||
442 | fi, | ||
443 | fi->data.file.file_size, | ||
444 | fi->meta, | ||
445 | &fi->keywords, | ||
446 | &fi->bo, | ||
447 | &fi->data.file.do_index, | ||
448 | &fi->client_info); | ||
449 | } | ||
450 | GNUNET_free (fi->filename); | ||
451 | GNUNET_free (fi->emsg); | ||
452 | if (NULL != fi->sks_uri) | ||
453 | GNUNET_FS_uri_destroy (fi->sks_uri); | ||
454 | if (NULL != fi->chk_uri) | ||
455 | GNUNET_FS_uri_destroy (fi->chk_uri); | ||
456 | /* clean up serialization */ | ||
457 | if ((NULL != fi->serialization) && (0 != unlink (fi->serialization))) | ||
458 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
459 | "unlink", | ||
460 | fi->serialization); | ||
461 | if (NULL != fi->keywords) | ||
462 | GNUNET_FS_uri_destroy (fi->keywords); | ||
463 | if (NULL != fi->meta) | ||
464 | GNUNET_CONTAINER_meta_data_destroy (fi->meta); | ||
465 | GNUNET_free (fi->serialization); | ||
466 | if (NULL != fi->te) | ||
467 | { | ||
468 | GNUNET_FS_tree_encoder_finish (fi->te, NULL); | ||
469 | fi->te = NULL; | ||
470 | } | ||
471 | GNUNET_free (fi); | ||
472 | } | ||
473 | |||
474 | |||
475 | /* end of fs_file_information.c */ | ||
diff --git a/src/fs/fs_getopt.c b/src/fs/fs_getopt.c deleted file mode 100644 index 43a02a9fa..000000000 --- a/src/fs/fs_getopt.c +++ /dev/null | |||
@@ -1,274 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_getopt.c | ||
23 | * @brief helper functions for command-line argument processing | ||
24 | * @author Igor Wronsky, Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_fs_service.h" | ||
28 | #include "gnunet_getopt_lib.h" | ||
29 | #include "fs_api.h" | ||
30 | |||
31 | /* ******************** command-line option parsing API ******************** */ | ||
32 | |||
33 | /** | ||
34 | * Command-line option parser function that allows the user | ||
35 | * to specify one or more '-k' options with keywords. Each | ||
36 | * specified keyword will be added to the URI. A pointer to | ||
37 | * the URI must be passed as the "scls" argument. | ||
38 | * | ||
39 | * @param ctx command line processor context | ||
40 | * @param scls must be of type "struct GNUNET_FS_Uri **" | ||
41 | * @param option name of the option (typically 'k') | ||
42 | * @param value command line argument given | ||
43 | * @return #GNUNET_OK on success | ||
44 | */ | ||
45 | static int | ||
46 | getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | ||
47 | void *scls, | ||
48 | const char *option, | ||
49 | const char *value) | ||
50 | { | ||
51 | struct GNUNET_FS_Uri **uri = scls; | ||
52 | struct GNUNET_FS_Uri *u = *uri; | ||
53 | char *val; | ||
54 | size_t slen; | ||
55 | |||
56 | if (NULL == u) | ||
57 | { | ||
58 | u = GNUNET_new (struct GNUNET_FS_Uri); | ||
59 | *uri = u; | ||
60 | u->type = GNUNET_FS_URI_KSK; | ||
61 | u->data.ksk.keywordCount = 0; | ||
62 | u->data.ksk.keywords = NULL; | ||
63 | } | ||
64 | else | ||
65 | { | ||
66 | GNUNET_assert (GNUNET_FS_URI_KSK == u->type); | ||
67 | } | ||
68 | slen = strlen (value); | ||
69 | if (0 == slen) | ||
70 | return GNUNET_SYSERR; /* cannot be empty */ | ||
71 | if (value[0] == '+') | ||
72 | { | ||
73 | /* simply preserve the "mandatory" flag */ | ||
74 | if (slen < 2) | ||
75 | return GNUNET_SYSERR; /* empty keywords not allowed */ | ||
76 | if ((value[1] == '"') && (slen > 3) && (value[slen - 1] == '"')) | ||
77 | { | ||
78 | /* remove the quotes, keep the '+' */ | ||
79 | val = GNUNET_malloc (slen - 1); | ||
80 | val[0] = '+'; | ||
81 | GNUNET_memcpy (&val[1], | ||
82 | &value[2], | ||
83 | slen - 3); | ||
84 | val[slen - 2] = '\0'; | ||
85 | } | ||
86 | else | ||
87 | { | ||
88 | /* no quotes, just keep the '+' */ | ||
89 | val = GNUNET_strdup (value); | ||
90 | } | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | if ((value[0] == '"') && (slen > 2) && (value[slen - 1] == '"')) | ||
95 | { | ||
96 | /* remove the quotes, add a space */ | ||
97 | val = GNUNET_malloc (slen); | ||
98 | val[0] = ' '; | ||
99 | GNUNET_memcpy (&val[1], | ||
100 | &value[1], | ||
101 | slen - 2); | ||
102 | val[slen - 1] = '\0'; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | /* add a space to indicate "not mandatory" */ | ||
107 | val = GNUNET_malloc (slen + 2); | ||
108 | strcpy (val, " "); | ||
109 | strcat (val, value); | ||
110 | } | ||
111 | } | ||
112 | GNUNET_array_append (u->data.ksk.keywords, | ||
113 | u->data.ksk.keywordCount, | ||
114 | val); | ||
115 | return GNUNET_OK; | ||
116 | } | ||
117 | |||
118 | |||
119 | /** | ||
120 | * Allow user to specify keywords. | ||
121 | * | ||
122 | * @param shortName short name of the option | ||
123 | * @param name long name of the option | ||
124 | * @param argumentHelp help text for the option argument | ||
125 | * @param description long help text for the option | ||
126 | * @param[out] topKeywords set to the desired value | ||
127 | */ | ||
128 | struct GNUNET_GETOPT_CommandLineOption | ||
129 | GNUNET_FS_GETOPT_KEYWORDS (char shortName, | ||
130 | const char *name, | ||
131 | const char *argumentHelp, | ||
132 | const char *description, | ||
133 | struct GNUNET_FS_Uri **topKeywords) | ||
134 | { | ||
135 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
136 | .shortName = shortName, | ||
137 | .name = name, | ||
138 | .argumentHelp = argumentHelp, | ||
139 | .description = description, | ||
140 | .require_argument = 1, | ||
141 | .processor = &getopt_set_keywords, | ||
142 | .scls = (void *) topKeywords | ||
143 | }; | ||
144 | |||
145 | return clo; | ||
146 | } | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Command-line option parser function that allows the user to specify | ||
151 | * one or more '-m' options with metadata. Each specified entry of | ||
152 | * the form "type=value" will be added to the metadata. A pointer to | ||
153 | * the metadata must be passed as the "scls" argument. | ||
154 | * | ||
155 | * @param ctx command line processor context | ||
156 | * @param scls must be of type "struct GNUNET_MetaData **" | ||
157 | * @param option name of the option (typically 'k') | ||
158 | * @param value command line argument given | ||
159 | * @return #GNUNET_OK on success | ||
160 | */ | ||
161 | static int | ||
162 | getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | ||
163 | void *scls, | ||
164 | const char *option, | ||
165 | const char *value) | ||
166 | { | ||
167 | struct GNUNET_CONTAINER_MetaData **mm = scls; | ||
168 | |||
169 | #if HAVE_EXTRACTOR_H && HAVE_LIBEXTRACTOR | ||
170 | enum EXTRACTOR_MetaType type; | ||
171 | const char *typename; | ||
172 | const char *typename_i18n; | ||
173 | #endif | ||
174 | struct GNUNET_CONTAINER_MetaData *meta; | ||
175 | char *tmp; | ||
176 | |||
177 | meta = *mm; | ||
178 | if (meta == NULL) | ||
179 | { | ||
180 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
181 | *mm = meta; | ||
182 | } | ||
183 | |||
184 | /* Use GNUNET_STRINGS_get_utf8_args() in main() to acquire utf-8-encoded | ||
185 | * commandline arguments, so that the following line is not needed. | ||
186 | */ | ||
187 | /*tmp = GNUNET_STRINGS_to_utf8 (value, strlen (value), locale_charset ());*/ | ||
188 | tmp = GNUNET_strdup (value); | ||
189 | #if HAVE_EXTRACTOR_H && HAVE_LIBEXTRACTOR | ||
190 | type = EXTRACTOR_metatype_get_max (); | ||
191 | while (type > 0) | ||
192 | { | ||
193 | type--; | ||
194 | typename = EXTRACTOR_metatype_to_string (type); | ||
195 | typename_i18n = dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, typename); | ||
196 | if ((strlen (tmp) >= strlen (typename) + 1) && | ||
197 | (tmp[strlen (typename)] == ':') && | ||
198 | (0 == strncmp (typename, tmp, strlen (typename)))) | ||
199 | { | ||
200 | GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", type, | ||
201 | EXTRACTOR_METAFORMAT_UTF8, | ||
202 | "text/plain", | ||
203 | &tmp[strlen (typename) + 1], | ||
204 | strlen (&tmp[strlen (typename) + 1]) | ||
205 | + 1); | ||
206 | GNUNET_free (tmp); | ||
207 | tmp = NULL; | ||
208 | break; | ||
209 | } | ||
210 | if ((strlen (tmp) >= strlen (typename_i18n) + 1) && | ||
211 | (tmp[strlen (typename_i18n)] == ':') && | ||
212 | (0 == strncmp (typename_i18n, tmp, strlen (typename_i18n)))) | ||
213 | { | ||
214 | GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", type, | ||
215 | EXTRACTOR_METAFORMAT_UTF8, | ||
216 | "text/plain", | ||
217 | &tmp[strlen (typename_i18n) + 1], | ||
218 | strlen (&tmp | ||
219 | [strlen (typename_i18n) + 1]) | ||
220 | + 1); | ||
221 | GNUNET_free (tmp); | ||
222 | tmp = NULL; | ||
223 | break; | ||
224 | } | ||
225 | } | ||
226 | #endif | ||
227 | |||
228 | if (NULL != tmp) | ||
229 | { | ||
230 | GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", | ||
231 | EXTRACTOR_METATYPE_UNKNOWN, | ||
232 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
233 | tmp, strlen (tmp) + 1); | ||
234 | GNUNET_free (tmp); | ||
235 | printf (_ | ||
236 | ( | ||
237 | "Unknown metadata type in metadata option `%s'. Using metadata type `unknown' instead.\n"), | ||
238 | value); | ||
239 | } | ||
240 | return GNUNET_OK; | ||
241 | } | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Allow user to specify metadata. | ||
246 | * | ||
247 | * @param shortName short name of the option | ||
248 | * @param name long name of the option | ||
249 | * @param argumentHelp help text for the option argument | ||
250 | * @param description long help text for the option | ||
251 | * @param[out] metadata set to the desired value | ||
252 | */ | ||
253 | struct GNUNET_GETOPT_CommandLineOption | ||
254 | GNUNET_FS_GETOPT_METADATA (char shortName, | ||
255 | const char *name, | ||
256 | const char *argumentHelp, | ||
257 | const char *description, | ||
258 | struct GNUNET_CONTAINER_MetaData **meta) | ||
259 | { | ||
260 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
261 | .shortName = shortName, | ||
262 | .name = name, | ||
263 | .argumentHelp = argumentHelp, | ||
264 | .description = description, | ||
265 | .require_argument = 1, | ||
266 | .processor = &getopt_set_metadata, | ||
267 | .scls = (void *) meta | ||
268 | }; | ||
269 | |||
270 | return clo; | ||
271 | } | ||
272 | |||
273 | |||
274 | /* end of fs_getopt.c */ | ||
diff --git a/src/fs/fs_list_indexed.c b/src/fs/fs_list_indexed.c deleted file mode 100644 index 0e16fb01b..000000000 --- a/src/fs/fs_list_indexed.c +++ /dev/null | |||
@@ -1,223 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003, 2004, 2006, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_list_indexed.c | ||
23 | * @author Christian Grothoff | ||
24 | * @brief provide a list of all indexed files | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | #include "gnunet_protocols.h" | ||
31 | #include "fs_api.h" | ||
32 | |||
33 | |||
34 | /** | ||
35 | * Context for #GNUNET_FS_get_indexed_files(). | ||
36 | */ | ||
37 | struct GNUNET_FS_GetIndexedContext | ||
38 | { | ||
39 | /** | ||
40 | * Connection to the FS service. | ||
41 | */ | ||
42 | struct GNUNET_MQ_Handle *mq; | ||
43 | |||
44 | /** | ||
45 | * Function to call for each indexed file. | ||
46 | */ | ||
47 | GNUNET_FS_IndexedFileProcessor iterator; | ||
48 | |||
49 | /** | ||
50 | * Closure for @e iterator. | ||
51 | */ | ||
52 | void *iterator_cls; | ||
53 | |||
54 | /** | ||
55 | * Continuation to trigger at the end. | ||
56 | */ | ||
57 | GNUNET_SCHEDULER_TaskCallback cont; | ||
58 | |||
59 | /** | ||
60 | * Closure for @e cont. | ||
61 | */ | ||
62 | void *cont_cls; | ||
63 | }; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Function called on each response from the FS | ||
68 | * service with information about indexed files. | ||
69 | * | ||
70 | * @param cls closure (of type `struct GNUNET_FS_GetIndexedContext *`) | ||
71 | * @param msg message with indexing information | ||
72 | */ | ||
73 | static void | ||
74 | handle_index_info_end (void *cls, | ||
75 | const struct GNUNET_MessageHeader *msg) | ||
76 | { | ||
77 | struct GNUNET_FS_GetIndexedContext *gic = cls; | ||
78 | |||
79 | (void) gic->iterator (gic->iterator_cls, | ||
80 | NULL, | ||
81 | NULL); | ||
82 | GNUNET_FS_get_indexed_files_cancel (gic); | ||
83 | } | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Check validity of response from the FS | ||
88 | * service with information about indexed files. | ||
89 | * | ||
90 | * @param cls closure (of type `struct GNUNET_FS_GetIndexedContext *`) | ||
91 | * @param iim message with indexing information | ||
92 | */ | ||
93 | static int | ||
94 | check_index_info (void *cls, | ||
95 | const struct IndexInfoMessage *iim) | ||
96 | { | ||
97 | uint16_t msize = ntohs (iim->header.size) - sizeof(*iim); | ||
98 | const char *filename; | ||
99 | |||
100 | filename = (const char *) &iim[1]; | ||
101 | if (filename[msize - 1] != '\0') | ||
102 | { | ||
103 | GNUNET_break (0); | ||
104 | return GNUNET_SYSERR; | ||
105 | } | ||
106 | return GNUNET_OK; | ||
107 | } | ||
108 | |||
109 | |||
110 | /** | ||
111 | * Function called on each response from the FS | ||
112 | * service with information about indexed files. | ||
113 | * | ||
114 | * @param cls closure (of type `struct GNUNET_FS_GetIndexedContext *`) | ||
115 | * @param iim message with indexing information | ||
116 | */ | ||
117 | static void | ||
118 | handle_index_info (void *cls, | ||
119 | const struct IndexInfoMessage *iim) | ||
120 | { | ||
121 | struct GNUNET_FS_GetIndexedContext *gic = cls; | ||
122 | const char *filename; | ||
123 | |||
124 | filename = (const char *) &iim[1]; | ||
125 | if (GNUNET_OK != | ||
126 | gic->iterator (gic->iterator_cls, | ||
127 | filename, | ||
128 | &iim->file_id)) | ||
129 | { | ||
130 | GNUNET_FS_get_indexed_files_cancel (gic); | ||
131 | return; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | |||
136 | /** | ||
137 | * Generic error handler, called with the appropriate error code and | ||
138 | * the same closure specified at the creation of the message queue. | ||
139 | * Not every message queue implementation supports an error handler. | ||
140 | * | ||
141 | * @param cls closure with the `struct GNUNET_FS_GetIndexedContent *` | ||
142 | * @param error error code | ||
143 | */ | ||
144 | static void | ||
145 | mq_error_handler (void *cls, | ||
146 | enum GNUNET_MQ_Error error) | ||
147 | { | ||
148 | struct GNUNET_FS_GetIndexedContext *gic = cls; | ||
149 | |||
150 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
151 | _ ("Failed to receive response from `%s' service.\n"), | ||
152 | "fs"); | ||
153 | (void) gic->iterator (gic->iterator_cls, NULL, NULL); | ||
154 | GNUNET_FS_get_indexed_files_cancel (gic); | ||
155 | } | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Iterate over all indexed files. | ||
160 | * | ||
161 | * @param h handle to the file sharing subsystem | ||
162 | * @param iterator function to call on each indexed file | ||
163 | * @param iterator_cls closure for iterator | ||
164 | * @return NULL on error ('iter' is not called) | ||
165 | */ | ||
166 | struct GNUNET_FS_GetIndexedContext * | ||
167 | GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, | ||
168 | GNUNET_FS_IndexedFileProcessor iterator, | ||
169 | void *iterator_cls) | ||
170 | { | ||
171 | struct GNUNET_FS_GetIndexedContext *gic | ||
172 | = GNUNET_new (struct GNUNET_FS_GetIndexedContext); | ||
173 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
174 | GNUNET_MQ_hd_fixed_size (index_info_end, | ||
175 | GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END, | ||
176 | struct GNUNET_MessageHeader, | ||
177 | gic), | ||
178 | GNUNET_MQ_hd_var_size (index_info, | ||
179 | GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY, | ||
180 | struct IndexInfoMessage, | ||
181 | gic), | ||
182 | GNUNET_MQ_handler_end () | ||
183 | }; | ||
184 | struct GNUNET_MQ_Envelope *env; | ||
185 | struct GNUNET_MessageHeader *msg; | ||
186 | |||
187 | gic->mq = GNUNET_CLIENT_connect (h->cfg, | ||
188 | "fs", | ||
189 | handlers, | ||
190 | &mq_error_handler, | ||
191 | h); | ||
192 | if (NULL == gic->mq) | ||
193 | { | ||
194 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
195 | _ ("Failed to not connect to `%s' service.\n"), | ||
196 | "fs"); | ||
197 | GNUNET_free (gic); | ||
198 | return NULL; | ||
199 | } | ||
200 | gic->iterator = iterator; | ||
201 | gic->iterator_cls = iterator_cls; | ||
202 | env = GNUNET_MQ_msg (msg, | ||
203 | GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET); | ||
204 | GNUNET_MQ_send (gic->mq, | ||
205 | env); | ||
206 | return gic; | ||
207 | } | ||
208 | |||
209 | |||
210 | /** | ||
211 | * Cancel iteration over all indexed files. | ||
212 | * | ||
213 | * @param gic operation to cancel | ||
214 | */ | ||
215 | void | ||
216 | GNUNET_FS_get_indexed_files_cancel (struct GNUNET_FS_GetIndexedContext *gic) | ||
217 | { | ||
218 | GNUNET_MQ_destroy (gic->mq); | ||
219 | GNUNET_free (gic); | ||
220 | } | ||
221 | |||
222 | |||
223 | /* end of fs_list_indexed.c */ | ||
diff --git a/src/fs/fs_misc.c b/src/fs/fs_misc.c deleted file mode 100644 index 2e7816d65..000000000 --- a/src/fs/fs_misc.c +++ /dev/null | |||
@@ -1,164 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2011, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/fs_misc.c | ||
22 | * @brief misc. functions related to file-sharing in general | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_constants.h" | ||
27 | #include "gnunet_fs_service.h" | ||
28 | #include "fs_api.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Suggest a filename based on given metadata. | ||
33 | * | ||
34 | * @param md given meta data | ||
35 | * @return NULL if meta data is useless for suggesting a filename | ||
36 | */ | ||
37 | char * | ||
38 | GNUNET_FS_meta_data_suggest_filename (const struct GNUNET_CONTAINER_MetaData | ||
39 | *md) | ||
40 | { | ||
41 | static const char *mimeMap[][2] = { | ||
42 | { "application/bz2", ".bz2" }, | ||
43 | { "application/gnunet-directory", ".gnd" }, | ||
44 | { "application/java", ".class" }, | ||
45 | { "application/msword", ".doc" }, | ||
46 | { "application/nar", ".nar" }, | ||
47 | { "application/narinfo", ".narinfo" }, | ||
48 | { "application/ogg", ".ogg" }, | ||
49 | { "application/pdf", ".pdf" }, | ||
50 | { "application/pgp-keys", ".key" }, | ||
51 | { "application/pgp-signature", ".pgp" }, | ||
52 | { "application/postscript", ".ps" }, | ||
53 | { "application/rar", ".rar" }, | ||
54 | { "application/rtf", ".rtf" }, | ||
55 | { "application/xml", ".xml" }, | ||
56 | { "application/x-debian-package", ".deb" }, | ||
57 | { "application/x-dvi", ".dvi" }, | ||
58 | { "application/x-flac", ".flac" }, | ||
59 | { "application/x-gzip", ".gz" }, | ||
60 | { "application/x-java-archive", ".jar" }, | ||
61 | { "application/x-java-vm", ".class" }, | ||
62 | { "application/x-python-code", ".pyc" }, | ||
63 | { "application/x-redhat-package-manager", ".rpm" }, | ||
64 | { "application/x-rpm", ".rpm" }, | ||
65 | { "application/x-tar", ".tar" }, | ||
66 | { "application/x-tex-pk", ".pk" }, | ||
67 | { "application/x-texinfo", ".texinfo" }, | ||
68 | { "application/x-xcf", ".xcf" }, | ||
69 | { "application/x-xfig", ".xfig" }, | ||
70 | { "application/zip", ".zip" }, | ||
71 | |||
72 | { "audio/midi", ".midi" }, | ||
73 | { "audio/mpeg", ".mp3" }, | ||
74 | { "audio/real", ".rm" }, | ||
75 | { "audio/x-wav", ".wav" }, | ||
76 | |||
77 | { "image/gif", ".gif" }, | ||
78 | { "image/jpeg", ".jpg" }, | ||
79 | { "image/pcx", ".pcx" }, | ||
80 | { "image/png", ".png" }, | ||
81 | { "image/tiff", ".tiff" }, | ||
82 | { "image/x-ms-bmp", ".bmp" }, | ||
83 | { "image/x-xpixmap", ".xpm" }, | ||
84 | |||
85 | { "text/css", ".css" }, | ||
86 | { "text/html", ".html" }, | ||
87 | { "text/plain", ".txt" }, | ||
88 | { "text/rtf", ".rtf" }, | ||
89 | { "text/x-c++hdr", ".h++" }, | ||
90 | { "text/x-c++src", ".c++" }, | ||
91 | { "text/x-chdr", ".h" }, | ||
92 | { "text/x-csrc", ".c" }, | ||
93 | { "text/x-java", ".java" }, | ||
94 | { "text/x-moc", ".moc" }, | ||
95 | { "text/x-pascal", ".pas" }, | ||
96 | { "text/x-perl", ".pl" }, | ||
97 | { "text/x-python", ".py" }, | ||
98 | { "text/x-tex", ".tex" }, | ||
99 | |||
100 | { "video/avi", ".avi" }, | ||
101 | { "video/mpeg", ".mpeg" }, | ||
102 | { "video/quicktime", ".qt" }, | ||
103 | { "video/real", ".rm" }, | ||
104 | { "video/x-msvideo", ".avi" }, | ||
105 | { NULL, NULL }, | ||
106 | }; | ||
107 | char *ret; | ||
108 | unsigned int i; | ||
109 | char *mime; | ||
110 | char *base; | ||
111 | const char *ext; | ||
112 | |||
113 | ret = | ||
114 | GNUNET_CONTAINER_meta_data_get_by_type (md, | ||
115 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); | ||
116 | if (ret != NULL) | ||
117 | return ret; | ||
118 | ext = NULL; | ||
119 | mime = | ||
120 | GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); | ||
121 | if (mime != NULL) | ||
122 | { | ||
123 | i = 0; | ||
124 | while ((mimeMap[i][0] != NULL) && (0 != strcmp (mime, mimeMap[i][0]))) | ||
125 | i++; | ||
126 | if (mimeMap[i][1] == NULL) | ||
127 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
128 | _ ("Did not find mime type `%s' in extension list.\n"), mime); | ||
129 | else | ||
130 | ext = mimeMap[i][1]; | ||
131 | GNUNET_free (mime); | ||
132 | } | ||
133 | base = | ||
134 | GNUNET_CONTAINER_meta_data_get_first_by_types (md, | ||
135 | EXTRACTOR_METATYPE_TITLE, | ||
136 | EXTRACTOR_METATYPE_BOOK_TITLE, | ||
137 | EXTRACTOR_METATYPE_ORIGINAL_TITLE, | ||
138 | EXTRACTOR_METATYPE_PACKAGE_NAME, | ||
139 | EXTRACTOR_METATYPE_URL, | ||
140 | EXTRACTOR_METATYPE_URI, | ||
141 | EXTRACTOR_METATYPE_DESCRIPTION, | ||
142 | EXTRACTOR_METATYPE_ISRC, | ||
143 | EXTRACTOR_METATYPE_JOURNAL_NAME, | ||
144 | EXTRACTOR_METATYPE_AUTHOR_NAME, | ||
145 | EXTRACTOR_METATYPE_SUBJECT, | ||
146 | EXTRACTOR_METATYPE_ALBUM, | ||
147 | EXTRACTOR_METATYPE_ARTIST, | ||
148 | EXTRACTOR_METATYPE_KEYWORDS, | ||
149 | EXTRACTOR_METATYPE_COMMENT, | ||
150 | EXTRACTOR_METATYPE_UNKNOWN, | ||
151 | -1); | ||
152 | if ((base == NULL) && (ext == NULL)) | ||
153 | return NULL; | ||
154 | if (base == NULL) | ||
155 | return GNUNET_strdup (ext); | ||
156 | if (ext == NULL) | ||
157 | return base; | ||
158 | GNUNET_asprintf (&ret, "%s%s", base, ext); | ||
159 | GNUNET_free (base); | ||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | |||
164 | /* end of fs_misc.c */ | ||
diff --git a/src/fs/fs_namespace.c b/src/fs/fs_namespace.c deleted file mode 100644 index 155486be5..000000000 --- a/src/fs/fs_namespace.c +++ /dev/null | |||
@@ -1,818 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2003-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_namespace.c | ||
23 | * @brief publishing to namespaces, and tracking updateable entries | ||
24 | * for our namespaces | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_signatures.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_fs_service.h" | ||
32 | #include "fs_api.h" | ||
33 | #include "fs_publish_ublock.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Information about an (updateable) node in the | ||
38 | * namespace. | ||
39 | */ | ||
40 | struct NamespaceUpdateNode | ||
41 | { | ||
42 | /** | ||
43 | * Identifier for this node. | ||
44 | */ | ||
45 | char *id; | ||
46 | |||
47 | /** | ||
48 | * Identifier of children of this node. | ||
49 | */ | ||
50 | char *update; | ||
51 | |||
52 | /** | ||
53 | * Metadata for this entry. | ||
54 | */ | ||
55 | struct GNUNET_CONTAINER_MetaData *md; | ||
56 | |||
57 | /** | ||
58 | * URI of this entry in the namespace. | ||
59 | */ | ||
60 | struct GNUNET_FS_Uri *uri; | ||
61 | |||
62 | /** | ||
63 | * Namespace update generation ID. Used to ensure | ||
64 | * freshness of the tree_id. | ||
65 | */ | ||
66 | unsigned int nug; | ||
67 | |||
68 | /** | ||
69 | * TREE this entry belongs to (if nug is current). | ||
70 | */ | ||
71 | unsigned int tree_id; | ||
72 | }; | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Handle to update information for a namespace. | ||
77 | */ | ||
78 | struct GNUNET_FS_UpdateInformationGraph | ||
79 | { | ||
80 | /** | ||
81 | * Handle to the FS service context. | ||
82 | */ | ||
83 | struct GNUNET_FS_Handle *h; | ||
84 | |||
85 | /** | ||
86 | * Array with information about nodes in the namespace. | ||
87 | */ | ||
88 | struct NamespaceUpdateNode **update_nodes; | ||
89 | |||
90 | /** | ||
91 | * Private key for the namespace. | ||
92 | */ | ||
93 | struct GNUNET_CRYPTO_EcdsaPrivateKey ns; | ||
94 | |||
95 | /** | ||
96 | * Hash map mapping identifiers of update nodes | ||
97 | * to the update nodes (initialized on-demand). | ||
98 | */ | ||
99 | struct GNUNET_CONTAINER_MultiHashMap *update_map; | ||
100 | |||
101 | /** | ||
102 | * Size of the update nodes array. | ||
103 | */ | ||
104 | unsigned int update_node_count; | ||
105 | |||
106 | /** | ||
107 | * Reference counter. | ||
108 | */ | ||
109 | unsigned int rc; | ||
110 | |||
111 | /** | ||
112 | * Generator for unique nug numbers. | ||
113 | */ | ||
114 | unsigned int nug_gen; | ||
115 | }; | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Return the name of the directory in which we store | ||
120 | * the update information graph for the given local namespace. | ||
121 | * | ||
122 | * @param h file-sharing handle | ||
123 | * @param ns namespace handle | ||
124 | * @return NULL on error, otherwise the name of the directory | ||
125 | */ | ||
126 | static char * | ||
127 | get_update_information_directory ( | ||
128 | struct GNUNET_FS_Handle *h, | ||
129 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns) | ||
130 | { | ||
131 | char *dn; | ||
132 | char *ret; | ||
133 | struct GNUNET_CRYPTO_EcdsaPublicKey pub; | ||
134 | struct GNUNET_HashCode hc; | ||
135 | struct GNUNET_CRYPTO_HashAsciiEncoded enc; | ||
136 | |||
137 | if (GNUNET_OK != | ||
138 | GNUNET_CONFIGURATION_get_value_filename (h->cfg, "FS", "UPDATE_DIR", &dn)) | ||
139 | { | ||
140 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "fs", "UPDATE_DIR"); | ||
141 | return NULL; | ||
142 | } | ||
143 | GNUNET_CRYPTO_ecdsa_key_get_public (ns, &pub); | ||
144 | GNUNET_CRYPTO_hash (&pub, sizeof(pub), &hc); | ||
145 | GNUNET_CRYPTO_hash_to_enc (&hc, &enc); | ||
146 | GNUNET_asprintf (&ret, | ||
147 | "%s%s%s", | ||
148 | dn, | ||
149 | DIR_SEPARATOR_STR, | ||
150 | (const char *) enc.encoding); | ||
151 | GNUNET_free (dn); | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Release memory occupied by UIG datastructure. | ||
158 | * | ||
159 | * @param uig data structure to free | ||
160 | */ | ||
161 | static void | ||
162 | free_update_information_graph (struct GNUNET_FS_UpdateInformationGraph *uig) | ||
163 | { | ||
164 | unsigned int i; | ||
165 | struct NamespaceUpdateNode *nsn; | ||
166 | |||
167 | for (i = 0; i < uig->update_node_count; i++) | ||
168 | { | ||
169 | nsn = uig->update_nodes[i]; | ||
170 | GNUNET_CONTAINER_meta_data_destroy (nsn->md); | ||
171 | GNUNET_FS_uri_destroy (nsn->uri); | ||
172 | GNUNET_free (nsn->id); | ||
173 | GNUNET_free (nsn->update); | ||
174 | GNUNET_free (nsn); | ||
175 | } | ||
176 | GNUNET_array_grow (uig->update_nodes, uig->update_node_count, 0); | ||
177 | if (NULL != uig->update_map) | ||
178 | GNUNET_CONTAINER_multihashmap_destroy (uig->update_map); | ||
179 | GNUNET_free (uig); | ||
180 | } | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Write a namespace's update node graph to a file. | ||
185 | * | ||
186 | * @param uig update information graph to dump | ||
187 | */ | ||
188 | static void | ||
189 | write_update_information_graph (struct GNUNET_FS_UpdateInformationGraph *uig) | ||
190 | { | ||
191 | char *fn; | ||
192 | struct GNUNET_BIO_WriteHandle *wh; | ||
193 | unsigned int i; | ||
194 | struct NamespaceUpdateNode *n; | ||
195 | char *uris; | ||
196 | |||
197 | fn = get_update_information_directory (uig->h, &uig->ns); | ||
198 | wh = GNUNET_BIO_write_open_file (fn); | ||
199 | if (NULL == wh) | ||
200 | { | ||
201 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
202 | _ ("Failed to open `%s' for writing: %s\n"), | ||
203 | fn, | ||
204 | strerror (errno)); | ||
205 | GNUNET_free (fn); | ||
206 | return; | ||
207 | } | ||
208 | if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, | ||
209 | "fs-namespace-node-count", | ||
210 | uig->update_node_count)) | ||
211 | goto END; | ||
212 | for (i = 0; i < uig->update_node_count; i++) | ||
213 | { | ||
214 | n = uig->update_nodes[i]; | ||
215 | uris = GNUNET_FS_uri_to_string (n->uri); | ||
216 | struct GNUNET_BIO_WriteSpec ws[] = { | ||
217 | GNUNET_BIO_write_spec_string ("fs-namespace-node-id", n->id), | ||
218 | GNUNET_BIO_write_spec_meta_data ("fs-namespace-node-meta", n->md), | ||
219 | GNUNET_BIO_write_spec_string ("fs-namespace-node-update", n->update), | ||
220 | GNUNET_BIO_write_spec_string ("fs-namespace-uris", uris), | ||
221 | GNUNET_BIO_write_spec_end (), | ||
222 | }; | ||
223 | if (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws)) | ||
224 | { | ||
225 | GNUNET_free (uris); | ||
226 | break; | ||
227 | } | ||
228 | GNUNET_free (uris); | ||
229 | } | ||
230 | END: | ||
231 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
232 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
233 | _ ("Failed to write `%s': %s\n"), | ||
234 | fn, | ||
235 | strerror (errno)); | ||
236 | GNUNET_free (fn); | ||
237 | } | ||
238 | |||
239 | |||
240 | /** | ||
241 | * Read the namespace update node graph from a file. | ||
242 | * | ||
243 | * @param h FS handle to use | ||
244 | * @param ns namespace to read | ||
245 | * @return update graph, never NULL | ||
246 | */ | ||
247 | static struct GNUNET_FS_UpdateInformationGraph * | ||
248 | read_update_information_graph (struct GNUNET_FS_Handle *h, | ||
249 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns) | ||
250 | { | ||
251 | struct GNUNET_FS_UpdateInformationGraph *uig; | ||
252 | char *fn; | ||
253 | struct GNUNET_BIO_ReadHandle *rh; | ||
254 | unsigned int i; | ||
255 | struct NamespaceUpdateNode *n; | ||
256 | char *uris; | ||
257 | uint32_t count; | ||
258 | char *emsg; | ||
259 | |||
260 | uig = GNUNET_new (struct GNUNET_FS_UpdateInformationGraph); | ||
261 | uig->h = h; | ||
262 | uig->ns = *ns; | ||
263 | fn = get_update_information_directory (h, ns); | ||
264 | if (GNUNET_YES != GNUNET_DISK_file_test (fn)) | ||
265 | { | ||
266 | GNUNET_free (fn); | ||
267 | return uig; | ||
268 | } | ||
269 | rh = GNUNET_BIO_read_open_file (fn); | ||
270 | if (NULL == rh) | ||
271 | { | ||
272 | GNUNET_free (fn); | ||
273 | return uig; | ||
274 | } | ||
275 | if (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "fs-namespace-count", | ||
276 | (int32_t *) &count)) | ||
277 | { | ||
278 | GNUNET_break (0); | ||
279 | goto END; | ||
280 | } | ||
281 | if (count > 1024 * 1024) | ||
282 | { | ||
283 | GNUNET_break (0); | ||
284 | goto END; | ||
285 | } | ||
286 | if (0 == count) | ||
287 | goto END; | ||
288 | uig->update_nodes = | ||
289 | GNUNET_malloc (count * sizeof(struct NamespaceUpdateNode *)); | ||
290 | |||
291 | for (i = 0; i < count; i++) | ||
292 | { | ||
293 | n = GNUNET_new (struct NamespaceUpdateNode); | ||
294 | struct GNUNET_BIO_ReadSpec rs[] = { | ||
295 | GNUNET_BIO_read_spec_string ("identifier", &n->id, 1024), | ||
296 | GNUNET_BIO_read_spec_meta_data ("meta", &n->md), | ||
297 | GNUNET_BIO_read_spec_string ("update-id", &n->update, 1024), | ||
298 | GNUNET_BIO_read_spec_string ("uri", &uris, 1024 * 2), | ||
299 | GNUNET_BIO_read_spec_end (), | ||
300 | }; | ||
301 | if (GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs)) | ||
302 | { | ||
303 | GNUNET_break (0); | ||
304 | GNUNET_free (n->id); | ||
305 | GNUNET_free (n->update); | ||
306 | if (n->md != NULL) | ||
307 | GNUNET_CONTAINER_meta_data_destroy (n->md); | ||
308 | GNUNET_free (n); | ||
309 | break; | ||
310 | } | ||
311 | n->uri = GNUNET_FS_uri_parse (uris, &emsg); | ||
312 | GNUNET_free (uris); | ||
313 | if (n->uri == NULL) | ||
314 | { | ||
315 | GNUNET_break (0); | ||
316 | GNUNET_free (emsg); | ||
317 | GNUNET_free (n->id); | ||
318 | GNUNET_free (n->update); | ||
319 | GNUNET_CONTAINER_meta_data_destroy (n->md); | ||
320 | GNUNET_free (n); | ||
321 | break; | ||
322 | } | ||
323 | uig->update_nodes[i] = n; | ||
324 | } | ||
325 | uig->update_node_count = i; | ||
326 | END: | ||
327 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
328 | { | ||
329 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
330 | _ ("Failed to read `%s': %s\n"), | ||
331 | fn, | ||
332 | emsg); | ||
333 | GNUNET_free (emsg); | ||
334 | } | ||
335 | GNUNET_free (fn); | ||
336 | return uig; | ||
337 | } | ||
338 | |||
339 | |||
340 | /** | ||
341 | * Context for the SKS publication. | ||
342 | */ | ||
343 | struct GNUNET_FS_PublishSksContext | ||
344 | { | ||
345 | /** | ||
346 | * URI of the new entry in the namespace. | ||
347 | */ | ||
348 | struct GNUNET_FS_Uri *uri; | ||
349 | |||
350 | /** | ||
351 | * Namespace update node to add to namespace on success (or to be | ||
352 | * deleted if publishing failed). | ||
353 | */ | ||
354 | struct NamespaceUpdateNode *nsn; | ||
355 | |||
356 | /** | ||
357 | * Namespace we're publishing to. | ||
358 | */ | ||
359 | struct GNUNET_CRYPTO_EcdsaPrivateKey ns; | ||
360 | |||
361 | /** | ||
362 | * Handle to the datastore. | ||
363 | */ | ||
364 | struct GNUNET_DATASTORE_Handle *dsh; | ||
365 | |||
366 | /** | ||
367 | * Handle to FS. | ||
368 | */ | ||
369 | struct GNUNET_FS_Handle *h; | ||
370 | |||
371 | /** | ||
372 | * Function to call once we're done. | ||
373 | */ | ||
374 | GNUNET_FS_PublishContinuation cont; | ||
375 | |||
376 | /** | ||
377 | * Closure for cont. | ||
378 | */ | ||
379 | void *cont_cls; | ||
380 | |||
381 | /** | ||
382 | * Handle for our UBlock operation request. | ||
383 | */ | ||
384 | struct GNUNET_FS_PublishUblockContext *uc; | ||
385 | }; | ||
386 | |||
387 | |||
388 | /** | ||
389 | * Function called by the UBlock construction with | ||
390 | * the result from the PUT (UBlock) request. | ||
391 | * | ||
392 | * @param cls closure of type "struct GNUNET_FS_PublishSksContext*" | ||
393 | * @param msg error message (or NULL) | ||
394 | */ | ||
395 | static void | ||
396 | sks_publish_cont (void *cls, const char *msg) | ||
397 | { | ||
398 | struct GNUNET_FS_PublishSksContext *psc = cls; | ||
399 | struct GNUNET_FS_UpdateInformationGraph *uig; | ||
400 | |||
401 | psc->uc = NULL; | ||
402 | if (NULL != msg) | ||
403 | { | ||
404 | if (NULL != psc->cont) | ||
405 | psc->cont (psc->cont_cls, NULL, msg); | ||
406 | GNUNET_FS_publish_sks_cancel (psc); | ||
407 | return; | ||
408 | } | ||
409 | if (NULL != psc->nsn) | ||
410 | { | ||
411 | /* FIXME: this can be done much more | ||
412 | * efficiently by simply appending to the | ||
413 | * file and overwriting the 4-byte header */ | ||
414 | uig = read_update_information_graph (psc->h, &psc->ns); | ||
415 | GNUNET_array_append (uig->update_nodes, uig->update_node_count, psc->nsn); | ||
416 | psc->nsn = NULL; | ||
417 | write_update_information_graph (uig); | ||
418 | free_update_information_graph (uig); | ||
419 | } | ||
420 | if (NULL != psc->cont) | ||
421 | psc->cont (psc->cont_cls, psc->uri, NULL); | ||
422 | GNUNET_FS_publish_sks_cancel (psc); | ||
423 | } | ||
424 | |||
425 | |||
426 | /** | ||
427 | * Publish an SBlock on GNUnet. | ||
428 | * | ||
429 | * @param h handle to the file sharing subsystem | ||
430 | * @param ns namespace to publish in | ||
431 | * @param identifier identifier to use | ||
432 | * @param update update identifier to use | ||
433 | * @param meta metadata to use | ||
434 | * @param uri URI to refer to in the SBlock | ||
435 | * @param bo block options | ||
436 | * @param options publication options | ||
437 | * @param cont continuation | ||
438 | * @param cont_cls closure for cont | ||
439 | * @return NULL on error ('cont' will still be called) | ||
440 | */ | ||
441 | struct GNUNET_FS_PublishSksContext * | ||
442 | GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, | ||
443 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns, | ||
444 | const char *identifier, | ||
445 | const char *update, | ||
446 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
447 | const struct GNUNET_FS_Uri *uri, | ||
448 | const struct GNUNET_FS_BlockOptions *bo, | ||
449 | enum GNUNET_FS_PublishOptions options, | ||
450 | GNUNET_FS_PublishContinuation cont, | ||
451 | void *cont_cls) | ||
452 | { | ||
453 | struct GNUNET_FS_PublishSksContext *psc; | ||
454 | struct GNUNET_FS_Uri *sks_uri; | ||
455 | |||
456 | sks_uri = GNUNET_new (struct GNUNET_FS_Uri); | ||
457 | sks_uri->type = GNUNET_FS_URI_SKS; | ||
458 | sks_uri->data.sks.identifier = GNUNET_strdup (identifier); | ||
459 | GNUNET_CRYPTO_ecdsa_key_get_public (ns, &sks_uri->data.sks.ns); | ||
460 | |||
461 | psc = GNUNET_new (struct GNUNET_FS_PublishSksContext); | ||
462 | psc->h = h; | ||
463 | psc->uri = sks_uri; | ||
464 | psc->cont = cont; | ||
465 | psc->cont_cls = cont_cls; | ||
466 | psc->ns = *ns; | ||
467 | if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) | ||
468 | { | ||
469 | psc->dsh = GNUNET_DATASTORE_connect (h->cfg); | ||
470 | if (NULL == psc->dsh) | ||
471 | { | ||
472 | sks_publish_cont (psc, _ ("Failed to connect to datastore.")); | ||
473 | return NULL; | ||
474 | } | ||
475 | } | ||
476 | if (NULL != update) | ||
477 | { | ||
478 | psc->nsn = GNUNET_new (struct NamespaceUpdateNode); | ||
479 | psc->nsn->id = GNUNET_strdup (identifier); | ||
480 | psc->nsn->update = GNUNET_strdup (update); | ||
481 | psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
482 | psc->nsn->uri = GNUNET_FS_uri_dup (uri); | ||
483 | } | ||
484 | psc->uc = GNUNET_FS_publish_ublock_ (h, | ||
485 | psc->dsh, | ||
486 | identifier, | ||
487 | update, | ||
488 | ns, | ||
489 | meta, | ||
490 | uri, | ||
491 | bo, | ||
492 | options, | ||
493 | &sks_publish_cont, | ||
494 | psc); | ||
495 | return psc; | ||
496 | } | ||
497 | |||
498 | |||
499 | /** | ||
500 | * Abort the SKS publishing operation. | ||
501 | * | ||
502 | * @param psc context of the operation to abort. | ||
503 | */ | ||
504 | void | ||
505 | GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc) | ||
506 | { | ||
507 | if (NULL != psc->uc) | ||
508 | { | ||
509 | GNUNET_FS_publish_ublock_cancel_ (psc->uc); | ||
510 | psc->uc = NULL; | ||
511 | } | ||
512 | if (NULL != psc->dsh) | ||
513 | { | ||
514 | GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO); | ||
515 | psc->dsh = NULL; | ||
516 | } | ||
517 | GNUNET_FS_uri_destroy (psc->uri); | ||
518 | if (NULL != psc->nsn) | ||
519 | { | ||
520 | GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md); | ||
521 | GNUNET_FS_uri_destroy (psc->nsn->uri); | ||
522 | GNUNET_free (psc->nsn->id); | ||
523 | GNUNET_free (psc->nsn->update); | ||
524 | GNUNET_free (psc->nsn); | ||
525 | } | ||
526 | GNUNET_free (psc); | ||
527 | } | ||
528 | |||
529 | |||
530 | /** | ||
531 | * Closure for 'process_update_node'. | ||
532 | */ | ||
533 | struct ProcessUpdateClosure | ||
534 | { | ||
535 | /** | ||
536 | * Function to call for each node. | ||
537 | */ | ||
538 | GNUNET_FS_IdentifierProcessor ip; | ||
539 | |||
540 | /** | ||
541 | * Closure for 'ip'. | ||
542 | */ | ||
543 | void *ip_cls; | ||
544 | }; | ||
545 | |||
546 | |||
547 | /** | ||
548 | * Call the iterator in the closure for each node. | ||
549 | * | ||
550 | * @param cls closure (of type 'struct ProcessUpdateClosure *') | ||
551 | * @param key current key code | ||
552 | * @param value value in the hash map (of type 'struct NamespaceUpdateNode *') | ||
553 | * @return GNUNET_YES if we should continue to | ||
554 | * iterate, | ||
555 | * GNUNET_NO if not. | ||
556 | */ | ||
557 | static int | ||
558 | process_update_node (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
559 | { | ||
560 | struct ProcessUpdateClosure *pc = cls; | ||
561 | struct NamespaceUpdateNode *nsn = value; | ||
562 | |||
563 | pc->ip (pc->ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update); | ||
564 | return GNUNET_YES; | ||
565 | } | ||
566 | |||
567 | |||
568 | /** | ||
569 | * Closure for 'find_trees'. | ||
570 | */ | ||
571 | struct FindTreeClosure | ||
572 | { | ||
573 | /** | ||
574 | * UIG we are operating on. | ||
575 | */ | ||
576 | struct GNUNET_FS_UpdateInformationGraph *uig; | ||
577 | |||
578 | /** | ||
579 | * Array with 'head's of TREEs. | ||
580 | */ | ||
581 | struct NamespaceUpdateNode **tree_array; | ||
582 | |||
583 | /** | ||
584 | * Size of 'tree_array' | ||
585 | */ | ||
586 | unsigned int tree_array_size; | ||
587 | |||
588 | /** | ||
589 | * Current generational ID used. | ||
590 | */ | ||
591 | unsigned int nug; | ||
592 | |||
593 | /** | ||
594 | * Identifier for the current TREE, or UINT_MAX for none yet. | ||
595 | */ | ||
596 | unsigned int id; | ||
597 | }; | ||
598 | |||
599 | |||
600 | /** | ||
601 | * Find all nodes reachable from the current node (including the | ||
602 | * current node itself). If they are in no tree, add them to the | ||
603 | * current one. If they are the head of another tree, merge the | ||
604 | * trees. If they are in the middle of another tree, let them be. | ||
605 | * We can tell that a node is already in an tree by checking if | ||
606 | * its 'nug' field is set to the current 'nug' value. It is the | ||
607 | * head of an tree if it is in the 'tree_array' under its respective | ||
608 | * 'tree_id'. | ||
609 | * | ||
610 | * In short, we're trying to find the smallest number of tree to | ||
611 | * cover a directed graph. | ||
612 | * | ||
613 | * @param cls closure (of type 'struct FindTreeClosure') | ||
614 | * @param key current key code | ||
615 | * @param value value in the hash map | ||
616 | * @return GNUNET_YES if we should continue to | ||
617 | * iterate, | ||
618 | * GNUNET_NO if not. | ||
619 | */ | ||
620 | static int | ||
621 | find_trees (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
622 | { | ||
623 | struct FindTreeClosure *fc = cls; | ||
624 | struct NamespaceUpdateNode *nsn = value; | ||
625 | struct GNUNET_HashCode hc; | ||
626 | |||
627 | if (nsn->nug == fc->nug) | ||
628 | { | ||
629 | if (UINT_MAX == nsn->tree_id) | ||
630 | return GNUNET_YES; /* circular */ | ||
631 | GNUNET_assert (nsn->tree_id < fc->tree_array_size); | ||
632 | if (fc->tree_array[nsn->tree_id] != nsn) | ||
633 | return GNUNET_YES; /* part of "another" (directed) TREE, | ||
634 | * and not root of it, end trace */ | ||
635 | if (nsn->tree_id == fc->id) | ||
636 | return GNUNET_YES; /* that's our own root (can this be?) */ | ||
637 | /* merge existing TREE, we have a root for both */ | ||
638 | fc->tree_array[nsn->tree_id] = NULL; | ||
639 | if (UINT_MAX == fc->id) | ||
640 | fc->id = nsn->tree_id; /* take over ID */ | ||
641 | } | ||
642 | else | ||
643 | { | ||
644 | nsn->nug = fc->nug; | ||
645 | nsn->tree_id = UINT_MAX; /* mark as undef */ | ||
646 | /* trace */ | ||
647 | GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc); | ||
648 | GNUNET_CONTAINER_multihashmap_get_multiple (fc->uig->update_map, | ||
649 | &hc, | ||
650 | &find_trees, | ||
651 | fc); | ||
652 | } | ||
653 | return GNUNET_YES; | ||
654 | } | ||
655 | |||
656 | |||
657 | /** | ||
658 | * List all of the identifiers in the namespace for which we could | ||
659 | * produce an update. Namespace updates form a graph where each node | ||
660 | * has a name. Each node can have any number of URI/meta-data entries | ||
661 | * which can each be linked to other nodes. Cycles are possible. | ||
662 | * | ||
663 | * Calling this function with "next_id" NULL will cause the library to | ||
664 | * call "ip" with a root for each strongly connected component of the | ||
665 | * graph (a root being a node from which all other nodes in the Tree | ||
666 | * are reachable). | ||
667 | * | ||
668 | * Calling this function with "next_id" being the name of a node will | ||
669 | * cause the library to call "ip" with all children of the node. Note | ||
670 | * that cycles within the final tree are possible (including self-loops). | ||
671 | * I know, odd definition of a tree, but the GUI will display an actual | ||
672 | * tree (GtkTreeView), so that's what counts for the term here. | ||
673 | * | ||
674 | * @param h fs handle to use | ||
675 | * @param ns namespace to inspect for updateable content | ||
676 | * @param next_id ID to look for; use NULL to look for tree roots | ||
677 | * @param ip function to call on each updateable identifier | ||
678 | * @param ip_cls closure for ip | ||
679 | */ | ||
680 | void | ||
681 | GNUNET_FS_namespace_list_updateable ( | ||
682 | struct GNUNET_FS_Handle *h, | ||
683 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns, | ||
684 | const char *next_id, | ||
685 | GNUNET_FS_IdentifierProcessor ip, | ||
686 | void *ip_cls) | ||
687 | { | ||
688 | unsigned int i; | ||
689 | unsigned int nug; | ||
690 | struct GNUNET_HashCode hc; | ||
691 | struct NamespaceUpdateNode *nsn; | ||
692 | struct ProcessUpdateClosure pc; | ||
693 | struct FindTreeClosure fc; | ||
694 | struct GNUNET_FS_UpdateInformationGraph *uig; | ||
695 | |||
696 | uig = read_update_information_graph (h, ns); | ||
697 | if (NULL == uig->update_nodes) | ||
698 | { | ||
699 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
700 | "No updateable nodes found for ID `%s'\n", | ||
701 | next_id); | ||
702 | free_update_information_graph (uig); | ||
703 | return; /* no nodes */ | ||
704 | } | ||
705 | uig->update_map = | ||
706 | GNUNET_CONTAINER_multihashmap_create (2 + 3 * uig->update_node_count / 4, | ||
707 | GNUNET_NO); | ||
708 | for (i = 0; i < uig->update_node_count; i++) | ||
709 | { | ||
710 | nsn = uig->update_nodes[i]; | ||
711 | GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc); | ||
712 | GNUNET_CONTAINER_multihashmap_put ( | ||
713 | uig->update_map, | ||
714 | &hc, | ||
715 | nsn, | ||
716 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
717 | } | ||
718 | if (NULL != next_id) | ||
719 | { | ||
720 | GNUNET_CRYPTO_hash (next_id, strlen (next_id), &hc); | ||
721 | pc.ip = ip; | ||
722 | pc.ip_cls = ip_cls; | ||
723 | GNUNET_CONTAINER_multihashmap_get_multiple (uig->update_map, | ||
724 | &hc, | ||
725 | &process_update_node, | ||
726 | &pc); | ||
727 | free_update_information_graph (uig); | ||
728 | return; | ||
729 | } | ||
730 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
731 | "Calculating TREEs to find roots of update trees\n"); | ||
732 | /* Find heads of TREEs in update graph */ | ||
733 | nug = ++uig->nug_gen; | ||
734 | fc.tree_array = NULL; | ||
735 | fc.tree_array_size = 0; | ||
736 | |||
737 | for (i = 0; i < uig->update_node_count; i++) | ||
738 | { | ||
739 | nsn = uig->update_nodes[i]; | ||
740 | if (nsn->nug == nug) | ||
741 | { | ||
742 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
743 | "TREE of node `%s' is %u\n", | ||
744 | nsn->id, | ||
745 | nsn->nug); | ||
746 | continue; /* already placed in TREE */ | ||
747 | } | ||
748 | GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc); | ||
749 | nsn->nug = nug; | ||
750 | nsn->tree_id = UINT_MAX; | ||
751 | fc.id = UINT_MAX; | ||
752 | fc.nug = nug; | ||
753 | fc.uig = uig; | ||
754 | GNUNET_CONTAINER_multihashmap_get_multiple (uig->update_map, | ||
755 | &hc, | ||
756 | &find_trees, | ||
757 | &fc); | ||
758 | if (UINT_MAX == fc.id) | ||
759 | { | ||
760 | /* start new TREE */ | ||
761 | for (fc.id = 0; fc.id < fc.tree_array_size; fc.id++) | ||
762 | { | ||
763 | if (NULL == fc.tree_array[fc.id]) | ||
764 | { | ||
765 | fc.tree_array[fc.id] = nsn; | ||
766 | nsn->tree_id = fc.id; | ||
767 | break; | ||
768 | } | ||
769 | } | ||
770 | if (fc.id == fc.tree_array_size) | ||
771 | { | ||
772 | GNUNET_array_append (fc.tree_array, fc.tree_array_size, nsn); | ||
773 | nsn->tree_id = fc.id; | ||
774 | } | ||
775 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
776 | "Starting new TREE %u with node `%s'\n", | ||
777 | nsn->tree_id, | ||
778 | nsn->id); | ||
779 | /* put all nodes with same identifier into this TREE */ | ||
780 | GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc); | ||
781 | fc.id = nsn->tree_id; | ||
782 | fc.nug = nug; | ||
783 | fc.uig = uig; | ||
784 | GNUNET_CONTAINER_multihashmap_get_multiple (uig->update_map, | ||
785 | &hc, | ||
786 | &find_trees, | ||
787 | &fc); | ||
788 | } | ||
789 | else | ||
790 | { | ||
791 | /* make head of TREE "id" */ | ||
792 | fc.tree_array[fc.id] = nsn; | ||
793 | nsn->tree_id = fc.id; | ||
794 | } | ||
795 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
796 | "TREE of node `%s' is %u\n", | ||
797 | nsn->id, | ||
798 | fc.id); | ||
799 | } | ||
800 | for (i = 0; i < fc.tree_array_size; i++) | ||
801 | { | ||
802 | nsn = fc.tree_array[i]; | ||
803 | if (NULL != nsn) | ||
804 | { | ||
805 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
806 | "Root of TREE %u is node `%s'\n", | ||
807 | i, | ||
808 | nsn->id); | ||
809 | ip (ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update); | ||
810 | } | ||
811 | } | ||
812 | GNUNET_array_grow (fc.tree_array, fc.tree_array_size, 0); | ||
813 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n"); | ||
814 | free_update_information_graph (uig); | ||
815 | } | ||
816 | |||
817 | |||
818 | /* end of fs_namespace.c */ | ||
diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c deleted file mode 100644 index f891f37a1..000000000 --- a/src/fs/fs_publish.c +++ /dev/null | |||
@@ -1,1624 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/fs_publish.c | ||
22 | * @brief publish a file or directory in GNUnet | ||
23 | * @see https://gnunet.org/encoding | ||
24 | * @author Krista Bennett | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_signatures.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_fs_service.h" | ||
32 | #include "fs_api.h" | ||
33 | #include "fs_tree.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Fill in all of the generic fields for | ||
38 | * a publish event and call the callback. | ||
39 | * | ||
40 | * @param pi structure to fill in | ||
41 | * @param pc overall publishing context | ||
42 | * @param p file information for the file being published | ||
43 | * @param offset where in the file are we so far | ||
44 | * @return value returned from callback | ||
45 | */ | ||
46 | void * | ||
47 | GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
48 | struct GNUNET_FS_PublishContext *pc, | ||
49 | const struct GNUNET_FS_FileInformation *p, | ||
50 | uint64_t offset) | ||
51 | { | ||
52 | pi->value.publish.pc = pc; | ||
53 | pi->value.publish.fi = p; | ||
54 | pi->value.publish.cctx = p->client_info; | ||
55 | pi->value.publish.pctx = (NULL == p->dir) ? NULL : p->dir->client_info; | ||
56 | pi->value.publish.filename = p->filename; | ||
57 | pi->value.publish.size = | ||
58 | (GNUNET_YES == p->is_directory) ? p->data.dir.dir_size : | ||
59 | p->data.file.file_size; | ||
60 | pi->value.publish.eta = | ||
61 | GNUNET_TIME_calculate_eta (p->start_time, offset, | ||
62 | pi->value.publish.size); | ||
63 | pi->value.publish.completed = offset; | ||
64 | pi->value.publish.duration = | ||
65 | GNUNET_TIME_absolute_get_duration (p->start_time); | ||
66 | pi->value.publish.anonymity = p->bo.anonymity_level; | ||
67 | pi->fsh = pc->h; | ||
68 | return pc->h->upcb (pc->h->upcb_cls, pi); | ||
69 | } | ||
70 | |||
71 | |||
72 | /** | ||
73 | * Cleanup the publish context, we're done with it. | ||
74 | * | ||
75 | * @param pc struct to clean up | ||
76 | */ | ||
77 | static void | ||
78 | publish_cleanup (struct GNUNET_FS_PublishContext *pc) | ||
79 | { | ||
80 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
81 | "Cleaning up publish context (done!)\n"); | ||
82 | if (NULL != pc->fhc) | ||
83 | { | ||
84 | GNUNET_CRYPTO_hash_file_cancel (pc->fhc); | ||
85 | pc->fhc = NULL; | ||
86 | } | ||
87 | GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL); | ||
88 | GNUNET_free (pc->nid); | ||
89 | GNUNET_free (pc->nuid); | ||
90 | GNUNET_free (pc->serialization); | ||
91 | if (NULL != pc->dsh) | ||
92 | { | ||
93 | GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO); | ||
94 | pc->dsh = NULL; | ||
95 | } | ||
96 | if (NULL != pc->mq) | ||
97 | { | ||
98 | GNUNET_MQ_destroy (pc->mq); | ||
99 | pc->mq = NULL; | ||
100 | } | ||
101 | GNUNET_assert (NULL == pc->upload_task); | ||
102 | GNUNET_free (pc); | ||
103 | } | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Function called by the datastore API with | ||
108 | * the result from the PUT request. | ||
109 | * | ||
110 | * @param cls the `struct GNUNET_FS_PublishContext *` | ||
111 | * @param success #GNUNET_OK on success | ||
112 | * @param min_expiration minimum expiration time required for content to be stored | ||
113 | * @param msg error message (or NULL) | ||
114 | */ | ||
115 | static void | ||
116 | ds_put_cont (void *cls, | ||
117 | int success, | ||
118 | struct GNUNET_TIME_Absolute min_expiration, | ||
119 | const char *msg) | ||
120 | { | ||
121 | struct GNUNET_FS_PublishContext *pc = cls; | ||
122 | struct GNUNET_FS_ProgressInfo pi; | ||
123 | |||
124 | pc->qre = NULL; | ||
125 | if (GNUNET_SYSERR == success) | ||
126 | { | ||
127 | GNUNET_asprintf (&pc->fi_pos->emsg, | ||
128 | _ ("Publishing failed: %s"), | ||
129 | msg); | ||
130 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
131 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
132 | pi.value.publish.specifics.error.message = pc->fi_pos->emsg; | ||
133 | pc->fi_pos->client_info = | ||
134 | GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi_pos, 0); | ||
135 | if ((GNUNET_YES != pc->fi_pos->is_directory) && | ||
136 | (NULL != pc->fi_pos->filename) && | ||
137 | (GNUNET_YES == pc->any_done) && | ||
138 | (GNUNET_YES == pc->fi_pos->data.file.do_index)) | ||
139 | { | ||
140 | /* run unindex to clean up */ | ||
141 | GNUNET_FS_unindex_start (pc->h, | ||
142 | pc->fi_pos->filename, | ||
143 | NULL); | ||
144 | } | ||
145 | return; | ||
146 | } | ||
147 | pc->any_done = GNUNET_YES; | ||
148 | GNUNET_assert (NULL == pc->upload_task); | ||
149 | pc->upload_task = | ||
150 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
151 | &GNUNET_FS_publish_main_, pc); | ||
152 | } | ||
153 | |||
154 | |||
155 | /** | ||
156 | * Generate the callback that signals clients | ||
157 | * that a file (or directory) has been completely | ||
158 | * published. | ||
159 | * | ||
160 | * @param p the completed upload | ||
161 | * @param pc context of the publication | ||
162 | */ | ||
163 | static void | ||
164 | signal_publish_completion (struct GNUNET_FS_FileInformation *p, | ||
165 | struct GNUNET_FS_PublishContext *pc) | ||
166 | { | ||
167 | struct GNUNET_FS_ProgressInfo pi; | ||
168 | |||
169 | pi.status = GNUNET_FS_STATUS_PUBLISH_COMPLETED; | ||
170 | pi.value.publish.eta = GNUNET_TIME_UNIT_ZERO; | ||
171 | pi.value.publish.specifics.completed.chk_uri = p->chk_uri; | ||
172 | pi.value.publish.specifics.completed.sks_uri = p->sks_uri; | ||
173 | p->client_info = | ||
174 | GNUNET_FS_publish_make_status_ (&pi, pc, p, | ||
175 | p->data.file.file_size); | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Generate the callback that signals clients | ||
181 | * that a file (or directory) has encountered | ||
182 | * a problem during publication. | ||
183 | * | ||
184 | * @param p the upload that had trouble | ||
185 | * @param pc context of the publication | ||
186 | * @param emsg error message | ||
187 | */ | ||
188 | static void | ||
189 | signal_publish_error (struct GNUNET_FS_FileInformation *p, | ||
190 | struct GNUNET_FS_PublishContext *pc, | ||
191 | const char *emsg) | ||
192 | { | ||
193 | struct GNUNET_FS_ProgressInfo pi; | ||
194 | |||
195 | p->emsg = GNUNET_strdup (emsg); | ||
196 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
197 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
198 | pi.value.publish.specifics.error.message = emsg; | ||
199 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); | ||
200 | if ((p->is_directory != GNUNET_YES) && | ||
201 | (NULL != p->filename) && | ||
202 | (GNUNET_YES == pc->any_done) && | ||
203 | (p->data.file.do_index == GNUNET_YES)) | ||
204 | { | ||
205 | /* run unindex to clean up */ | ||
206 | GNUNET_FS_unindex_start (pc->h, | ||
207 | p->filename, | ||
208 | NULL); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Datastore returns from reservation cancel request. | ||
215 | * | ||
216 | * @param cls the `struct GNUNET_FS_PublishContext *` | ||
217 | * @param success success code (not used) | ||
218 | * @param min_expiration minimum expiration time required for content to be stored | ||
219 | * @param msg error message (typically NULL, not used) | ||
220 | */ | ||
221 | static void | ||
222 | finish_release_reserve (void *cls, int success, | ||
223 | struct GNUNET_TIME_Absolute min_expiration, | ||
224 | const char *msg) | ||
225 | { | ||
226 | struct GNUNET_FS_PublishContext *pc = cls; | ||
227 | |||
228 | pc->qre = NULL; | ||
229 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
230 | "Releasing reserve done!\n"); | ||
231 | signal_publish_completion (pc->fi, pc); | ||
232 | pc->all_done = GNUNET_YES; | ||
233 | GNUNET_FS_publish_sync_ (pc); | ||
234 | } | ||
235 | |||
236 | |||
237 | /** | ||
238 | * We've finished publishing the SBlock as part of a larger upload. | ||
239 | * Check the result and complete the larger upload. | ||
240 | * | ||
241 | * @param cls the `struct GNUNET_FS_PublishContext *` of the larger upload | ||
242 | * @param uri URI of the published SBlock | ||
243 | * @param emsg NULL on success, otherwise error message | ||
244 | */ | ||
245 | static void | ||
246 | publish_sblocks_cont (void *cls, | ||
247 | const struct GNUNET_FS_Uri *uri, | ||
248 | const char *emsg) | ||
249 | { | ||
250 | struct GNUNET_FS_PublishContext *pc = cls; | ||
251 | |||
252 | pc->sks_pc = NULL; | ||
253 | if (NULL != emsg) | ||
254 | { | ||
255 | signal_publish_error (pc->fi, pc, emsg); | ||
256 | GNUNET_FS_publish_sync_ (pc); | ||
257 | return; | ||
258 | } | ||
259 | if (NULL != uri) | ||
260 | { | ||
261 | /* sks publication, remember namespace URI */ | ||
262 | pc->fi->sks_uri = GNUNET_FS_uri_dup (uri); | ||
263 | } | ||
264 | GNUNET_assert (pc->qre == NULL); | ||
265 | if ((pc->dsh != NULL) && (pc->rid != 0)) | ||
266 | { | ||
267 | pc->qre = | ||
268 | GNUNET_DATASTORE_release_reserve (pc->dsh, pc->rid, UINT_MAX, UINT_MAX, | ||
269 | &finish_release_reserve, pc); | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | finish_release_reserve (pc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * We are almost done publishing the structure, | ||
280 | * add SBlocks (if needed). | ||
281 | * | ||
282 | * @param pc overall upload data | ||
283 | */ | ||
284 | static void | ||
285 | publish_sblock (struct GNUNET_FS_PublishContext *pc) | ||
286 | { | ||
287 | if (NULL != pc->ns) | ||
288 | pc->sks_pc = GNUNET_FS_publish_sks (pc->h, | ||
289 | pc->ns, | ||
290 | pc->nid, | ||
291 | pc->nuid, | ||
292 | pc->fi->meta, | ||
293 | pc->fi->chk_uri, | ||
294 | &pc->fi->bo, | ||
295 | pc->options, | ||
296 | &publish_sblocks_cont, pc); | ||
297 | else | ||
298 | publish_sblocks_cont (pc, NULL, NULL); | ||
299 | } | ||
300 | |||
301 | |||
302 | /** | ||
303 | * We've finished publishing a KBlock as part of a larger upload. | ||
304 | * Check the result and continue the larger upload. | ||
305 | * | ||
306 | * @param cls the `struct GNUNET_FS_PublishContext *` | ||
307 | * of the larger upload | ||
308 | * @param uri URI of the published blocks | ||
309 | * @param emsg NULL on success, otherwise error message | ||
310 | */ | ||
311 | static void | ||
312 | publish_kblocks_cont (void *cls, | ||
313 | const struct GNUNET_FS_Uri *uri, | ||
314 | const char *emsg) | ||
315 | { | ||
316 | struct GNUNET_FS_PublishContext *pc = cls; | ||
317 | struct GNUNET_FS_FileInformation *p = pc->fi_pos; | ||
318 | |||
319 | pc->ksk_pc = NULL; | ||
320 | if (NULL != emsg) | ||
321 | { | ||
322 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
323 | "Error uploading KSK blocks: %s\n", | ||
324 | emsg); | ||
325 | signal_publish_error (p, pc, emsg); | ||
326 | GNUNET_FS_file_information_sync_ (p); | ||
327 | GNUNET_FS_publish_sync_ (pc); | ||
328 | GNUNET_assert (NULL == pc->upload_task); | ||
329 | pc->upload_task = | ||
330 | GNUNET_SCHEDULER_add_with_priority | ||
331 | (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
332 | &GNUNET_FS_publish_main_, | ||
333 | pc); | ||
334 | return; | ||
335 | } | ||
336 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
337 | "KSK blocks published, moving on to next file\n"); | ||
338 | if (NULL != p->dir) | ||
339 | signal_publish_completion (p, pc); | ||
340 | /* move on to next file */ | ||
341 | if (NULL != p->next) | ||
342 | pc->fi_pos = p->next; | ||
343 | else | ||
344 | pc->fi_pos = p->dir; | ||
345 | GNUNET_FS_publish_sync_ (pc); | ||
346 | GNUNET_assert (NULL == pc->upload_task); | ||
347 | pc->upload_task = | ||
348 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
349 | &GNUNET_FS_publish_main_, pc); | ||
350 | } | ||
351 | |||
352 | |||
353 | /** | ||
354 | * Function called by the tree encoder to obtain | ||
355 | * a block of plaintext data (for the lowest level | ||
356 | * of the tree). | ||
357 | * | ||
358 | * @param cls our publishing context | ||
359 | * @param offset identifies which block to get | ||
360 | * @param max (maximum) number of bytes to get; returning | ||
361 | * fewer will also cause errors | ||
362 | * @param buf where to copy the plaintext buffer | ||
363 | * @param emsg location to store an error message (on error) | ||
364 | * @return number of bytes copied to buf, 0 on error | ||
365 | */ | ||
366 | static size_t | ||
367 | block_reader (void *cls, | ||
368 | uint64_t offset, | ||
369 | size_t max, | ||
370 | void *buf, | ||
371 | char **emsg) | ||
372 | { | ||
373 | struct GNUNET_FS_PublishContext *pc = cls; | ||
374 | struct GNUNET_FS_FileInformation *p; | ||
375 | const char *dd; | ||
376 | size_t pt_size; | ||
377 | |||
378 | p = pc->fi_pos; | ||
379 | if (GNUNET_YES == p->is_directory) | ||
380 | { | ||
381 | pt_size = GNUNET_MIN (max, p->data.dir.dir_size - offset); | ||
382 | dd = p->data.dir.dir_data; | ||
383 | GNUNET_memcpy (buf, &dd[offset], pt_size); | ||
384 | } | ||
385 | else | ||
386 | { | ||
387 | if (UINT64_MAX == offset) | ||
388 | { | ||
389 | if (&GNUNET_FS_data_reader_file_ == p->data.file.reader) | ||
390 | { | ||
391 | /* force closing the file to avoid keeping too many files open */ | ||
392 | p->data.file.reader (p->data.file.reader_cls, offset, 0, NULL, NULL); | ||
393 | } | ||
394 | return 0; | ||
395 | } | ||
396 | pt_size = GNUNET_MIN (max, p->data.file.file_size - offset); | ||
397 | if (0 == pt_size) | ||
398 | return 0; /* calling reader with pt_size==0 | ||
399 | * might free buf, so don't! */ | ||
400 | if (pt_size != | ||
401 | p->data.file.reader (p->data.file.reader_cls, offset, pt_size, buf, | ||
402 | emsg)) | ||
403 | return 0; | ||
404 | } | ||
405 | return pt_size; | ||
406 | } | ||
407 | |||
408 | |||
409 | /** | ||
410 | * The tree encoder has finished processing a | ||
411 | * file. Call it's finish method and deal with | ||
412 | * the final result. | ||
413 | * | ||
414 | * @param cls our publishing context | ||
415 | */ | ||
416 | static void | ||
417 | encode_cont (void *cls) | ||
418 | { | ||
419 | struct GNUNET_FS_PublishContext *pc = cls; | ||
420 | struct GNUNET_FS_FileInformation *p; | ||
421 | struct GNUNET_FS_ProgressInfo pi; | ||
422 | char *emsg; | ||
423 | uint64_t flen; | ||
424 | |||
425 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
426 | "Finished with tree encoder\n"); | ||
427 | p = pc->fi_pos; | ||
428 | p->chk_uri = GNUNET_FS_tree_encoder_get_uri (p->te); | ||
429 | GNUNET_FS_file_information_sync_ (p); | ||
430 | GNUNET_FS_tree_encoder_finish (p->te, &emsg); | ||
431 | p->te = NULL; | ||
432 | if (NULL != emsg) | ||
433 | { | ||
434 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
435 | "Error during tree walk: %s\n", | ||
436 | emsg); | ||
437 | GNUNET_asprintf (&p->emsg, | ||
438 | _ ("Publishing failed: %s"), | ||
439 | emsg); | ||
440 | GNUNET_free (emsg); | ||
441 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
442 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
443 | pi.value.publish.specifics.error.message = p->emsg; | ||
444 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | /* final progress event */ | ||
449 | GNUNET_assert (NULL != p->chk_uri); | ||
450 | flen = GNUNET_FS_uri_chk_get_file_size (p->chk_uri); | ||
451 | pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; | ||
452 | pi.value.publish.specifics.progress.data = NULL; | ||
453 | pi.value.publish.specifics.progress.offset = flen; | ||
454 | pi.value.publish.specifics.progress.data_len = 0; | ||
455 | pi.value.publish.specifics.progress.depth = GNUNET_FS_compute_depth (flen); | ||
456 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, flen); | ||
457 | } | ||
458 | /* continue with main */ /* continue with main */ | ||
459 | GNUNET_assert (NULL == pc->upload_task); | ||
460 | pc->upload_task = | ||
461 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
462 | &GNUNET_FS_publish_main_, pc); | ||
463 | } | ||
464 | |||
465 | |||
466 | /** | ||
467 | * Function called asking for the current (encoded) | ||
468 | * block to be processed. After processing the | ||
469 | * client should either call #GNUNET_FS_tree_encoder_next | ||
470 | * or (on error) #GNUNET_FS_tree_encoder_finish. | ||
471 | * | ||
472 | * @param cls closure | ||
473 | * @param chk content hash key for the block | ||
474 | * @param offset offset of the block in the file | ||
475 | * @param depth depth of the block in the file, 0 for DBLOCK | ||
476 | * @param type type of the block (IBLOCK or DBLOCK) | ||
477 | * @param block the (encrypted) block | ||
478 | * @param block_size size of @a block (in bytes) | ||
479 | */ | ||
480 | static void | ||
481 | block_proc (void *cls, | ||
482 | const struct ContentHashKey *chk, | ||
483 | uint64_t offset, | ||
484 | unsigned int depth, | ||
485 | enum GNUNET_BLOCK_Type type, | ||
486 | const void *block, | ||
487 | uint16_t block_size) | ||
488 | { | ||
489 | struct GNUNET_FS_PublishContext *pc = cls; | ||
490 | struct GNUNET_FS_FileInformation *p; | ||
491 | struct OnDemandBlock odb; | ||
492 | |||
493 | p = pc->fi_pos; | ||
494 | if (NULL == pc->dsh) | ||
495 | { | ||
496 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
497 | "Waiting for datastore connection\n"); | ||
498 | GNUNET_assert (NULL == pc->upload_task); | ||
499 | pc->upload_task = | ||
500 | GNUNET_SCHEDULER_add_with_priority | ||
501 | (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); | ||
502 | return; | ||
503 | } | ||
504 | |||
505 | if ((GNUNET_YES != p->is_directory) && | ||
506 | (GNUNET_YES == p->data.file.do_index) && | ||
507 | (GNUNET_BLOCK_TYPE_FS_DBLOCK == type)) | ||
508 | { | ||
509 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
510 | "Indexing block `%s' for offset %llu with index size %u\n", | ||
511 | GNUNET_h2s (&chk->query), | ||
512 | (unsigned long long) offset, | ||
513 | (unsigned int) sizeof(struct OnDemandBlock)); | ||
514 | odb.offset = GNUNET_htonll (offset); | ||
515 | odb.file_id = p->data.file.file_id; | ||
516 | GNUNET_assert (pc->qre == NULL); | ||
517 | pc->qre = | ||
518 | GNUNET_DATASTORE_put (pc->dsh, | ||
519 | (p->is_directory == GNUNET_YES) ? 0 : pc->rid, | ||
520 | &chk->query, | ||
521 | sizeof(struct OnDemandBlock), | ||
522 | &odb, | ||
523 | GNUNET_BLOCK_TYPE_FS_ONDEMAND, | ||
524 | p->bo.content_priority, | ||
525 | p->bo.anonymity_level, | ||
526 | p->bo.replication_level, | ||
527 | p->bo.expiration_time, | ||
528 | -2, 1, | ||
529 | &ds_put_cont, pc); | ||
530 | return; | ||
531 | } | ||
532 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
533 | "Publishing block `%s' for offset %llu with size %u\n", | ||
534 | GNUNET_h2s (&chk->query), | ||
535 | (unsigned long long) offset, | ||
536 | (unsigned int) block_size); | ||
537 | GNUNET_assert (pc->qre == NULL); | ||
538 | pc->qre = | ||
539 | GNUNET_DATASTORE_put (pc->dsh, (p->is_directory == GNUNET_YES) ? 0 : | ||
540 | pc->rid, | ||
541 | &chk->query, | ||
542 | block_size, | ||
543 | block, | ||
544 | type, | ||
545 | p->bo.content_priority, | ||
546 | p->bo.anonymity_level, | ||
547 | p->bo.replication_level, | ||
548 | p->bo.expiration_time, | ||
549 | -2, 1, | ||
550 | &ds_put_cont, | ||
551 | pc); | ||
552 | } | ||
553 | |||
554 | |||
555 | /** | ||
556 | * Function called with information about our | ||
557 | * progress in computing the tree encoding. | ||
558 | * | ||
559 | * @param cls closure | ||
560 | * @param offset where are we in the file | ||
561 | * @param pt_block plaintext of the currently processed block | ||
562 | * @param pt_size size of @a pt_block | ||
563 | * @param depth depth of the block in the tree, 0 for DBLOCK | ||
564 | */ | ||
565 | static void | ||
566 | progress_proc (void *cls, uint64_t offset, | ||
567 | const void *pt_block, | ||
568 | size_t pt_size, | ||
569 | unsigned int depth) | ||
570 | { | ||
571 | struct GNUNET_FS_PublishContext *pc = cls; | ||
572 | struct GNUNET_FS_FileInformation *p; | ||
573 | struct GNUNET_FS_FileInformation *par; | ||
574 | struct GNUNET_FS_ProgressInfo pi; | ||
575 | |||
576 | p = pc->fi_pos; | ||
577 | pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; | ||
578 | pi.value.publish.specifics.progress.data = pt_block; | ||
579 | pi.value.publish.specifics.progress.offset = offset; | ||
580 | pi.value.publish.specifics.progress.data_len = pt_size; | ||
581 | pi.value.publish.specifics.progress.depth = depth; | ||
582 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, offset); | ||
583 | if ((0 != depth) || | ||
584 | (GNUNET_YES == p->is_directory)) | ||
585 | return; | ||
586 | while (NULL != (par = p->dir)) | ||
587 | { | ||
588 | p = par; | ||
589 | GNUNET_assert (GNUNET_YES == par->is_directory); | ||
590 | p->data.dir.contents_completed += pt_size; | ||
591 | pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY; | ||
592 | pi.value.publish.specifics.progress_directory.completed = | ||
593 | p->data.dir.contents_completed; | ||
594 | pi.value.publish.specifics.progress_directory.total = | ||
595 | p->data.dir.contents_size; | ||
596 | pi.value.publish.specifics.progress_directory.eta = | ||
597 | GNUNET_TIME_calculate_eta (p->start_time, | ||
598 | p | ||
599 | ->data.dir.contents_completed, | ||
600 | p | ||
601 | ->data.dir.contents_size); | ||
602 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); | ||
603 | } | ||
604 | } | ||
605 | |||
606 | |||
607 | /** | ||
608 | * We are uploading a file or directory; load (if necessary) the next | ||
609 | * block into memory, encrypt it and send it to the FS service. Then | ||
610 | * continue with the main task. | ||
611 | * | ||
612 | * @param pc overall upload data | ||
613 | */ | ||
614 | static void | ||
615 | publish_content (struct GNUNET_FS_PublishContext *pc) | ||
616 | { | ||
617 | struct GNUNET_FS_FileInformation *p; | ||
618 | char *emsg; | ||
619 | struct GNUNET_FS_DirectoryBuilder *db; | ||
620 | struct GNUNET_FS_FileInformation *dirpos; | ||
621 | void *raw_data; | ||
622 | uint64_t size; | ||
623 | |||
624 | p = pc->fi_pos; | ||
625 | GNUNET_assert (NULL != p); | ||
626 | if (NULL == p->te) | ||
627 | { | ||
628 | if (GNUNET_YES == p->is_directory) | ||
629 | { | ||
630 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating directory\n"); | ||
631 | db = GNUNET_FS_directory_builder_create (p->meta); | ||
632 | dirpos = p->data.dir.entries; | ||
633 | while (NULL != dirpos) | ||
634 | { | ||
635 | if (GNUNET_YES == dirpos->is_directory) | ||
636 | { | ||
637 | raw_data = dirpos->data.dir.dir_data; | ||
638 | dirpos->data.dir.dir_data = NULL; | ||
639 | } | ||
640 | else | ||
641 | { | ||
642 | raw_data = NULL; | ||
643 | if ((dirpos->data.file.file_size < MAX_INLINE_SIZE) && | ||
644 | (dirpos->data.file.file_size > 0)) | ||
645 | { | ||
646 | raw_data = GNUNET_malloc (dirpos->data.file.file_size); | ||
647 | emsg = NULL; | ||
648 | if (dirpos->data.file.file_size != | ||
649 | dirpos->data.file.reader (dirpos->data.file.reader_cls, 0, | ||
650 | dirpos->data.file.file_size, raw_data, | ||
651 | &emsg)) | ||
652 | { | ||
653 | GNUNET_free (emsg); | ||
654 | GNUNET_free (raw_data); | ||
655 | raw_data = NULL; | ||
656 | } | ||
657 | dirpos->data.file.reader (dirpos->data.file.reader_cls, UINT64_MAX, | ||
658 | 0, 0, NULL); | ||
659 | } | ||
660 | } | ||
661 | GNUNET_FS_directory_builder_add (db, dirpos->chk_uri, dirpos->meta, | ||
662 | raw_data); | ||
663 | GNUNET_free (raw_data); | ||
664 | dirpos = dirpos->next; | ||
665 | } | ||
666 | GNUNET_free (p->data.dir.dir_data); | ||
667 | p->data.dir.dir_data = NULL; | ||
668 | p->data.dir.dir_size = 0; | ||
669 | GNUNET_FS_directory_builder_finish (db, &p->data.dir.dir_size, | ||
670 | &p->data.dir.dir_data); | ||
671 | GNUNET_FS_file_information_sync_ (p); | ||
672 | } | ||
673 | size = (GNUNET_YES == p->is_directory) ? p->data.dir.dir_size : | ||
674 | p->data.file.file_size; | ||
675 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
676 | "Creating tree encoder\n"); | ||
677 | p->te = | ||
678 | GNUNET_FS_tree_encoder_create (pc->h, size, pc, &block_reader, | ||
679 | &block_proc, &progress_proc, | ||
680 | &encode_cont); | ||
681 | } | ||
682 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
683 | "Processing next block from tree\n"); | ||
684 | GNUNET_FS_tree_encoder_next (p->te); | ||
685 | } | ||
686 | |||
687 | |||
688 | /** | ||
689 | * Check the response from the "fs" service to our 'start index' | ||
690 | * request. | ||
691 | * | ||
692 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
693 | * @param msg the response we got | ||
694 | */ | ||
695 | static int | ||
696 | check_index_start_failed (void *cls, | ||
697 | const struct GNUNET_MessageHeader *msg) | ||
698 | { | ||
699 | size_t msize = ntohs (msg->size) - sizeof(*msg); | ||
700 | const char *emsg = (const char *) &msg[1]; | ||
701 | |||
702 | if (emsg[msize - sizeof(struct GNUNET_MessageHeader) - 1] != '\0') | ||
703 | { | ||
704 | GNUNET_break (0); | ||
705 | return GNUNET_SYSERR; | ||
706 | } | ||
707 | return GNUNET_OK; | ||
708 | } | ||
709 | |||
710 | |||
711 | /** | ||
712 | * Process the response from the "fs" service to our 'start index' | ||
713 | * request. | ||
714 | * | ||
715 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
716 | * @param msg the response we got | ||
717 | */ | ||
718 | static void | ||
719 | handle_index_start_failed (void *cls, | ||
720 | const struct GNUNET_MessageHeader *msg) | ||
721 | { | ||
722 | struct GNUNET_FS_PublishContext *pc = cls; | ||
723 | struct GNUNET_FS_FileInformation *p; | ||
724 | const char *emsg = (const char *) &msg[1]; | ||
725 | char *msgtxt; | ||
726 | |||
727 | GNUNET_MQ_destroy (pc->mq); | ||
728 | pc->mq = NULL; | ||
729 | p = pc->fi_pos; | ||
730 | GNUNET_asprintf (&msgtxt, | ||
731 | _ ("Can not index file `%s': %s.\n"), | ||
732 | p->filename, | ||
733 | gettext (emsg)); | ||
734 | signal_publish_error (p, | ||
735 | pc, | ||
736 | msgtxt); | ||
737 | GNUNET_free (msgtxt); | ||
738 | GNUNET_FS_file_information_sync_ (p); | ||
739 | GNUNET_FS_publish_sync_ (pc); | ||
740 | } | ||
741 | |||
742 | |||
743 | /** | ||
744 | * Process the response from the "fs" service to our 'start index' | ||
745 | * request. | ||
746 | * | ||
747 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
748 | * @param msg the response we got | ||
749 | */ | ||
750 | static void | ||
751 | handle_index_start_ok (void *cls, | ||
752 | const struct GNUNET_MessageHeader *msg) | ||
753 | { | ||
754 | struct GNUNET_FS_PublishContext *pc = cls; | ||
755 | struct GNUNET_FS_FileInformation *p; | ||
756 | |||
757 | GNUNET_MQ_destroy (pc->mq); | ||
758 | pc->mq = NULL; | ||
759 | p = pc->fi_pos; | ||
760 | p->data.file.index_start_confirmed = GNUNET_YES; | ||
761 | GNUNET_FS_file_information_sync_ (p); | ||
762 | publish_content (pc); | ||
763 | } | ||
764 | |||
765 | |||
766 | /** | ||
767 | * Generic error handler, called with the appropriate error code and | ||
768 | * the same closure specified at the creation of the message queue. | ||
769 | * Not every message queue implementation supports an error handler. | ||
770 | * | ||
771 | * @param cls closure with the `struct GNUNET_FS_PublishContext *` | ||
772 | * @param error error code | ||
773 | */ | ||
774 | static void | ||
775 | index_mq_error_handler (void *cls, | ||
776 | enum GNUNET_MQ_Error error) | ||
777 | { | ||
778 | struct GNUNET_FS_PublishContext *pc = cls; | ||
779 | struct GNUNET_FS_FileInformation *p; | ||
780 | |||
781 | if (NULL != pc->mq) | ||
782 | { | ||
783 | GNUNET_MQ_destroy (pc->mq); | ||
784 | pc->mq = NULL; | ||
785 | } | ||
786 | p = pc->fi_pos; | ||
787 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
788 | _ ("Can not index file `%s': %s. Will try to insert instead.\n"), | ||
789 | p->filename, | ||
790 | _ ("error on index-start request to `fs' service")); | ||
791 | p->data.file.do_index = GNUNET_NO; | ||
792 | GNUNET_FS_file_information_sync_ (p); | ||
793 | publish_content (pc); | ||
794 | } | ||
795 | |||
796 | |||
797 | /** | ||
798 | * Function called once the hash computation over an | ||
799 | * indexed file has completed. | ||
800 | * | ||
801 | * @param cls closure, our publishing context | ||
802 | * @param res resulting hash, NULL on error | ||
803 | */ | ||
804 | static void | ||
805 | hash_for_index_cb (void *cls, | ||
806 | const struct GNUNET_HashCode *res) | ||
807 | { | ||
808 | struct GNUNET_FS_PublishContext *pc = cls; | ||
809 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
810 | GNUNET_MQ_hd_fixed_size (index_start_ok, | ||
811 | GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK, | ||
812 | struct GNUNET_MessageHeader, | ||
813 | pc), | ||
814 | GNUNET_MQ_hd_var_size (index_start_failed, | ||
815 | GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED, | ||
816 | struct GNUNET_MessageHeader, | ||
817 | pc), | ||
818 | GNUNET_MQ_handler_end () | ||
819 | }; | ||
820 | struct GNUNET_FS_FileInformation *p; | ||
821 | struct GNUNET_MQ_Envelope *env; | ||
822 | struct IndexStartMessage *ism; | ||
823 | size_t slen; | ||
824 | uint64_t dev; | ||
825 | uint64_t ino; | ||
826 | char *fn; | ||
827 | |||
828 | pc->fhc = NULL; | ||
829 | p = pc->fi_pos; | ||
830 | if (NULL == res) | ||
831 | { | ||
832 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
833 | _ ( | ||
834 | "Can not index file `%s': %s. Will try to insert instead.\n"), | ||
835 | p->filename, | ||
836 | _ ("failed to compute hash")); | ||
837 | p->data.file.do_index = GNUNET_NO; | ||
838 | GNUNET_FS_file_information_sync_ (p); | ||
839 | publish_content (pc); | ||
840 | return; | ||
841 | } | ||
842 | if (GNUNET_YES == p->data.file.index_start_confirmed) | ||
843 | { | ||
844 | publish_content (pc); | ||
845 | return; | ||
846 | } | ||
847 | fn = GNUNET_STRINGS_filename_expand (p->filename); | ||
848 | GNUNET_assert (fn != NULL); | ||
849 | slen = strlen (fn) + 1; | ||
850 | if (slen >= | ||
851 | GNUNET_MAX_MESSAGE_SIZE - sizeof(struct IndexStartMessage)) | ||
852 | { | ||
853 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
854 | _ | ||
855 | ("Can not index file `%s': %s. Will try to insert instead.\n"), | ||
856 | fn, _ ("filename too long")); | ||
857 | GNUNET_free (fn); | ||
858 | p->data.file.do_index = GNUNET_NO; | ||
859 | GNUNET_FS_file_information_sync_ (p); | ||
860 | publish_content (pc); | ||
861 | return; | ||
862 | } | ||
863 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
864 | "Hash of indexed file `%s' is `%s'\n", | ||
865 | p->filename, | ||
866 | GNUNET_h2s (res)); | ||
867 | if (0 != (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) | ||
868 | { | ||
869 | p->data.file.file_id = *res; | ||
870 | p->data.file.have_hash = GNUNET_YES; | ||
871 | p->data.file.index_start_confirmed = GNUNET_YES; | ||
872 | GNUNET_FS_file_information_sync_ (p); | ||
873 | publish_content (pc); | ||
874 | GNUNET_free (fn); | ||
875 | return; | ||
876 | } | ||
877 | pc->mq = GNUNET_CLIENT_connect (pc->h->cfg, | ||
878 | "fs", | ||
879 | handlers, | ||
880 | &index_mq_error_handler, | ||
881 | pc); | ||
882 | if (NULL == pc->mq) | ||
883 | { | ||
884 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
885 | _ ( | ||
886 | "Can not index file `%s': %s. Will try to insert instead.\n"), | ||
887 | p->filename, | ||
888 | _ ("could not connect to `fs' service")); | ||
889 | p->data.file.do_index = GNUNET_NO; | ||
890 | publish_content (pc); | ||
891 | GNUNET_free (fn); | ||
892 | return; | ||
893 | } | ||
894 | if (p->data.file.have_hash != GNUNET_YES) | ||
895 | { | ||
896 | p->data.file.file_id = *res; | ||
897 | p->data.file.have_hash = GNUNET_YES; | ||
898 | GNUNET_FS_file_information_sync_ (p); | ||
899 | } | ||
900 | env = GNUNET_MQ_msg_extra (ism, | ||
901 | slen, | ||
902 | GNUNET_MESSAGE_TYPE_FS_INDEX_START); | ||
903 | if (GNUNET_OK == | ||
904 | GNUNET_DISK_file_get_identifiers (p->filename, | ||
905 | &dev, | ||
906 | &ino)) | ||
907 | { | ||
908 | ism->device = GNUNET_htonll (dev); | ||
909 | ism->inode = GNUNET_htonll (ino); | ||
910 | } | ||
911 | else | ||
912 | { | ||
913 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
914 | _ ("Failed to get file identifiers for `%s'\n"), | ||
915 | p->filename); | ||
916 | } | ||
917 | ism->file_id = *res; | ||
918 | GNUNET_memcpy (&ism[1], | ||
919 | fn, | ||
920 | slen); | ||
921 | GNUNET_free (fn); | ||
922 | GNUNET_MQ_send (pc->mq, | ||
923 | env); | ||
924 | } | ||
925 | |||
926 | |||
927 | /** | ||
928 | * We've computed the CHK/LOC URI, now publish the KSKs (if applicable). | ||
929 | * | ||
930 | * @param pc publishing context to do this for | ||
931 | */ | ||
932 | static void | ||
933 | publish_kblocks (struct GNUNET_FS_PublishContext *pc) | ||
934 | { | ||
935 | struct GNUNET_FS_FileInformation *p; | ||
936 | |||
937 | p = pc->fi_pos; | ||
938 | /* upload of "p" complete, publish KBlocks! */ | ||
939 | if (NULL != p->keywords) | ||
940 | { | ||
941 | pc->ksk_pc = GNUNET_FS_publish_ksk (pc->h, | ||
942 | p->keywords, | ||
943 | p->meta, | ||
944 | p->chk_uri, | ||
945 | &p->bo, | ||
946 | pc->options, | ||
947 | &publish_kblocks_cont, | ||
948 | pc); | ||
949 | } | ||
950 | else | ||
951 | { | ||
952 | publish_kblocks_cont (pc, p->chk_uri, NULL); | ||
953 | } | ||
954 | } | ||
955 | |||
956 | |||
957 | /** | ||
958 | * Process the response from the "fs" service to our LOC sign request. | ||
959 | * | ||
960 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
961 | * @param sig the response we got | ||
962 | */ | ||
963 | static void | ||
964 | handle_signature_response (void *cls, | ||
965 | const struct ResponseLocSignatureMessage *sig) | ||
966 | { | ||
967 | struct GNUNET_FS_PublishContext *pc = cls; | ||
968 | struct GNUNET_FS_FileInformation *p; | ||
969 | |||
970 | p = pc->fi_pos; | ||
971 | p->chk_uri->type = GNUNET_FS_URI_LOC; | ||
972 | /* p->data.loc.fi kept from CHK before */ | ||
973 | p->chk_uri->data.loc.peer = sig->peer; | ||
974 | p->chk_uri->data.loc.expirationTime | ||
975 | = GNUNET_TIME_absolute_ntoh (sig->expiration_time); | ||
976 | p->chk_uri->data.loc.contentSignature = sig->signature; | ||
977 | GNUNET_FS_file_information_sync_ (p); | ||
978 | GNUNET_FS_publish_sync_ (pc); | ||
979 | publish_kblocks (pc); | ||
980 | } | ||
981 | |||
982 | |||
983 | /** | ||
984 | * Generic error handler, called with the appropriate error code and | ||
985 | * the same closure specified at the creation of the message queue. | ||
986 | * Not every message queue implementation supports an error handler. | ||
987 | * | ||
988 | * @param cls closure with the `struct GNUNET_FS_PublishContext *` | ||
989 | * @param error error code | ||
990 | */ | ||
991 | static void | ||
992 | loc_mq_error_handler (void *cls, | ||
993 | enum GNUNET_MQ_Error error) | ||
994 | { | ||
995 | struct GNUNET_FS_PublishContext *pc = cls; | ||
996 | |||
997 | if (NULL != pc->mq) | ||
998 | { | ||
999 | GNUNET_MQ_destroy (pc->mq); | ||
1000 | pc->mq = NULL; | ||
1001 | } | ||
1002 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1003 | _ ("Can not create LOC URI. Will continue with CHK instead.\n")); | ||
1004 | publish_kblocks (pc); | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | /** | ||
1009 | * We're publishing without anonymity. Contact the FS service | ||
1010 | * to create a signed LOC URI for further processing, then | ||
1011 | * continue with KSKs. | ||
1012 | * | ||
1013 | * @param pc the publishing context do to this for | ||
1014 | */ | ||
1015 | static void | ||
1016 | create_loc_uri (struct GNUNET_FS_PublishContext *pc) | ||
1017 | { | ||
1018 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
1019 | GNUNET_MQ_hd_fixed_size (signature_response, | ||
1020 | GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE, | ||
1021 | struct ResponseLocSignatureMessage, | ||
1022 | pc), | ||
1023 | GNUNET_MQ_handler_end () | ||
1024 | }; | ||
1025 | struct GNUNET_MQ_Envelope *env; | ||
1026 | struct RequestLocSignatureMessage *req; | ||
1027 | struct GNUNET_FS_FileInformation *p; | ||
1028 | |||
1029 | if (NULL != pc->mq) | ||
1030 | GNUNET_MQ_destroy (pc->mq); | ||
1031 | pc->mq = GNUNET_CLIENT_connect (pc->h->cfg, | ||
1032 | "fs", | ||
1033 | handlers, | ||
1034 | &loc_mq_error_handler, | ||
1035 | pc); | ||
1036 | if (NULL == pc->mq) | ||
1037 | { | ||
1038 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1039 | _ ( | ||
1040 | "Can not create LOC URI. Will continue with CHK instead.\n")); | ||
1041 | publish_kblocks (pc); | ||
1042 | return; | ||
1043 | } | ||
1044 | p = pc->fi_pos; | ||
1045 | env = GNUNET_MQ_msg (req, | ||
1046 | GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN); | ||
1047 | req->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); | ||
1048 | req->expiration_time = GNUNET_TIME_absolute_hton (p->bo.expiration_time); | ||
1049 | req->chk = p->chk_uri->data.chk.chk; | ||
1050 | req->file_length = GNUNET_htonll (p->chk_uri->data.chk.file_length); | ||
1051 | GNUNET_MQ_send (pc->mq, | ||
1052 | env); | ||
1053 | } | ||
1054 | |||
1055 | |||
1056 | /** | ||
1057 | * Main function that performs the upload. | ||
1058 | * | ||
1059 | * @param cls `struct GNUNET_FS_PublishContext *` identifies the upload | ||
1060 | */ | ||
1061 | void | ||
1062 | GNUNET_FS_publish_main_ (void *cls) | ||
1063 | { | ||
1064 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1065 | struct GNUNET_FS_ProgressInfo pi; | ||
1066 | struct GNUNET_FS_FileInformation *p; | ||
1067 | char *fn; | ||
1068 | |||
1069 | pc->upload_task = NULL; | ||
1070 | p = pc->fi_pos; | ||
1071 | if (NULL == p) | ||
1072 | { | ||
1073 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1074 | "Publishing complete, now publishing SKS and KSK blocks.\n"); | ||
1075 | /* upload of entire hierarchy complete, | ||
1076 | * publish namespace entries */ | ||
1077 | GNUNET_FS_publish_sync_ (pc); | ||
1078 | publish_sblock (pc); | ||
1079 | return; | ||
1080 | } | ||
1081 | /* find starting position */ | ||
1082 | while ((GNUNET_YES == p->is_directory) && | ||
1083 | (NULL != p->data.dir.entries) && | ||
1084 | (NULL == p->emsg) && | ||
1085 | (NULL == p->data.dir.entries->chk_uri)) | ||
1086 | { | ||
1087 | p = p->data.dir.entries; | ||
1088 | pc->fi_pos = p; | ||
1089 | GNUNET_FS_publish_sync_ (pc); | ||
1090 | } | ||
1091 | /* abort on error */ | ||
1092 | if (NULL != p->emsg) | ||
1093 | { | ||
1094 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1095 | "Error uploading: %s\n", | ||
1096 | p->emsg); | ||
1097 | /* error with current file, abort all | ||
1098 | * related files as well! */ | ||
1099 | while (NULL != p->dir) | ||
1100 | { | ||
1101 | fn = GNUNET_CONTAINER_meta_data_get_by_type (p->meta, | ||
1102 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); | ||
1103 | p = p->dir; | ||
1104 | if (fn != NULL) | ||
1105 | { | ||
1106 | GNUNET_asprintf (&p->emsg, | ||
1107 | _ ("Recursive upload failed at `%s': %s"), | ||
1108 | fn, | ||
1109 | p->emsg); | ||
1110 | GNUNET_free (fn); | ||
1111 | } | ||
1112 | else | ||
1113 | { | ||
1114 | GNUNET_asprintf (&p->emsg, | ||
1115 | _ ("Recursive upload failed: %s"), | ||
1116 | p->emsg); | ||
1117 | } | ||
1118 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
1119 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
1120 | pi.value.publish.specifics.error.message = p->emsg; | ||
1121 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); | ||
1122 | } | ||
1123 | pc->all_done = GNUNET_YES; | ||
1124 | GNUNET_FS_publish_sync_ (pc); | ||
1125 | return; | ||
1126 | } | ||
1127 | /* handle completion */ | ||
1128 | if (NULL != p->chk_uri) | ||
1129 | { | ||
1130 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1131 | "File upload complete, now publishing KSK blocks.\n"); | ||
1132 | GNUNET_FS_publish_sync_ (pc); | ||
1133 | |||
1134 | if ((0 == p->bo.anonymity_level) && | ||
1135 | (GNUNET_YES != | ||
1136 | GNUNET_FS_uri_test_loc (p->chk_uri))) | ||
1137 | { | ||
1138 | /* zero anonymity, box CHK URI in LOC URI */ | ||
1139 | create_loc_uri (pc); | ||
1140 | } | ||
1141 | else | ||
1142 | { | ||
1143 | publish_kblocks (pc); | ||
1144 | } | ||
1145 | return; | ||
1146 | } | ||
1147 | if ((GNUNET_YES != p->is_directory) && (p->data.file.do_index)) | ||
1148 | { | ||
1149 | if (NULL == p->filename) | ||
1150 | { | ||
1151 | p->data.file.do_index = GNUNET_NO; | ||
1152 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1153 | _ ( | ||
1154 | "Can not index file `%s': %s. Will try to insert instead.\n"), | ||
1155 | "<no-name>", | ||
1156 | _ ("needs to be an actual file")); | ||
1157 | GNUNET_FS_file_information_sync_ (p); | ||
1158 | publish_content (pc); | ||
1159 | return; | ||
1160 | } | ||
1161 | if (p->data.file.have_hash) | ||
1162 | { | ||
1163 | hash_for_index_cb (pc, &p->data.file.file_id); | ||
1164 | } | ||
1165 | else | ||
1166 | { | ||
1167 | p->start_time = GNUNET_TIME_absolute_get (); | ||
1168 | pc->fhc = | ||
1169 | GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, p->filename, | ||
1170 | HASHING_BLOCKSIZE, &hash_for_index_cb, pc); | ||
1171 | } | ||
1172 | return; | ||
1173 | } | ||
1174 | publish_content (pc); | ||
1175 | } | ||
1176 | |||
1177 | |||
1178 | /** | ||
1179 | * Signal the FS's progress function that we are starting | ||
1180 | * an upload. | ||
1181 | * | ||
1182 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
1183 | * @param fi the entry in the publish-structure | ||
1184 | * @param length length of the file or directory | ||
1185 | * @param meta metadata for the file or directory (can be modified) | ||
1186 | * @param uri pointer to the keywords that will be used for this entry (can be modified) | ||
1187 | * @param bo block options | ||
1188 | * @param do_index should we index? | ||
1189 | * @param client_info pointer to client context set upon creation (can be modified) | ||
1190 | * @return #GNUNET_OK to continue (always) | ||
1191 | */ | ||
1192 | static int | ||
1193 | fip_signal_start (void *cls, | ||
1194 | struct GNUNET_FS_FileInformation *fi, | ||
1195 | uint64_t length, | ||
1196 | struct GNUNET_CONTAINER_MetaData *meta, | ||
1197 | struct GNUNET_FS_Uri **uri, | ||
1198 | struct GNUNET_FS_BlockOptions *bo, | ||
1199 | int *do_index, | ||
1200 | void **client_info) | ||
1201 | { | ||
1202 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1203 | struct GNUNET_FS_ProgressInfo pi; | ||
1204 | unsigned int kc; | ||
1205 | uint64_t left; | ||
1206 | |||
1207 | if (GNUNET_YES == pc->skip_next_fi_callback) | ||
1208 | { | ||
1209 | pc->skip_next_fi_callback = GNUNET_NO; | ||
1210 | return GNUNET_OK; | ||
1211 | } | ||
1212 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1213 | "Starting publish operation\n"); | ||
1214 | if (*do_index) | ||
1215 | { | ||
1216 | /* space for on-demand blocks */ | ||
1217 | pc->reserve_space += | ||
1218 | ((length + DBLOCK_SIZE | ||
1219 | - 1) / DBLOCK_SIZE) * sizeof(struct OnDemandBlock); | ||
1220 | } | ||
1221 | else | ||
1222 | { | ||
1223 | /* space for DBlocks */ | ||
1224 | pc->reserve_space += length; | ||
1225 | } | ||
1226 | /* entries for IBlocks and DBlocks, space for IBlocks */ | ||
1227 | left = length; | ||
1228 | while (1) | ||
1229 | { | ||
1230 | left = (left + DBLOCK_SIZE - 1) / DBLOCK_SIZE; | ||
1231 | pc->reserve_entries += left; | ||
1232 | if (left <= 1) | ||
1233 | break; | ||
1234 | left = left * sizeof(struct ContentHashKey); | ||
1235 | pc->reserve_space += left; | ||
1236 | } | ||
1237 | pc->reserve_entries++; | ||
1238 | /* entries and space for keywords */ | ||
1239 | if (NULL != *uri) | ||
1240 | { | ||
1241 | kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri); | ||
1242 | pc->reserve_entries += kc; | ||
1243 | pc->reserve_space += GNUNET_MAX_MESSAGE_SIZE * kc; | ||
1244 | } | ||
1245 | pi.status = GNUNET_FS_STATUS_PUBLISH_START; | ||
1246 | *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0); | ||
1247 | GNUNET_FS_file_information_sync_ (fi); | ||
1248 | if ((fi->is_directory) && (fi->dir != NULL)) | ||
1249 | { | ||
1250 | /* We are a directory, and we are not top-level; process entries in directory */ | ||
1251 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1252 | GNUNET_FS_file_information_inspect (fi, &fip_signal_start, pc); | ||
1253 | } | ||
1254 | return GNUNET_OK; | ||
1255 | } | ||
1256 | |||
1257 | |||
1258 | /** | ||
1259 | * Actually signal the FS's progress function that we are suspending | ||
1260 | * an upload. | ||
1261 | * | ||
1262 | * @param fi the entry in the publish-structure | ||
1263 | * @param pc the publish context of which a file is being suspended | ||
1264 | */ | ||
1265 | static void | ||
1266 | suspend_operation (struct GNUNET_FS_FileInformation *fi, | ||
1267 | struct GNUNET_FS_PublishContext *pc) | ||
1268 | { | ||
1269 | struct GNUNET_FS_ProgressInfo pi; | ||
1270 | uint64_t off; | ||
1271 | |||
1272 | if (NULL != pc->ksk_pc) | ||
1273 | { | ||
1274 | GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); | ||
1275 | pc->ksk_pc = NULL; | ||
1276 | } | ||
1277 | if (NULL != pc->sks_pc) | ||
1278 | { | ||
1279 | GNUNET_FS_publish_sks_cancel (pc->sks_pc); | ||
1280 | pc->sks_pc = NULL; | ||
1281 | } | ||
1282 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1283 | "Suspending publish operation\n"); | ||
1284 | GNUNET_free (fi->serialization); | ||
1285 | fi->serialization = NULL; | ||
1286 | off = (NULL == fi->chk_uri) ? 0 : (GNUNET_YES == fi->is_directory) ? | ||
1287 | fi->data.dir.dir_size : fi->data.file.file_size; | ||
1288 | pi.status = GNUNET_FS_STATUS_PUBLISH_SUSPEND; | ||
1289 | GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off)); | ||
1290 | if (NULL != pc->qre) | ||
1291 | { | ||
1292 | GNUNET_DATASTORE_cancel (pc->qre); | ||
1293 | pc->qre = NULL; | ||
1294 | } | ||
1295 | if (NULL != pc->dsh) | ||
1296 | { | ||
1297 | GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO); | ||
1298 | pc->dsh = NULL; | ||
1299 | } | ||
1300 | pc->rid = 0; | ||
1301 | } | ||
1302 | |||
1303 | |||
1304 | /** | ||
1305 | * Signal the FS's progress function that we are suspending | ||
1306 | * an upload. Performs the recursion. | ||
1307 | * | ||
1308 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
1309 | * @param fi the entry in the publish-structure | ||
1310 | * @param length length of the file or directory | ||
1311 | * @param meta metadata for the file or directory (can be modified) | ||
1312 | * @param uri pointer to the keywords that will be used for this entry (can be modified) | ||
1313 | * @param bo block options | ||
1314 | * @param do_index should we index? | ||
1315 | * @param client_info pointer to client context set upon creation (can be modified) | ||
1316 | * @return #GNUNET_OK to continue (always) | ||
1317 | */ | ||
1318 | static int | ||
1319 | fip_signal_suspend (void *cls, | ||
1320 | struct GNUNET_FS_FileInformation *fi, | ||
1321 | uint64_t length, | ||
1322 | struct GNUNET_CONTAINER_MetaData *meta, | ||
1323 | struct GNUNET_FS_Uri **uri, | ||
1324 | struct GNUNET_FS_BlockOptions *bo, | ||
1325 | int *do_index, | ||
1326 | void **client_info) | ||
1327 | { | ||
1328 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1329 | |||
1330 | if (GNUNET_YES == pc->skip_next_fi_callback) | ||
1331 | { | ||
1332 | pc->skip_next_fi_callback = GNUNET_NO; | ||
1333 | return GNUNET_OK; | ||
1334 | } | ||
1335 | if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) | ||
1336 | { | ||
1337 | /* process entries in directory */ | ||
1338 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1339 | GNUNET_FS_file_information_inspect (fi, &fip_signal_suspend, pc); | ||
1340 | } | ||
1341 | suspend_operation (fi, pc); | ||
1342 | *client_info = NULL; | ||
1343 | return GNUNET_OK; | ||
1344 | } | ||
1345 | |||
1346 | |||
1347 | /** | ||
1348 | * Create SUSPEND event for the given publish operation | ||
1349 | * and then clean up our state (without stop signal). | ||
1350 | * | ||
1351 | * @param cls the `struct GNUNET_FS_PublishContext` to signal for | ||
1352 | */ | ||
1353 | void | ||
1354 | GNUNET_FS_publish_signal_suspend_ (void *cls) | ||
1355 | { | ||
1356 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1357 | |||
1358 | if (NULL != pc->upload_task) | ||
1359 | { | ||
1360 | GNUNET_SCHEDULER_cancel (pc->upload_task); | ||
1361 | pc->upload_task = NULL; | ||
1362 | } | ||
1363 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1364 | GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_suspend, pc); | ||
1365 | suspend_operation (pc->fi, pc); | ||
1366 | GNUNET_FS_end_top (pc->h, pc->top); | ||
1367 | pc->top = NULL; | ||
1368 | publish_cleanup (pc); | ||
1369 | } | ||
1370 | |||
1371 | |||
1372 | /** | ||
1373 | * We have gotten a reply for our space reservation request. | ||
1374 | * Either fail (insufficient space) or start publishing for good. | ||
1375 | * | ||
1376 | * @param cls the `struct GNUNET_FS_PublishContext *` | ||
1377 | * @param success positive reservation ID on success | ||
1378 | * @param min_expiration minimum expiration time required for content to be stored | ||
1379 | * @param msg error message on error, otherwise NULL | ||
1380 | */ | ||
1381 | static void | ||
1382 | finish_reserve (void *cls, | ||
1383 | int success, | ||
1384 | struct GNUNET_TIME_Absolute min_expiration, | ||
1385 | const char *msg) | ||
1386 | { | ||
1387 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1388 | |||
1389 | pc->qre = NULL; | ||
1390 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1391 | "Reservation complete (%d)!\n", | ||
1392 | success); | ||
1393 | if ((msg != NULL) || (success <= 0)) | ||
1394 | { | ||
1395 | GNUNET_asprintf (&pc->fi->emsg, | ||
1396 | _ ("Datastore failure: %s"), | ||
1397 | msg); | ||
1398 | signal_publish_error (pc->fi, pc, pc->fi->emsg); | ||
1399 | return; | ||
1400 | } | ||
1401 | pc->rid = success; | ||
1402 | GNUNET_assert (NULL == pc->upload_task); | ||
1403 | pc->upload_task = | ||
1404 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
1405 | &GNUNET_FS_publish_main_, pc); | ||
1406 | } | ||
1407 | |||
1408 | |||
1409 | /** | ||
1410 | * Calculate the total size of all of the files in the directory structure. | ||
1411 | * | ||
1412 | * @param fi file structure to traverse | ||
1413 | */ | ||
1414 | static uint64_t | ||
1415 | compute_contents_size (struct GNUNET_FS_FileInformation *fi) | ||
1416 | { | ||
1417 | struct GNUNET_FS_FileInformation *ent; | ||
1418 | |||
1419 | if (GNUNET_YES != fi->is_directory) | ||
1420 | return fi->data.file.file_size; | ||
1421 | fi->data.dir.contents_size = 0; | ||
1422 | for (ent = fi->data.dir.entries; NULL != ent; ent = ent->next) | ||
1423 | fi->data.dir.contents_size += compute_contents_size (ent); | ||
1424 | return fi->data.dir.contents_size; | ||
1425 | } | ||
1426 | |||
1427 | |||
1428 | /** | ||
1429 | * Publish a file or directory. | ||
1430 | * | ||
1431 | * @param h handle to the file sharing subsystem | ||
1432 | * @param fi information about the file or directory structure to publish | ||
1433 | * @param ns namespace to publish the file in, NULL for no namespace | ||
1434 | * @param nid identifier to use for the published content in the namespace | ||
1435 | * (can be NULL, must be NULL if namespace is NULL) | ||
1436 | * @param nuid update-identifier that will be used for future updates | ||
1437 | * (can be NULL, must be NULL if namespace or nid is NULL) | ||
1438 | * @param options options for the publication | ||
1439 | * @return context that can be used to control the publish operation | ||
1440 | */ | ||
1441 | struct GNUNET_FS_PublishContext * | ||
1442 | GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h, | ||
1443 | struct GNUNET_FS_FileInformation *fi, | ||
1444 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns, | ||
1445 | const char *nid, | ||
1446 | const char *nuid, | ||
1447 | enum GNUNET_FS_PublishOptions options) | ||
1448 | { | ||
1449 | struct GNUNET_FS_PublishContext *ret; | ||
1450 | struct GNUNET_DATASTORE_Handle *dsh; | ||
1451 | |||
1452 | GNUNET_assert (NULL != h); | ||
1453 | compute_contents_size (fi); | ||
1454 | if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) | ||
1455 | { | ||
1456 | dsh = GNUNET_DATASTORE_connect (h->cfg); | ||
1457 | if (NULL == dsh) | ||
1458 | return NULL; | ||
1459 | } | ||
1460 | else | ||
1461 | { | ||
1462 | dsh = NULL; | ||
1463 | } | ||
1464 | ret = GNUNET_new (struct GNUNET_FS_PublishContext); | ||
1465 | ret->dsh = dsh; | ||
1466 | ret->h = h; | ||
1467 | ret->fi = fi; | ||
1468 | if (NULL != ns) | ||
1469 | { | ||
1470 | ret->ns = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey); | ||
1471 | *ret->ns = *ns; | ||
1472 | GNUNET_assert (NULL != nid); | ||
1473 | ret->nid = GNUNET_strdup (nid); | ||
1474 | if (NULL != nuid) | ||
1475 | ret->nuid = GNUNET_strdup (nuid); | ||
1476 | } | ||
1477 | ret->options = options; | ||
1478 | /* signal start */ | ||
1479 | GNUNET_FS_file_information_inspect (ret->fi, &fip_signal_start, ret); | ||
1480 | ret->fi_pos = ret->fi; | ||
1481 | ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, ret); | ||
1482 | GNUNET_FS_publish_sync_ (ret); | ||
1483 | if (NULL != ret->dsh) | ||
1484 | { | ||
1485 | GNUNET_assert (NULL == ret->qre); | ||
1486 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1487 | _ ( | ||
1488 | "Reserving space for %u entries and %llu bytes for publication\n"), | ||
1489 | (unsigned int) ret->reserve_entries, | ||
1490 | (unsigned long long) ret->reserve_space); | ||
1491 | ret->qre = | ||
1492 | GNUNET_DATASTORE_reserve (ret->dsh, ret->reserve_space, | ||
1493 | ret->reserve_entries, | ||
1494 | &finish_reserve, | ||
1495 | ret); | ||
1496 | } | ||
1497 | else | ||
1498 | { | ||
1499 | GNUNET_assert (NULL == ret->upload_task); | ||
1500 | ret->upload_task = | ||
1501 | GNUNET_SCHEDULER_add_with_priority | ||
1502 | (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, ret); | ||
1503 | } | ||
1504 | return ret; | ||
1505 | } | ||
1506 | |||
1507 | |||
1508 | /** | ||
1509 | * Signal the FS's progress function that we are stopping | ||
1510 | * an upload. | ||
1511 | * | ||
1512 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
1513 | * @param fi the entry in the publish-structure | ||
1514 | * @param length length of the file or directory | ||
1515 | * @param meta metadata for the file or directory (can be modified) | ||
1516 | * @param uri pointer to the keywords that will be used for this entry (can be modified) | ||
1517 | * @param bo block options (can be modified) | ||
1518 | * @param do_index should we index? | ||
1519 | * @param client_info pointer to client context set upon creation (can be modified) | ||
1520 | * @return #GNUNET_OK to continue (always) | ||
1521 | */ | ||
1522 | static int | ||
1523 | fip_signal_stop (void *cls, | ||
1524 | struct GNUNET_FS_FileInformation *fi, | ||
1525 | uint64_t length, | ||
1526 | struct GNUNET_CONTAINER_MetaData *meta, | ||
1527 | struct GNUNET_FS_Uri **uri, | ||
1528 | struct GNUNET_FS_BlockOptions *bo, | ||
1529 | int *do_index, void **client_info) | ||
1530 | { | ||
1531 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1532 | struct GNUNET_FS_ProgressInfo pi; | ||
1533 | uint64_t off; | ||
1534 | |||
1535 | if (GNUNET_YES == pc->skip_next_fi_callback) | ||
1536 | { | ||
1537 | pc->skip_next_fi_callback = GNUNET_NO; | ||
1538 | return GNUNET_OK; | ||
1539 | } | ||
1540 | if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) | ||
1541 | { | ||
1542 | /* process entries in directory first */ | ||
1543 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1544 | GNUNET_FS_file_information_inspect (fi, &fip_signal_stop, pc); | ||
1545 | } | ||
1546 | if (NULL != fi->serialization) | ||
1547 | { | ||
1548 | GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO, | ||
1549 | fi->serialization); | ||
1550 | GNUNET_free (fi->serialization); | ||
1551 | fi->serialization = NULL; | ||
1552 | } | ||
1553 | off = (fi->chk_uri == NULL) ? 0 : length; | ||
1554 | pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; | ||
1555 | GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off)); | ||
1556 | *client_info = NULL; | ||
1557 | return GNUNET_OK; | ||
1558 | } | ||
1559 | |||
1560 | |||
1561 | /** | ||
1562 | * Stop an upload. Will abort incomplete uploads (but | ||
1563 | * not remove blocks that have already been published) or | ||
1564 | * simply clean up the state for completed uploads. | ||
1565 | * Must NOT be called from within the event callback! | ||
1566 | * | ||
1567 | * @param pc context for the upload to stop | ||
1568 | */ | ||
1569 | void | ||
1570 | GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc) | ||
1571 | { | ||
1572 | struct GNUNET_FS_ProgressInfo pi; | ||
1573 | uint64_t off; | ||
1574 | |||
1575 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1576 | "Publish stop called\n"); | ||
1577 | GNUNET_FS_end_top (pc->h, pc->top); | ||
1578 | if (NULL != pc->ksk_pc) | ||
1579 | { | ||
1580 | GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); | ||
1581 | pc->ksk_pc = NULL; | ||
1582 | } | ||
1583 | if (NULL != pc->sks_pc) | ||
1584 | { | ||
1585 | GNUNET_FS_publish_sks_cancel (pc->sks_pc); | ||
1586 | pc->sks_pc = NULL; | ||
1587 | } | ||
1588 | if (NULL != pc->upload_task) | ||
1589 | { | ||
1590 | GNUNET_SCHEDULER_cancel (pc->upload_task); | ||
1591 | pc->upload_task = NULL; | ||
1592 | } | ||
1593 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1594 | GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_stop, pc); | ||
1595 | |||
1596 | if (NULL != pc->fi->serialization) | ||
1597 | { | ||
1598 | GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO, | ||
1599 | pc->fi->serialization); | ||
1600 | GNUNET_free (pc->fi->serialization); | ||
1601 | pc->fi->serialization = NULL; | ||
1602 | } | ||
1603 | off = (NULL == pc->fi->chk_uri) ? 0 : GNUNET_ntohll ( | ||
1604 | pc->fi->chk_uri->data.chk.file_length); | ||
1605 | |||
1606 | if (NULL != pc->serialization) | ||
1607 | { | ||
1608 | GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, | ||
1609 | pc->serialization); | ||
1610 | GNUNET_free (pc->serialization); | ||
1611 | pc->serialization = NULL; | ||
1612 | } | ||
1613 | if (NULL != pc->qre) | ||
1614 | { | ||
1615 | GNUNET_DATASTORE_cancel (pc->qre); | ||
1616 | pc->qre = NULL; | ||
1617 | } | ||
1618 | pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; | ||
1619 | GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi, off)); | ||
1620 | publish_cleanup (pc); | ||
1621 | } | ||
1622 | |||
1623 | |||
1624 | /* end of fs_publish.c */ | ||
diff --git a/src/fs/fs_publish_ksk.c b/src/fs/fs_publish_ksk.c deleted file mode 100644 index 372ac705d..000000000 --- a/src/fs/fs_publish_ksk.c +++ /dev/null | |||
@@ -1,260 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2012, 2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_publish_ksk.c | ||
23 | * @brief publish a URI under a keyword in GNUnet | ||
24 | * @see https://gnunet.org/encoding and #2564 | ||
25 | * @author Krista Bennett | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_constants.h" | ||
31 | #include "gnunet_signatures.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_fs_service.h" | ||
34 | #include "fs_api.h" | ||
35 | #include "fs_tree.h" | ||
36 | #include "fs_publish_ublock.h" | ||
37 | |||
38 | /** | ||
39 | * Context for the KSK publication. | ||
40 | */ | ||
41 | struct GNUNET_FS_PublishKskContext | ||
42 | { | ||
43 | /** | ||
44 | * Keywords to use. | ||
45 | */ | ||
46 | struct GNUNET_FS_Uri *ksk_uri; | ||
47 | |||
48 | /** | ||
49 | * URI to publish. | ||
50 | */ | ||
51 | struct GNUNET_FS_Uri *uri; | ||
52 | |||
53 | /** | ||
54 | * Metadata to use. | ||
55 | */ | ||
56 | struct GNUNET_CONTAINER_MetaData *meta; | ||
57 | |||
58 | /** | ||
59 | * Global FS context. | ||
60 | */ | ||
61 | struct GNUNET_FS_Handle *h; | ||
62 | |||
63 | /** | ||
64 | * UBlock publishing operation that is active. | ||
65 | */ | ||
66 | struct GNUNET_FS_PublishUblockContext *uc; | ||
67 | |||
68 | /** | ||
69 | * Handle to the datastore, NULL if we are just simulating. | ||
70 | */ | ||
71 | struct GNUNET_DATASTORE_Handle *dsh; | ||
72 | |||
73 | /** | ||
74 | * Current task. | ||
75 | */ | ||
76 | struct GNUNET_SCHEDULER_Task *ksk_task; | ||
77 | |||
78 | /** | ||
79 | * Function to call once we're done. | ||
80 | */ | ||
81 | GNUNET_FS_PublishContinuation cont; | ||
82 | |||
83 | /** | ||
84 | * Closure for cont. | ||
85 | */ | ||
86 | void *cont_cls; | ||
87 | |||
88 | /** | ||
89 | * When should the KBlocks expire? | ||
90 | */ | ||
91 | struct GNUNET_FS_BlockOptions bo; | ||
92 | |||
93 | /** | ||
94 | * Options to use. | ||
95 | */ | ||
96 | enum GNUNET_FS_PublishOptions options; | ||
97 | |||
98 | /** | ||
99 | * Keyword that we are currently processing. | ||
100 | */ | ||
101 | unsigned int i; | ||
102 | }; | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Continuation of #GNUNET_FS_publish_ksk() that performs | ||
107 | * the actual publishing operation (iterating over all | ||
108 | * of the keywords). | ||
109 | * | ||
110 | * @param cls closure of type `struct PublishKskContext *` | ||
111 | */ | ||
112 | static void | ||
113 | publish_ksk_cont (void *cls); | ||
114 | |||
115 | |||
116 | /** | ||
117 | * Function called by the datastore API with | ||
118 | * the result from the PUT request. | ||
119 | * | ||
120 | * @param cls closure of type `struct GNUNET_FS_PublishKskContext *` | ||
121 | * @param msg error message (or NULL) | ||
122 | */ | ||
123 | static void | ||
124 | kb_put_cont (void *cls, | ||
125 | const char *msg) | ||
126 | { | ||
127 | struct GNUNET_FS_PublishKskContext *pkc = cls; | ||
128 | |||
129 | pkc->uc = NULL; | ||
130 | if (NULL != msg) | ||
131 | { | ||
132 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
133 | "KBlock PUT operation failed: %s\n", msg); | ||
134 | pkc->cont (pkc->cont_cls, NULL, msg); | ||
135 | GNUNET_FS_publish_ksk_cancel (pkc); | ||
136 | return; | ||
137 | } | ||
138 | pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); | ||
139 | } | ||
140 | |||
141 | |||
142 | /** | ||
143 | * Continuation of #GNUNET_FS_publish_ksk() that performs the actual | ||
144 | * publishing operation (iterating over all of the keywords). | ||
145 | * | ||
146 | * @param cls closure of type `struct GNUNET_FS_PublishKskContext *` | ||
147 | */ | ||
148 | static void | ||
149 | publish_ksk_cont (void *cls) | ||
150 | { | ||
151 | struct GNUNET_FS_PublishKskContext *pkc = cls; | ||
152 | const char *keyword; | ||
153 | |||
154 | pkc->ksk_task = NULL; | ||
155 | if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || | ||
156 | (NULL == pkc->dsh)) | ||
157 | { | ||
158 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
159 | "KSK PUT operation complete\n"); | ||
160 | pkc->cont (pkc->cont_cls, pkc->ksk_uri, | ||
161 | NULL); | ||
162 | GNUNET_FS_publish_ksk_cancel (pkc); | ||
163 | return; | ||
164 | } | ||
165 | keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++]; | ||
166 | pkc->uc = GNUNET_FS_publish_ublock_ (pkc->h, | ||
167 | pkc->dsh, | ||
168 | keyword + 1 /* skip '+' */, | ||
169 | NULL, | ||
170 | GNUNET_CRYPTO_ecdsa_key_get_anonymous (), | ||
171 | pkc->meta, | ||
172 | pkc->uri, | ||
173 | &pkc->bo, | ||
174 | pkc->options, | ||
175 | &kb_put_cont, pkc); | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Publish a CHK under various keywords on GNUnet. | ||
181 | * | ||
182 | * @param h handle to the file sharing subsystem | ||
183 | * @param ksk_uri keywords to use | ||
184 | * @param meta metadata to use | ||
185 | * @param uri URI to refer to in the KBlock | ||
186 | * @param bo per-block options | ||
187 | * @param options publication options | ||
188 | * @param cont continuation | ||
189 | * @param cont_cls closure for cont | ||
190 | * @return NULL on error ('cont' will still be called) | ||
191 | */ | ||
192 | struct GNUNET_FS_PublishKskContext * | ||
193 | GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, | ||
194 | const struct GNUNET_FS_Uri *ksk_uri, | ||
195 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
196 | const struct GNUNET_FS_Uri *uri, | ||
197 | const struct GNUNET_FS_BlockOptions *bo, | ||
198 | enum GNUNET_FS_PublishOptions options, | ||
199 | GNUNET_FS_PublishContinuation cont, void *cont_cls) | ||
200 | { | ||
201 | struct GNUNET_FS_PublishKskContext *pkc; | ||
202 | |||
203 | GNUNET_assert (NULL != uri); | ||
204 | pkc = GNUNET_new (struct GNUNET_FS_PublishKskContext); | ||
205 | pkc->h = h; | ||
206 | pkc->bo = *bo; | ||
207 | pkc->options = options; | ||
208 | pkc->cont = cont; | ||
209 | pkc->cont_cls = cont_cls; | ||
210 | pkc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
211 | if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) | ||
212 | { | ||
213 | pkc->dsh = GNUNET_DATASTORE_connect (h->cfg); | ||
214 | if (NULL == pkc->dsh) | ||
215 | { | ||
216 | cont (cont_cls, | ||
217 | NULL, | ||
218 | _ ("Could not connect to datastore.")); | ||
219 | GNUNET_free (pkc); | ||
220 | return NULL; | ||
221 | } | ||
222 | } | ||
223 | pkc->uri = GNUNET_FS_uri_dup (uri); | ||
224 | pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); | ||
225 | pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); | ||
226 | return pkc; | ||
227 | } | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Abort the KSK publishing operation. | ||
232 | * | ||
233 | * @param pkc context of the operation to abort. | ||
234 | */ | ||
235 | void | ||
236 | GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc) | ||
237 | { | ||
238 | if (NULL != pkc->ksk_task) | ||
239 | { | ||
240 | GNUNET_SCHEDULER_cancel (pkc->ksk_task); | ||
241 | pkc->ksk_task = NULL; | ||
242 | } | ||
243 | if (NULL != pkc->uc) | ||
244 | { | ||
245 | GNUNET_FS_publish_ublock_cancel_ (pkc->uc); | ||
246 | pkc->uc = NULL; | ||
247 | } | ||
248 | if (NULL != pkc->dsh) | ||
249 | { | ||
250 | GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); | ||
251 | pkc->dsh = NULL; | ||
252 | } | ||
253 | GNUNET_CONTAINER_meta_data_destroy (pkc->meta); | ||
254 | GNUNET_FS_uri_destroy (pkc->ksk_uri); | ||
255 | GNUNET_FS_uri_destroy (pkc->uri); | ||
256 | GNUNET_free (pkc); | ||
257 | } | ||
258 | |||
259 | |||
260 | /* end of fs_publish_ksk.c */ | ||
diff --git a/src/fs/fs_publish_ublock.c b/src/fs/fs_publish_ublock.c deleted file mode 100644 index fd6f2bd72..000000000 --- a/src/fs/fs_publish_ublock.c +++ /dev/null | |||
@@ -1,324 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2012, 2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_publish_ublock.c | ||
23 | * @brief publish a UBLOCK in GNUnet | ||
24 | * @see https://gnunet.org/encoding and #2564 | ||
25 | * @author Krista Bennett | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_constants.h" | ||
30 | #include "gnunet_signatures.h" | ||
31 | #include "fs_publish_ublock.h" | ||
32 | #include "fs_api.h" | ||
33 | #include "fs_tree.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Derive the key for symmetric encryption/decryption from | ||
38 | * the public key and the label. | ||
39 | * | ||
40 | * @param skey where to store symmetric key | ||
41 | * @param iv where to store the IV | ||
42 | * @param label label to use for key derivation | ||
43 | * @param pub public key to use for key derivation | ||
44 | */ | ||
45 | static void | ||
46 | derive_ublock_encryption_key (struct GNUNET_CRYPTO_SymmetricSessionKey *skey, | ||
47 | struct GNUNET_CRYPTO_SymmetricInitializationVector | ||
48 | *iv, | ||
49 | const char *label, | ||
50 | const struct GNUNET_CRYPTO_EcdsaPublicKey *pub) | ||
51 | { | ||
52 | struct GNUNET_HashCode key; | ||
53 | |||
54 | /* derive key from 'label' and public key of the namespace */ | ||
55 | GNUNET_assert (GNUNET_YES == | ||
56 | GNUNET_CRYPTO_kdf (&key, sizeof(key), | ||
57 | "UBLOCK-ENC", strlen ("UBLOCK-ENC"), | ||
58 | label, strlen (label), | ||
59 | pub, sizeof(*pub), | ||
60 | NULL, 0)); | ||
61 | GNUNET_CRYPTO_hash_to_aes_key (&key, skey, iv); | ||
62 | } | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Decrypt the given UBlock, storing the result in output. | ||
67 | * | ||
68 | * @param input input data | ||
69 | * @param input_len number of bytes in @a input | ||
70 | * @param ns public key under which the UBlock was stored | ||
71 | * @param label label under which the UBlock was stored | ||
72 | * @param output where to write the result, has input_len bytes | ||
73 | */ | ||
74 | void | ||
75 | GNUNET_FS_ublock_decrypt_ (const void *input, | ||
76 | size_t input_len, | ||
77 | const struct GNUNET_CRYPTO_EcdsaPublicKey *ns, | ||
78 | const char *label, | ||
79 | void *output) | ||
80 | { | ||
81 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
82 | struct GNUNET_CRYPTO_SymmetricSessionKey skey; | ||
83 | |||
84 | derive_ublock_encryption_key (&skey, &iv, | ||
85 | label, ns); | ||
86 | GNUNET_CRYPTO_symmetric_decrypt (input, input_len, | ||
87 | &skey, &iv, | ||
88 | output); | ||
89 | } | ||
90 | |||
91 | |||
92 | /** | ||
93 | * Context for 'ublock_put_cont'. | ||
94 | */ | ||
95 | struct GNUNET_FS_PublishUblockContext | ||
96 | { | ||
97 | /** | ||
98 | * Function to call when done. | ||
99 | */ | ||
100 | GNUNET_FS_UBlockContinuation cont; | ||
101 | |||
102 | /** | ||
103 | * Closure of 'cont'. | ||
104 | */ | ||
105 | void *cont_cls; | ||
106 | |||
107 | /** | ||
108 | * Handle for active datastore operation. | ||
109 | */ | ||
110 | struct GNUNET_DATASTORE_QueueEntry *qre; | ||
111 | |||
112 | /** | ||
113 | * Task to run continuation asynchronously. | ||
114 | */ | ||
115 | struct GNUNET_SCHEDULER_Task *task; | ||
116 | }; | ||
117 | |||
118 | |||
119 | /** | ||
120 | * Continuation of #GNUNET_FS_publish_ublock_(). | ||
121 | * | ||
122 | * @param cls closure of type "struct GNUNET_FS_PublishUblockContext*" | ||
123 | * @param success #GNUNET_SYSERR on failure (including timeout/queue drop) | ||
124 | * #GNUNET_NO if content was already there | ||
125 | * #GNUNET_YES (or other positive value) on success | ||
126 | * @param min_expiration minimum expiration time required for 0-priority content to be stored | ||
127 | * by the datacache at this time, zero for unknown, forever if we have no | ||
128 | * space for 0-priority content | ||
129 | * @param msg NULL on success, otherwise an error message | ||
130 | */ | ||
131 | static void | ||
132 | ublock_put_cont (void *cls, | ||
133 | int32_t success, | ||
134 | struct GNUNET_TIME_Absolute min_expiration, | ||
135 | const char *msg) | ||
136 | { | ||
137 | struct GNUNET_FS_PublishUblockContext *uc = cls; | ||
138 | |||
139 | uc->qre = NULL; | ||
140 | uc->cont (uc->cont_cls, msg); | ||
141 | GNUNET_free (uc); | ||
142 | } | ||
143 | |||
144 | |||
145 | /** | ||
146 | * Run the continuation. | ||
147 | * | ||
148 | * @param cls the `struct GNUNET_FS_PublishUblockContext *` | ||
149 | */ | ||
150 | static void | ||
151 | run_cont (void *cls) | ||
152 | { | ||
153 | struct GNUNET_FS_PublishUblockContext *uc = cls; | ||
154 | |||
155 | uc->task = NULL; | ||
156 | uc->cont (uc->cont_cls, NULL); | ||
157 | GNUNET_free (uc); | ||
158 | } | ||
159 | |||
160 | |||
161 | /** | ||
162 | * Publish a UBlock. | ||
163 | * | ||
164 | * @param h handle to the file sharing subsystem | ||
165 | * @param dsh datastore handle to use for storage operation | ||
166 | * @param label identifier to use | ||
167 | * @param ulabel update label to use, may be an empty string for none | ||
168 | * @param ns namespace to publish in | ||
169 | * @param meta metadata to use | ||
170 | * @param uri URI to refer to in the UBlock | ||
171 | * @param bo per-block options | ||
172 | * @param options publication options | ||
173 | * @param cont continuation | ||
174 | * @param cont_cls closure for @a cont | ||
175 | * @return NULL on error (@a cont will still be called) | ||
176 | */ | ||
177 | struct GNUNET_FS_PublishUblockContext * | ||
178 | GNUNET_FS_publish_ublock_ (struct GNUNET_FS_Handle *h, | ||
179 | struct GNUNET_DATASTORE_Handle *dsh, | ||
180 | const char *label, | ||
181 | const char *ulabel, | ||
182 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns, | ||
183 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
184 | const struct GNUNET_FS_Uri *uri, | ||
185 | const struct GNUNET_FS_BlockOptions *bo, | ||
186 | enum GNUNET_FS_PublishOptions options, | ||
187 | GNUNET_FS_UBlockContinuation cont, void *cont_cls) | ||
188 | { | ||
189 | struct GNUNET_FS_PublishUblockContext *uc; | ||
190 | struct GNUNET_HashCode query; | ||
191 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
192 | struct GNUNET_CRYPTO_SymmetricSessionKey skey; | ||
193 | struct GNUNET_CRYPTO_EcdsaPrivateKey *nsd; | ||
194 | struct GNUNET_CRYPTO_EcdsaPublicKey pub; | ||
195 | char *uris; | ||
196 | size_t size; | ||
197 | char *kbe; | ||
198 | char *sptr; | ||
199 | ssize_t mdsize; | ||
200 | size_t slen; | ||
201 | size_t ulen; | ||
202 | struct UBlock *ub_plain; | ||
203 | struct UBlock *ub_enc; | ||
204 | |||
205 | /* compute ublock to publish */ | ||
206 | if (NULL == meta) | ||
207 | mdsize = 0; | ||
208 | else | ||
209 | mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); | ||
210 | GNUNET_assert (mdsize >= 0); | ||
211 | uris = GNUNET_FS_uri_to_string (uri); | ||
212 | slen = strlen (uris) + 1; | ||
213 | if (NULL == ulabel) | ||
214 | ulen = 1; | ||
215 | else | ||
216 | ulen = strlen (ulabel) + 1; | ||
217 | size = mdsize + sizeof(struct UBlock) + slen + ulen; | ||
218 | if (size > MAX_UBLOCK_SIZE) | ||
219 | { | ||
220 | size = MAX_UBLOCK_SIZE; | ||
221 | mdsize = size - sizeof(struct UBlock) - (slen + ulen); | ||
222 | } | ||
223 | ub_plain = GNUNET_malloc (size); | ||
224 | kbe = (char *) &ub_plain[1]; | ||
225 | if (NULL != ulabel) | ||
226 | GNUNET_memcpy (kbe, ulabel, ulen); | ||
227 | kbe += ulen; | ||
228 | GNUNET_memcpy (kbe, uris, slen); | ||
229 | kbe += slen; | ||
230 | GNUNET_free (uris); | ||
231 | sptr = kbe; | ||
232 | if (NULL != meta) | ||
233 | mdsize = | ||
234 | GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, mdsize, | ||
235 | GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); | ||
236 | if (-1 == mdsize) | ||
237 | { | ||
238 | GNUNET_break (0); | ||
239 | GNUNET_free (ub_plain); | ||
240 | cont (cont_cls, _ ("Internal error.")); | ||
241 | return NULL; | ||
242 | } | ||
243 | size = sizeof(struct UBlock) + slen + mdsize + ulen; | ||
244 | |||
245 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
246 | "Publishing under identifier `%s'\n", | ||
247 | label); | ||
248 | /* get public key of the namespace */ | ||
249 | GNUNET_CRYPTO_ecdsa_key_get_public (ns, | ||
250 | &pub); | ||
251 | derive_ublock_encryption_key (&skey, &iv, | ||
252 | label, &pub); | ||
253 | |||
254 | /* encrypt ublock */ | ||
255 | ub_enc = GNUNET_malloc (size); | ||
256 | GNUNET_CRYPTO_symmetric_encrypt (&ub_plain[1], | ||
257 | ulen + slen + mdsize, | ||
258 | &skey, &iv, | ||
259 | &ub_enc[1]); | ||
260 | GNUNET_free (ub_plain); | ||
261 | ub_enc->purpose.size = htonl (ulen + slen + mdsize | ||
262 | + sizeof(struct UBlock) | ||
263 | - sizeof(struct GNUNET_CRYPTO_EcdsaSignature)); | ||
264 | ub_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK); | ||
265 | |||
266 | /* derive signing-key from 'label' and public key of the namespace */ | ||
267 | nsd = GNUNET_CRYPTO_ecdsa_private_key_derive (ns, label, "fs-ublock"); | ||
268 | GNUNET_CRYPTO_ecdsa_key_get_public (nsd, | ||
269 | &ub_enc->verification_key); | ||
270 | GNUNET_assert (GNUNET_OK == | ||
271 | GNUNET_CRYPTO_ecdsa_sign_ (nsd, | ||
272 | &ub_enc->purpose, | ||
273 | &ub_enc->signature)); | ||
274 | GNUNET_CRYPTO_hash (&ub_enc->verification_key, | ||
275 | sizeof(ub_enc->verification_key), | ||
276 | &query); | ||
277 | GNUNET_free (nsd); | ||
278 | |||
279 | uc = GNUNET_new (struct GNUNET_FS_PublishUblockContext); | ||
280 | uc->cont = cont; | ||
281 | uc->cont_cls = cont_cls; | ||
282 | if (NULL != dsh) | ||
283 | { | ||
284 | uc->qre = | ||
285 | GNUNET_DATASTORE_put (dsh, | ||
286 | 0, | ||
287 | &query, | ||
288 | ulen + slen + mdsize + sizeof(struct UBlock), | ||
289 | ub_enc, | ||
290 | GNUNET_BLOCK_TYPE_FS_UBLOCK, | ||
291 | bo->content_priority, | ||
292 | bo->anonymity_level, | ||
293 | bo->replication_level, | ||
294 | bo->expiration_time, | ||
295 | -2, 1, | ||
296 | &ublock_put_cont, uc); | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | uc->task = GNUNET_SCHEDULER_add_now (&run_cont, | ||
301 | uc); | ||
302 | } | ||
303 | GNUNET_free (ub_enc); | ||
304 | return uc; | ||
305 | } | ||
306 | |||
307 | |||
308 | /** | ||
309 | * Abort UBlock publishing operation. | ||
310 | * | ||
311 | * @param uc operation to abort. | ||
312 | */ | ||
313 | void | ||
314 | GNUNET_FS_publish_ublock_cancel_ (struct GNUNET_FS_PublishUblockContext *uc) | ||
315 | { | ||
316 | if (NULL != uc->qre) | ||
317 | GNUNET_DATASTORE_cancel (uc->qre); | ||
318 | if (NULL != uc->task) | ||
319 | GNUNET_SCHEDULER_cancel (uc->task); | ||
320 | GNUNET_free (uc); | ||
321 | } | ||
322 | |||
323 | |||
324 | /* end of fs_publish_ublock.c */ | ||
diff --git a/src/fs/fs_publish_ublock.h b/src/fs/fs_publish_ublock.h deleted file mode 100644 index 83c6a50aa..000000000 --- a/src/fs/fs_publish_ublock.h +++ /dev/null | |||
@@ -1,108 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2012, 2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_publish_ublock.h | ||
23 | * @brief publish a UBLOCK in GNUnet | ||
24 | * @see https://gnunet.org/encoding and #2564 | ||
25 | * @author Krista Bennett | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #ifndef FS_PUBLISH_UBLOCK_H | ||
29 | #define FS_PUBLISH_UBLOCK_H | ||
30 | |||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_datastore_service.h" | ||
33 | #include "gnunet_fs_service.h" | ||
34 | #include "gnunet_identity_service.h" | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Decrypt the given UBlock, storing the result in output. | ||
39 | * | ||
40 | * @param input input data | ||
41 | * @param input_len number of bytes in input | ||
42 | * @param ns public key under which the UBlock was stored | ||
43 | * @param label label under which the UBlock was stored | ||
44 | * @param output where to write the result, has input_len bytes | ||
45 | */ | ||
46 | void | ||
47 | GNUNET_FS_ublock_decrypt_ (const void *input, | ||
48 | size_t input_len, | ||
49 | const struct GNUNET_CRYPTO_EcdsaPublicKey *ns, | ||
50 | const char *label, | ||
51 | void *output); | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Context for 'ublock_put_cont'. | ||
56 | */ | ||
57 | struct GNUNET_FS_PublishUblockContext; | ||
58 | |||
59 | |||
60 | /** | ||
61 | * Signature of a function called as the continuation of a UBlock | ||
62 | * publication. | ||
63 | * | ||
64 | * @param cls closure | ||
65 | * @param emsg error message, NULL on success | ||
66 | */ | ||
67 | typedef void (*GNUNET_FS_UBlockContinuation) (void *cls, | ||
68 | const char *emsg); | ||
69 | |||
70 | |||
71 | /** | ||
72 | * Publish a UBlock. | ||
73 | * | ||
74 | * @param h handle to the file sharing subsystem | ||
75 | * @param dsh datastore handle to use for storage operation | ||
76 | * @param label identifier to use | ||
77 | * @param ulabel update label to use, may be an empty string for none | ||
78 | * @param ns namespace to publish in | ||
79 | * @param meta metadata to use | ||
80 | * @param uri URI to refer to in the UBlock | ||
81 | * @param bo per-block options | ||
82 | * @param options publication options | ||
83 | * @param cont continuation | ||
84 | * @param cont_cls closure for cont | ||
85 | * @return NULL on error ('cont' will still be called) | ||
86 | */ | ||
87 | struct GNUNET_FS_PublishUblockContext * | ||
88 | GNUNET_FS_publish_ublock_ (struct GNUNET_FS_Handle *h, | ||
89 | struct GNUNET_DATASTORE_Handle *dsh, | ||
90 | const char *label, | ||
91 | const char *ulabel, | ||
92 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns, | ||
93 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
94 | const struct GNUNET_FS_Uri *uri, | ||
95 | const struct GNUNET_FS_BlockOptions *bo, | ||
96 | enum GNUNET_FS_PublishOptions options, | ||
97 | GNUNET_FS_UBlockContinuation cont, void *cont_cls); | ||
98 | |||
99 | |||
100 | /** | ||
101 | * Abort UBlock publishing operation. | ||
102 | * | ||
103 | * @param uc operation to abort. | ||
104 | */ | ||
105 | void | ||
106 | GNUNET_FS_publish_ublock_cancel_ (struct GNUNET_FS_PublishUblockContext *uc); | ||
107 | |||
108 | #endif | ||
diff --git a/src/fs/fs_search.c b/src/fs/fs_search.c deleted file mode 100644 index 3dbee43ef..000000000 --- a/src/fs/fs_search.c +++ /dev/null | |||
@@ -1,1835 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001-2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/fs_search.c | ||
22 | * @brief Helper functions for searching. | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_constants.h" | ||
27 | #include "gnunet_fs_service.h" | ||
28 | #include "gnunet_protocols.h" | ||
29 | #include "fs_api.h" | ||
30 | #include "fs_publish_ublock.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Number of availability trials we perform per search result. | ||
35 | */ | ||
36 | #define AVAILABILITY_TRIALS_MAX 8 | ||
37 | |||
38 | /** | ||
39 | * Fill in all of the generic fields for a search event and | ||
40 | * call the callback. | ||
41 | * | ||
42 | * @param pi structure to fill in | ||
43 | * @param h file-sharing handle | ||
44 | * @param sc overall search context | ||
45 | * @return value returned by the callback | ||
46 | */ | ||
47 | void * | ||
48 | GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
49 | struct GNUNET_FS_Handle *h, | ||
50 | struct GNUNET_FS_SearchContext *sc) | ||
51 | { | ||
52 | void *ret; | ||
53 | |||
54 | pi->value.search.sc = sc; | ||
55 | pi->value.search.cctx = (NULL != sc) ? sc->client_info : NULL; | ||
56 | pi->value.search.pctx = | ||
57 | ((NULL == sc) || (NULL == sc->psearch_result)) | ||
58 | ? NULL | ||
59 | : sc->psearch_result->client_info; | ||
60 | pi->value.search.query = (NULL != sc) ? sc->uri : NULL; | ||
61 | pi->value.search.duration = (NULL != sc) | ||
62 | ? GNUNET_TIME_absolute_get_duration ( | ||
63 | sc->start_time) | ||
64 | : GNUNET_TIME_UNIT_ZERO; | ||
65 | pi->value.search.anonymity = (NULL != sc) ? sc->anonymity : 0; | ||
66 | pi->fsh = h; | ||
67 | ret = h->upcb (h->upcb_cls, pi); | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | |||
72 | /** | ||
73 | * Check if the given result is identical to the given URI. | ||
74 | * | ||
75 | * @param cls points to the URI we check against | ||
76 | * @param key not used | ||
77 | * @param value a `struct GNUNET_FS_SearchResult` who's URI we | ||
78 | * should compare with | ||
79 | * @return #GNUNET_SYSERR if the result is present, | ||
80 | * #GNUNET_OK otherwise | ||
81 | */ | ||
82 | static int | ||
83 | test_result_present (void *cls, | ||
84 | const struct GNUNET_HashCode *key, | ||
85 | void *value) | ||
86 | { | ||
87 | const struct GNUNET_FS_Uri *uri = cls; | ||
88 | struct GNUNET_FS_SearchResult *sr = value; | ||
89 | |||
90 | if (GNUNET_FS_uri_test_equal (uri, sr->uri)) | ||
91 | return GNUNET_SYSERR; | ||
92 | return GNUNET_OK; | ||
93 | } | ||
94 | |||
95 | |||
96 | /** | ||
97 | * We've found a new CHK result. Let the client | ||
98 | * know about it. | ||
99 | * | ||
100 | * @param sc the search context | ||
101 | * @param sr the specific result | ||
102 | */ | ||
103 | static void | ||
104 | notify_client_chk_result (struct GNUNET_FS_SearchContext *sc, | ||
105 | struct GNUNET_FS_SearchResult *sr) | ||
106 | { | ||
107 | struct GNUNET_FS_ProgressInfo pi; | ||
108 | |||
109 | pi.status = GNUNET_FS_STATUS_SEARCH_RESULT; | ||
110 | pi.value.search.specifics.result.meta = sr->meta; | ||
111 | pi.value.search.specifics.result.uri = sr->uri; | ||
112 | pi.value.search.specifics.result.result = sr; | ||
113 | pi.value.search.specifics.result.applicability_rank = sr->optional_support; | ||
114 | sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); | ||
115 | } | ||
116 | |||
117 | |||
118 | /** | ||
119 | * We've found new information about an existing CHK result. Let the | ||
120 | * client know about it. | ||
121 | * | ||
122 | * @param sc the search context | ||
123 | * @param sr the specific result | ||
124 | */ | ||
125 | static void | ||
126 | notify_client_chk_update (struct GNUNET_FS_SearchContext *sc, | ||
127 | struct GNUNET_FS_SearchResult *sr) | ||
128 | { | ||
129 | struct GNUNET_FS_ProgressInfo pi; | ||
130 | |||
131 | pi.status = GNUNET_FS_STATUS_SEARCH_UPDATE; | ||
132 | pi.value.search.specifics.update.cctx = sr->client_info; | ||
133 | pi.value.search.specifics.update.meta = sr->meta; | ||
134 | pi.value.search.specifics.update.uri = sr->uri; | ||
135 | pi.value.search.specifics.update.availability_rank = | ||
136 | 2 * sr->availability_success - sr->availability_trials; | ||
137 | pi.value.search.specifics.update.availability_certainty = | ||
138 | sr->availability_trials; | ||
139 | pi.value.search.specifics.update.applicability_rank = sr->optional_support; | ||
140 | pi.value.search.specifics.update.current_probe_time | ||
141 | = GNUNET_TIME_absolute_get_duration (sr->probe_active_time); | ||
142 | sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Context for "get_result_present". | ||
148 | */ | ||
149 | struct GetResultContext | ||
150 | { | ||
151 | /** | ||
152 | * The URI we're looking for. | ||
153 | */ | ||
154 | const struct GNUNET_FS_Uri *uri; | ||
155 | |||
156 | /** | ||
157 | * Where to store a pointer to the search | ||
158 | * result struct if we found a match. | ||
159 | */ | ||
160 | struct GNUNET_FS_SearchResult *sr; | ||
161 | }; | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Check if the given result is identical to the given URI and if so | ||
166 | * return it. | ||
167 | * | ||
168 | * @param cls a `struct GetResultContext` | ||
169 | * @param key not used | ||
170 | * @param value a `struct GNUNET_FS_SearchResult` who's URI we | ||
171 | * should compare with | ||
172 | * @return #GNUNET_OK | ||
173 | */ | ||
174 | static int | ||
175 | get_result_present (void *cls, | ||
176 | const struct GNUNET_HashCode *key, | ||
177 | void *value) | ||
178 | { | ||
179 | struct GetResultContext *grc = cls; | ||
180 | struct GNUNET_FS_SearchResult *sr = value; | ||
181 | |||
182 | if (GNUNET_FS_uri_test_equal (grc->uri, sr->uri)) | ||
183 | grc->sr = sr; | ||
184 | return GNUNET_OK; | ||
185 | } | ||
186 | |||
187 | |||
188 | /** | ||
189 | * Signal result of last probe to client and then schedule next | ||
190 | * probe. | ||
191 | * | ||
192 | * @param sr search result to signal for | ||
193 | */ | ||
194 | static void | ||
195 | signal_probe_result (struct GNUNET_FS_SearchResult *sr) | ||
196 | { | ||
197 | struct GNUNET_FS_ProgressInfo pi; | ||
198 | |||
199 | pi.status = GNUNET_FS_STATUS_SEARCH_UPDATE; | ||
200 | pi.value.search.specifics.update.cctx = sr->client_info; | ||
201 | pi.value.search.specifics.update.meta = sr->meta; | ||
202 | pi.value.search.specifics.update.uri = sr->uri; | ||
203 | pi.value.search.specifics.update.availability_rank | ||
204 | = 2 * sr->availability_success - sr->availability_trials; | ||
205 | pi.value.search.specifics.update.availability_certainty | ||
206 | = sr->availability_trials; | ||
207 | pi.value.search.specifics.update.applicability_rank = sr->optional_support; | ||
208 | pi.value.search.specifics.update.current_probe_time | ||
209 | = GNUNET_TIME_absolute_get_duration (sr->probe_active_time); | ||
210 | sr->client_info = GNUNET_FS_search_make_status_ (&pi, sr->h, sr->sc); | ||
211 | GNUNET_FS_search_start_probe_ (sr); | ||
212 | } | ||
213 | |||
214 | |||
215 | /** | ||
216 | * Handle the case where we have failed to receive a response for our probe. | ||
217 | * | ||
218 | * @param cls our `struct GNUNET_FS_SearchResult *` | ||
219 | */ | ||
220 | static void | ||
221 | probe_failure_handler (void *cls) | ||
222 | { | ||
223 | struct GNUNET_FS_SearchResult *sr = cls; | ||
224 | |||
225 | sr->probe_cancel_task = NULL; | ||
226 | sr->availability_trials++; | ||
227 | GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); | ||
228 | sr->probe_ctx = NULL; | ||
229 | GNUNET_FS_stop_probe_ping_task_ (sr); | ||
230 | GNUNET_FS_search_result_sync_ (sr); | ||
231 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
232 | "Probe #%u for search result %p failed\n", | ||
233 | sr->availability_trials, | ||
234 | sr); | ||
235 | signal_probe_result (sr); | ||
236 | } | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Handle the case where we have gotten a response for our probe. | ||
241 | * | ||
242 | * @param cls our `struct GNUNET_FS_SearchResult *` | ||
243 | */ | ||
244 | static void | ||
245 | probe_success_handler (void *cls) | ||
246 | { | ||
247 | struct GNUNET_FS_SearchResult *sr = cls; | ||
248 | |||
249 | sr->probe_cancel_task = NULL; | ||
250 | sr->availability_trials++; | ||
251 | sr->availability_success++; | ||
252 | GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); | ||
253 | sr->probe_ctx = NULL; | ||
254 | GNUNET_FS_stop_probe_ping_task_ (sr); | ||
255 | GNUNET_FS_search_result_sync_ (sr); | ||
256 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
257 | "Probe #%u for search result %p succeeded\n", | ||
258 | sr->availability_trials, | ||
259 | sr); | ||
260 | signal_probe_result (sr); | ||
261 | } | ||
262 | |||
263 | |||
264 | /** | ||
265 | * Notification of FS that a search probe has made progress. | ||
266 | * This function is used INSTEAD of the client's event handler | ||
267 | * for downloads where the #GNUNET_FS_DOWNLOAD_IS_PROBE flag is set. | ||
268 | * | ||
269 | * @param cls closure, always NULL (!), actual closure | ||
270 | * is in the client-context of the info struct | ||
271 | * @param info details about the event, specifying the event type | ||
272 | * and various bits about the event | ||
273 | * @return client-context (for the next progress call | ||
274 | * for this operation; should be set to NULL for | ||
275 | * SUSPEND and STOPPED events). The value returned | ||
276 | * will be passed to future callbacks in the respective | ||
277 | * field in the `struct GNUNET_FS_ProgressInfo`. | ||
278 | */ | ||
279 | void * | ||
280 | GNUNET_FS_search_probe_progress_ (void *cls, | ||
281 | const struct GNUNET_FS_ProgressInfo *info) | ||
282 | { | ||
283 | struct GNUNET_FS_SearchResult *sr = info->value.download.cctx; | ||
284 | struct GNUNET_TIME_Relative dur; | ||
285 | |||
286 | switch (info->status) | ||
287 | { | ||
288 | case GNUNET_FS_STATUS_DOWNLOAD_START: | ||
289 | /* ignore */ | ||
290 | break; | ||
291 | case GNUNET_FS_STATUS_DOWNLOAD_RESUME: | ||
292 | /* probes should never be resumed */ | ||
293 | GNUNET_assert (0); | ||
294 | break; | ||
295 | case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND: | ||
296 | /* probes should never be suspended */ | ||
297 | GNUNET_break (0); | ||
298 | break; | ||
299 | case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: | ||
300 | /* ignore */ | ||
301 | break; | ||
302 | case GNUNET_FS_STATUS_DOWNLOAD_ERROR: | ||
303 | if (NULL != sr->probe_cancel_task) | ||
304 | { | ||
305 | GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); | ||
306 | sr->probe_cancel_task = NULL; | ||
307 | } | ||
308 | sr->probe_cancel_task = | ||
309 | GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time, | ||
310 | &probe_failure_handler, sr); | ||
311 | break; | ||
312 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: | ||
313 | if (NULL != sr->probe_cancel_task) | ||
314 | { | ||
315 | GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); | ||
316 | sr->probe_cancel_task = NULL; | ||
317 | } | ||
318 | sr->probe_cancel_task = | ||
319 | GNUNET_SCHEDULER_add_now (&probe_success_handler, sr); | ||
320 | break; | ||
321 | case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: | ||
322 | if (NULL != sr->probe_cancel_task) | ||
323 | { | ||
324 | GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); | ||
325 | sr->probe_cancel_task = NULL; | ||
326 | } | ||
327 | sr = NULL; | ||
328 | break; | ||
329 | case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: | ||
330 | if (NULL == sr->probe_cancel_task) | ||
331 | { | ||
332 | sr->probe_active_time = GNUNET_TIME_absolute_get (); | ||
333 | sr->probe_cancel_task = | ||
334 | GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time, | ||
335 | &probe_failure_handler, sr); | ||
336 | } | ||
337 | break; | ||
338 | case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: | ||
339 | if (NULL != sr->probe_cancel_task) | ||
340 | { | ||
341 | GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); | ||
342 | sr->probe_cancel_task = NULL; | ||
343 | } | ||
344 | dur = GNUNET_TIME_absolute_get_duration (sr->probe_active_time); | ||
345 | sr->remaining_probe_time = | ||
346 | GNUNET_TIME_relative_subtract (sr->remaining_probe_time, dur); | ||
347 | if (0 == sr->remaining_probe_time.rel_value_us) | ||
348 | sr->probe_cancel_task = | ||
349 | GNUNET_SCHEDULER_add_now (&probe_failure_handler, sr); | ||
350 | GNUNET_FS_search_result_sync_ (sr); | ||
351 | break; | ||
352 | |||
353 | default: | ||
354 | GNUNET_break (0); | ||
355 | return NULL; | ||
356 | } | ||
357 | return sr; | ||
358 | } | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Task run periodically to remind clients that a probe is active. | ||
363 | * | ||
364 | * @param cls the `struct GNUNET_FS_SearchResult` that we are probing for | ||
365 | */ | ||
366 | static void | ||
367 | probe_ping_task_cb (void *cls) | ||
368 | { | ||
369 | struct GNUNET_FS_Handle *h = cls; | ||
370 | |||
371 | for (struct GNUNET_FS_SearchResult *sr = h->probes_head; | ||
372 | NULL != sr; | ||
373 | sr = sr->next) | ||
374 | if (NULL != sr->probe_ctx->mq) | ||
375 | signal_probe_result (sr); | ||
376 | h->probe_ping_task | ||
377 | = GNUNET_SCHEDULER_add_delayed (GNUNET_FS_PROBE_UPDATE_FREQUENCY, | ||
378 | &probe_ping_task_cb, | ||
379 | h); | ||
380 | } | ||
381 | |||
382 | |||
383 | /** | ||
384 | * Start the ping task for this search result. | ||
385 | * | ||
386 | * @param sr result to start pinging for. | ||
387 | */ | ||
388 | static void | ||
389 | start_probe_ping_task (struct GNUNET_FS_SearchResult *sr) | ||
390 | { | ||
391 | struct GNUNET_FS_Handle *h = sr->h; | ||
392 | |||
393 | GNUNET_CONTAINER_DLL_insert (h->probes_head, | ||
394 | h->probes_tail, | ||
395 | sr); | ||
396 | if (NULL == h->probe_ping_task) | ||
397 | h->probe_ping_task | ||
398 | = GNUNET_SCHEDULER_add_now (&probe_ping_task_cb, | ||
399 | h); | ||
400 | } | ||
401 | |||
402 | |||
403 | /** | ||
404 | * Stop the ping task for this search result. | ||
405 | * | ||
406 | * @param sr result to start pinging for. | ||
407 | */ | ||
408 | void | ||
409 | GNUNET_FS_stop_probe_ping_task_ (struct GNUNET_FS_SearchResult *sr) | ||
410 | { | ||
411 | struct GNUNET_FS_Handle *h = sr->h; | ||
412 | |||
413 | GNUNET_CONTAINER_DLL_remove (h->probes_head, | ||
414 | h->probes_tail, | ||
415 | sr); | ||
416 | if (NULL == h->probes_head) | ||
417 | { | ||
418 | GNUNET_SCHEDULER_cancel (h->probe_ping_task); | ||
419 | h->probe_ping_task = NULL; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | |||
424 | /** | ||
425 | * Start download probes for the given search result. | ||
426 | * | ||
427 | * @param sr the search result | ||
428 | */ | ||
429 | void | ||
430 | GNUNET_FS_search_start_probe_ (struct GNUNET_FS_SearchResult *sr) | ||
431 | { | ||
432 | uint64_t off; | ||
433 | uint64_t len; | ||
434 | |||
435 | if (NULL != sr->probe_ctx) | ||
436 | return; | ||
437 | if (NULL != sr->download) | ||
438 | return; | ||
439 | if (0 == (sr->h->flags & GNUNET_FS_FLAGS_DO_PROBES)) | ||
440 | return; | ||
441 | if (sr->availability_trials > AVAILABILITY_TRIALS_MAX) | ||
442 | return; | ||
443 | if ( (GNUNET_FS_URI_CHK != sr->uri->type) && | ||
444 | (GNUNET_FS_URI_LOC != sr->uri->type) ) | ||
445 | return; | ||
446 | len = GNUNET_FS_uri_chk_get_file_size (sr->uri); | ||
447 | if (0 == len) | ||
448 | return; | ||
449 | if ((len <= DBLOCK_SIZE) && (sr->availability_success > 0)) | ||
450 | return; | ||
451 | off = len / DBLOCK_SIZE; | ||
452 | if (off > 0) | ||
453 | off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, off); | ||
454 | off *= DBLOCK_SIZE; | ||
455 | if (len - off < DBLOCK_SIZE) | ||
456 | len = len - off; | ||
457 | else | ||
458 | len = DBLOCK_SIZE; | ||
459 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
460 | "Starting probe #%u (at offset %llu) for search result %p\n", | ||
461 | sr->availability_trials + 1, | ||
462 | (unsigned long long) off, | ||
463 | sr); | ||
464 | sr->remaining_probe_time = | ||
465 | GNUNET_TIME_relative_saturating_multiply (sr->h->avg_block_latency, | ||
466 | 2 * (1 | ||
467 | + sr->availability_trials)); | ||
468 | sr->probe_ctx = | ||
469 | GNUNET_FS_download_start (sr->h, sr->uri, sr->meta, NULL, NULL, off, | ||
470 | len, sr->anonymity, | ||
471 | GNUNET_FS_DOWNLOAD_NO_TEMPORARIES | ||
472 | | GNUNET_FS_DOWNLOAD_IS_PROBE, sr, NULL); | ||
473 | start_probe_ping_task (sr); | ||
474 | } | ||
475 | |||
476 | |||
477 | /** | ||
478 | * Start download probes for the given search result. | ||
479 | * | ||
480 | * @param h file-sharing handle to use for the operation | ||
481 | * @param uri URI to probe | ||
482 | * @param meta meta data associated with the URI | ||
483 | * @param client_info client info pointer to use for associated events | ||
484 | * @param anonymity anonymity level to use for the probes | ||
485 | * @return the search result handle to access the probe activity | ||
486 | */ | ||
487 | struct GNUNET_FS_SearchResult * | ||
488 | GNUNET_FS_probe (struct GNUNET_FS_Handle *h, | ||
489 | const struct GNUNET_FS_Uri *uri, | ||
490 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
491 | void *client_info, | ||
492 | uint32_t anonymity) | ||
493 | { | ||
494 | struct GNUNET_FS_SearchResult *sr; | ||
495 | |||
496 | GNUNET_assert (NULL != h); | ||
497 | GNUNET_assert (NULL != uri); | ||
498 | sr = GNUNET_new (struct GNUNET_FS_SearchResult); | ||
499 | sr->h = h; | ||
500 | sr->uri = GNUNET_FS_uri_dup (uri); | ||
501 | sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
502 | sr->client_info = client_info; | ||
503 | sr->anonymity = anonymity; | ||
504 | GNUNET_FS_search_start_probe_ (sr); | ||
505 | return sr; | ||
506 | } | ||
507 | |||
508 | |||
509 | /** | ||
510 | * Stop probing activity associated with a search result. | ||
511 | * | ||
512 | * @param sr search result | ||
513 | */ | ||
514 | static void | ||
515 | GNUNET_FS_search_stop_probe_ (struct GNUNET_FS_SearchResult *sr) | ||
516 | { | ||
517 | if (NULL != sr->probe_ctx) | ||
518 | { | ||
519 | GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); | ||
520 | sr->probe_ctx = NULL; | ||
521 | GNUNET_FS_stop_probe_ping_task_ (sr); | ||
522 | } | ||
523 | if (NULL != sr->probe_cancel_task) | ||
524 | { | ||
525 | GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); | ||
526 | sr->probe_cancel_task = NULL; | ||
527 | } | ||
528 | } | ||
529 | |||
530 | |||
531 | /** | ||
532 | * Stop probe activity. Must ONLY be used on values | ||
533 | * returned from #GNUNET_FS_probe. | ||
534 | * | ||
535 | * @param sr search result to stop probing for (freed) | ||
536 | * @return the value of the 'client_info' pointer | ||
537 | */ | ||
538 | void * | ||
539 | GNUNET_FS_probe_stop (struct GNUNET_FS_SearchResult *sr) | ||
540 | { | ||
541 | void *client_info; | ||
542 | |||
543 | GNUNET_assert (NULL == sr->sc); | ||
544 | GNUNET_FS_search_stop_probe_ (sr); | ||
545 | GNUNET_FS_uri_destroy (sr->uri); | ||
546 | GNUNET_CONTAINER_meta_data_destroy (sr->meta); | ||
547 | client_info = sr->client_info; | ||
548 | GNUNET_free (sr); | ||
549 | return client_info; | ||
550 | } | ||
551 | |||
552 | |||
553 | /** | ||
554 | * We have received a KSK result. Check how it fits in with the | ||
555 | * overall query and notify the client accordingly. | ||
556 | * | ||
557 | * @param sc context for the overall query | ||
558 | * @param ent entry for the specific keyword | ||
559 | * @param uri the URI that was found | ||
560 | * @param meta metadata associated with the URI | ||
561 | * under the @a ent keyword | ||
562 | */ | ||
563 | static void | ||
564 | process_ksk_result (struct GNUNET_FS_SearchContext *sc, | ||
565 | struct SearchRequestEntry *ent, | ||
566 | const struct GNUNET_FS_Uri *uri, | ||
567 | const struct GNUNET_CONTAINER_MetaData *meta) | ||
568 | { | ||
569 | struct GNUNET_HashCode key; | ||
570 | struct GNUNET_FS_SearchResult *sr; | ||
571 | struct GetResultContext grc; | ||
572 | int is_new; | ||
573 | unsigned int koff; | ||
574 | |||
575 | /* check if new */ | ||
576 | GNUNET_assert (NULL != sc); | ||
577 | if (GNUNET_OK != | ||
578 | GNUNET_FS_uri_to_key (uri, | ||
579 | &key)) | ||
580 | { | ||
581 | GNUNET_break_op (0); | ||
582 | return; | ||
583 | } | ||
584 | if (GNUNET_SYSERR == | ||
585 | GNUNET_CONTAINER_multihashmap_get_multiple (ent->results, | ||
586 | &key, | ||
587 | &test_result_present, | ||
588 | (void *) uri)) | ||
589 | return; /* duplicate result */ | ||
590 | /* try to find search result in master map */ | ||
591 | grc.sr = NULL; | ||
592 | grc.uri = uri; | ||
593 | GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, | ||
594 | &key, | ||
595 | &get_result_present, &grc); | ||
596 | sr = grc.sr; | ||
597 | is_new = (NULL == sr) || (sr->mandatory_missing > 0); | ||
598 | if (NULL == sr) | ||
599 | { | ||
600 | sr = GNUNET_new (struct GNUNET_FS_SearchResult); | ||
601 | sr->h = sc->h; | ||
602 | sr->sc = sc; | ||
603 | sr->anonymity = sc->anonymity; | ||
604 | sr->uri = GNUNET_FS_uri_dup (uri); | ||
605 | sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
606 | sr->mandatory_missing = sc->mandatory_count; | ||
607 | sr->key = key; | ||
608 | sr->keyword_bitmap = GNUNET_malloc ((sc->uri->data.ksk.keywordCount + 7) | ||
609 | / 8); /* round up, count bits */ | ||
610 | GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr, | ||
611 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
612 | } | ||
613 | else | ||
614 | { | ||
615 | GNUNET_CONTAINER_meta_data_merge (sr->meta, meta); | ||
616 | } | ||
617 | GNUNET_break (GNUNET_OK == | ||
618 | GNUNET_CONTAINER_multihashmap_put (ent->results, | ||
619 | &sr->key, | ||
620 | sr, | ||
621 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
622 | |||
623 | koff = ent - sc->requests; | ||
624 | GNUNET_assert ((ent >= sc->requests) && | ||
625 | (koff < sc->uri->data.ksk.keywordCount)); | ||
626 | sr->keyword_bitmap[koff / 8] |= (1 << (koff % 8)); | ||
627 | /* check if mandatory satisfied */ | ||
628 | if (1 <= GNUNET_CONTAINER_multihashmap_size (ent->results)) | ||
629 | { | ||
630 | if (ent->mandatory) | ||
631 | { | ||
632 | GNUNET_break (sr->mandatory_missing > 0); | ||
633 | sr->mandatory_missing--; | ||
634 | } | ||
635 | else | ||
636 | { | ||
637 | sr->optional_support++; | ||
638 | } | ||
639 | } | ||
640 | if (0 != sr->mandatory_missing) | ||
641 | { | ||
642 | GNUNET_break (NULL == sr->client_info); | ||
643 | return; | ||
644 | } | ||
645 | if (is_new) | ||
646 | notify_client_chk_result (sc, sr); | ||
647 | else | ||
648 | notify_client_chk_update (sc, sr); | ||
649 | GNUNET_FS_search_result_sync_ (sr); | ||
650 | GNUNET_FS_search_start_probe_ (sr); | ||
651 | } | ||
652 | |||
653 | |||
654 | /** | ||
655 | * Start search for content, internal API. | ||
656 | * | ||
657 | * @param h handle to the file sharing subsystem | ||
658 | * @param uri specifies the search parameters; can be | ||
659 | * a KSK URI or an SKS URI. | ||
660 | * @param anonymity desired level of anonymity | ||
661 | * @param options options for the search | ||
662 | * @param cctx client context | ||
663 | * @param psearch parent search result (for namespace update searches) | ||
664 | * @return context that can be used to control the search | ||
665 | */ | ||
666 | static struct GNUNET_FS_SearchContext * | ||
667 | search_start (struct GNUNET_FS_Handle *h, | ||
668 | const struct GNUNET_FS_Uri *uri, | ||
669 | uint32_t anonymity, | ||
670 | enum GNUNET_FS_SearchOptions options, | ||
671 | void *cctx, | ||
672 | struct GNUNET_FS_SearchResult *psearch); | ||
673 | |||
674 | |||
675 | /** | ||
676 | * We have received an SKS result. Start searching for updates and | ||
677 | * notify the client if it is a new result. | ||
678 | * | ||
679 | * @param sc context for the overall query | ||
680 | * @param id_update identifier for updates, NULL for none | ||
681 | * @param uri the URI that was found | ||
682 | * @param meta metadata associated with the URI | ||
683 | */ | ||
684 | static void | ||
685 | process_sks_result (struct GNUNET_FS_SearchContext *sc, | ||
686 | const char *id_update, | ||
687 | const struct GNUNET_FS_Uri *uri, | ||
688 | const struct GNUNET_CONTAINER_MetaData *meta) | ||
689 | { | ||
690 | struct GNUNET_FS_Uri uu; | ||
691 | struct GNUNET_HashCode key; | ||
692 | struct GNUNET_FS_SearchResult *sr; | ||
693 | |||
694 | /* check if new */ | ||
695 | GNUNET_assert (NULL != sc); | ||
696 | if (GNUNET_OK != | ||
697 | GNUNET_FS_uri_to_key (uri, | ||
698 | &key)) | ||
699 | { | ||
700 | GNUNET_break (0); | ||
701 | return; | ||
702 | } | ||
703 | GNUNET_CRYPTO_hash_xor (&uri->data.chk.chk.key, | ||
704 | &uri->data.chk.chk.query, | ||
705 | &key); | ||
706 | if (GNUNET_SYSERR == | ||
707 | GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, &key, | ||
708 | &test_result_present, | ||
709 | (void *) uri)) | ||
710 | return; /* duplicate result */ | ||
711 | sr = GNUNET_new (struct GNUNET_FS_SearchResult); | ||
712 | sr->h = sc->h; | ||
713 | sr->sc = sc; | ||
714 | sr->anonymity = sc->anonymity; | ||
715 | sr->uri = GNUNET_FS_uri_dup (uri); | ||
716 | sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
717 | sr->key = key; | ||
718 | GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr, | ||
719 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
720 | GNUNET_FS_search_result_sync_ (sr); | ||
721 | GNUNET_FS_search_start_probe_ (sr); | ||
722 | /* notify client */ | ||
723 | if (0 == sr->mandatory_missing) | ||
724 | notify_client_chk_result (sc, sr); | ||
725 | else | ||
726 | GNUNET_break (NULL == sr->client_info); | ||
727 | /* search for updates */ | ||
728 | if (0 == strlen (id_update)) | ||
729 | return; /* no updates */ | ||
730 | uu.type = GNUNET_FS_URI_SKS; | ||
731 | uu.data.sks.ns = sc->uri->data.sks.ns; | ||
732 | uu.data.sks.identifier = GNUNET_strdup (id_update); | ||
733 | (void) search_start (sc->h, &uu, sc->anonymity, sc->options, NULL, sr); | ||
734 | GNUNET_free (uu.data.sks.identifier); | ||
735 | } | ||
736 | |||
737 | |||
738 | /** | ||
739 | * Decrypt a ublock using a 'keyword' as the passphrase. Given the | ||
740 | * KSK public key derived from the keyword, this function looks up | ||
741 | * the original keyword in the search context and decrypts the | ||
742 | * given ciphertext block. | ||
743 | * | ||
744 | * @param sc search context with the keywords | ||
745 | * @param dpub derived public key used for the search | ||
746 | * @param edata encrypted data | ||
747 | * @param edata_size number of bytes in @a edata (and @a data) | ||
748 | * @param data where to store the plaintext | ||
749 | * @return keyword index on success, #GNUNET_SYSERR on error (no such | ||
750 | * keyword, internal error) | ||
751 | */ | ||
752 | static int | ||
753 | decrypt_block_with_keyword (const struct GNUNET_FS_SearchContext *sc, | ||
754 | const struct GNUNET_CRYPTO_EcdsaPublicKey *dpub, | ||
755 | const void *edata, | ||
756 | size_t edata_size, | ||
757 | char *data) | ||
758 | { | ||
759 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon; | ||
760 | struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub; | ||
761 | unsigned int i; | ||
762 | |||
763 | /* find key */ | ||
764 | for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) | ||
765 | if (0 == memcmp (dpub, | ||
766 | &sc->requests[i].dpub, | ||
767 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
768 | break; | ||
769 | if (i == sc->uri->data.ksk.keywordCount) | ||
770 | { | ||
771 | /* oops, does not match any of our keywords!? */ | ||
772 | GNUNET_break (0); | ||
773 | return GNUNET_SYSERR; | ||
774 | } | ||
775 | /* decrypt */ | ||
776 | anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous (); | ||
777 | GNUNET_CRYPTO_ecdsa_key_get_public (anon, &anon_pub); | ||
778 | GNUNET_FS_ublock_decrypt_ (edata, edata_size, | ||
779 | &anon_pub, | ||
780 | sc->requests[i].keyword, | ||
781 | data); | ||
782 | return i; | ||
783 | } | ||
784 | |||
785 | |||
786 | /** | ||
787 | * Process a keyword search result. The actual type of block is | ||
788 | * a UBlock; we know it is a keyword search result because that's | ||
789 | * what we were searching for. | ||
790 | * | ||
791 | * @param sc our search context | ||
792 | * @param ub the ublock with the keyword search result | ||
793 | * @param size size of @a ub | ||
794 | */ | ||
795 | static void | ||
796 | process_kblock (struct GNUNET_FS_SearchContext *sc, | ||
797 | const struct UBlock *ub, | ||
798 | size_t size) | ||
799 | { | ||
800 | size_t j; | ||
801 | char pt[size - sizeof(struct UBlock)]; | ||
802 | const char *eos; | ||
803 | struct GNUNET_CONTAINER_MetaData *meta; | ||
804 | struct GNUNET_FS_Uri *uri; | ||
805 | char *emsg; | ||
806 | int i; | ||
807 | |||
808 | if (-1 == (i = decrypt_block_with_keyword (sc, | ||
809 | &ub->verification_key, | ||
810 | &ub[1], | ||
811 | size - sizeof(struct UBlock), | ||
812 | pt))) | ||
813 | return; | ||
814 | /* parse; pt[0] is just '\0', so we skip over that */ | ||
815 | eos = memchr (&pt[1], '\0', sizeof(pt) - 1); | ||
816 | if (NULL == eos) | ||
817 | { | ||
818 | GNUNET_break_op (0); | ||
819 | return; | ||
820 | } | ||
821 | if (NULL == (uri = GNUNET_FS_uri_parse (&pt[1], &emsg))) | ||
822 | { | ||
823 | if (GNUNET_FS_VERSION > 0x00090400) | ||
824 | { | ||
825 | /* we broke this in 0x00090300, so don't bitch | ||
826 | too loudly just one version up... */ | ||
827 | GNUNET_break_op (0); /* ublock malformed */ | ||
828 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
829 | _ ("Failed to parse URI `%s': %s\n"), | ||
830 | &pt[1], | ||
831 | emsg); | ||
832 | } | ||
833 | GNUNET_free (emsg); | ||
834 | return; | ||
835 | } | ||
836 | j = eos - pt + 1; | ||
837 | if (sizeof(pt) == j) | ||
838 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
839 | else | ||
840 | meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], sizeof(pt) - j); | ||
841 | if (NULL == meta) | ||
842 | { | ||
843 | GNUNET_break_op (0); /* ublock malformed */ | ||
844 | GNUNET_FS_uri_destroy (uri); | ||
845 | return; | ||
846 | } | ||
847 | process_ksk_result (sc, | ||
848 | &sc->requests[i], | ||
849 | uri, | ||
850 | meta); | ||
851 | |||
852 | /* clean up */ | ||
853 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
854 | GNUNET_FS_uri_destroy (uri); | ||
855 | } | ||
856 | |||
857 | |||
858 | /** | ||
859 | * Process a namespace-search result. The actual type of block is | ||
860 | * a UBlock; we know it is a namespace search result because that's | ||
861 | * what we were searching for. | ||
862 | * | ||
863 | * @param sc our search context | ||
864 | * @param ub the ublock with a namespace result | ||
865 | * @param size size of @a ub | ||
866 | */ | ||
867 | static void | ||
868 | process_sblock (struct GNUNET_FS_SearchContext *sc, | ||
869 | const struct UBlock *ub, | ||
870 | size_t size) | ||
871 | { | ||
872 | size_t len = size - sizeof(struct UBlock); | ||
873 | char pt[len]; | ||
874 | struct GNUNET_FS_Uri *uri; | ||
875 | struct GNUNET_CONTAINER_MetaData *meta; | ||
876 | const char *id; | ||
877 | const char *uris; | ||
878 | size_t off; | ||
879 | char *emsg; | ||
880 | |||
881 | GNUNET_FS_ublock_decrypt_ (&ub[1], len, | ||
882 | &sc->uri->data.sks.ns, | ||
883 | sc->uri->data.sks.identifier, | ||
884 | pt); | ||
885 | /* parse */ | ||
886 | if (0 == (off = GNUNET_STRINGS_buffer_tokenize (pt, len, 2, &id, &uris))) | ||
887 | { | ||
888 | GNUNET_break_op (0); /* ublock malformed */ | ||
889 | return; | ||
890 | } | ||
891 | if (NULL == (meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[off], len | ||
892 | - off))) | ||
893 | { | ||
894 | GNUNET_break_op (0); /* ublock malformed */ | ||
895 | return; | ||
896 | } | ||
897 | if (NULL == (uri = GNUNET_FS_uri_parse (uris, &emsg))) | ||
898 | { | ||
899 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
900 | _ ("Failed to parse URI `%s': %s\n"), | ||
901 | uris, emsg); | ||
902 | GNUNET_break_op (0); /* ublock malformed */ | ||
903 | GNUNET_free (emsg); | ||
904 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
905 | return; | ||
906 | } | ||
907 | /* process */ | ||
908 | process_sks_result (sc, id, uri, meta); | ||
909 | /* clean up */ | ||
910 | GNUNET_FS_uri_destroy (uri); | ||
911 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
912 | } | ||
913 | |||
914 | |||
915 | /** | ||
916 | * Shutdown any existing connection to the FS | ||
917 | * service and try to establish a fresh one | ||
918 | * (and then re-transmit our search request). | ||
919 | * | ||
920 | * @param sc the search to reconnec | ||
921 | */ | ||
922 | static void | ||
923 | try_reconnect (struct GNUNET_FS_SearchContext *sc); | ||
924 | |||
925 | |||
926 | /** | ||
927 | * We check a result message from the service. | ||
928 | * | ||
929 | * @param cls closure | ||
930 | * @param msg result message received | ||
931 | */ | ||
932 | static int | ||
933 | check_result (void *cls, | ||
934 | const struct ClientPutMessage *cm) | ||
935 | { | ||
936 | /* payload of any variable size is OK */ | ||
937 | return GNUNET_OK; | ||
938 | } | ||
939 | |||
940 | |||
941 | /** | ||
942 | * We process a search result from the service. | ||
943 | * | ||
944 | * @param cls closure | ||
945 | * @param msg result message received | ||
946 | */ | ||
947 | static void | ||
948 | handle_result (void *cls, | ||
949 | const struct ClientPutMessage *cm) | ||
950 | { | ||
951 | struct GNUNET_FS_SearchContext *sc = cls; | ||
952 | uint16_t msize = ntohs (cm->header.size) - sizeof(*cm); | ||
953 | enum GNUNET_BLOCK_Type type = ntohl (cm->type); | ||
954 | |||
955 | if (GNUNET_TIME_absolute_get_duration (GNUNET_TIME_absolute_ntoh ( | ||
956 | cm->expiration)).rel_value_us > 0) | ||
957 | { | ||
958 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
959 | "Result received has already expired.\n"); | ||
960 | return; /* result expired */ | ||
961 | } | ||
962 | switch (type) | ||
963 | { | ||
964 | case GNUNET_BLOCK_TYPE_FS_UBLOCK: | ||
965 | if (GNUNET_FS_URI_SKS == sc->uri->type) | ||
966 | process_sblock (sc, | ||
967 | (const struct UBlock *) &cm[1], | ||
968 | msize); | ||
969 | else | ||
970 | process_kblock (sc, | ||
971 | (const struct UBlock *) &cm[1], | ||
972 | msize); | ||
973 | break; | ||
974 | |||
975 | case GNUNET_BLOCK_TYPE_ANY: | ||
976 | GNUNET_break (0); | ||
977 | break; | ||
978 | |||
979 | case GNUNET_BLOCK_TYPE_FS_DBLOCK: | ||
980 | GNUNET_break (0); | ||
981 | break; | ||
982 | |||
983 | case GNUNET_BLOCK_TYPE_FS_ONDEMAND: | ||
984 | GNUNET_break (0); | ||
985 | break; | ||
986 | |||
987 | case GNUNET_BLOCK_TYPE_FS_IBLOCK: | ||
988 | GNUNET_break (0); | ||
989 | break; | ||
990 | |||
991 | default: | ||
992 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
993 | _ ("Got result with unknown block type `%d', ignoring"), | ||
994 | type); | ||
995 | break; | ||
996 | } | ||
997 | } | ||
998 | |||
999 | |||
1000 | /** | ||
1001 | * Schedule the transmission of the (next) search request | ||
1002 | * to the service. | ||
1003 | * | ||
1004 | * @param sc context for the search | ||
1005 | */ | ||
1006 | static void | ||
1007 | schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc); | ||
1008 | |||
1009 | |||
1010 | /** | ||
1011 | * Closure for #build_result_set(). | ||
1012 | */ | ||
1013 | struct MessageBuilderContext | ||
1014 | { | ||
1015 | /** | ||
1016 | * How many entries can we store to xoff. | ||
1017 | */ | ||
1018 | unsigned int put_cnt; | ||
1019 | |||
1020 | /** | ||
1021 | * How many entries should we skip. | ||
1022 | */ | ||
1023 | unsigned int skip_cnt; | ||
1024 | |||
1025 | /** | ||
1026 | * Where to store the keys. | ||
1027 | */ | ||
1028 | struct GNUNET_HashCode *xoff; | ||
1029 | |||
1030 | /** | ||
1031 | * Search context we are iterating for. | ||
1032 | */ | ||
1033 | struct GNUNET_FS_SearchContext *sc; | ||
1034 | |||
1035 | /** | ||
1036 | * Keyword offset the search result must match (0 for SKS) | ||
1037 | */ | ||
1038 | unsigned int keyword_offset; | ||
1039 | }; | ||
1040 | |||
1041 | |||
1042 | /** | ||
1043 | * Iterating over the known results, pick those matching the given | ||
1044 | * result range and store their keys at 'xoff'. | ||
1045 | * | ||
1046 | * @param cls the `struct MessageBuilderContext` | ||
1047 | * @param key key for a result | ||
1048 | * @param value the search result | ||
1049 | * @return #GNUNET_OK to continue iterating | ||
1050 | */ | ||
1051 | static int | ||
1052 | build_result_set (void *cls, | ||
1053 | const struct GNUNET_HashCode *key, | ||
1054 | void *value) | ||
1055 | { | ||
1056 | struct MessageBuilderContext *mbc = cls; | ||
1057 | struct GNUNET_FS_SearchResult *sr = value; | ||
1058 | |||
1059 | if ((NULL != sr->keyword_bitmap) && | ||
1060 | (0 == (sr->keyword_bitmap[mbc->keyword_offset / 8] & (1 | ||
1061 | << (mbc-> | ||
1062 | keyword_offset | ||
1063 | % 8))))) | ||
1064 | return GNUNET_OK; /* have no match for this keyword yet */ | ||
1065 | if (mbc->skip_cnt > 0) | ||
1066 | { | ||
1067 | mbc->skip_cnt--; | ||
1068 | return GNUNET_OK; | ||
1069 | } | ||
1070 | if (0 == mbc->put_cnt) | ||
1071 | return GNUNET_SYSERR; | ||
1072 | mbc->xoff[--mbc->put_cnt] = *key; | ||
1073 | |||
1074 | return GNUNET_OK; | ||
1075 | } | ||
1076 | |||
1077 | |||
1078 | /** | ||
1079 | * Iterating over the known results, count those matching the given | ||
1080 | * result range and increment put count for each. | ||
1081 | * | ||
1082 | * @param cls the `struct MessageBuilderContext` | ||
1083 | * @param key key for a result | ||
1084 | * @param value the search result | ||
1085 | * @return #GNUNET_OK to continue iterating | ||
1086 | */ | ||
1087 | static int | ||
1088 | find_result_set (void *cls, | ||
1089 | const struct GNUNET_HashCode *key, | ||
1090 | void *value) | ||
1091 | { | ||
1092 | struct MessageBuilderContext *mbc = cls; | ||
1093 | struct GNUNET_FS_SearchResult *sr = value; | ||
1094 | |||
1095 | if ((NULL != sr->keyword_bitmap) && | ||
1096 | (0 == (sr->keyword_bitmap[mbc->keyword_offset / 8] & (1 | ||
1097 | << (mbc-> | ||
1098 | keyword_offset | ||
1099 | % 8))))) | ||
1100 | return GNUNET_OK; /* have no match for this keyword yet */ | ||
1101 | mbc->put_cnt++; | ||
1102 | return GNUNET_OK; | ||
1103 | } | ||
1104 | |||
1105 | |||
1106 | /** | ||
1107 | * Schedule the transmission of the (next) search request | ||
1108 | * to the service. | ||
1109 | * | ||
1110 | * @param sc context for the search | ||
1111 | */ | ||
1112 | static void | ||
1113 | schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc) | ||
1114 | { | ||
1115 | struct MessageBuilderContext mbc; | ||
1116 | struct GNUNET_MQ_Envelope *env; | ||
1117 | struct SearchMessage *sm; | ||
1118 | struct GNUNET_CRYPTO_EcdsaPublicKey dpub; | ||
1119 | unsigned int total_seen_results; /* total number of result hashes to send */ | ||
1120 | uint32_t options; | ||
1121 | unsigned int left; | ||
1122 | unsigned int todo; | ||
1123 | unsigned int fit; | ||
1124 | unsigned int search_request_map_offset; | ||
1125 | unsigned int keyword_offset; | ||
1126 | int first_call; | ||
1127 | |||
1128 | memset (&mbc, 0, sizeof(mbc)); | ||
1129 | mbc.sc = sc; | ||
1130 | if (GNUNET_FS_uri_test_ksk (sc->uri)) | ||
1131 | { | ||
1132 | /* This will calculate the result set size ONLY for | ||
1133 | "keyword_offset == 0", so we will have to recalculate | ||
1134 | it for the other keywords later! */ | ||
1135 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1136 | &find_result_set, | ||
1137 | &mbc); | ||
1138 | total_seen_results = mbc.put_cnt; | ||
1139 | } | ||
1140 | else | ||
1141 | { | ||
1142 | total_seen_results | ||
1143 | = GNUNET_CONTAINER_multihashmap_size (sc->master_result_map); | ||
1144 | } | ||
1145 | search_request_map_offset = 0; | ||
1146 | keyword_offset = 0; | ||
1147 | first_call = GNUNET_YES; | ||
1148 | while ((0 != (left = | ||
1149 | (total_seen_results - search_request_map_offset))) || | ||
1150 | (GNUNET_YES == first_call)) | ||
1151 | { | ||
1152 | first_call = GNUNET_NO; | ||
1153 | options = SEARCH_MESSAGE_OPTION_NONE; | ||
1154 | if (0 != (sc->options & GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY)) | ||
1155 | options |= SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY; | ||
1156 | |||
1157 | fit = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof(*sm)) / sizeof(struct | ||
1158 | GNUNET_HashCode); | ||
1159 | todo = GNUNET_MIN (fit, | ||
1160 | left); | ||
1161 | env = GNUNET_MQ_msg_extra (sm, | ||
1162 | sizeof(struct GNUNET_HashCode) * todo, | ||
1163 | GNUNET_MESSAGE_TYPE_FS_START_SEARCH); | ||
1164 | mbc.skip_cnt = search_request_map_offset; | ||
1165 | mbc.xoff = (struct GNUNET_HashCode *) &sm[1]; | ||
1166 | sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK); | ||
1167 | sm->anonymity_level = htonl (sc->anonymity); | ||
1168 | memset (&sm->target, | ||
1169 | 0, | ||
1170 | sizeof(struct GNUNET_PeerIdentity)); | ||
1171 | |||
1172 | if (GNUNET_FS_uri_test_ksk (sc->uri)) | ||
1173 | { | ||
1174 | mbc.keyword_offset = keyword_offset; | ||
1175 | /* calculate how many results we can send in this message */ | ||
1176 | mbc.put_cnt = todo; | ||
1177 | /* now build message */ | ||
1178 | sm->query = sc->requests[keyword_offset].uquery; | ||
1179 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1180 | &build_result_set, | ||
1181 | &mbc); | ||
1182 | search_request_map_offset += todo; | ||
1183 | GNUNET_assert (0 == mbc.put_cnt); | ||
1184 | GNUNET_assert (total_seen_results >= search_request_map_offset); | ||
1185 | if (total_seen_results != search_request_map_offset) | ||
1186 | { | ||
1187 | /* more requesting to be done... */ | ||
1188 | sm->options = htonl (options | SEARCH_MESSAGE_OPTION_CONTINUED); | ||
1189 | } | ||
1190 | else | ||
1191 | { | ||
1192 | sm->options = htonl (options); | ||
1193 | keyword_offset++; | ||
1194 | if (sc->uri->data.ksk.keywordCount != keyword_offset) | ||
1195 | { | ||
1196 | /* more keywords => more requesting to be done... */ | ||
1197 | first_call = GNUNET_YES; | ||
1198 | search_request_map_offset = 0; | ||
1199 | mbc.put_cnt = 0; | ||
1200 | mbc.keyword_offset = keyword_offset; | ||
1201 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1202 | &find_result_set, | ||
1203 | &mbc); | ||
1204 | total_seen_results = mbc.put_cnt; | ||
1205 | } | ||
1206 | } | ||
1207 | } | ||
1208 | else | ||
1209 | { | ||
1210 | GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri)); | ||
1211 | |||
1212 | GNUNET_CRYPTO_ecdsa_public_key_derive (&sc->uri->data.sks.ns, | ||
1213 | sc->uri->data.sks.identifier, | ||
1214 | "fs-ublock", | ||
1215 | &dpub); | ||
1216 | GNUNET_CRYPTO_hash (&dpub, | ||
1217 | sizeof(dpub), | ||
1218 | &sm->query); | ||
1219 | mbc.put_cnt = todo; | ||
1220 | mbc.keyword_offset = 0; | ||
1221 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1222 | &build_result_set, | ||
1223 | &mbc); | ||
1224 | GNUNET_assert (total_seen_results >= search_request_map_offset); | ||
1225 | if (total_seen_results != search_request_map_offset) | ||
1226 | { | ||
1227 | /* more requesting to be done... */ | ||
1228 | sm->options = htonl (options | SEARCH_MESSAGE_OPTION_CONTINUED); | ||
1229 | } | ||
1230 | else | ||
1231 | { | ||
1232 | sm->options = htonl (options); | ||
1233 | } | ||
1234 | } | ||
1235 | GNUNET_MQ_send (sc->mq, | ||
1236 | env); | ||
1237 | } | ||
1238 | } | ||
1239 | |||
1240 | |||
1241 | /** | ||
1242 | * Generic error handler, called with the appropriate error code and | ||
1243 | * the same closure specified at the creation of the message queue. | ||
1244 | * Not every message queue implementation supports an error handler. | ||
1245 | * | ||
1246 | * @param cls closure with the `struct GNUNET_FS_SearchContext *` | ||
1247 | * @param error error code | ||
1248 | */ | ||
1249 | static void | ||
1250 | search_mq_error_handler (void *cls, | ||
1251 | enum GNUNET_MQ_Error error) | ||
1252 | { | ||
1253 | struct GNUNET_FS_SearchContext *sc = cls; | ||
1254 | |||
1255 | if (NULL != sc->mq) | ||
1256 | { | ||
1257 | GNUNET_MQ_destroy (sc->mq); | ||
1258 | sc->mq = NULL; | ||
1259 | } | ||
1260 | try_reconnect (sc); | ||
1261 | } | ||
1262 | |||
1263 | |||
1264 | /** | ||
1265 | * Reconnect to the FS service and transmit | ||
1266 | * our queries NOW. | ||
1267 | * | ||
1268 | * @param cls our search context | ||
1269 | */ | ||
1270 | static void | ||
1271 | do_reconnect (void *cls) | ||
1272 | { | ||
1273 | struct GNUNET_FS_SearchContext *sc = cls; | ||
1274 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
1275 | GNUNET_MQ_hd_var_size (result, | ||
1276 | GNUNET_MESSAGE_TYPE_FS_PUT, | ||
1277 | struct ClientPutMessage, | ||
1278 | sc), | ||
1279 | GNUNET_MQ_handler_end () | ||
1280 | }; | ||
1281 | |||
1282 | sc->task = NULL; | ||
1283 | sc->mq = GNUNET_CLIENT_connect (sc->h->cfg, | ||
1284 | "fs", | ||
1285 | handlers, | ||
1286 | &search_mq_error_handler, | ||
1287 | sc); | ||
1288 | if (NULL == sc->mq) | ||
1289 | { | ||
1290 | try_reconnect (sc); | ||
1291 | return; | ||
1292 | } | ||
1293 | schedule_transmit_search_request (sc); | ||
1294 | } | ||
1295 | |||
1296 | |||
1297 | /** | ||
1298 | * Shutdown any existing connection to the FS | ||
1299 | * service and try to establish a fresh one | ||
1300 | * (and then re-transmit our search request). | ||
1301 | * | ||
1302 | * @param sc the search to reconnec | ||
1303 | */ | ||
1304 | static void | ||
1305 | try_reconnect (struct GNUNET_FS_SearchContext *sc) | ||
1306 | { | ||
1307 | if (NULL != sc->mq) | ||
1308 | { | ||
1309 | GNUNET_MQ_destroy (sc->mq); | ||
1310 | sc->mq = NULL; | ||
1311 | } | ||
1312 | sc->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (sc->reconnect_backoff); | ||
1313 | sc->task = | ||
1314 | GNUNET_SCHEDULER_add_delayed (sc->reconnect_backoff, | ||
1315 | &do_reconnect, | ||
1316 | sc); | ||
1317 | } | ||
1318 | |||
1319 | |||
1320 | /** | ||
1321 | * Start search for content, internal API. | ||
1322 | * | ||
1323 | * @param h handle to the file sharing subsystem | ||
1324 | * @param uri specifies the search parameters; can be | ||
1325 | * a KSK URI or an SKS URI. | ||
1326 | * @param anonymity desired level of anonymity | ||
1327 | * @param options options for the search | ||
1328 | * @param cctx initial value for the client context | ||
1329 | * @param psearch parent search result (for namespace update searches) | ||
1330 | * @return context that can be used to control the search | ||
1331 | */ | ||
1332 | static struct GNUNET_FS_SearchContext * | ||
1333 | search_start (struct GNUNET_FS_Handle *h, | ||
1334 | const struct GNUNET_FS_Uri *uri, | ||
1335 | uint32_t anonymity, | ||
1336 | enum GNUNET_FS_SearchOptions options, | ||
1337 | void *cctx, | ||
1338 | struct GNUNET_FS_SearchResult *psearch) | ||
1339 | { | ||
1340 | struct GNUNET_FS_SearchContext *sc; | ||
1341 | struct GNUNET_FS_ProgressInfo pi; | ||
1342 | |||
1343 | sc = GNUNET_new (struct GNUNET_FS_SearchContext); | ||
1344 | sc->h = h; | ||
1345 | sc->options = options; | ||
1346 | sc->uri = GNUNET_FS_uri_dup (uri); | ||
1347 | sc->anonymity = anonymity; | ||
1348 | sc->start_time = GNUNET_TIME_absolute_get (); | ||
1349 | if (NULL != psearch) | ||
1350 | { | ||
1351 | sc->psearch_result = psearch; | ||
1352 | psearch->update_search = sc; | ||
1353 | } | ||
1354 | sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO); | ||
1355 | sc->client_info = cctx; | ||
1356 | if (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc)) | ||
1357 | { | ||
1358 | GNUNET_FS_uri_destroy (sc->uri); | ||
1359 | GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); | ||
1360 | GNUNET_free (sc); | ||
1361 | return NULL; | ||
1362 | } | ||
1363 | GNUNET_FS_search_sync_ (sc); | ||
1364 | pi.status = GNUNET_FS_STATUS_SEARCH_START; | ||
1365 | sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); | ||
1366 | return sc; | ||
1367 | } | ||
1368 | |||
1369 | |||
1370 | /** | ||
1371 | * Update the 'results' map for the individual keywords with the | ||
1372 | * results from the 'global' result set. | ||
1373 | * | ||
1374 | * @param cls closure, the `struct GNUNET_FS_SearchContext *` | ||
1375 | * @param key current key code | ||
1376 | * @param value value in the hash map, the `struct GNUNET_FS_SearchResult *` | ||
1377 | * @return #GNUNET_YES (we should continue to iterate) | ||
1378 | */ | ||
1379 | static int | ||
1380 | update_sre_result_maps (void *cls, | ||
1381 | const struct GNUNET_HashCode *key, | ||
1382 | void *value) | ||
1383 | { | ||
1384 | struct GNUNET_FS_SearchContext *sc = cls; | ||
1385 | struct GNUNET_FS_SearchResult *sr = value; | ||
1386 | |||
1387 | for (unsigned int i = 0; i < sc->uri->data.ksk.keywordCount; i++) | ||
1388 | { | ||
1389 | if (0 != (sr->keyword_bitmap[i / 8] & (1 << (i % 8)))) | ||
1390 | GNUNET_break (GNUNET_OK == | ||
1391 | GNUNET_CONTAINER_multihashmap_put (sc->requests[i].results, | ||
1392 | &sr->key, | ||
1393 | sr, | ||
1394 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1395 | } | ||
1396 | return GNUNET_YES; | ||
1397 | } | ||
1398 | |||
1399 | |||
1400 | /** | ||
1401 | * Build the request and actually initiate the search using the | ||
1402 | * GNUnet FS service. | ||
1403 | * | ||
1404 | * @param sc search context | ||
1405 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1406 | */ | ||
1407 | int | ||
1408 | GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc) | ||
1409 | { | ||
1410 | unsigned int i; | ||
1411 | const char *keyword; | ||
1412 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon; | ||
1413 | struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub; | ||
1414 | struct SearchRequestEntry *sre; | ||
1415 | |||
1416 | GNUNET_assert (NULL == sc->mq); | ||
1417 | if (GNUNET_FS_uri_test_ksk (sc->uri)) | ||
1418 | { | ||
1419 | GNUNET_assert (0 != sc->uri->data.ksk.keywordCount); | ||
1420 | anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous (); | ||
1421 | GNUNET_CRYPTO_ecdsa_key_get_public (anon, &anon_pub); | ||
1422 | sc->requests | ||
1423 | = GNUNET_new_array (sc->uri->data.ksk.keywordCount, | ||
1424 | struct SearchRequestEntry); | ||
1425 | |||
1426 | for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) | ||
1427 | { | ||
1428 | keyword = &sc->uri->data.ksk.keywords[i][1]; | ||
1429 | sre = &sc->requests[i]; | ||
1430 | sre->keyword = GNUNET_strdup (keyword); | ||
1431 | GNUNET_CRYPTO_ecdsa_public_key_derive (&anon_pub, | ||
1432 | keyword, | ||
1433 | "fs-ublock", | ||
1434 | &sre->dpub); | ||
1435 | GNUNET_CRYPTO_hash (&sre->dpub, | ||
1436 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey), | ||
1437 | &sre->uquery); | ||
1438 | sre->mandatory = (sc->uri->data.ksk.keywords[i][0] == '+'); | ||
1439 | if (sre->mandatory) | ||
1440 | sc->mandatory_count++; | ||
1441 | sre->results = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO); | ||
1442 | } | ||
1443 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1444 | &update_sre_result_maps, | ||
1445 | sc); | ||
1446 | } | ||
1447 | GNUNET_assert (NULL == sc->task); | ||
1448 | do_reconnect (sc); | ||
1449 | if (NULL == sc->mq) | ||
1450 | { | ||
1451 | GNUNET_SCHEDULER_cancel (sc->task); | ||
1452 | sc->task = NULL; | ||
1453 | return GNUNET_SYSERR; | ||
1454 | } | ||
1455 | return GNUNET_OK; | ||
1456 | } | ||
1457 | |||
1458 | |||
1459 | /** | ||
1460 | * Freeze probes for the given search result. | ||
1461 | * | ||
1462 | * @param cls the global FS handle | ||
1463 | * @param key the key for the search result (unused) | ||
1464 | * @param value the search result to free | ||
1465 | * @return #GNUNET_OK | ||
1466 | */ | ||
1467 | static int | ||
1468 | search_result_freeze_probes (void *cls, | ||
1469 | const struct GNUNET_HashCode *key, | ||
1470 | void *value) | ||
1471 | { | ||
1472 | struct GNUNET_FS_SearchResult *sr = value; | ||
1473 | |||
1474 | if (NULL != sr->probe_ctx) | ||
1475 | { | ||
1476 | GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); | ||
1477 | sr->probe_ctx = NULL; | ||
1478 | GNUNET_FS_stop_probe_ping_task_ (sr); | ||
1479 | } | ||
1480 | if (NULL != sr->probe_cancel_task) | ||
1481 | { | ||
1482 | GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); | ||
1483 | sr->probe_cancel_task = NULL; | ||
1484 | } | ||
1485 | if (NULL != sr->update_search) | ||
1486 | GNUNET_FS_search_pause (sr->update_search); | ||
1487 | return GNUNET_OK; | ||
1488 | } | ||
1489 | |||
1490 | |||
1491 | /** | ||
1492 | * Resume probes for the given search result. | ||
1493 | * | ||
1494 | * @param cls the global FS handle | ||
1495 | * @param key the key for the search result (unused) | ||
1496 | * @param value the search result to free | ||
1497 | * @return #GNUNET_OK | ||
1498 | */ | ||
1499 | static int | ||
1500 | search_result_resume_probes (void *cls, | ||
1501 | const struct GNUNET_HashCode *key, | ||
1502 | void *value) | ||
1503 | { | ||
1504 | struct GNUNET_FS_SearchResult *sr = value; | ||
1505 | |||
1506 | GNUNET_FS_search_start_probe_ (sr); | ||
1507 | if (NULL != sr->update_search) | ||
1508 | GNUNET_FS_search_continue (sr->update_search); | ||
1509 | return GNUNET_OK; | ||
1510 | } | ||
1511 | |||
1512 | |||
1513 | /** | ||
1514 | * Signal suspend and free the given search result. | ||
1515 | * | ||
1516 | * @param cls the global FS handle | ||
1517 | * @param key the key for the search result (unused) | ||
1518 | * @param value the search result to free | ||
1519 | * @return #GNUNET_OK | ||
1520 | */ | ||
1521 | static int | ||
1522 | search_result_suspend (void *cls, | ||
1523 | const struct GNUNET_HashCode *key, | ||
1524 | void *value) | ||
1525 | { | ||
1526 | struct GNUNET_FS_SearchContext *sc = cls; | ||
1527 | struct GNUNET_FS_SearchResult *sr = value; | ||
1528 | struct GNUNET_FS_ProgressInfo pi; | ||
1529 | |||
1530 | if (NULL != sr->download) | ||
1531 | { | ||
1532 | GNUNET_FS_download_signal_suspend_ (sr->download); | ||
1533 | sr->download = NULL; | ||
1534 | } | ||
1535 | if (NULL != sr->update_search) | ||
1536 | { | ||
1537 | GNUNET_FS_search_signal_suspend_ (sr->update_search); | ||
1538 | sr->update_search = NULL; | ||
1539 | } | ||
1540 | GNUNET_FS_search_stop_probe_ (sr); | ||
1541 | if (0 == sr->mandatory_missing) | ||
1542 | { | ||
1543 | /* client is aware of search result, notify about suspension event */ | ||
1544 | pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND; | ||
1545 | pi.value.search.specifics.result_suspend.cctx = sr->client_info; | ||
1546 | pi.value.search.specifics.result_suspend.meta = sr->meta; | ||
1547 | pi.value.search.specifics.result_suspend.uri = sr->uri; | ||
1548 | sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); | ||
1549 | } | ||
1550 | GNUNET_break (NULL == sr->client_info); | ||
1551 | GNUNET_free (sr->serialization); | ||
1552 | GNUNET_FS_uri_destroy (sr->uri); | ||
1553 | GNUNET_CONTAINER_meta_data_destroy (sr->meta); | ||
1554 | GNUNET_free (sr->keyword_bitmap); | ||
1555 | GNUNET_free (sr); | ||
1556 | return GNUNET_OK; | ||
1557 | } | ||
1558 | |||
1559 | |||
1560 | /** | ||
1561 | * Create SUSPEND event for the given search operation | ||
1562 | * and then clean up our state (without stop signal). | ||
1563 | * | ||
1564 | * @param cls the `struct GNUNET_FS_SearchContext` to signal for | ||
1565 | */ | ||
1566 | void | ||
1567 | GNUNET_FS_search_signal_suspend_ (void *cls) | ||
1568 | { | ||
1569 | struct GNUNET_FS_SearchContext *sc = cls; | ||
1570 | struct GNUNET_FS_ProgressInfo pi; | ||
1571 | unsigned int i; | ||
1572 | |||
1573 | GNUNET_FS_end_top (sc->h, sc->top); | ||
1574 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1575 | &search_result_suspend, sc); | ||
1576 | pi.status = GNUNET_FS_STATUS_SEARCH_SUSPEND; | ||
1577 | sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); | ||
1578 | GNUNET_break (NULL == sc->client_info); | ||
1579 | if (sc->task != NULL) | ||
1580 | { | ||
1581 | GNUNET_SCHEDULER_cancel (sc->task); | ||
1582 | sc->task = NULL; | ||
1583 | } | ||
1584 | if (NULL != sc->mq) | ||
1585 | { | ||
1586 | GNUNET_MQ_destroy (sc->mq); | ||
1587 | sc->mq = NULL; | ||
1588 | } | ||
1589 | GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); | ||
1590 | if (NULL != sc->requests) | ||
1591 | { | ||
1592 | GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri)); | ||
1593 | for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) | ||
1594 | { | ||
1595 | GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results); | ||
1596 | GNUNET_free (sc->requests[i].keyword); | ||
1597 | } | ||
1598 | } | ||
1599 | GNUNET_free (sc->requests); | ||
1600 | GNUNET_free (sc->emsg); | ||
1601 | GNUNET_FS_uri_destroy (sc->uri); | ||
1602 | GNUNET_free (sc->serialization); | ||
1603 | GNUNET_free (sc); | ||
1604 | } | ||
1605 | |||
1606 | |||
1607 | /** | ||
1608 | * Start search for content. | ||
1609 | * | ||
1610 | * @param h handle to the file sharing subsystem | ||
1611 | * @param uri specifies the search parameters; can be | ||
1612 | * a KSK URI or an SKS URI. | ||
1613 | * @param anonymity desired level of anonymity | ||
1614 | * @param options options for the search | ||
1615 | * @param cctx initial value for the client context | ||
1616 | * @return context that can be used to control the search | ||
1617 | */ | ||
1618 | struct GNUNET_FS_SearchContext * | ||
1619 | GNUNET_FS_search_start (struct GNUNET_FS_Handle *h, | ||
1620 | const struct GNUNET_FS_Uri *uri, uint32_t anonymity, | ||
1621 | enum GNUNET_FS_SearchOptions options, void *cctx) | ||
1622 | { | ||
1623 | struct GNUNET_FS_SearchContext *ret; | ||
1624 | |||
1625 | ret = search_start (h, uri, anonymity, options, cctx, NULL); | ||
1626 | if (NULL == ret) | ||
1627 | return NULL; | ||
1628 | ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, ret); | ||
1629 | return ret; | ||
1630 | } | ||
1631 | |||
1632 | |||
1633 | /** | ||
1634 | * Pause search. | ||
1635 | * | ||
1636 | * @param sc context for the search that should be paused | ||
1637 | */ | ||
1638 | void | ||
1639 | GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc) | ||
1640 | { | ||
1641 | struct GNUNET_FS_ProgressInfo pi; | ||
1642 | |||
1643 | if (NULL != sc->task) | ||
1644 | { | ||
1645 | GNUNET_SCHEDULER_cancel (sc->task); | ||
1646 | sc->task = NULL; | ||
1647 | } | ||
1648 | if (NULL != sc->mq) | ||
1649 | { | ||
1650 | GNUNET_MQ_destroy (sc->mq); | ||
1651 | sc->mq = NULL; | ||
1652 | } | ||
1653 | GNUNET_FS_search_sync_ (sc); | ||
1654 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1655 | &search_result_freeze_probes, | ||
1656 | sc); | ||
1657 | pi.status = GNUNET_FS_STATUS_SEARCH_PAUSED; | ||
1658 | sc->client_info = GNUNET_FS_search_make_status_ (&pi, | ||
1659 | sc->h, | ||
1660 | sc); | ||
1661 | } | ||
1662 | |||
1663 | |||
1664 | /** | ||
1665 | * Continue paused search. | ||
1666 | * | ||
1667 | * @param sc context for the search that should be resumed | ||
1668 | */ | ||
1669 | void | ||
1670 | GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc) | ||
1671 | { | ||
1672 | struct GNUNET_FS_ProgressInfo pi; | ||
1673 | |||
1674 | GNUNET_assert (NULL == sc->mq); | ||
1675 | GNUNET_assert (NULL == sc->task); | ||
1676 | do_reconnect (sc); | ||
1677 | GNUNET_FS_search_sync_ (sc); | ||
1678 | pi.status = GNUNET_FS_STATUS_SEARCH_CONTINUED; | ||
1679 | sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); | ||
1680 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1681 | &search_result_resume_probes, sc); | ||
1682 | } | ||
1683 | |||
1684 | |||
1685 | /** | ||
1686 | * Signal stop for the given search result. | ||
1687 | * | ||
1688 | * @param cls the global FS handle | ||
1689 | * @param key the key for the search result (unused) | ||
1690 | * @param value the search result to free | ||
1691 | * @return #GNUNET_OK | ||
1692 | */ | ||
1693 | static int | ||
1694 | search_result_stop (void *cls, | ||
1695 | const struct GNUNET_HashCode *key, | ||
1696 | void *value) | ||
1697 | { | ||
1698 | struct GNUNET_FS_SearchContext *sc = cls; | ||
1699 | struct GNUNET_FS_SearchResult *sr = value; | ||
1700 | struct GNUNET_FS_ProgressInfo pi; | ||
1701 | |||
1702 | GNUNET_FS_search_stop_probe_ (sr); | ||
1703 | if (NULL != sr->download) | ||
1704 | { | ||
1705 | sr->download->search = NULL; | ||
1706 | sr->download->top | ||
1707 | = GNUNET_FS_make_top (sr->download->h, | ||
1708 | &GNUNET_FS_download_signal_suspend_, | ||
1709 | sr->download); | ||
1710 | if (NULL != sr->download->serialization) | ||
1711 | { | ||
1712 | GNUNET_FS_remove_sync_file_ (sc->h, | ||
1713 | GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD, | ||
1714 | sr->download->serialization); | ||
1715 | GNUNET_free (sr->download->serialization); | ||
1716 | sr->download->serialization = NULL; | ||
1717 | } | ||
1718 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT; | ||
1719 | GNUNET_FS_download_make_status_ (&pi, | ||
1720 | sr->download); | ||
1721 | GNUNET_FS_download_sync_ (sr->download); | ||
1722 | sr->download = NULL; | ||
1723 | } | ||
1724 | if (0 != sr->mandatory_missing) | ||
1725 | { | ||
1726 | /* client is unaware of search result as | ||
1727 | it does not match required keywords */ | ||
1728 | GNUNET_break (NULL == sr->client_info); | ||
1729 | return GNUNET_OK; | ||
1730 | } | ||
1731 | pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED; | ||
1732 | pi.value.search.specifics.result_stopped.cctx = sr->client_info; | ||
1733 | pi.value.search.specifics.result_stopped.meta = sr->meta; | ||
1734 | pi.value.search.specifics.result_stopped.uri = sr->uri; | ||
1735 | sr->client_info = GNUNET_FS_search_make_status_ (&pi, sr->h, sc); | ||
1736 | return GNUNET_OK; | ||
1737 | } | ||
1738 | |||
1739 | |||
1740 | /** | ||
1741 | * Free the given search result. | ||
1742 | * | ||
1743 | * @param cls the global FS handle | ||
1744 | * @param key the key for the search result (unused) | ||
1745 | * @param value the search result to free | ||
1746 | * @return #GNUNET_OK | ||
1747 | */ | ||
1748 | static int | ||
1749 | search_result_free (void *cls, | ||
1750 | const struct GNUNET_HashCode *key, | ||
1751 | void *value) | ||
1752 | { | ||
1753 | struct GNUNET_FS_SearchResult *sr = value; | ||
1754 | |||
1755 | if (NULL != sr->update_search) | ||
1756 | { | ||
1757 | GNUNET_FS_search_stop (sr->update_search); | ||
1758 | GNUNET_assert (NULL == sr->update_search); | ||
1759 | } | ||
1760 | GNUNET_break (NULL == sr->probe_ctx); | ||
1761 | GNUNET_break (NULL == sr->probe_cancel_task); | ||
1762 | GNUNET_break (NULL == sr->client_info); | ||
1763 | GNUNET_free (sr->serialization); | ||
1764 | GNUNET_FS_uri_destroy (sr->uri); | ||
1765 | GNUNET_CONTAINER_meta_data_destroy (sr->meta); | ||
1766 | GNUNET_free (sr->keyword_bitmap); | ||
1767 | GNUNET_free (sr); | ||
1768 | return GNUNET_OK; | ||
1769 | } | ||
1770 | |||
1771 | |||
1772 | /** | ||
1773 | * Stop search for content. | ||
1774 | * | ||
1775 | * @param sc context for the search that should be stopped | ||
1776 | */ | ||
1777 | void | ||
1778 | GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc) | ||
1779 | { | ||
1780 | struct GNUNET_FS_ProgressInfo pi; | ||
1781 | unsigned int i; | ||
1782 | |||
1783 | if (NULL != sc->top) | ||
1784 | GNUNET_FS_end_top (sc->h, sc->top); | ||
1785 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1786 | &search_result_stop, | ||
1787 | sc); | ||
1788 | if (NULL != sc->psearch_result) | ||
1789 | sc->psearch_result->update_search = NULL; | ||
1790 | if (NULL != sc->serialization) | ||
1791 | { | ||
1792 | GNUNET_FS_remove_sync_file_ (sc->h, | ||
1793 | (NULL != sc->psearch_result) | ||
1794 | ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH | ||
1795 | : GNUNET_FS_SYNC_PATH_MASTER_SEARCH, | ||
1796 | sc->serialization); | ||
1797 | GNUNET_FS_remove_sync_dir_ (sc->h, | ||
1798 | (NULL != sc->psearch_result) | ||
1799 | ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH | ||
1800 | : GNUNET_FS_SYNC_PATH_MASTER_SEARCH, | ||
1801 | sc->serialization); | ||
1802 | GNUNET_free (sc->serialization); | ||
1803 | } | ||
1804 | pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED; | ||
1805 | sc->client_info = GNUNET_FS_search_make_status_ (&pi, | ||
1806 | sc->h, | ||
1807 | sc); | ||
1808 | GNUNET_break (NULL == sc->client_info); | ||
1809 | if (NULL != sc->task) | ||
1810 | { | ||
1811 | GNUNET_SCHEDULER_cancel (sc->task); | ||
1812 | sc->task = NULL; | ||
1813 | } | ||
1814 | if (NULL != sc->mq) | ||
1815 | { | ||
1816 | GNUNET_MQ_destroy (sc->mq); | ||
1817 | sc->mq = NULL; | ||
1818 | } | ||
1819 | GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, | ||
1820 | &search_result_free, sc); | ||
1821 | GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); | ||
1822 | if (NULL != sc->requests) | ||
1823 | { | ||
1824 | GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri)); | ||
1825 | for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) | ||
1826 | GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results); | ||
1827 | } | ||
1828 | GNUNET_free (sc->requests); | ||
1829 | GNUNET_free (sc->emsg); | ||
1830 | GNUNET_FS_uri_destroy (sc->uri); | ||
1831 | GNUNET_free (sc); | ||
1832 | } | ||
1833 | |||
1834 | |||
1835 | /* end of fs_search.c */ | ||
diff --git a/src/fs/fs_sharetree.c b/src/fs/fs_sharetree.c deleted file mode 100644 index 3610b202e..000000000 --- a/src/fs/fs_sharetree.c +++ /dev/null | |||
@@ -1,456 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2005-2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_sharetree.c | ||
23 | * @brief code to manipulate the 'struct GNUNET_FS_ShareTreeItem' tree | ||
24 | * @author LRN | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_fs_service.h" | ||
29 | #include "gnunet_scheduler_lib.h" | ||
30 | #include <pthread.h> | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Entry for each unique keyword to track how often | ||
35 | * it occurred. Contains the keyword and the counter. | ||
36 | */ | ||
37 | struct KeywordCounter | ||
38 | { | ||
39 | /** | ||
40 | * This is a doubly-linked list | ||
41 | */ | ||
42 | struct KeywordCounter *prev; | ||
43 | |||
44 | /** | ||
45 | * This is a doubly-linked list | ||
46 | */ | ||
47 | struct KeywordCounter *next; | ||
48 | |||
49 | /** | ||
50 | * Keyword that was found. | ||
51 | */ | ||
52 | const char *value; | ||
53 | |||
54 | /** | ||
55 | * How many files have this keyword? | ||
56 | */ | ||
57 | unsigned int count; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Aggregate information we keep for meta data in each directory. | ||
63 | */ | ||
64 | struct MetaCounter | ||
65 | { | ||
66 | /** | ||
67 | * This is a doubly-linked list | ||
68 | */ | ||
69 | struct MetaCounter *prev; | ||
70 | |||
71 | /** | ||
72 | * This is a doubly-linked list | ||
73 | */ | ||
74 | struct MetaCounter *next; | ||
75 | |||
76 | /** | ||
77 | * Name of the plugin that provided that piece of metadata | ||
78 | */ | ||
79 | const char *plugin_name; | ||
80 | |||
81 | /** | ||
82 | * MIME-type of the metadata itself | ||
83 | */ | ||
84 | const char *data_mime_type; | ||
85 | |||
86 | /** | ||
87 | * The actual meta data. | ||
88 | */ | ||
89 | const char *data; | ||
90 | |||
91 | /** | ||
92 | * Number of bytes in 'data'. | ||
93 | */ | ||
94 | size_t data_size; | ||
95 | |||
96 | /** | ||
97 | * Type of the data | ||
98 | */ | ||
99 | enum EXTRACTOR_MetaType type; | ||
100 | |||
101 | /** | ||
102 | * Format of the data | ||
103 | */ | ||
104 | enum EXTRACTOR_MetaFormat format; | ||
105 | |||
106 | /** | ||
107 | * How many files have meta entries matching this value? | ||
108 | * (type and format do not have to match). | ||
109 | */ | ||
110 | unsigned int count; | ||
111 | }; | ||
112 | |||
113 | |||
114 | /** | ||
115 | * A structure that forms a singly-linked list that serves as a stack | ||
116 | * for metadata-processing function. | ||
117 | */ | ||
118 | struct TrimContext | ||
119 | { | ||
120 | /** | ||
121 | * Map from the hash over the keyword to an 'struct KeywordCounter *' | ||
122 | * counter that says how often this keyword was | ||
123 | * encountered in the current directory. | ||
124 | */ | ||
125 | struct GNUNET_CONTAINER_MultiHashMap *keywordcounter; | ||
126 | |||
127 | /** | ||
128 | * Map from the hash over the metadata to an 'struct MetaCounter *' | ||
129 | * counter that says how often this metadata was | ||
130 | * encountered in the current directory. | ||
131 | */ | ||
132 | struct GNUNET_CONTAINER_MultiHashMap *metacounter; | ||
133 | |||
134 | /** | ||
135 | * Position we are currently manipulating. | ||
136 | */ | ||
137 | struct GNUNET_FS_ShareTreeItem *pos; | ||
138 | |||
139 | /** | ||
140 | * Number of times an item has to be found to be moved to the parent. | ||
141 | */ | ||
142 | unsigned int move_threshold; | ||
143 | }; | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Add the given keyword to the keyword statistics tracker. | ||
148 | * | ||
149 | * @param cls the multihashmap we store the keyword counters in | ||
150 | * @param keyword the keyword to count | ||
151 | * @param is_mandatory ignored | ||
152 | * @return always GNUNET_OK | ||
153 | */ | ||
154 | static int | ||
155 | add_to_keyword_counter (void *cls, const char *keyword, int is_mandatory) | ||
156 | { | ||
157 | struct GNUNET_CONTAINER_MultiHashMap *mcm = cls; | ||
158 | struct KeywordCounter *cnt; | ||
159 | struct GNUNET_HashCode hc; | ||
160 | size_t klen; | ||
161 | |||
162 | klen = strlen (keyword) + 1; | ||
163 | GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); | ||
164 | cnt = GNUNET_CONTAINER_multihashmap_get (mcm, &hc); | ||
165 | if (cnt == NULL) | ||
166 | { | ||
167 | cnt = GNUNET_malloc (sizeof(struct KeywordCounter) + klen); | ||
168 | cnt->value = (const char *) &cnt[1]; | ||
169 | GNUNET_memcpy (&cnt[1], keyword, klen); | ||
170 | GNUNET_assert (GNUNET_OK == | ||
171 | GNUNET_CONTAINER_multihashmap_put (mcm, | ||
172 | &hc, cnt, | ||
173 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
174 | } | ||
175 | cnt->count++; | ||
176 | return GNUNET_OK; | ||
177 | } | ||
178 | |||
179 | |||
180 | /** | ||
181 | * Function called on each meta data item. Increments the | ||
182 | * respective counter. | ||
183 | * | ||
184 | * @param cls the container multihashmap to update | ||
185 | * @param plugin_name name of the plugin that produced this value; | ||
186 | * special values can be used (e.g. '<zlib>' for zlib being | ||
187 | * used in the main libextractor library and yielding | ||
188 | * meta data). | ||
189 | * @param type libextractor-type describing the meta data | ||
190 | * @param format basic format information about data | ||
191 | * @param data_mime_type mime-type of data (not of the original file); | ||
192 | * can be NULL (if mime-type is not known) | ||
193 | * @param data actual meta-data found | ||
194 | * @param data_len number of bytes in data | ||
195 | * @return 0 to continue extracting / iterating | ||
196 | */ | ||
197 | static int | ||
198 | add_to_meta_counter (void *cls, const char *plugin_name, | ||
199 | enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat | ||
200 | format, | ||
201 | const char *data_mime_type, const char *data, size_t | ||
202 | data_len) | ||
203 | { | ||
204 | struct GNUNET_CONTAINER_MultiHashMap *map = cls; | ||
205 | struct GNUNET_HashCode key; | ||
206 | struct MetaCounter *cnt; | ||
207 | |||
208 | GNUNET_CRYPTO_hash (data, data_len, &key); | ||
209 | cnt = GNUNET_CONTAINER_multihashmap_get (map, &key); | ||
210 | if (NULL == cnt) | ||
211 | { | ||
212 | cnt = GNUNET_new (struct MetaCounter); | ||
213 | cnt->data = data; | ||
214 | cnt->data_size = data_len; | ||
215 | cnt->plugin_name = plugin_name; | ||
216 | cnt->type = type; | ||
217 | cnt->format = format; | ||
218 | cnt->data_mime_type = data_mime_type; | ||
219 | GNUNET_assert (GNUNET_OK == | ||
220 | GNUNET_CONTAINER_multihashmap_put (map, | ||
221 | &key, cnt, | ||
222 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
223 | } | ||
224 | cnt->count++; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Remove keywords above the threshold. | ||
231 | * | ||
232 | * @param cls the 'struct TrimContext' with the pos to remove the keywords from | ||
233 | * @param keyword the keyword to check | ||
234 | * @param is_mandatory ignored | ||
235 | * @return always GNUNET_OK | ||
236 | */ | ||
237 | static int | ||
238 | remove_high_frequency_keywords (void *cls, const char *keyword, int | ||
239 | is_mandatory) | ||
240 | { | ||
241 | struct TrimContext *tc = cls; | ||
242 | struct KeywordCounter *counter; | ||
243 | struct GNUNET_HashCode hc; | ||
244 | size_t klen; | ||
245 | |||
246 | klen = strlen (keyword) + 1; | ||
247 | GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); | ||
248 | counter = GNUNET_CONTAINER_multihashmap_get (tc->keywordcounter, &hc); | ||
249 | GNUNET_assert (NULL != counter); | ||
250 | if (counter->count < tc->move_threshold) | ||
251 | return GNUNET_OK; | ||
252 | GNUNET_FS_uri_ksk_remove_keyword (tc->pos->ksk_uri, | ||
253 | counter->value); | ||
254 | return GNUNET_OK; | ||
255 | } | ||
256 | |||
257 | |||
258 | /** | ||
259 | * Move "frequent" keywords over to the target ksk uri, free the | ||
260 | * counters. | ||
261 | * | ||
262 | * @param cls the 'struct TrimContext' | ||
263 | * @param key key of the entry | ||
264 | * @param value the 'struct KeywordCounter' | ||
265 | * @return GNUNET_YES (always) | ||
266 | */ | ||
267 | static int | ||
268 | migrate_and_drop_keywords (void *cls, const struct GNUNET_HashCode *key, | ||
269 | void *value) | ||
270 | { | ||
271 | struct TrimContext *tc = cls; | ||
272 | struct KeywordCounter *counter = value; | ||
273 | |||
274 | if (counter->count >= tc->move_threshold) | ||
275 | { | ||
276 | if (NULL == tc->pos->ksk_uri) | ||
277 | tc->pos->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, | ||
278 | &counter->value); | ||
279 | else | ||
280 | GNUNET_FS_uri_ksk_add_keyword (tc->pos->ksk_uri, counter->value, | ||
281 | GNUNET_NO); | ||
282 | } | ||
283 | GNUNET_assert (GNUNET_YES == | ||
284 | GNUNET_CONTAINER_multihashmap_remove (tc->keywordcounter, | ||
285 | key, | ||
286 | counter)); | ||
287 | GNUNET_free (counter); | ||
288 | return GNUNET_YES; | ||
289 | } | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Copy "frequent" metadata items over to the | ||
294 | * target metadata container, free the counters. | ||
295 | * | ||
296 | * @param cls the 'struct TrimContext' | ||
297 | * @param key key of the entry | ||
298 | * @param value the 'struct KeywordCounter' | ||
299 | * @return GNUNET_YES (always) | ||
300 | */ | ||
301 | static int | ||
302 | migrate_and_drop_metadata (void *cls, const struct GNUNET_HashCode *key, | ||
303 | void *value) | ||
304 | { | ||
305 | struct TrimContext *tc = cls; | ||
306 | struct MetaCounter *counter = value; | ||
307 | |||
308 | if (counter->count >= tc->move_threshold) | ||
309 | { | ||
310 | if (NULL == tc->pos->meta) | ||
311 | tc->pos->meta = GNUNET_CONTAINER_meta_data_create (); | ||
312 | GNUNET_CONTAINER_meta_data_insert (tc->pos->meta, | ||
313 | counter->plugin_name, | ||
314 | counter->type, | ||
315 | counter->format, | ||
316 | counter->data_mime_type, counter->data, | ||
317 | counter->data_size); | ||
318 | } | ||
319 | GNUNET_assert (GNUNET_YES == | ||
320 | GNUNET_CONTAINER_multihashmap_remove (tc->metacounter, | ||
321 | key, | ||
322 | counter)); | ||
323 | GNUNET_free (counter); | ||
324 | return GNUNET_YES; | ||
325 | } | ||
326 | |||
327 | |||
328 | /** | ||
329 | * Process a share item tree, moving frequent keywords up and | ||
330 | * copying frequent metadata up. | ||
331 | * | ||
332 | * @param tc trim context with hash maps to use | ||
333 | * @param tree tree to trim | ||
334 | */ | ||
335 | static void | ||
336 | share_tree_trim (struct TrimContext *tc, | ||
337 | struct GNUNET_FS_ShareTreeItem *tree) | ||
338 | { | ||
339 | struct GNUNET_FS_ShareTreeItem *pos; | ||
340 | unsigned int num_children; | ||
341 | |||
342 | /* first, trim all children */ | ||
343 | num_children = 0; | ||
344 | for (pos = tree->children_head; NULL != pos; pos = pos->next) | ||
345 | { | ||
346 | share_tree_trim (tc, pos); | ||
347 | num_children++; | ||
348 | } | ||
349 | |||
350 | /* consider adding filename to directory meta data */ | ||
351 | if (tree->is_directory == GNUNET_YES) | ||
352 | { | ||
353 | const char *user = getenv ("USER"); | ||
354 | if ((user == NULL) || | ||
355 | (0 != strncasecmp (user, tree->short_filename, strlen (user)))) | ||
356 | { | ||
357 | /* only use filename if it doesn't match $USER */ | ||
358 | if (NULL == tree->meta) | ||
359 | tree->meta = GNUNET_CONTAINER_meta_data_create (); | ||
360 | GNUNET_CONTAINER_meta_data_insert (tree->meta, "<libgnunetfs>", | ||
361 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, | ||
362 | EXTRACTOR_METAFORMAT_UTF8, | ||
363 | "text/plain", tree->short_filename, | ||
364 | strlen (tree->short_filename) + 1); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | if (1 >= num_children) | ||
369 | return; /* nothing to trim */ | ||
370 | |||
371 | /* now, count keywords and meta data in children */ | ||
372 | for (pos = tree->children_head; NULL != pos; pos = pos->next) | ||
373 | { | ||
374 | if (NULL != pos->meta) | ||
375 | GNUNET_CONTAINER_meta_data_iterate (pos->meta, &add_to_meta_counter, | ||
376 | tc->metacounter); | ||
377 | if (NULL != pos->ksk_uri) | ||
378 | GNUNET_FS_uri_ksk_get_keywords (pos->ksk_uri, &add_to_keyword_counter, | ||
379 | tc->keywordcounter); | ||
380 | } | ||
381 | |||
382 | /* calculate threshold for moving keywords / meta data */ | ||
383 | tc->move_threshold = 1 + (num_children / 2); | ||
384 | |||
385 | /* remove high-frequency keywords from children */ | ||
386 | for (pos = tree->children_head; NULL != pos; pos = pos->next) | ||
387 | { | ||
388 | tc->pos = pos; | ||
389 | if (NULL != pos->ksk_uri) | ||
390 | { | ||
391 | struct GNUNET_FS_Uri *ksk_uri_copy = GNUNET_FS_uri_dup (pos->ksk_uri); | ||
392 | GNUNET_FS_uri_ksk_get_keywords (ksk_uri_copy, | ||
393 | &remove_high_frequency_keywords, tc); | ||
394 | GNUNET_FS_uri_destroy (ksk_uri_copy); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | /* add high-frequency meta data and keywords to parent */ | ||
399 | tc->pos = tree; | ||
400 | GNUNET_CONTAINER_multihashmap_iterate (tc->keywordcounter, | ||
401 | &migrate_and_drop_keywords, | ||
402 | tc); | ||
403 | GNUNET_CONTAINER_multihashmap_iterate (tc->metacounter, | ||
404 | &migrate_and_drop_metadata, | ||
405 | tc); | ||
406 | } | ||
407 | |||
408 | |||
409 | /** | ||
410 | * Process a share item tree, moving frequent keywords up and | ||
411 | * copying frequent metadata up. | ||
412 | * | ||
413 | * @param toplevel toplevel directory in the tree, returned by the scanner | ||
414 | */ | ||
415 | void | ||
416 | GNUNET_FS_share_tree_trim (struct GNUNET_FS_ShareTreeItem *toplevel) | ||
417 | { | ||
418 | struct TrimContext tc; | ||
419 | |||
420 | if (toplevel == NULL) | ||
421 | return; | ||
422 | tc.keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO); | ||
423 | tc.metacounter = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO); | ||
424 | share_tree_trim (&tc, toplevel); | ||
425 | GNUNET_CONTAINER_multihashmap_destroy (tc.keywordcounter); | ||
426 | GNUNET_CONTAINER_multihashmap_destroy (tc.metacounter); | ||
427 | } | ||
428 | |||
429 | |||
430 | /** | ||
431 | * Release memory of a share item tree. | ||
432 | * | ||
433 | * @param toplevel toplevel of the tree to be freed | ||
434 | */ | ||
435 | void | ||
436 | GNUNET_FS_share_tree_free (struct GNUNET_FS_ShareTreeItem *toplevel) | ||
437 | { | ||
438 | struct GNUNET_FS_ShareTreeItem *pos; | ||
439 | |||
440 | while (NULL != (pos = toplevel->children_head)) | ||
441 | GNUNET_FS_share_tree_free (pos); | ||
442 | if (NULL != toplevel->parent) | ||
443 | GNUNET_CONTAINER_DLL_remove (toplevel->parent->children_head, | ||
444 | toplevel->parent->children_tail, | ||
445 | toplevel); | ||
446 | if (NULL != toplevel->meta) | ||
447 | GNUNET_CONTAINER_meta_data_destroy (toplevel->meta); | ||
448 | if (NULL != toplevel->ksk_uri) | ||
449 | GNUNET_FS_uri_destroy (toplevel->ksk_uri); | ||
450 | GNUNET_free (toplevel->filename); | ||
451 | GNUNET_free (toplevel->short_filename); | ||
452 | GNUNET_free (toplevel); | ||
453 | } | ||
454 | |||
455 | |||
456 | /* end fs_sharetree.c */ | ||
diff --git a/src/fs/fs_test_lib.c b/src/fs/fs_test_lib.c deleted file mode 100644 index dc4b214d9..000000000 --- a/src/fs/fs_test_lib.c +++ /dev/null | |||
@@ -1,659 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2011, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_test_lib.c | ||
23 | * @brief library routines for testing FS publishing and downloading; | ||
24 | * this code is limited to flat files | ||
25 | * and no keywords (those functions can be tested with | ||
26 | * single-peer setups; this is for testing routing). | ||
27 | * @author Christian Grothoff | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include "fs_api.h" | ||
31 | #include "fs_test_lib.h" | ||
32 | |||
33 | |||
34 | #define CONTENT_LIFETIME GNUNET_TIME_UNIT_HOURS | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Handle for a publishing operation started for testing FS. | ||
39 | */ | ||
40 | struct TestPublishOperation | ||
41 | { | ||
42 | /** | ||
43 | * Handle for the operation to connect to the peer's 'fs' service. | ||
44 | */ | ||
45 | struct GNUNET_TESTBED_Operation *fs_op; | ||
46 | |||
47 | /** | ||
48 | * Handle to the file sharing context using this daemon. | ||
49 | */ | ||
50 | struct GNUNET_FS_Handle *fs; | ||
51 | |||
52 | /** | ||
53 | * Function to call when upload is done. | ||
54 | */ | ||
55 | GNUNET_FS_TEST_UriContinuation publish_cont; | ||
56 | |||
57 | /** | ||
58 | * Closure for publish_cont. | ||
59 | */ | ||
60 | void *publish_cont_cls; | ||
61 | |||
62 | /** | ||
63 | * Task to abort publishing (timeout). | ||
64 | */ | ||
65 | struct GNUNET_SCHEDULER_Task *publish_timeout_task; | ||
66 | |||
67 | /** | ||
68 | * Seed for file generation. | ||
69 | */ | ||
70 | uint32_t publish_seed; | ||
71 | |||
72 | /** | ||
73 | * Context for current publishing operation. | ||
74 | */ | ||
75 | struct GNUNET_FS_PublishContext *publish_context; | ||
76 | |||
77 | /** | ||
78 | * Result URI. | ||
79 | */ | ||
80 | struct GNUNET_FS_Uri *publish_uri; | ||
81 | |||
82 | /** | ||
83 | * Name of the temporary file used, or NULL for none. | ||
84 | */ | ||
85 | char *publish_tmp_file; | ||
86 | |||
87 | /** | ||
88 | * Size of the file. | ||
89 | */ | ||
90 | uint64_t size; | ||
91 | |||
92 | /** | ||
93 | * Anonymity level used. | ||
94 | */ | ||
95 | uint32_t anonymity; | ||
96 | |||
97 | /** | ||
98 | * Verbosity level of the current operation. | ||
99 | */ | ||
100 | unsigned int verbose; | ||
101 | |||
102 | /** | ||
103 | * Are we testing indexing? (YES: index, NO: insert, SYSERR: simulate) | ||
104 | */ | ||
105 | int do_index; | ||
106 | }; | ||
107 | |||
108 | |||
109 | /** | ||
110 | * Handle for a download operation started for testing FS. | ||
111 | */ | ||
112 | struct TestDownloadOperation | ||
113 | { | ||
114 | /** | ||
115 | * Handle for the operation to connect to the peer's 'fs' service. | ||
116 | */ | ||
117 | struct GNUNET_TESTBED_Operation *fs_op; | ||
118 | |||
119 | /** | ||
120 | * Handle to the file sharing context using this daemon. | ||
121 | */ | ||
122 | struct GNUNET_FS_Handle *fs; | ||
123 | |||
124 | /** | ||
125 | * Handle to the daemon via testing. | ||
126 | */ | ||
127 | struct GNUNET_TESTING_Daemon *daemon; | ||
128 | |||
129 | /** | ||
130 | * Function to call when download is done. | ||
131 | */ | ||
132 | GNUNET_SCHEDULER_TaskCallback download_cont; | ||
133 | |||
134 | /** | ||
135 | * Closure for download_cont. | ||
136 | */ | ||
137 | void *download_cont_cls; | ||
138 | |||
139 | /** | ||
140 | * URI to download. | ||
141 | */ | ||
142 | struct GNUNET_FS_Uri *uri; | ||
143 | |||
144 | /** | ||
145 | * Task to abort downloading (timeout). | ||
146 | */ | ||
147 | struct GNUNET_SCHEDULER_Task *download_timeout_task; | ||
148 | |||
149 | /** | ||
150 | * Context for current download operation. | ||
151 | */ | ||
152 | struct GNUNET_FS_DownloadContext *download_context; | ||
153 | |||
154 | /** | ||
155 | * Size of the file. | ||
156 | */ | ||
157 | uint64_t size; | ||
158 | |||
159 | /** | ||
160 | * Anonymity level used. | ||
161 | */ | ||
162 | uint32_t anonymity; | ||
163 | |||
164 | /** | ||
165 | * Seed for download verification. | ||
166 | */ | ||
167 | uint32_t download_seed; | ||
168 | |||
169 | /** | ||
170 | * Verbosity level of the current operation. | ||
171 | */ | ||
172 | unsigned int verbose; | ||
173 | }; | ||
174 | |||
175 | |||
176 | /** | ||
177 | * Task scheduled to report on the completion of our publish operation. | ||
178 | * | ||
179 | * @param cls the publish operation context | ||
180 | * @param tc scheduler context (unused) | ||
181 | */ | ||
182 | static void | ||
183 | report_uri (void *cls) | ||
184 | { | ||
185 | struct TestPublishOperation *po = cls; | ||
186 | |||
187 | GNUNET_FS_publish_stop (po->publish_context); | ||
188 | GNUNET_TESTBED_operation_done (po->fs_op); | ||
189 | po->publish_cont (po->publish_cont_cls, | ||
190 | po->publish_uri, | ||
191 | (GNUNET_YES == po->do_index) | ||
192 | ? po->publish_tmp_file | ||
193 | : NULL); | ||
194 | GNUNET_FS_uri_destroy (po->publish_uri); | ||
195 | if ((GNUNET_YES != po->do_index) && | ||
196 | (NULL != po->publish_tmp_file)) | ||
197 | (void) GNUNET_DISK_directory_remove (po->publish_tmp_file); | ||
198 | GNUNET_free (po->publish_tmp_file); | ||
199 | GNUNET_free (po); | ||
200 | } | ||
201 | |||
202 | |||
203 | /** | ||
204 | * Task scheduled to run when publish operation times out. | ||
205 | * | ||
206 | * @param cls the publish operation context | ||
207 | */ | ||
208 | static void | ||
209 | publish_timeout (void *cls) | ||
210 | { | ||
211 | struct TestPublishOperation *po = cls; | ||
212 | |||
213 | po->publish_timeout_task = NULL; | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
215 | "Timeout while trying to publish data\n"); | ||
216 | GNUNET_TESTBED_operation_done (po->fs_op); | ||
217 | GNUNET_FS_publish_stop (po->publish_context); | ||
218 | po->publish_cont (po->publish_cont_cls, NULL, NULL); | ||
219 | (void) GNUNET_DISK_directory_remove (po->publish_tmp_file); | ||
220 | GNUNET_free (po->publish_tmp_file); | ||
221 | GNUNET_free (po); | ||
222 | } | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Progress callback for file-sharing events while publishing. | ||
227 | * | ||
228 | * @param cls the publish operation context | ||
229 | * @param info information about the event | ||
230 | */ | ||
231 | static void * | ||
232 | publish_progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) | ||
233 | { | ||
234 | struct TestPublishOperation *po = cls; | ||
235 | |||
236 | switch (info->status) | ||
237 | { | ||
238 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
239 | GNUNET_SCHEDULER_cancel (po->publish_timeout_task); | ||
240 | po->publish_timeout_task = NULL; | ||
241 | po->publish_uri = | ||
242 | GNUNET_FS_uri_dup (info->value.publish.specifics.completed.chk_uri); | ||
243 | GNUNET_SCHEDULER_add_now (&report_uri, | ||
244 | po); | ||
245 | break; | ||
246 | |||
247 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
248 | if (po->verbose) | ||
249 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Publishing at %llu/%llu bytes\n", | ||
250 | (unsigned long long) info->value.publish.completed, | ||
251 | (unsigned long long) info->value.publish.size); | ||
252 | break; | ||
253 | |||
254 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
255 | break; | ||
256 | |||
257 | case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: | ||
258 | if (po->verbose) | ||
259 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Download at %llu/%llu bytes\n", | ||
260 | (unsigned long long) info->value.download.completed, | ||
261 | (unsigned long long) info->value.download.size); | ||
262 | break; | ||
263 | |||
264 | default: | ||
265 | break; | ||
266 | } | ||
267 | return NULL; | ||
268 | } | ||
269 | |||
270 | |||
271 | /** | ||
272 | * Generate test data for publishing test. | ||
273 | * | ||
274 | * @param cls pointer to uint32_t with publishing seed | ||
275 | * @param offset offset to generate data for | ||
276 | * @param max maximum number of bytes to generate | ||
277 | * @param buf where to write generated data | ||
278 | * @param emsg where to store error message (unused) | ||
279 | * @return number of bytes written to buf | ||
280 | */ | ||
281 | static size_t | ||
282 | file_generator (void *cls, | ||
283 | uint64_t offset, | ||
284 | size_t max, | ||
285 | void *buf, | ||
286 | char **emsg) | ||
287 | { | ||
288 | uint32_t *publish_seed = cls; | ||
289 | uint64_t pos; | ||
290 | uint8_t *cbuf = buf; | ||
291 | int mod; | ||
292 | |||
293 | if (emsg != NULL) | ||
294 | *emsg = NULL; | ||
295 | if (buf == NULL) | ||
296 | return 0; | ||
297 | for (pos = 0; pos < 8; pos++) | ||
298 | cbuf[pos] = (uint8_t) (offset >> pos * 8); | ||
299 | for (pos = 8; pos < max; pos++) | ||
300 | { | ||
301 | mod = (255 - (offset / 1024 / 32)); | ||
302 | if (mod == 0) | ||
303 | mod = 1; | ||
304 | cbuf[pos] = (uint8_t) ((offset * (*publish_seed)) % mod); | ||
305 | } | ||
306 | return max; | ||
307 | } | ||
308 | |||
309 | |||
310 | /** | ||
311 | * Connect adapter for publishing operation. | ||
312 | * | ||
313 | * @param cls the 'struct TestPublishOperation' | ||
314 | * @param cfg configuration of the peer to connect to; will be available until | ||
315 | * GNUNET_TESTBED_operation_done() is called on the operation returned | ||
316 | * from GNUNET_TESTBED_service_connect() | ||
317 | * @return service handle to return in 'op_result', NULL on error | ||
318 | */ | ||
319 | static void * | ||
320 | publish_connect_adapter (void *cls, | ||
321 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
322 | { | ||
323 | struct TestPublishOperation *po = cls; | ||
324 | |||
325 | return GNUNET_FS_start (cfg, | ||
326 | "fs-test-publish", | ||
327 | &publish_progress_cb, po, | ||
328 | GNUNET_FS_FLAGS_NONE, | ||
329 | GNUNET_FS_OPTIONS_END); | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Adapter function called to destroy connection to file-sharing service. | ||
335 | * | ||
336 | * @param cls the 'struct GNUNET_FS_Handle' | ||
337 | * @param op_result unused (different for publish/download!) | ||
338 | */ | ||
339 | static void | ||
340 | fs_disconnect_adapter (void *cls, | ||
341 | void *op_result) | ||
342 | { | ||
343 | struct GNUNET_FS_Handle *fs = op_result; | ||
344 | |||
345 | GNUNET_FS_stop (fs); | ||
346 | } | ||
347 | |||
348 | |||
349 | /** | ||
350 | * Callback to be called when testbed has connected to the fs service | ||
351 | * | ||
352 | * @param cls the 'struct TestPublishOperation' | ||
353 | * @param op the operation that has been finished | ||
354 | * @param ca_result the 'struct GNUNET_FS_Handle ' (NULL on error) | ||
355 | * @param emsg error message in case the operation has failed; will be NULL if | ||
356 | * operation has executed successfully. | ||
357 | */ | ||
358 | static void | ||
359 | publish_fs_connect_complete_cb (void *cls, | ||
360 | struct GNUNET_TESTBED_Operation *op, | ||
361 | void *ca_result, | ||
362 | const char *emsg) | ||
363 | { | ||
364 | struct TestPublishOperation *po = cls; | ||
365 | struct GNUNET_FS_FileInformation *fi; | ||
366 | struct GNUNET_DISK_FileHandle *fh; | ||
367 | char *em; | ||
368 | uint64_t off; | ||
369 | char buf[DBLOCK_SIZE]; | ||
370 | size_t bsize; | ||
371 | struct GNUNET_FS_BlockOptions bo; | ||
372 | |||
373 | if (NULL == ca_result) | ||
374 | { | ||
375 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
376 | "Failed to connect to FS for publishing: %s\n", emsg); | ||
377 | po->publish_cont (po->publish_cont_cls, | ||
378 | NULL, NULL); | ||
379 | GNUNET_TESTBED_operation_done (po->fs_op); | ||
380 | GNUNET_free (po); | ||
381 | return; | ||
382 | } | ||
383 | po->fs = ca_result; | ||
384 | |||
385 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (CONTENT_LIFETIME); | ||
386 | bo.anonymity_level = po->anonymity; | ||
387 | bo.content_priority = 42; | ||
388 | bo.replication_level = 1; | ||
389 | if (GNUNET_YES == po->do_index) | ||
390 | { | ||
391 | po->publish_tmp_file = GNUNET_DISK_mktemp ("fs-test-publish-index"); | ||
392 | GNUNET_assert (po->publish_tmp_file != NULL); | ||
393 | fh = GNUNET_DISK_file_open (po->publish_tmp_file, | ||
394 | GNUNET_DISK_OPEN_WRITE | ||
395 | | GNUNET_DISK_OPEN_CREATE, | ||
396 | GNUNET_DISK_PERM_USER_READ | ||
397 | | GNUNET_DISK_PERM_USER_WRITE); | ||
398 | GNUNET_assert (NULL != fh); | ||
399 | off = 0; | ||
400 | while (off < po->size) | ||
401 | { | ||
402 | bsize = GNUNET_MIN (sizeof(buf), po->size - off); | ||
403 | emsg = NULL; | ||
404 | GNUNET_assert (bsize == file_generator (&po->publish_seed, off, bsize, | ||
405 | buf, &em)); | ||
406 | GNUNET_assert (em == NULL); | ||
407 | GNUNET_assert (bsize == GNUNET_DISK_file_write (fh, buf, bsize)); | ||
408 | off += bsize; | ||
409 | } | ||
410 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); | ||
411 | fi = GNUNET_FS_file_information_create_from_file (po->fs, po, | ||
412 | po->publish_tmp_file, | ||
413 | NULL, NULL, po->do_index, | ||
414 | &bo); | ||
415 | GNUNET_assert (NULL != fi); | ||
416 | } | ||
417 | else | ||
418 | { | ||
419 | fi = GNUNET_FS_file_information_create_from_reader (po->fs, po, | ||
420 | po->size, | ||
421 | &file_generator, | ||
422 | &po->publish_seed, | ||
423 | NULL, NULL, | ||
424 | po->do_index, &bo); | ||
425 | GNUNET_assert (NULL != fi); | ||
426 | } | ||
427 | po->publish_context = | ||
428 | GNUNET_FS_publish_start (po->fs, fi, NULL, NULL, NULL, | ||
429 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
430 | } | ||
431 | |||
432 | |||
433 | /** | ||
434 | * Publish a file at the given peer. | ||
435 | * | ||
436 | * @param peer where to publish | ||
437 | * @param timeout if this operation cannot be completed within the | ||
438 | * given period, call the continuation with an error code | ||
439 | * @param anonymity option for publication | ||
440 | * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, | ||
441 | * GNUNET_SYSERR for simulation | ||
442 | * @param size size of the file to publish | ||
443 | * @param seed seed to use for file generation | ||
444 | * @param verbose how verbose to be in reporting | ||
445 | * @param cont function to call when done | ||
446 | * @param cont_cls closure for cont | ||
447 | */ | ||
448 | void | ||
449 | GNUNET_FS_TEST_publish (struct GNUNET_TESTBED_Peer *peer, | ||
450 | struct GNUNET_TIME_Relative timeout, uint32_t anonymity, | ||
451 | int do_index, uint64_t size, uint32_t seed, | ||
452 | unsigned int verbose, | ||
453 | GNUNET_FS_TEST_UriContinuation cont, void *cont_cls) | ||
454 | { | ||
455 | struct TestPublishOperation *po; | ||
456 | |||
457 | po = GNUNET_new (struct TestPublishOperation); | ||
458 | po->publish_cont = cont; | ||
459 | po->publish_cont_cls = cont_cls; | ||
460 | po->publish_seed = seed; | ||
461 | po->anonymity = anonymity; | ||
462 | po->size = size; | ||
463 | po->verbose = verbose; | ||
464 | po->do_index = do_index; | ||
465 | po->fs_op = GNUNET_TESTBED_service_connect (po, | ||
466 | peer, | ||
467 | "fs", | ||
468 | &publish_fs_connect_complete_cb, | ||
469 | po, | ||
470 | &publish_connect_adapter, | ||
471 | &fs_disconnect_adapter, | ||
472 | po); | ||
473 | po->publish_timeout_task = | ||
474 | GNUNET_SCHEDULER_add_delayed (timeout, &publish_timeout, po); | ||
475 | } | ||
476 | |||
477 | |||
478 | /* ************************** download ************************ */ | ||
479 | |||
480 | |||
481 | /** | ||
482 | * Task scheduled to run when download operation times out. | ||
483 | * | ||
484 | * @param cls the download operation context | ||
485 | */ | ||
486 | static void | ||
487 | download_timeout (void *cls) | ||
488 | { | ||
489 | struct TestDownloadOperation *dop = cls; | ||
490 | |||
491 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
492 | "Timeout while trying to download file\n"); | ||
493 | dop->download_timeout_task = NULL; | ||
494 | GNUNET_FS_download_stop (dop->download_context, | ||
495 | GNUNET_YES); | ||
496 | GNUNET_SCHEDULER_add_now (dop->download_cont, | ||
497 | dop->download_cont_cls); | ||
498 | GNUNET_TESTBED_operation_done (dop->fs_op); | ||
499 | GNUNET_FS_uri_destroy (dop->uri); | ||
500 | GNUNET_free (dop); | ||
501 | } | ||
502 | |||
503 | |||
504 | /** | ||
505 | * Task scheduled to report on the completion of our download operation. | ||
506 | * | ||
507 | * @param cls the download operation context | ||
508 | */ | ||
509 | static void | ||
510 | report_success (void *cls) | ||
511 | { | ||
512 | struct TestDownloadOperation *dop = cls; | ||
513 | |||
514 | GNUNET_FS_download_stop (dop->download_context, | ||
515 | GNUNET_YES); | ||
516 | GNUNET_SCHEDULER_add_now (dop->download_cont, | ||
517 | dop->download_cont_cls); | ||
518 | GNUNET_TESTBED_operation_done (dop->fs_op); | ||
519 | GNUNET_FS_uri_destroy (dop->uri); | ||
520 | GNUNET_free (dop); | ||
521 | } | ||
522 | |||
523 | |||
524 | /** | ||
525 | * Progress callback for file-sharing events while downloading. | ||
526 | * | ||
527 | * @param cls the download operation context | ||
528 | * @param info information about the event | ||
529 | */ | ||
530 | static void * | ||
531 | download_progress_cb (void *cls, | ||
532 | const struct GNUNET_FS_ProgressInfo *info) | ||
533 | { | ||
534 | struct TestDownloadOperation *dop = cls; | ||
535 | |||
536 | switch (info->status) | ||
537 | { | ||
538 | case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: | ||
539 | if (dop->verbose) | ||
540 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
541 | "Download at %llu/%llu bytes\n", | ||
542 | (unsigned long long) info->value.download.completed, | ||
543 | (unsigned long long) info->value.download.size); | ||
544 | break; | ||
545 | |||
546 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: | ||
547 | GNUNET_SCHEDULER_cancel (dop->download_timeout_task); | ||
548 | dop->download_timeout_task = NULL; | ||
549 | GNUNET_SCHEDULER_add_now (&report_success, dop); | ||
550 | break; | ||
551 | |||
552 | case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: | ||
553 | case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: | ||
554 | break; | ||
555 | |||
556 | /* FIXME: monitor data correctness during download progress */ | ||
557 | /* FIXME: do performance reports given sufficient verbosity */ | ||
558 | /* FIXME: advance timeout task to "immediate" on error */ | ||
559 | default: | ||
560 | break; | ||
561 | } | ||
562 | return NULL; | ||
563 | } | ||
564 | |||
565 | |||
566 | /** | ||
567 | * Connect adapter for download operation. | ||
568 | * | ||
569 | * @param cls the 'struct TestDownloadOperation' | ||
570 | * @param cfg configuration of the peer to connect to; will be available until | ||
571 | * GNUNET_TESTBED_operation_done() is called on the operation returned | ||
572 | * from GNUNET_TESTBED_service_connect() | ||
573 | * @return service handle to return in 'op_result', NULL on error | ||
574 | */ | ||
575 | static void * | ||
576 | download_connect_adapter (void *cls, | ||
577 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
578 | { | ||
579 | struct TestPublishOperation *po = cls; | ||
580 | |||
581 | return GNUNET_FS_start (cfg, | ||
582 | "fs-test-download", | ||
583 | &download_progress_cb, po, | ||
584 | GNUNET_FS_FLAGS_NONE, | ||
585 | GNUNET_FS_OPTIONS_END); | ||
586 | } | ||
587 | |||
588 | |||
589 | /** | ||
590 | * Callback to be called when testbed has connected to the fs service | ||
591 | * | ||
592 | * @param cls the 'struct TestPublishOperation' | ||
593 | * @param op the operation that has been finished | ||
594 | * @param ca_result the 'struct GNUNET_FS_Handle ' (NULL on error) | ||
595 | * @param emsg error message in case the operation has failed; will be NULL if | ||
596 | * operation has executed successfully. | ||
597 | */ | ||
598 | static void | ||
599 | download_fs_connect_complete_cb (void *cls, | ||
600 | struct GNUNET_TESTBED_Operation *op, | ||
601 | void *ca_result, | ||
602 | const char *emsg) | ||
603 | { | ||
604 | struct TestDownloadOperation *dop = cls; | ||
605 | |||
606 | dop->fs = ca_result; | ||
607 | GNUNET_assert (NULL != dop->fs); | ||
608 | dop->download_context = | ||
609 | GNUNET_FS_download_start (dop->fs, dop->uri, NULL, NULL, NULL, 0, dop->size, | ||
610 | dop->anonymity, GNUNET_FS_DOWNLOAD_OPTION_NONE, | ||
611 | NULL, NULL); | ||
612 | } | ||
613 | |||
614 | |||
615 | /** | ||
616 | * Perform test download. | ||
617 | * | ||
618 | * @param peer which peer to download from | ||
619 | * @param timeout if this operation cannot be completed within the | ||
620 | * given period, call the continuation with an error code | ||
621 | * @param anonymity option for download | ||
622 | * @param seed used for file validation | ||
623 | * @param uri URI of file to download (CHK/LOC only) | ||
624 | * @param verbose how verbose to be in reporting | ||
625 | * @param cont function to call when done | ||
626 | * @param cont_cls closure for cont | ||
627 | */ | ||
628 | void | ||
629 | GNUNET_FS_TEST_download (struct GNUNET_TESTBED_Peer *peer, | ||
630 | struct GNUNET_TIME_Relative timeout, | ||
631 | uint32_t anonymity, uint32_t seed, | ||
632 | const struct GNUNET_FS_Uri *uri, unsigned int verbose, | ||
633 | GNUNET_SCHEDULER_TaskCallback cont, void *cont_cls) | ||
634 | { | ||
635 | struct TestDownloadOperation *dop; | ||
636 | |||
637 | dop = GNUNET_new (struct TestDownloadOperation); | ||
638 | dop->uri = GNUNET_FS_uri_dup (uri); | ||
639 | dop->size = GNUNET_FS_uri_chk_get_file_size (uri); | ||
640 | dop->verbose = verbose; | ||
641 | dop->anonymity = anonymity; | ||
642 | dop->download_cont = cont; | ||
643 | dop->download_cont_cls = cont_cls; | ||
644 | dop->download_seed = seed; | ||
645 | |||
646 | dop->fs_op = GNUNET_TESTBED_service_connect (dop, | ||
647 | peer, | ||
648 | "fs", | ||
649 | &download_fs_connect_complete_cb, | ||
650 | dop, | ||
651 | &download_connect_adapter, | ||
652 | &fs_disconnect_adapter, | ||
653 | dop); | ||
654 | dop->download_timeout_task = | ||
655 | GNUNET_SCHEDULER_add_delayed (timeout, &download_timeout, dop); | ||
656 | } | ||
657 | |||
658 | |||
659 | /* end of fs_test_lib.c */ | ||
diff --git a/src/fs/fs_test_lib.h b/src/fs/fs_test_lib.h deleted file mode 100644 index 36244eb19..000000000 --- a/src/fs/fs_test_lib.h +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_test_lib.h | ||
23 | * @brief library routines for testing FS publishing and downloading; | ||
24 | * this code is limited to flat files | ||
25 | * and no keywords (those functions can be tested with | ||
26 | * single-peer setups; this is for testing routing). | ||
27 | * @author Christian Grothoff | ||
28 | */ | ||
29 | #ifndef FS_TEST_LIB_H | ||
30 | #define FS_TEST_LIB_H | ||
31 | |||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_fs_service.h" | ||
34 | #include "gnunet_testbed_service.h" | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Function signature. | ||
39 | * | ||
40 | * @param cls closure (user defined) | ||
41 | * @param uri a URI, NULL for errors | ||
42 | * @param fn name of the file on disk to be removed upon | ||
43 | * completion, or NULL for inserted files (also NULL on error) | ||
44 | */ | ||
45 | typedef void | ||
46 | (*GNUNET_FS_TEST_UriContinuation) (void *cls, | ||
47 | const struct GNUNET_FS_Uri *uri, | ||
48 | const char *fn); | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Publish a file at the given daemon. | ||
53 | * | ||
54 | * @param peer where to publish | ||
55 | * @param timeout if this operation cannot be completed within the | ||
56 | * given period, call the continuation with an error code | ||
57 | * @param anonymity option for publication | ||
58 | * @param do_index #GNUNET_YES for index, #GNUNET_NO for insertion, | ||
59 | * #GNUNET_SYSERR for simulation | ||
60 | * @param size size of the file to publish | ||
61 | * @param seed seed to use for file generation | ||
62 | * @param verbose how verbose to be in reporting | ||
63 | * @param cont function to call when done | ||
64 | * @param cont_cls closure for @a cont | ||
65 | */ | ||
66 | void | ||
67 | GNUNET_FS_TEST_publish (struct GNUNET_TESTBED_Peer *peer, | ||
68 | struct GNUNET_TIME_Relative timeout, | ||
69 | uint32_t anonymity, | ||
70 | int do_index, | ||
71 | uint64_t size, | ||
72 | uint32_t seed, | ||
73 | unsigned int verbose, | ||
74 | GNUNET_FS_TEST_UriContinuation cont, | ||
75 | void *cont_cls); | ||
76 | |||
77 | |||
78 | /** | ||
79 | * Perform test download. | ||
80 | * | ||
81 | * @param peer which peer to download from | ||
82 | * @param timeout if this operation cannot be completed within the | ||
83 | * given period, call the continuation with an error code | ||
84 | * @param anonymity option for download | ||
85 | * @param seed used for file validation | ||
86 | * @param uri URI of file to download (CHK/LOC only) | ||
87 | * @param verbose how verbose to be in reporting | ||
88 | * @param cont function to call when done | ||
89 | * @param cont_cls closure for @a cont | ||
90 | */ | ||
91 | void | ||
92 | GNUNET_FS_TEST_download (struct GNUNET_TESTBED_Peer *peer, | ||
93 | struct GNUNET_TIME_Relative timeout, | ||
94 | uint32_t anonymity, | ||
95 | uint32_t seed, | ||
96 | const struct GNUNET_FS_Uri *uri, | ||
97 | unsigned int verbose, | ||
98 | GNUNET_SCHEDULER_TaskCallback cont, | ||
99 | void *cont_cls); | ||
100 | |||
101 | |||
102 | #endif | ||
diff --git a/src/fs/fs_test_lib_data.conf b/src/fs/fs_test_lib_data.conf deleted file mode 100644 index c99674798..000000000 --- a/src/fs/fs_test_lib_data.conf +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-fs-test-lib/ | ||
4 | |||
5 | [ats] | ||
6 | WAN_QUOTA_IN = 3932160 | ||
7 | WAN_QUOTA_OUT = 3932160 | ||
8 | |||
9 | [datastore] | ||
10 | QUOTA = 2 GB | ||
11 | #PLUGIN = heap | ||
12 | # | ||
13 | [fs] | ||
14 | IMMEDIATE_START = YES | ||
15 | |||
16 | [testbed] | ||
17 | OVERLAY_TOPOLOGY = CLIQUE | ||
diff --git a/src/fs/fs_tree.c b/src/fs/fs_tree.c deleted file mode 100644 index 4d49809f8..000000000 --- a/src/fs/fs_tree.c +++ /dev/null | |||
@@ -1,463 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/fs_tree.c | ||
22 | * @brief Merkle-tree-ish-CHK file encoding for GNUnet | ||
23 | * @see http://gnunet.org/encoding.php3 | ||
24 | * @author Krista Bennett | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "fs_tree.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Context for an ECRS-based file encoder that computes | ||
33 | * the Merkle-ish-CHK tree. | ||
34 | */ | ||
35 | struct GNUNET_FS_TreeEncoder | ||
36 | { | ||
37 | /** | ||
38 | * Global FS context. | ||
39 | */ | ||
40 | struct GNUNET_FS_Handle *h; | ||
41 | |||
42 | /** | ||
43 | * Closure for all callbacks. | ||
44 | */ | ||
45 | void *cls; | ||
46 | |||
47 | /** | ||
48 | * Function to call on encrypted blocks. | ||
49 | */ | ||
50 | GNUNET_FS_TreeBlockProcessor proc; | ||
51 | |||
52 | /** | ||
53 | * Function to call with progress information. | ||
54 | */ | ||
55 | GNUNET_FS_TreeProgressCallback progress; | ||
56 | |||
57 | /** | ||
58 | * Function to call to receive input data. | ||
59 | */ | ||
60 | GNUNET_FS_DataReader reader; | ||
61 | |||
62 | /** | ||
63 | * Function to call once we're done with processing. | ||
64 | */ | ||
65 | GNUNET_SCHEDULER_TaskCallback cont; | ||
66 | |||
67 | /** | ||
68 | * Set to an error message (if we had an error). | ||
69 | */ | ||
70 | char *emsg; | ||
71 | |||
72 | /** | ||
73 | * Set to the URI (upon successful completion) | ||
74 | */ | ||
75 | struct GNUNET_FS_Uri *uri; | ||
76 | |||
77 | /** | ||
78 | * Overall file size. | ||
79 | */ | ||
80 | uint64_t size; | ||
81 | |||
82 | /** | ||
83 | * How far are we? | ||
84 | */ | ||
85 | uint64_t publish_offset; | ||
86 | |||
87 | /** | ||
88 | * How deep are we? Depth 0 is for the DBLOCKs. | ||
89 | */ | ||
90 | unsigned int current_depth; | ||
91 | |||
92 | /** | ||
93 | * How deep is the tree? Always > 0. | ||
94 | */ | ||
95 | unsigned int chk_tree_depth; | ||
96 | |||
97 | /** | ||
98 | * In-memory cache of the current CHK tree. | ||
99 | * This struct will contain the CHK values | ||
100 | * from the root to the currently processed | ||
101 | * node in the tree as identified by | ||
102 | * "current_depth" and "publish_offset". | ||
103 | * The "chktree" will be initially NULL, | ||
104 | * then allocated to a sufficient number of | ||
105 | * entries for the size of the file and | ||
106 | * finally freed once the upload is complete. | ||
107 | */ | ||
108 | struct ContentHashKey *chk_tree; | ||
109 | |||
110 | /** | ||
111 | * Are we currently in 'GNUNET_FS_tree_encoder_next'? | ||
112 | * Flag used to prevent recursion. | ||
113 | */ | ||
114 | int in_next; | ||
115 | }; | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Compute the depth of the CHK tree. | ||
120 | * | ||
121 | * @param flen file length for which to compute the depth | ||
122 | * @return depth of the tree, always > 0. A depth of 1 means only a DBLOCK. | ||
123 | */ | ||
124 | unsigned int | ||
125 | GNUNET_FS_compute_depth (uint64_t flen) | ||
126 | { | ||
127 | unsigned int treeDepth; | ||
128 | uint64_t fl; | ||
129 | |||
130 | treeDepth = 1; | ||
131 | fl = DBLOCK_SIZE; | ||
132 | while (fl < flen) | ||
133 | { | ||
134 | treeDepth++; | ||
135 | if (fl * CHK_PER_INODE < fl) | ||
136 | { | ||
137 | /* integer overflow, this is a HUGE file... */ | ||
138 | return treeDepth; | ||
139 | } | ||
140 | fl = fl * CHK_PER_INODE; | ||
141 | } | ||
142 | return treeDepth; | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Calculate how many bytes of payload a block tree of the given | ||
148 | * depth MAY correspond to at most (this function ignores the fact that | ||
149 | * some blocks will only be present partially due to the total file | ||
150 | * size cutting some blocks off at the end). | ||
151 | * | ||
152 | * @param depth depth of the block. depth==0 is a DBLOCK. | ||
153 | * @return number of bytes of payload a subtree of this depth may correspond to | ||
154 | */ | ||
155 | uint64_t | ||
156 | GNUNET_FS_tree_compute_tree_size (unsigned int depth) | ||
157 | { | ||
158 | uint64_t rsize; | ||
159 | unsigned int i; | ||
160 | |||
161 | rsize = DBLOCK_SIZE; | ||
162 | for (i = 0; i < depth; i++) | ||
163 | rsize *= CHK_PER_INODE; | ||
164 | return rsize; | ||
165 | } | ||
166 | |||
167 | |||
168 | /** | ||
169 | * Compute the size of the current IBLOCK. The encoder is | ||
170 | * triggering the calculation of the size of an IBLOCK at the | ||
171 | * *end* (hence end_offset) of its construction. The IBLOCK | ||
172 | * maybe a full or a partial IBLOCK, and this function is to | ||
173 | * calculate how long it should be. | ||
174 | * | ||
175 | * @param depth depth of the IBlock in the tree, 0 would be a DBLOCK, | ||
176 | * must be > 0 (this function is for IBLOCKs only!) | ||
177 | * @param end_offset current offset in the payload (!) of the overall file, | ||
178 | * must be > 0 (since this function is called at the | ||
179 | * end of a block). | ||
180 | * @return size of the corresponding IBlock | ||
181 | */ | ||
182 | static uint16_t | ||
183 | GNUNET_FS_tree_compute_iblock_size (unsigned int depth, uint64_t end_offset) | ||
184 | { | ||
185 | unsigned int ret; | ||
186 | uint64_t mod; | ||
187 | uint64_t bds; | ||
188 | |||
189 | GNUNET_assert (depth > 0); | ||
190 | GNUNET_assert (end_offset > 0); | ||
191 | bds = GNUNET_FS_tree_compute_tree_size (depth); | ||
192 | mod = end_offset % bds; | ||
193 | if (0 == mod) | ||
194 | { | ||
195 | /* we were triggered at the end of a full block */ | ||
196 | ret = CHK_PER_INODE; | ||
197 | } | ||
198 | else | ||
199 | { | ||
200 | /* we were triggered at the end of the file */ | ||
201 | bds /= CHK_PER_INODE; | ||
202 | ret = mod / bds; | ||
203 | if (0 != mod % bds) | ||
204 | ret++; | ||
205 | } | ||
206 | return (uint16_t) (ret * sizeof(struct ContentHashKey)); | ||
207 | } | ||
208 | |||
209 | |||
210 | /** | ||
211 | * Compute how many bytes of data should be stored in | ||
212 | * the specified block. | ||
213 | * | ||
214 | * @param fsize overall file size, must be > 0. | ||
215 | * @param offset offset in the original data corresponding | ||
216 | * to the beginning of the tree induced by the block; | ||
217 | * must be <= fsize | ||
218 | * @param depth depth of the node in the tree, 0 for DBLOCK | ||
219 | * @return number of bytes stored in this node | ||
220 | */ | ||
221 | size_t | ||
222 | GNUNET_FS_tree_calculate_block_size (uint64_t fsize, uint64_t offset, | ||
223 | unsigned int depth) | ||
224 | { | ||
225 | size_t ret; | ||
226 | uint64_t rsize; | ||
227 | uint64_t epos; | ||
228 | unsigned int chks; | ||
229 | |||
230 | GNUNET_assert (fsize > 0); | ||
231 | GNUNET_assert (offset <= fsize); | ||
232 | if (depth == 0) | ||
233 | { | ||
234 | ret = DBLOCK_SIZE; | ||
235 | if ((offset + ret > fsize) || (offset + ret < offset)) | ||
236 | ret = (size_t) (fsize - offset); | ||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | rsize = GNUNET_FS_tree_compute_tree_size (depth - 1); | ||
241 | epos = offset + rsize * CHK_PER_INODE; | ||
242 | if ((epos < offset) || (epos > fsize)) | ||
243 | epos = fsize; | ||
244 | /* round up when computing #CHKs in our IBlock */ | ||
245 | chks = (epos - offset + rsize - 1) / rsize; | ||
246 | GNUNET_assert (chks <= CHK_PER_INODE); | ||
247 | return chks * sizeof(struct ContentHashKey); | ||
248 | } | ||
249 | |||
250 | |||
251 | /** | ||
252 | * Initialize a tree encoder. This function will call @a proc and | ||
253 | * "progress" on each block in the tree. Once all blocks have been | ||
254 | * processed, "cont" will be scheduled. The @a reader will be called | ||
255 | * to obtain the (plaintext) blocks for the file. Note that this | ||
256 | * function will not actually call @a proc. The client must | ||
257 | * call #GNUNET_FS_tree_encoder_next to trigger encryption (and | ||
258 | * calling of @a proc) for the each block. | ||
259 | * | ||
260 | * @param h the global FS context | ||
261 | * @param size overall size of the file to encode | ||
262 | * @param cls closure for reader, proc, progress and cont | ||
263 | * @param reader function to call to read plaintext data | ||
264 | * @param proc function to call on each encrypted block | ||
265 | * @param progress function to call with progress information | ||
266 | * @param cont function to call when done | ||
267 | */ | ||
268 | struct GNUNET_FS_TreeEncoder * | ||
269 | GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size, | ||
270 | void *cls, | ||
271 | GNUNET_FS_DataReader reader, | ||
272 | GNUNET_FS_TreeBlockProcessor proc, | ||
273 | GNUNET_FS_TreeProgressCallback progress, | ||
274 | GNUNET_SCHEDULER_TaskCallback cont) | ||
275 | { | ||
276 | struct GNUNET_FS_TreeEncoder *te; | ||
277 | |||
278 | te = GNUNET_new (struct GNUNET_FS_TreeEncoder); | ||
279 | te->h = h; | ||
280 | te->size = size; | ||
281 | te->cls = cls; | ||
282 | te->reader = reader; | ||
283 | te->proc = proc; | ||
284 | te->progress = progress; | ||
285 | te->cont = cont; | ||
286 | te->chk_tree_depth = GNUNET_FS_compute_depth (size); | ||
287 | te->chk_tree | ||
288 | = GNUNET_new_array (te->chk_tree_depth * CHK_PER_INODE, | ||
289 | struct ContentHashKey); | ||
290 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
291 | "Created tree encoder for file with %llu bytes and depth %u\n", | ||
292 | (unsigned long long) size, | ||
293 | te->chk_tree_depth); | ||
294 | return te; | ||
295 | } | ||
296 | |||
297 | |||
298 | /** | ||
299 | * Compute the offset of the CHK for the | ||
300 | * current block in the IBlock above. | ||
301 | * | ||
302 | * @param depth depth of the IBlock in the tree (aka overall | ||
303 | * number of tree levels minus depth); 0 == DBlock | ||
304 | * @param end_offset current offset in the overall file, | ||
305 | * at the *beginning* of the block for DBLOCKs (depth==0), | ||
306 | * otherwise at the *end* of the block (exclusive) | ||
307 | * @return (array of CHKs') offset in the above IBlock | ||
308 | */ | ||
309 | static unsigned int | ||
310 | compute_chk_offset (unsigned int depth, uint64_t end_offset) | ||
311 | { | ||
312 | uint64_t bds; | ||
313 | unsigned int ret; | ||
314 | |||
315 | bds = GNUNET_FS_tree_compute_tree_size (depth); | ||
316 | if (depth > 0) | ||
317 | end_offset--; /* round down since for depth > 0 offset is at the END of the block */ | ||
318 | ret = end_offset / bds; | ||
319 | return ret % CHK_PER_INODE; | ||
320 | } | ||
321 | |||
322 | |||
323 | /** | ||
324 | * Encrypt the next block of the file (and call proc and progress | ||
325 | * accordingly; or of course "cont" if we have already completed | ||
326 | * encoding of the entire file). | ||
327 | * | ||
328 | * @param te tree encoder to use | ||
329 | */ | ||
330 | void | ||
331 | GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder *te) | ||
332 | { | ||
333 | struct ContentHashKey *mychk; | ||
334 | const void *pt_block; | ||
335 | uint16_t pt_size; | ||
336 | char iob[DBLOCK_SIZE]; | ||
337 | char enc[DBLOCK_SIZE]; | ||
338 | struct GNUNET_CRYPTO_SymmetricSessionKey sk; | ||
339 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
340 | unsigned int off; | ||
341 | |||
342 | GNUNET_assert (GNUNET_NO == te->in_next); | ||
343 | te->in_next = GNUNET_YES; | ||
344 | if (te->chk_tree_depth == te->current_depth) | ||
345 | { | ||
346 | off = CHK_PER_INODE * (te->chk_tree_depth - 1); | ||
347 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TE done, reading CHK `%s' from %u\n", | ||
348 | GNUNET_h2s (&te->chk_tree[off].query), off); | ||
349 | te->uri = GNUNET_new (struct GNUNET_FS_Uri); | ||
350 | te->uri->type = GNUNET_FS_URI_CHK; | ||
351 | te->uri->data.chk.chk = te->chk_tree[off]; | ||
352 | te->uri->data.chk.file_length = GNUNET_htonll (te->size); | ||
353 | te->in_next = GNUNET_NO; | ||
354 | te->cont (te->cls); | ||
355 | return; | ||
356 | } | ||
357 | if (0 == te->current_depth) | ||
358 | { | ||
359 | /* read DBLOCK */ | ||
360 | pt_size = GNUNET_MIN (DBLOCK_SIZE, te->size - te->publish_offset); | ||
361 | if (pt_size != | ||
362 | te->reader (te->cls, te->publish_offset, pt_size, iob, &te->emsg)) | ||
363 | { | ||
364 | te->in_next = GNUNET_NO; | ||
365 | te->cont (te->cls); | ||
366 | return; | ||
367 | } | ||
368 | pt_block = iob; | ||
369 | } | ||
370 | else | ||
371 | { | ||
372 | pt_size = | ||
373 | GNUNET_FS_tree_compute_iblock_size (te->current_depth, | ||
374 | te->publish_offset); | ||
375 | pt_block = &te->chk_tree[(te->current_depth - 1) * CHK_PER_INODE]; | ||
376 | } | ||
377 | off = compute_chk_offset (te->current_depth, te->publish_offset); | ||
378 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
379 | "TE is at offset %llu and depth %u with block size %u and target-CHK-offset %u\n", | ||
380 | (unsigned long long) te->publish_offset, te->current_depth, | ||
381 | (unsigned int) pt_size, (unsigned int) off); | ||
382 | mychk = &te->chk_tree[te->current_depth * CHK_PER_INODE + off]; | ||
383 | GNUNET_CRYPTO_hash (pt_block, pt_size, &mychk->key); | ||
384 | GNUNET_CRYPTO_hash_to_aes_key (&mychk->key, &sk, &iv); | ||
385 | GNUNET_CRYPTO_symmetric_encrypt (pt_block, pt_size, &sk, &iv, enc); | ||
386 | GNUNET_CRYPTO_hash (enc, pt_size, &mychk->query); | ||
387 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
388 | "TE calculates query to be `%s', stored at %u\n", | ||
389 | GNUNET_h2s (&mychk->query), | ||
390 | te->current_depth * CHK_PER_INODE + off); | ||
391 | if (NULL != te->proc) | ||
392 | te->proc (te->cls, mychk, te->publish_offset, te->current_depth, | ||
393 | (0 == | ||
394 | te->current_depth) ? GNUNET_BLOCK_TYPE_FS_DBLOCK : | ||
395 | GNUNET_BLOCK_TYPE_FS_IBLOCK, enc, pt_size); | ||
396 | if (NULL != te->progress) | ||
397 | te->progress (te->cls, te->publish_offset, pt_block, pt_size, | ||
398 | te->current_depth); | ||
399 | if (0 == te->current_depth) | ||
400 | { | ||
401 | te->publish_offset += pt_size; | ||
402 | if ((te->publish_offset == te->size) || | ||
403 | (0 == te->publish_offset % (CHK_PER_INODE * DBLOCK_SIZE))) | ||
404 | te->current_depth++; | ||
405 | } | ||
406 | else | ||
407 | { | ||
408 | if ((off == CHK_PER_INODE) || (te->publish_offset == te->size)) | ||
409 | te->current_depth++; | ||
410 | else | ||
411 | te->current_depth = 0; | ||
412 | } | ||
413 | te->in_next = GNUNET_NO; | ||
414 | } | ||
415 | |||
416 | |||
417 | /** | ||
418 | * Get the resulting URI from the encoding. | ||
419 | * | ||
420 | * @param te the tree encoder to clean up | ||
421 | * @return uri set to the resulting URI (if encoding finished), NULL otherwise | ||
422 | */ | ||
423 | struct GNUNET_FS_Uri * | ||
424 | GNUNET_FS_tree_encoder_get_uri (struct GNUNET_FS_TreeEncoder *te) | ||
425 | { | ||
426 | if (NULL != te->uri) | ||
427 | return GNUNET_FS_uri_dup (te->uri); | ||
428 | return NULL; | ||
429 | } | ||
430 | |||
431 | |||
432 | /** | ||
433 | * Clean up a tree encoder and return information | ||
434 | * about possible errors. | ||
435 | * | ||
436 | * @param te the tree encoder to clean up | ||
437 | * @param emsg set to an error message (if an error occurred | ||
438 | * within the tree encoder; if this function is called | ||
439 | * prior to completion and prior to an internal error, | ||
440 | * both "*emsg" will be set to NULL). | ||
441 | */ | ||
442 | void | ||
443 | GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder *te, | ||
444 | char **emsg) | ||
445 | { | ||
446 | if (NULL != te->reader) | ||
447 | { | ||
448 | (void) te->reader (te->cls, UINT64_MAX, 0, 0, NULL); | ||
449 | te->reader = NULL; | ||
450 | } | ||
451 | GNUNET_assert (GNUNET_NO == te->in_next); | ||
452 | if (NULL != te->uri) | ||
453 | GNUNET_FS_uri_destroy (te->uri); | ||
454 | if (emsg != NULL) | ||
455 | *emsg = te->emsg; | ||
456 | else | ||
457 | GNUNET_free (te->emsg); | ||
458 | GNUNET_free (te->chk_tree); | ||
459 | GNUNET_free (te); | ||
460 | } | ||
461 | |||
462 | |||
463 | /* end of fs_tree.c */ | ||
diff --git a/src/fs/fs_tree.h b/src/fs/fs_tree.h deleted file mode 100644 index 1fb681d27..000000000 --- a/src/fs/fs_tree.h +++ /dev/null | |||
@@ -1,217 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_tree.h | ||
23 | * @brief Merkle-tree-ish-CHK file encoding for GNUnet | ||
24 | * @see https://gnunet.org/encoding | ||
25 | * @author Krista Bennett | ||
26 | * @author Christian Grothoff | ||
27 | * | ||
28 | * TODO: | ||
29 | * - decide if this API should be made public (gnunet_fs_service.h) | ||
30 | * or remain "internal" (but with exported symbols?) | ||
31 | */ | ||
32 | #ifndef GNUNET_FS_TREE_H | ||
33 | #define GNUNET_FS_TREE_H | ||
34 | |||
35 | #include "fs_api.h" | ||
36 | |||
37 | /** | ||
38 | * Compute the depth of the CHK tree. | ||
39 | * | ||
40 | * @param flen file length for which to compute the depth | ||
41 | * @return depth of the tree, always > 0. A depth of 1 means only a DBLOCK. | ||
42 | */ | ||
43 | unsigned int | ||
44 | GNUNET_FS_compute_depth (uint64_t flen); | ||
45 | |||
46 | |||
47 | /** | ||
48 | * Calculate how many bytes of payload a block tree of the given | ||
49 | * depth MAY correspond to at most (this function ignores the fact that | ||
50 | * some blocks will only be present partially due to the total file | ||
51 | * size cutting some blocks off at the end). | ||
52 | * | ||
53 | * @param depth depth of the block. depth==0 is a DBLOCK. | ||
54 | * @return number of bytes of payload a subtree of this depth may correspond to | ||
55 | */ | ||
56 | uint64_t | ||
57 | GNUNET_FS_tree_compute_tree_size (unsigned int depth); | ||
58 | |||
59 | |||
60 | /** | ||
61 | * Compute how many bytes of data should be stored in | ||
62 | * the specified block. | ||
63 | * | ||
64 | * @param fsize overall file size, must be > 0. | ||
65 | * @param offset offset in the original data corresponding | ||
66 | * to the beginning of the tree induced by the block; | ||
67 | * must be < fsize | ||
68 | * @param depth depth of the node in the tree, 0 for DBLOCK | ||
69 | * @return number of bytes stored in this node | ||
70 | */ | ||
71 | size_t | ||
72 | GNUNET_FS_tree_calculate_block_size (uint64_t fsize, uint64_t offset, | ||
73 | unsigned int depth); | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Context for an ECRS-based file encoder that computes | ||
78 | * the Merkle-ish-CHK tree. | ||
79 | */ | ||
80 | struct GNUNET_FS_TreeEncoder; | ||
81 | |||
82 | |||
83 | /** | ||
84 | * Function called asking for the current (encoded) | ||
85 | * block to be processed. After processing the | ||
86 | * client should either call "GNUNET_FS_tree_encode_next" | ||
87 | * or (on error) "GNUNET_FS_tree_encode_finish". | ||
88 | * | ||
89 | * @param cls closure | ||
90 | * @param chk content hash key for the block | ||
91 | * @param offset offset of the block | ||
92 | * @param depth depth of the block, 0 for DBLOCKs | ||
93 | * @param type type of the block (IBLOCK or DBLOCK) | ||
94 | * @param block the (encrypted) block | ||
95 | * @param block_size size of block (in bytes) | ||
96 | */ | ||
97 | typedef void (*GNUNET_FS_TreeBlockProcessor) (void *cls, | ||
98 | const struct ContentHashKey *chk, | ||
99 | uint64_t offset, | ||
100 | unsigned int depth, | ||
101 | enum GNUNET_BLOCK_Type type, | ||
102 | const void *block, | ||
103 | uint16_t block_size); | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Function called with information about our | ||
108 | * progress in computing the tree encoding. | ||
109 | * | ||
110 | * @param cls closure | ||
111 | * @param offset where are we in the file | ||
112 | * @param pt_block plaintext of the currently processed block | ||
113 | * @param pt_size size of pt_block | ||
114 | * @param depth depth of the block in the tree, 0 for DBLOCKS | ||
115 | */ | ||
116 | typedef void (*GNUNET_FS_TreeProgressCallback) (void *cls, uint64_t offset, | ||
117 | const void *pt_block, | ||
118 | size_t pt_size, | ||
119 | unsigned int depth); | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Initialize a tree encoder. This function will call "proc" and | ||
124 | * "progress" on each block in the tree. Once all blocks have been | ||
125 | * processed, "cont" will be scheduled. The "reader" will be called | ||
126 | * to obtain the (plaintext) blocks for the file. Note that this | ||
127 | * function will actually never call "proc"; the "proc" function must | ||
128 | * be triggered by calling "GNUNET_FS_tree_encoder_next" to trigger | ||
129 | * encryption (and calling of "proc") for each block. | ||
130 | * | ||
131 | * @param h the global FS context | ||
132 | * @param size overall size of the file to encode | ||
133 | * @param cls closure for reader, proc, progress and cont | ||
134 | * @param reader function to call to read plaintext data | ||
135 | * @param proc function to call on each encrypted block | ||
136 | * @param progress function to call with progress information | ||
137 | * @param cont function to call when done | ||
138 | * @return tree encoder context | ||
139 | */ | ||
140 | struct GNUNET_FS_TreeEncoder * | ||
141 | GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size, | ||
142 | void *cls, GNUNET_FS_DataReader reader, | ||
143 | GNUNET_FS_TreeBlockProcessor proc, | ||
144 | GNUNET_FS_TreeProgressCallback progress, | ||
145 | GNUNET_SCHEDULER_TaskCallback cont); | ||
146 | |||
147 | |||
148 | /** | ||
149 | * Encrypt the next block of the file (and | ||
150 | * call proc and progress accordingly; or | ||
151 | * of course "cont" if we have already completed | ||
152 | * encoding of the entire file). | ||
153 | * | ||
154 | * @param te tree encoder to use | ||
155 | */ | ||
156 | void | ||
157 | GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder *te); | ||
158 | |||
159 | |||
160 | /** | ||
161 | * Get the resulting URI from the encoding. | ||
162 | * | ||
163 | * @param te the tree encoder to clean up | ||
164 | * @return uri set to the resulting URI (if encoding finished), NULL otherwise | ||
165 | */ | ||
166 | struct GNUNET_FS_Uri * | ||
167 | GNUNET_FS_tree_encoder_get_uri (struct GNUNET_FS_TreeEncoder *te); | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Clean up a tree encoder and return information | ||
172 | * about possible errors. | ||
173 | * | ||
174 | * @param te the tree encoder to clean up | ||
175 | * @param emsg set to an error message (if an error occurred | ||
176 | * within the tree encoder; if this function is called | ||
177 | * prior to completion and prior to an internal error, | ||
178 | * both "*emsg" will be set to NULL). | ||
179 | */ | ||
180 | void | ||
181 | GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder *te, | ||
182 | char **emsg); | ||
183 | |||
184 | |||
185 | #if 0 | ||
186 | /* the functions below will be needed for persistence | ||
187 | but are not yet implemented -- FIXME... */ | ||
188 | /** | ||
189 | * Get data that would be needed to resume | ||
190 | * the encoding later. | ||
191 | * | ||
192 | * @param te encoding to resume | ||
193 | * @param data set to the resume data | ||
194 | * @param size set to the size of the resume data | ||
195 | */ | ||
196 | void | ||
197 | GNUNET_FS_tree_encoder_resume_get_data (const struct GNUNET_FS_TreeEncoder *te, | ||
198 | void **data, size_t *size); | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Reset tree encoder to point previously | ||
203 | * obtained for resuming. | ||
204 | * | ||
205 | * @param te encoding to resume | ||
206 | * @param data the resume data | ||
207 | * @param size the size of the resume data | ||
208 | */ | ||
209 | void | ||
210 | GNUNET_FS_tree_encoder_resume (struct GNUNET_FS_TreeEncoder *te, | ||
211 | const void *data, size_t size); | ||
212 | |||
213 | #endif | ||
214 | |||
215 | #endif | ||
216 | |||
217 | /* end of fs_tree.h */ | ||
diff --git a/src/fs/fs_unindex.c b/src/fs/fs_unindex.c deleted file mode 100644 index 8c27af9de..000000000 --- a/src/fs/fs_unindex.c +++ /dev/null | |||
@@ -1,901 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003--2013, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_unindex.c | ||
23 | * @author Krista Grothoff | ||
24 | * @author Christian Grothoff | ||
25 | * @brief Unindex file. | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | #include "gnunet_protocols.h" | ||
31 | #include "fs_api.h" | ||
32 | #include "fs_tree.h" | ||
33 | #include "block_fs.h" | ||
34 | #include "fs_publish_ublock.h" | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Function called by the tree encoder to obtain | ||
39 | * a block of plaintext data (for the lowest level | ||
40 | * of the tree). | ||
41 | * | ||
42 | * @param cls our publishing context | ||
43 | * @param offset identifies which block to get | ||
44 | * @param max (maximum) number of bytes to get; returning | ||
45 | * fewer will also cause errors | ||
46 | * @param buf where to copy the plaintext buffer | ||
47 | * @param emsg location to store an error message (on error) | ||
48 | * @return number of bytes copied to buf, 0 on error | ||
49 | */ | ||
50 | static size_t | ||
51 | unindex_reader (void *cls, | ||
52 | uint64_t offset, | ||
53 | size_t max, | ||
54 | void *buf, | ||
55 | char **emsg) | ||
56 | { | ||
57 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
58 | size_t pt_size; | ||
59 | |||
60 | pt_size = GNUNET_MIN (max, uc->file_size - offset); | ||
61 | if (offset != GNUNET_DISK_file_seek (uc->fh, offset, GNUNET_DISK_SEEK_SET)) | ||
62 | { | ||
63 | *emsg = GNUNET_strdup (_ ("Failed to find given position in file")); | ||
64 | return 0; | ||
65 | } | ||
66 | if (pt_size != GNUNET_DISK_file_read (uc->fh, buf, pt_size)) | ||
67 | { | ||
68 | *emsg = GNUNET_strdup (_ ("Failed to read file")); | ||
69 | return 0; | ||
70 | } | ||
71 | return pt_size; | ||
72 | } | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Fill in all of the generic fields for | ||
77 | * an unindex event and call the callback. | ||
78 | * | ||
79 | * @param pi structure to fill in | ||
80 | * @param uc overall unindex context | ||
81 | * @param offset where we are in the file (for progress) | ||
82 | */ | ||
83 | void | ||
84 | GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
85 | struct GNUNET_FS_UnindexContext *uc, | ||
86 | uint64_t offset) | ||
87 | { | ||
88 | pi->value.unindex.uc = uc; | ||
89 | pi->value.unindex.cctx = uc->client_info; | ||
90 | pi->value.unindex.filename = uc->filename; | ||
91 | pi->value.unindex.size = uc->file_size; | ||
92 | pi->value.unindex.eta = | ||
93 | GNUNET_TIME_calculate_eta (uc->start_time, offset, uc->file_size); | ||
94 | pi->value.unindex.duration = | ||
95 | GNUNET_TIME_absolute_get_duration (uc->start_time); | ||
96 | pi->value.unindex.completed = offset; | ||
97 | pi->fsh = uc->h; | ||
98 | uc->client_info = uc->h->upcb (uc->h->upcb_cls, pi); | ||
99 | } | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Function called with information about our | ||
104 | * progress in computing the tree encoding. | ||
105 | * | ||
106 | * @param cls closure | ||
107 | * @param offset where are we in the file | ||
108 | * @param pt_block plaintext of the currently processed block | ||
109 | * @param pt_size size of pt_block | ||
110 | * @param depth depth of the block in the tree, 0 for DBLOCK | ||
111 | */ | ||
112 | static void | ||
113 | unindex_progress (void *cls, | ||
114 | uint64_t offset, | ||
115 | const void *pt_block, | ||
116 | size_t pt_size, | ||
117 | unsigned int depth) | ||
118 | { | ||
119 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
120 | struct GNUNET_FS_ProgressInfo pi; | ||
121 | |||
122 | pi.status = GNUNET_FS_STATUS_UNINDEX_PROGRESS; | ||
123 | pi.value.unindex.specifics.progress.data = pt_block; | ||
124 | pi.value.unindex.specifics.progress.offset = offset; | ||
125 | pi.value.unindex.specifics.progress.data_len = pt_size; | ||
126 | pi.value.unindex.specifics.progress.depth = depth; | ||
127 | GNUNET_FS_unindex_make_status_ (&pi, uc, offset); | ||
128 | } | ||
129 | |||
130 | |||
131 | /** | ||
132 | * We've encountered an error during | ||
133 | * unindexing. Signal the client. | ||
134 | * | ||
135 | * @param uc context for the failed unindexing operation | ||
136 | */ | ||
137 | static void | ||
138 | signal_unindex_error (struct GNUNET_FS_UnindexContext *uc) | ||
139 | { | ||
140 | struct GNUNET_FS_ProgressInfo pi; | ||
141 | |||
142 | pi.status = GNUNET_FS_STATUS_UNINDEX_ERROR; | ||
143 | pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
144 | pi.value.unindex.specifics.error.message = uc->emsg; | ||
145 | GNUNET_FS_unindex_make_status_ (&pi, uc, 0); | ||
146 | } | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Continuation called to notify client about result of the | ||
151 | * datastore removal operation. | ||
152 | * | ||
153 | * @param cls closure | ||
154 | * @param success #GNUNET_SYSERR on failure | ||
155 | * @param min_expiration minimum expiration time required for content to be stored | ||
156 | * @param msg NULL on success, otherwise an error message | ||
157 | */ | ||
158 | static void | ||
159 | process_cont (void *cls, | ||
160 | int success, | ||
161 | struct GNUNET_TIME_Absolute min_expiration, | ||
162 | const char *msg) | ||
163 | { | ||
164 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
165 | |||
166 | if (success == GNUNET_SYSERR) | ||
167 | { | ||
168 | uc->emsg = GNUNET_strdup (msg); | ||
169 | signal_unindex_error (uc); | ||
170 | return; | ||
171 | } | ||
172 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
173 | "Datastore REMOVE operation succeeded\n"); | ||
174 | GNUNET_FS_tree_encoder_next (uc->tc); | ||
175 | } | ||
176 | |||
177 | |||
178 | /** | ||
179 | * Function called asking for the current (encoded) | ||
180 | * block to be processed. After processing the | ||
181 | * client should either call "GNUNET_FS_tree_encode_next" | ||
182 | * or (on error) "GNUNET_FS_tree_encode_finish". | ||
183 | * | ||
184 | * @param cls closure | ||
185 | * @param chk content hash key for the block (key for lookup in the datastore) | ||
186 | * @param offset offset of the block | ||
187 | * @param depth depth of the block, 0 for DBLOCK | ||
188 | * @param type type of the block (IBLOCK or DBLOCK) | ||
189 | * @param block the (encrypted) block | ||
190 | * @param block_size size of block (in bytes) | ||
191 | */ | ||
192 | static void | ||
193 | unindex_process (void *cls, | ||
194 | const struct ContentHashKey *chk, | ||
195 | uint64_t offset, | ||
196 | unsigned int depth, | ||
197 | enum GNUNET_BLOCK_Type type, | ||
198 | const void *block, | ||
199 | uint16_t block_size) | ||
200 | { | ||
201 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
202 | uint32_t size; | ||
203 | const void *data; | ||
204 | struct OnDemandBlock odb; | ||
205 | |||
206 | if (type != GNUNET_BLOCK_TYPE_FS_DBLOCK) | ||
207 | { | ||
208 | size = block_size; | ||
209 | data = block; | ||
210 | } | ||
211 | else /* on-demand encoded DBLOCK */ | ||
212 | { | ||
213 | size = sizeof(struct OnDemandBlock); | ||
214 | odb.offset = GNUNET_htonll (offset); | ||
215 | odb.file_id = uc->file_id; | ||
216 | data = &odb; | ||
217 | } | ||
218 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
219 | "Sending REMOVE request to DATASTORE service\n"); | ||
220 | GNUNET_DATASTORE_remove (uc->dsh, &chk->query, size, data, -2, 1, | ||
221 | &process_cont, uc); | ||
222 | uc->chk = *chk; | ||
223 | } | ||
224 | |||
225 | |||
226 | /** | ||
227 | * Function called with the response from the FS service to our | ||
228 | * unindexing request. | ||
229 | * | ||
230 | * @param cls closure, unindex context | ||
231 | * @param msg the response | ||
232 | */ | ||
233 | static void | ||
234 | handle_unindex_response (void *cls, | ||
235 | const struct GNUNET_MessageHeader *msg) | ||
236 | { | ||
237 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
238 | struct GNUNET_FS_ProgressInfo pi; | ||
239 | |||
240 | if (NULL != uc->mq) | ||
241 | { | ||
242 | GNUNET_MQ_destroy (uc->mq); | ||
243 | uc->mq = NULL; | ||
244 | } | ||
245 | uc->state = UNINDEX_STATE_COMPLETE; | ||
246 | pi.status = GNUNET_FS_STATUS_UNINDEX_COMPLETED; | ||
247 | pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO; | ||
248 | GNUNET_FS_unindex_sync_ (uc); | ||
249 | GNUNET_FS_unindex_make_status_ (&pi, | ||
250 | uc, | ||
251 | uc->file_size); | ||
252 | } | ||
253 | |||
254 | |||
255 | /** | ||
256 | * Generic error handler, called with the appropriate error code and | ||
257 | * the same closure specified at the creation of the message queue. | ||
258 | * Not every message queue implementation supports an error handler. | ||
259 | * | ||
260 | * @param cls closure with the `struct GNUNET_FS_UnindexContext *` | ||
261 | * @param error error code | ||
262 | */ | ||
263 | static void | ||
264 | unindex_mq_error_handler (void *cls, | ||
265 | enum GNUNET_MQ_Error error) | ||
266 | { | ||
267 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
268 | |||
269 | if (NULL != uc->mq) | ||
270 | { | ||
271 | GNUNET_MQ_destroy (uc->mq); | ||
272 | uc->mq = NULL; | ||
273 | } | ||
274 | uc->state = UNINDEX_STATE_ERROR; | ||
275 | uc->emsg = GNUNET_strdup (_ ("Error communicating with `fs' service.")); | ||
276 | GNUNET_FS_unindex_sync_ (uc); | ||
277 | signal_unindex_error (uc); | ||
278 | } | ||
279 | |||
280 | |||
281 | /** | ||
282 | * Function called when we are done with removing UBlocks. | ||
283 | * Disconnect from datastore and notify FS service about | ||
284 | * the unindex event. | ||
285 | * | ||
286 | * @param uc our unindexing context | ||
287 | */ | ||
288 | static void | ||
289 | unindex_finish (struct GNUNET_FS_UnindexContext *uc) | ||
290 | { | ||
291 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
292 | GNUNET_MQ_hd_fixed_size (unindex_response, | ||
293 | GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK, | ||
294 | struct GNUNET_MessageHeader, | ||
295 | uc), | ||
296 | GNUNET_MQ_handler_end () | ||
297 | }; | ||
298 | char *emsg; | ||
299 | struct GNUNET_MQ_Envelope *env; | ||
300 | struct UnindexMessage *req; | ||
301 | |||
302 | /* generate final progress message */ | ||
303 | unindex_progress (uc, | ||
304 | uc->file_size, | ||
305 | NULL, | ||
306 | 0, | ||
307 | 0); | ||
308 | GNUNET_FS_tree_encoder_finish (uc->tc, | ||
309 | &emsg); | ||
310 | uc->tc = NULL; | ||
311 | GNUNET_DISK_file_close (uc->fh); | ||
312 | uc->fh = NULL; | ||
313 | GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); | ||
314 | uc->dsh = NULL; | ||
315 | uc->state = UNINDEX_STATE_FS_NOTIFY; | ||
316 | GNUNET_FS_unindex_sync_ (uc); | ||
317 | uc->mq = GNUNET_CLIENT_connect (uc->h->cfg, | ||
318 | "fs", | ||
319 | handlers, | ||
320 | &unindex_mq_error_handler, | ||
321 | uc); | ||
322 | if (NULL == uc->mq) | ||
323 | { | ||
324 | uc->state = UNINDEX_STATE_ERROR; | ||
325 | uc->emsg = | ||
326 | GNUNET_strdup (_ ("Failed to connect to FS service for unindexing.")); | ||
327 | GNUNET_FS_unindex_sync_ (uc); | ||
328 | signal_unindex_error (uc); | ||
329 | return; | ||
330 | } | ||
331 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
332 | "Sending UNINDEX message to FS service\n"); | ||
333 | env = GNUNET_MQ_msg (req, | ||
334 | GNUNET_MESSAGE_TYPE_FS_UNINDEX); | ||
335 | req->reserved = 0; | ||
336 | req->file_id = uc->file_id; | ||
337 | GNUNET_MQ_send (uc->mq, | ||
338 | env); | ||
339 | } | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Function called by the directory scanner as we extract keywords | ||
344 | * that we will need to remove UBlocks. | ||
345 | * | ||
346 | * @param cls the 'struct GNUNET_FS_UnindexContext *' | ||
347 | * @param filename which file we are making progress on | ||
348 | * @param is_directory #GNUNET_YES if this is a directory, | ||
349 | * #GNUNET_NO if this is a file | ||
350 | * #GNUNET_SYSERR if it is neither (or unknown) | ||
351 | * @param reason kind of progress we are making | ||
352 | */ | ||
353 | static void | ||
354 | unindex_directory_scan_cb (void *cls, | ||
355 | const char *filename, | ||
356 | int is_directory, | ||
357 | enum GNUNET_FS_DirScannerProgressUpdateReason reason) | ||
358 | { | ||
359 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
360 | static struct GNUNET_FS_ShareTreeItem *directory_scan_result; | ||
361 | |||
362 | switch (reason) | ||
363 | { | ||
364 | case GNUNET_FS_DIRSCANNER_FINISHED: | ||
365 | directory_scan_result = GNUNET_FS_directory_scan_get_result (uc->dscan); | ||
366 | uc->dscan = NULL; | ||
367 | if (NULL != directory_scan_result->ksk_uri) | ||
368 | { | ||
369 | uc->ksk_uri = GNUNET_FS_uri_dup (directory_scan_result->ksk_uri); | ||
370 | uc->state = UNINDEX_STATE_DS_REMOVE_KBLOCKS; | ||
371 | GNUNET_FS_unindex_sync_ (uc); | ||
372 | GNUNET_FS_unindex_do_remove_kblocks_ (uc); | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | uc->emsg = GNUNET_strdup (_ ("Failed to get KSKs from directory scan.")); | ||
377 | GNUNET_FS_unindex_sync_ (uc); | ||
378 | unindex_finish (uc); | ||
379 | } | ||
380 | GNUNET_FS_share_tree_free (directory_scan_result); | ||
381 | break; | ||
382 | |||
383 | case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR: | ||
384 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
385 | _ ("Internal error scanning `%s'.\n"), | ||
386 | uc->filename); | ||
387 | GNUNET_FS_directory_scan_abort (uc->dscan); | ||
388 | uc->dscan = NULL; | ||
389 | uc->emsg = GNUNET_strdup (_ ("Failed to get KSKs from directory scan.")); | ||
390 | GNUNET_FS_unindex_sync_ (uc); | ||
391 | unindex_finish (uc); | ||
392 | break; | ||
393 | |||
394 | default: | ||
395 | break; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | |||
400 | /** | ||
401 | * If necessary, connect to the datastore and remove the UBlocks. | ||
402 | * | ||
403 | * @param uc context for the unindex operation. | ||
404 | */ | ||
405 | void | ||
406 | GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc) | ||
407 | { | ||
408 | char *ex; | ||
409 | |||
410 | if (GNUNET_OK != | ||
411 | GNUNET_CONFIGURATION_get_value_string (uc->h->cfg, "FS", "EXTRACTORS", | ||
412 | &ex)) | ||
413 | ex = NULL; | ||
414 | uc->dscan = GNUNET_FS_directory_scan_start (uc->filename, | ||
415 | GNUNET_NO, ex, | ||
416 | &unindex_directory_scan_cb, | ||
417 | uc); | ||
418 | GNUNET_free (ex); | ||
419 | } | ||
420 | |||
421 | |||
422 | /** | ||
423 | * Continuation called to notify client about result of the remove | ||
424 | * operation for the UBlock. | ||
425 | * | ||
426 | * @param cls the 'struct GNUNET_FS_UnindexContext *' | ||
427 | * @param success GNUNET_SYSERR on failure (including timeout/queue drop) | ||
428 | * GNUNET_NO if content was already there | ||
429 | * GNUNET_YES (or other positive value) on success | ||
430 | * @param min_expiration minimum expiration time required for 0-priority content to be stored | ||
431 | * by the datacache at this time, zero for unknown, forever if we have no | ||
432 | * space for 0-priority content | ||
433 | * @param msg NULL on success, otherwise an error message | ||
434 | */ | ||
435 | static void | ||
436 | continue_after_remove (void *cls, | ||
437 | int32_t success, | ||
438 | struct GNUNET_TIME_Absolute min_expiration, | ||
439 | const char *msg) | ||
440 | { | ||
441 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
442 | |||
443 | uc->dqe = NULL; | ||
444 | if (success != GNUNET_YES) | ||
445 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
446 | _ ("Failed to remove UBlock: %s\n"), | ||
447 | msg); | ||
448 | uc->ksk_offset++; | ||
449 | GNUNET_FS_unindex_do_remove_kblocks_ (uc); | ||
450 | } | ||
451 | |||
452 | |||
453 | /** | ||
454 | * Function called from datastore with result from us looking for | ||
455 | * a UBlock. There are four cases: | ||
456 | * 1) no result, means we move on to the next keyword | ||
457 | * 2) data hash is the same as an already seen data hash, means we move on to | ||
458 | * next keyword | ||
459 | * 3) UBlock for a different CHK, means we keep looking for more | ||
460 | * 4) UBlock is for our CHK, means we remove the block and then move | ||
461 | * on to the next keyword | ||
462 | * | ||
463 | * @param cls the 'struct GNUNET_FS_UnindexContext *' | ||
464 | * @param key key for the content | ||
465 | * @param size number of bytes in data | ||
466 | * @param data content stored | ||
467 | * @param type type of the content | ||
468 | * @param priority priority of the content | ||
469 | * @param anonymity anonymity-level for the content | ||
470 | * @param replication replication-level for the content | ||
471 | * @param expiration expiration time for the content | ||
472 | * @param uid unique identifier for the datum; | ||
473 | * maybe 0 if no unique identifier is available | ||
474 | */ | ||
475 | static void | ||
476 | process_kblock_for_unindex (void *cls, | ||
477 | const struct GNUNET_HashCode *key, | ||
478 | size_t size, | ||
479 | const void *data, | ||
480 | enum GNUNET_BLOCK_Type type, | ||
481 | uint32_t priority, | ||
482 | uint32_t anonymity, | ||
483 | uint32_t replication, | ||
484 | struct GNUNET_TIME_Absolute expiration, | ||
485 | uint64_t uid) | ||
486 | { | ||
487 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
488 | const struct UBlock *ub; | ||
489 | struct GNUNET_FS_Uri *chk_uri; | ||
490 | struct GNUNET_HashCode query; | ||
491 | |||
492 | uc->dqe = NULL; | ||
493 | if (NULL == data) | ||
494 | { | ||
495 | /* no result */ | ||
496 | uc->ksk_offset++; | ||
497 | GNUNET_FS_unindex_do_remove_kblocks_ (uc); | ||
498 | return; | ||
499 | } | ||
500 | GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type); | ||
501 | if (size < sizeof(struct UBlock)) | ||
502 | { | ||
503 | GNUNET_break (0); | ||
504 | goto get_next; | ||
505 | } | ||
506 | ub = data; | ||
507 | GNUNET_CRYPTO_hash (&ub->verification_key, | ||
508 | sizeof(ub->verification_key), | ||
509 | &query); | ||
510 | if (0 != memcmp (&query, | ||
511 | key, | ||
512 | sizeof(struct GNUNET_HashCode))) | ||
513 | { | ||
514 | /* result does not match our keyword, skip */ | ||
515 | goto get_next; | ||
516 | } | ||
517 | { | ||
518 | char pt[size - sizeof(struct UBlock)]; | ||
519 | struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub; | ||
520 | const char *keyword; | ||
521 | |||
522 | GNUNET_CRYPTO_ecdsa_key_get_public ( | ||
523 | GNUNET_CRYPTO_ecdsa_key_get_anonymous (), | ||
524 | &anon_pub); | ||
525 | keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1]; | ||
526 | GNUNET_FS_ublock_decrypt_ (&ub[1], size - sizeof(struct UBlock), | ||
527 | &anon_pub, | ||
528 | keyword, | ||
529 | pt); | ||
530 | if (NULL == memchr (&pt[1], 0, sizeof(pt) - 1)) | ||
531 | { | ||
532 | GNUNET_break_op (0); /* malformed UBlock */ | ||
533 | goto get_next; | ||
534 | } | ||
535 | chk_uri = GNUNET_FS_uri_parse (&pt[1], NULL); | ||
536 | if (NULL == chk_uri) | ||
537 | { | ||
538 | GNUNET_break_op (0); /* malformed UBlock */ | ||
539 | goto get_next; | ||
540 | } | ||
541 | } | ||
542 | if (0 != memcmp (&uc->chk, | ||
543 | &chk_uri->data.chk.chk, | ||
544 | sizeof(struct ContentHashKey))) | ||
545 | { | ||
546 | /* different CHK, ignore */ | ||
547 | GNUNET_FS_uri_destroy (chk_uri); | ||
548 | goto get_next; | ||
549 | } | ||
550 | GNUNET_FS_uri_destroy (chk_uri); | ||
551 | /* matches! */ | ||
552 | uc->dqe = GNUNET_DATASTORE_remove (uc->dsh, | ||
553 | key, | ||
554 | size, | ||
555 | data, | ||
556 | 0 /* priority */, | ||
557 | 1 /* queue size */, | ||
558 | &continue_after_remove, | ||
559 | uc); | ||
560 | return; | ||
561 | get_next: | ||
562 | uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh, | ||
563 | uid + 1 /* next_uid */, | ||
564 | false /* random */, | ||
565 | &uc->uquery, | ||
566 | GNUNET_BLOCK_TYPE_FS_UBLOCK, | ||
567 | 0 /* priority */, | ||
568 | 1 /* queue size */, | ||
569 | &process_kblock_for_unindex, | ||
570 | uc); | ||
571 | } | ||
572 | |||
573 | |||
574 | /** | ||
575 | * If necessary, connect to the datastore and remove the KBlocks. | ||
576 | * | ||
577 | * @param uc context for the unindex operation. | ||
578 | */ | ||
579 | void | ||
580 | GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc) | ||
581 | { | ||
582 | const char *keyword; | ||
583 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon; | ||
584 | struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub; | ||
585 | struct GNUNET_CRYPTO_EcdsaPublicKey dpub; | ||
586 | |||
587 | if (NULL == uc->dsh) | ||
588 | uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg); | ||
589 | if (NULL == uc->dsh) | ||
590 | { | ||
591 | uc->state = UNINDEX_STATE_ERROR; | ||
592 | uc->emsg = GNUNET_strdup (_ ("Failed to connect to `datastore' service.")); | ||
593 | GNUNET_FS_unindex_sync_ (uc); | ||
594 | signal_unindex_error (uc); | ||
595 | return; | ||
596 | } | ||
597 | if ((NULL == uc->ksk_uri) || | ||
598 | (uc->ksk_offset >= uc->ksk_uri->data.ksk.keywordCount)) | ||
599 | { | ||
600 | unindex_finish (uc); | ||
601 | return; | ||
602 | } | ||
603 | anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous (); | ||
604 | GNUNET_CRYPTO_ecdsa_key_get_public (anon, | ||
605 | &anon_pub); | ||
606 | keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1]; | ||
607 | GNUNET_CRYPTO_ecdsa_public_key_derive (&anon_pub, | ||
608 | keyword, | ||
609 | "fs-ublock", | ||
610 | &dpub); | ||
611 | GNUNET_CRYPTO_hash (&dpub, | ||
612 | sizeof(dpub), | ||
613 | &uc->uquery); | ||
614 | uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh, | ||
615 | 0 /* next_uid */, | ||
616 | false /* random */, | ||
617 | &uc->uquery, | ||
618 | GNUNET_BLOCK_TYPE_FS_UBLOCK, | ||
619 | 0 /* priority */, | ||
620 | 1 /* queue size */, | ||
621 | &process_kblock_for_unindex, | ||
622 | uc); | ||
623 | } | ||
624 | |||
625 | |||
626 | /** | ||
627 | * Function called when the tree encoder has | ||
628 | * processed all blocks. Clean up. | ||
629 | * | ||
630 | * @param cls our unindexing context | ||
631 | */ | ||
632 | static void | ||
633 | unindex_extract_keywords (void *cls) | ||
634 | { | ||
635 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
636 | |||
637 | uc->state = UNINDEX_STATE_EXTRACT_KEYWORDS; | ||
638 | GNUNET_FS_unindex_sync_ (uc); | ||
639 | GNUNET_FS_unindex_do_extract_keywords_ (uc); | ||
640 | } | ||
641 | |||
642 | |||
643 | /** | ||
644 | * Connect to the datastore and remove the blocks. | ||
645 | * | ||
646 | * @param uc context for the unindex operation. | ||
647 | */ | ||
648 | void | ||
649 | GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc) | ||
650 | { | ||
651 | if (NULL == uc->dsh) | ||
652 | uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg); | ||
653 | if (NULL == uc->dsh) | ||
654 | { | ||
655 | uc->state = UNINDEX_STATE_ERROR; | ||
656 | uc->emsg = GNUNET_strdup (_ ("Failed to connect to `datastore' service.")); | ||
657 | GNUNET_FS_unindex_sync_ (uc); | ||
658 | signal_unindex_error (uc); | ||
659 | return; | ||
660 | } | ||
661 | uc->fh = | ||
662 | GNUNET_DISK_file_open (uc->filename, GNUNET_DISK_OPEN_READ, | ||
663 | GNUNET_DISK_PERM_NONE); | ||
664 | if (NULL == uc->fh) | ||
665 | { | ||
666 | GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); | ||
667 | uc->dsh = NULL; | ||
668 | uc->state = UNINDEX_STATE_ERROR; | ||
669 | uc->emsg = GNUNET_strdup (_ ("Failed to open file for unindexing.")); | ||
670 | GNUNET_FS_unindex_sync_ (uc); | ||
671 | signal_unindex_error (uc); | ||
672 | return; | ||
673 | } | ||
674 | uc->tc = | ||
675 | GNUNET_FS_tree_encoder_create (uc->h, | ||
676 | uc->file_size, | ||
677 | uc, | ||
678 | &unindex_reader, | ||
679 | &unindex_process, | ||
680 | &unindex_progress, | ||
681 | &unindex_extract_keywords); | ||
682 | GNUNET_FS_tree_encoder_next (uc->tc); | ||
683 | } | ||
684 | |||
685 | |||
686 | /** | ||
687 | * Function called once the hash of the file | ||
688 | * that is being unindexed has been computed. | ||
689 | * | ||
690 | * @param cls closure, unindex context | ||
691 | * @param file_id computed hash, NULL on error | ||
692 | */ | ||
693 | void | ||
694 | GNUNET_FS_unindex_process_hash_ (void *cls, | ||
695 | const struct GNUNET_HashCode *file_id) | ||
696 | { | ||
697 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
698 | |||
699 | uc->fhc = NULL; | ||
700 | if (uc->state != UNINDEX_STATE_HASHING) | ||
701 | { | ||
702 | GNUNET_FS_unindex_stop (uc); | ||
703 | return; | ||
704 | } | ||
705 | if (file_id == NULL) | ||
706 | { | ||
707 | uc->state = UNINDEX_STATE_ERROR; | ||
708 | uc->emsg = GNUNET_strdup (_ ("Failed to compute hash of file.")); | ||
709 | GNUNET_FS_unindex_sync_ (uc); | ||
710 | signal_unindex_error (uc); | ||
711 | return; | ||
712 | } | ||
713 | uc->file_id = *file_id; | ||
714 | uc->state = UNINDEX_STATE_DS_REMOVE; | ||
715 | GNUNET_FS_unindex_sync_ (uc); | ||
716 | GNUNET_FS_unindex_do_remove_ (uc); | ||
717 | } | ||
718 | |||
719 | |||
720 | /** | ||
721 | * Create SUSPEND event for the given unindex operation | ||
722 | * and then clean up our state (without stop signal). | ||
723 | * | ||
724 | * @param cls the `struct GNUNET_FS_UnindexContext` to signal for | ||
725 | */ | ||
726 | void | ||
727 | GNUNET_FS_unindex_signal_suspend_ (void *cls) | ||
728 | { | ||
729 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
730 | struct GNUNET_FS_ProgressInfo pi; | ||
731 | |||
732 | /* FIXME: lots of duplication with unindex_stop here! */ | ||
733 | if (uc->dscan != NULL) | ||
734 | { | ||
735 | GNUNET_FS_directory_scan_abort (uc->dscan); | ||
736 | uc->dscan = NULL; | ||
737 | } | ||
738 | if (NULL != uc->dqe) | ||
739 | { | ||
740 | GNUNET_DATASTORE_cancel (uc->dqe); | ||
741 | uc->dqe = NULL; | ||
742 | } | ||
743 | if (uc->fhc != NULL) | ||
744 | { | ||
745 | GNUNET_CRYPTO_hash_file_cancel (uc->fhc); | ||
746 | uc->fhc = NULL; | ||
747 | } | ||
748 | if (NULL != uc->ksk_uri) | ||
749 | { | ||
750 | GNUNET_FS_uri_destroy (uc->ksk_uri); | ||
751 | uc->ksk_uri = NULL; | ||
752 | } | ||
753 | if (NULL != uc->mq) | ||
754 | { | ||
755 | GNUNET_MQ_destroy (uc->mq); | ||
756 | uc->mq = NULL; | ||
757 | } | ||
758 | if (NULL != uc->dsh) | ||
759 | { | ||
760 | GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); | ||
761 | uc->dsh = NULL; | ||
762 | } | ||
763 | if (NULL != uc->tc) | ||
764 | { | ||
765 | GNUNET_FS_tree_encoder_finish (uc->tc, NULL); | ||
766 | uc->tc = NULL; | ||
767 | } | ||
768 | if (uc->fh != NULL) | ||
769 | { | ||
770 | GNUNET_DISK_file_close (uc->fh); | ||
771 | uc->fh = NULL; | ||
772 | } | ||
773 | GNUNET_FS_end_top (uc->h, uc->top); | ||
774 | pi.status = GNUNET_FS_STATUS_UNINDEX_SUSPEND; | ||
775 | GNUNET_FS_unindex_make_status_ (&pi, uc, | ||
776 | (uc->state == | ||
777 | UNINDEX_STATE_COMPLETE) ? uc->file_size : 0); | ||
778 | GNUNET_break (NULL == uc->client_info); | ||
779 | GNUNET_free (uc->filename); | ||
780 | GNUNET_free (uc->serialization); | ||
781 | GNUNET_free (uc->emsg); | ||
782 | GNUNET_free (uc); | ||
783 | } | ||
784 | |||
785 | |||
786 | /** | ||
787 | * Unindex a file. | ||
788 | * | ||
789 | * @param h handle to the file sharing subsystem | ||
790 | * @param filename file to unindex | ||
791 | * @param cctx initial value for the client context | ||
792 | * @return NULL on error, otherwise handle | ||
793 | */ | ||
794 | struct GNUNET_FS_UnindexContext * | ||
795 | GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h, | ||
796 | const char *filename, | ||
797 | void *cctx) | ||
798 | { | ||
799 | struct GNUNET_FS_UnindexContext *uc; | ||
800 | struct GNUNET_FS_ProgressInfo pi; | ||
801 | uint64_t size; | ||
802 | |||
803 | if (GNUNET_OK != | ||
804 | GNUNET_DISK_file_size (filename, | ||
805 | &size, | ||
806 | GNUNET_YES, | ||
807 | GNUNET_YES)) | ||
808 | return NULL; | ||
809 | uc = GNUNET_new (struct GNUNET_FS_UnindexContext); | ||
810 | uc->h = h; | ||
811 | uc->filename = GNUNET_strdup (filename); | ||
812 | uc->start_time = GNUNET_TIME_absolute_get (); | ||
813 | uc->file_size = size; | ||
814 | uc->client_info = cctx; | ||
815 | GNUNET_FS_unindex_sync_ (uc); | ||
816 | pi.status = GNUNET_FS_STATUS_UNINDEX_START; | ||
817 | pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
818 | GNUNET_FS_unindex_make_status_ (&pi, uc, 0); | ||
819 | uc->fhc = | ||
820 | GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
821 | filename, | ||
822 | HASHING_BLOCKSIZE, | ||
823 | &GNUNET_FS_unindex_process_hash_, uc); | ||
824 | uc->top = GNUNET_FS_make_top (h, | ||
825 | &GNUNET_FS_unindex_signal_suspend_, | ||
826 | uc); | ||
827 | return uc; | ||
828 | } | ||
829 | |||
830 | |||
831 | /** | ||
832 | * Clean up after completion of an unindex operation. | ||
833 | * | ||
834 | * @param uc handle | ||
835 | */ | ||
836 | void | ||
837 | GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc) | ||
838 | { | ||
839 | struct GNUNET_FS_ProgressInfo pi; | ||
840 | |||
841 | if (NULL != uc->dscan) | ||
842 | { | ||
843 | GNUNET_FS_directory_scan_abort (uc->dscan); | ||
844 | uc->dscan = NULL; | ||
845 | } | ||
846 | if (NULL != uc->dqe) | ||
847 | { | ||
848 | GNUNET_DATASTORE_cancel (uc->dqe); | ||
849 | uc->dqe = NULL; | ||
850 | } | ||
851 | if (NULL != uc->fhc) | ||
852 | { | ||
853 | GNUNET_CRYPTO_hash_file_cancel (uc->fhc); | ||
854 | uc->fhc = NULL; | ||
855 | } | ||
856 | if (NULL != uc->mq) | ||
857 | { | ||
858 | GNUNET_MQ_destroy (uc->mq); | ||
859 | uc->mq = NULL; | ||
860 | } | ||
861 | if (NULL != uc->dsh) | ||
862 | { | ||
863 | GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); | ||
864 | uc->dsh = NULL; | ||
865 | } | ||
866 | if (NULL != uc->ksk_uri) | ||
867 | { | ||
868 | GNUNET_FS_uri_destroy (uc->ksk_uri); | ||
869 | uc->ksk_uri = NULL; | ||
870 | } | ||
871 | if (NULL != uc->tc) | ||
872 | { | ||
873 | GNUNET_FS_tree_encoder_finish (uc->tc, NULL); | ||
874 | uc->tc = NULL; | ||
875 | } | ||
876 | if (uc->fh != NULL) | ||
877 | { | ||
878 | GNUNET_DISK_file_close (uc->fh); | ||
879 | uc->fh = NULL; | ||
880 | } | ||
881 | GNUNET_FS_end_top (uc->h, uc->top); | ||
882 | if (uc->serialization != NULL) | ||
883 | { | ||
884 | GNUNET_FS_remove_sync_file_ (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, | ||
885 | uc->serialization); | ||
886 | GNUNET_free (uc->serialization); | ||
887 | uc->serialization = NULL; | ||
888 | } | ||
889 | pi.status = GNUNET_FS_STATUS_UNINDEX_STOPPED; | ||
890 | pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO; | ||
891 | GNUNET_FS_unindex_make_status_ (&pi, uc, | ||
892 | (uc->state == | ||
893 | UNINDEX_STATE_COMPLETE) ? uc->file_size : 0); | ||
894 | GNUNET_break (NULL == uc->client_info); | ||
895 | GNUNET_free (uc->emsg); | ||
896 | GNUNET_free (uc->filename); | ||
897 | GNUNET_free (uc); | ||
898 | } | ||
899 | |||
900 | |||
901 | /* end of fs_unindex.c */ | ||
diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c deleted file mode 100644 index 73ea5d60d..000000000 --- a/src/fs/fs_uri.c +++ /dev/null | |||
@@ -1,2055 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003--2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_uri.c | ||
23 | * @brief Parses and produces uri strings. | ||
24 | * @author Igor Wronsky, Christian Grothoff | ||
25 | * | ||
26 | * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER". | ||
27 | * The specific structure of "IDENTIFIER" depends on the module and | ||
28 | * maybe differentiated into additional subcategories if applicable. | ||
29 | * This module only deals with fs identifiers (MODULE = "fs"). | ||
30 | * <p> | ||
31 | * | ||
32 | * This module only parses URIs for the AFS module. The FS URIs fall | ||
33 | * into four categories, "chk", "sks", "ksk" and "loc". The first three | ||
34 | * categories were named in analogy (!) to Freenet, but they do NOT | ||
35 | * work in exactly the same way. They are very similar from the user's | ||
36 | * point of view (unique file identifier, subspace, keyword), but the | ||
37 | * implementation is rather different in pretty much every detail. | ||
38 | * The concrete URI formats are: | ||
39 | * | ||
40 | * </p> | ||
41 | * | ||
42 | * <ul><li> | ||
43 | * | ||
44 | * First, there are URIs that identify a file. They have the format | ||
45 | * "gnunet://fs/chk/HEX1.HEX2.SIZE". These URIs can be used to | ||
46 | * download the file. The description, filename, mime-type and other | ||
47 | * meta-data is NOT part of the file-URI since a URI uniquely | ||
48 | * identifies a resource (and the contents of the file would be the | ||
49 | * same even if it had a different description). | ||
50 | * | ||
51 | * </li><li> | ||
52 | * | ||
53 | * The second category identifies entries in a namespace. The format | ||
54 | * is "gnunet://fs/sks/NAMESPACE/IDENTIFIER" where the namespace | ||
55 | * should be given in HEX. Applications may allow using a nickname | ||
56 | * for the namespace if the nickname is not ambiguous. The identifier | ||
57 | * can be either an ASCII sequence or a HEX-encoding. If the | ||
58 | * identifier is in ASCII but the format is ambiguous and could denote | ||
59 | * a HEX-string a "/" is appended to indicate ASCII encoding. | ||
60 | * | ||
61 | * </li> <li> | ||
62 | * | ||
63 | * The third category identifies ordinary searches. The format is | ||
64 | * "gnunet://fs/ksk/KEYWORD[+KEYWORD]*". Using the "+" syntax | ||
65 | * it is possible to encode searches with the boolean "AND" operator. | ||
66 | * "+" is used since it indicates a commutative 'and' operation and | ||
67 | * is unlikely to be used in a keyword by itself. | ||
68 | * | ||
69 | * </li><li> | ||
70 | * | ||
71 | * The last category identifies a datum on a specific machine. The | ||
72 | * format is "gnunet://fs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME". PEER is | ||
73 | * the BinName of the public key of the peer storing the datum. The | ||
74 | * signature (SIG) certifies that this peer has this content. | ||
75 | * HEX1, HEX2 and SIZE correspond to a 'chk' URI. | ||
76 | * | ||
77 | * </li></ul> | ||
78 | * | ||
79 | * The encoding for hexadecimal values is defined in the hashing.c | ||
80 | * module in the gnunetutil library and discussed there. | ||
81 | * | ||
82 | */ | ||
83 | #include "platform.h" | ||
84 | #include "gnunet_fs_service.h" | ||
85 | #include "gnunet_signatures.h" | ||
86 | #include "fs_api.h" | ||
87 | #include <unitypes.h> | ||
88 | #include <unicase.h> | ||
89 | #include <uniconv.h> | ||
90 | #include <unistr.h> | ||
91 | #include <unistdio.h> | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Get a unique key from a URI. This is for putting URIs | ||
96 | * into HashMaps. The key may change between FS implementations. | ||
97 | * | ||
98 | * @param uri uri to convert to a unique key | ||
99 | * @param key where to store the unique key | ||
100 | * @return #GNUNET_OK on success | ||
101 | */ | ||
102 | int | ||
103 | GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, | ||
104 | struct GNUNET_HashCode *key) | ||
105 | { | ||
106 | switch (uri->type) | ||
107 | { | ||
108 | case GNUNET_FS_URI_CHK: | ||
109 | *key = uri->data.chk.chk.query; | ||
110 | return GNUNET_OK; | ||
111 | |||
112 | case GNUNET_FS_URI_SKS: | ||
113 | GNUNET_CRYPTO_hash (uri->data.sks.identifier, | ||
114 | strlen (uri->data.sks.identifier), | ||
115 | key); | ||
116 | return GNUNET_OK; | ||
117 | |||
118 | case GNUNET_FS_URI_KSK: | ||
119 | if (uri->data.ksk.keywordCount > 0) | ||
120 | { | ||
121 | GNUNET_CRYPTO_hash (uri->data.ksk.keywords[0], | ||
122 | strlen (uri->data.ksk.keywords[0]), | ||
123 | key); | ||
124 | return GNUNET_OK; | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | memset (key, 0, sizeof(struct GNUNET_HashCode)); | ||
129 | return GNUNET_SYSERR; | ||
130 | } | ||
131 | break; | ||
132 | |||
133 | case GNUNET_FS_URI_LOC: | ||
134 | GNUNET_CRYPTO_hash (&uri->data.loc.fi, | ||
135 | sizeof(struct FileIdentifier) | ||
136 | + sizeof(struct GNUNET_PeerIdentity), | ||
137 | key); | ||
138 | return GNUNET_OK; | ||
139 | |||
140 | default: | ||
141 | memset (key, 0, sizeof(struct GNUNET_HashCode)); | ||
142 | return GNUNET_SYSERR; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | |||
147 | /** | ||
148 | * Convert keyword URI to a human readable format | ||
149 | * (i.e. the search query that was used in the first place) | ||
150 | * | ||
151 | * @param uri ksk uri to convert to a string | ||
152 | * @return string with the keywords | ||
153 | */ | ||
154 | char * | ||
155 | GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri) | ||
156 | { | ||
157 | size_t n; | ||
158 | char *ret; | ||
159 | unsigned int i; | ||
160 | const char *keyword; | ||
161 | char **keywords; | ||
162 | unsigned int keywordCount; | ||
163 | |||
164 | if ((NULL == uri) || (GNUNET_FS_URI_KSK != uri->type)) | ||
165 | { | ||
166 | GNUNET_break (0); | ||
167 | return NULL; | ||
168 | } | ||
169 | keywords = uri->data.ksk.keywords; | ||
170 | keywordCount = uri->data.ksk.keywordCount; | ||
171 | n = keywordCount + 1; | ||
172 | for (i = 0; i < keywordCount; i++) | ||
173 | { | ||
174 | keyword = keywords[i]; | ||
175 | n += strlen (keyword) - 1; | ||
176 | if (NULL != strstr (&keyword[1], " ")) | ||
177 | n += 2; | ||
178 | if (keyword[0] == '+') | ||
179 | n++; | ||
180 | } | ||
181 | ret = GNUNET_malloc (n); | ||
182 | strcpy (ret, ""); | ||
183 | for (i = 0; i < keywordCount; i++) | ||
184 | { | ||
185 | keyword = keywords[i]; | ||
186 | if (NULL != strstr (&keyword[1], " ")) | ||
187 | { | ||
188 | strcat (ret, "\""); | ||
189 | if (keyword[0] == '+') | ||
190 | strcat (ret, keyword); | ||
191 | else | ||
192 | strcat (ret, &keyword[1]); | ||
193 | strcat (ret, "\""); | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | if (keyword[0] == '+') | ||
198 | strcat (ret, keyword); | ||
199 | else | ||
200 | strcat (ret, &keyword[1]); | ||
201 | } | ||
202 | strcat (ret, " "); | ||
203 | } | ||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Given a keyword with %-encoding (and possibly quotes to protect | ||
210 | * spaces), return a copy of the keyword without %-encoding and | ||
211 | * without double-quotes (%22). Also, add a space at the beginning | ||
212 | * if there is not a '+'. | ||
213 | * | ||
214 | * @param in string with %-encoding | ||
215 | * @param emsg where to store the parser error message (if any) | ||
216 | * @return decoded string with leading space (or preserved plus) | ||
217 | */ | ||
218 | static char * | ||
219 | percent_decode_keyword (const char *in, char **emsg) | ||
220 | { | ||
221 | char *out; | ||
222 | char *ret; | ||
223 | unsigned int rpos; | ||
224 | unsigned int wpos; | ||
225 | unsigned int hx; | ||
226 | |||
227 | out = GNUNET_strdup (in); | ||
228 | rpos = 0; | ||
229 | wpos = 0; | ||
230 | while (out[rpos] != '\0') | ||
231 | { | ||
232 | if (out[rpos] == '%') | ||
233 | { | ||
234 | if (1 != sscanf (&out[rpos + 1], "%2X", &hx)) | ||
235 | { | ||
236 | GNUNET_free (out); | ||
237 | *emsg = GNUNET_strdup ( | ||
238 | _ ( /* xgettext:no-c-format */ | ||
239 | "Malformed KSK URI (`%' must be followed by HEX number)")); | ||
240 | return NULL; | ||
241 | } | ||
242 | rpos += 3; | ||
243 | if (hx == '"') | ||
244 | continue; /* skip double quote */ | ||
245 | out[wpos++] = (char) hx; | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | out[wpos++] = out[rpos++]; | ||
250 | } | ||
251 | } | ||
252 | out[wpos] = '\0'; | ||
253 | if (out[0] == '+') | ||
254 | { | ||
255 | ret = GNUNET_strdup (out); | ||
256 | } | ||
257 | else | ||
258 | { | ||
259 | /* need to prefix with space */ | ||
260 | ret = GNUNET_malloc (strlen (out) + 2); | ||
261 | strcpy (ret, " "); | ||
262 | strcat (ret, out); | ||
263 | } | ||
264 | GNUNET_free (out); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | |||
269 | #define GNUNET_FS_URI_KSK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX | ||
270 | |||
271 | /** | ||
272 | * Parse a KSK URI. | ||
273 | * | ||
274 | * @param s an uri string | ||
275 | * @param emsg where to store the parser error message (if any) | ||
276 | * @return NULL on error, otherwise the KSK URI | ||
277 | */ | ||
278 | static struct GNUNET_FS_Uri * | ||
279 | uri_ksk_parse (const char *s, char **emsg) | ||
280 | { | ||
281 | struct GNUNET_FS_Uri *ret; | ||
282 | char **keywords; | ||
283 | unsigned int pos; | ||
284 | int max; | ||
285 | int iret; | ||
286 | int i; | ||
287 | size_t slen; | ||
288 | char *dup; | ||
289 | int saw_quote; | ||
290 | |||
291 | slen = strlen (s); | ||
292 | pos = strlen (GNUNET_FS_URI_KSK_PREFIX); | ||
293 | if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_KSK_PREFIX, pos))) | ||
294 | return NULL; /* not KSK URI */ | ||
295 | if ((s[slen - 1] == '+') || (s[pos] == '+')) | ||
296 | { | ||
297 | *emsg = | ||
298 | GNUNET_strdup (_ ("Malformed KSK URI (must not begin or end with `+')")); | ||
299 | return NULL; | ||
300 | } | ||
301 | max = 1; | ||
302 | saw_quote = 0; | ||
303 | for (i = pos; i < slen; i++) | ||
304 | { | ||
305 | if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) | ||
306 | { | ||
307 | saw_quote = (saw_quote + 1) % 2; | ||
308 | i += 3; | ||
309 | continue; | ||
310 | } | ||
311 | if ((s[i] == '+') && (saw_quote == 0)) | ||
312 | { | ||
313 | max++; | ||
314 | if (s[i - 1] == '+') | ||
315 | { | ||
316 | *emsg = GNUNET_strdup (_ ("Malformed KSK URI (`++' not allowed)")); | ||
317 | return NULL; | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | if (saw_quote == 1) | ||
322 | { | ||
323 | *emsg = GNUNET_strdup (_ ("Malformed KSK URI (quotes not balanced)")); | ||
324 | return NULL; | ||
325 | } | ||
326 | iret = max; | ||
327 | dup = GNUNET_strdup (s); | ||
328 | keywords = GNUNET_new_array (max, char *); | ||
329 | for (i = slen - 1; i >= (int) pos; i--) | ||
330 | { | ||
331 | if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) | ||
332 | { | ||
333 | saw_quote = (saw_quote + 1) % 2; | ||
334 | continue; | ||
335 | } | ||
336 | if ((dup[i] == '+') && (saw_quote == 0)) | ||
337 | { | ||
338 | keywords[--max] = percent_decode_keyword (&dup[i + 1], emsg); | ||
339 | if (NULL == keywords[max]) | ||
340 | goto CLEANUP; | ||
341 | dup[i] = '\0'; | ||
342 | } | ||
343 | } | ||
344 | keywords[--max] = percent_decode_keyword (&dup[pos], emsg); | ||
345 | if (NULL == keywords[max]) | ||
346 | goto CLEANUP; | ||
347 | GNUNET_assert (0 == max); | ||
348 | GNUNET_free (dup); | ||
349 | ret = GNUNET_new (struct GNUNET_FS_Uri); | ||
350 | ret->type = GNUNET_FS_URI_KSK; | ||
351 | ret->data.ksk.keywordCount = iret; | ||
352 | ret->data.ksk.keywords = keywords; | ||
353 | return ret; | ||
354 | CLEANUP: | ||
355 | for (i = 0; i < max; i++) | ||
356 | GNUNET_free (keywords[i]); | ||
357 | GNUNET_free (keywords); | ||
358 | GNUNET_free (dup); | ||
359 | return NULL; | ||
360 | } | ||
361 | |||
362 | |||
363 | #define GNUNET_FS_URI_SKS_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX | ||
364 | |||
365 | /** | ||
366 | * Parse an SKS URI. | ||
367 | * | ||
368 | * @param s an uri string | ||
369 | * @param emsg where to store the parser error message (if any) | ||
370 | * @return NULL on error, SKS URI otherwise | ||
371 | */ | ||
372 | static struct GNUNET_FS_Uri * | ||
373 | uri_sks_parse (const char *s, char **emsg) | ||
374 | { | ||
375 | struct GNUNET_FS_Uri *ret; | ||
376 | struct GNUNET_CRYPTO_EcdsaPublicKey ns; | ||
377 | size_t pos; | ||
378 | char *end; | ||
379 | |||
380 | pos = strlen (GNUNET_FS_URI_SKS_PREFIX); | ||
381 | if ((strlen (s) <= pos) || (0 != strncmp (s, GNUNET_FS_URI_SKS_PREFIX, pos))) | ||
382 | return NULL; /* not an SKS URI */ | ||
383 | end = strchr (&s[pos], '/'); | ||
384 | if ((NULL == end) || | ||
385 | (GNUNET_OK != GNUNET_STRINGS_string_to_data (&s[pos], | ||
386 | end - &s[pos], | ||
387 | &ns, | ||
388 | sizeof(ns)))) | ||
389 | { | ||
390 | *emsg = GNUNET_strdup (_ ("Malformed SKS URI (wrong syntax)")); | ||
391 | return NULL; /* malformed */ | ||
392 | } | ||
393 | end++; /* skip over '/' */ | ||
394 | ret = GNUNET_new (struct GNUNET_FS_Uri); | ||
395 | ret->type = GNUNET_FS_URI_SKS; | ||
396 | ret->data.sks.ns = ns; | ||
397 | ret->data.sks.identifier = GNUNET_strdup (end); | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | |||
402 | #define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX | ||
403 | |||
404 | |||
405 | /** | ||
406 | * Parse a CHK URI. | ||
407 | * | ||
408 | * @param s an uri string | ||
409 | * @param emsg where to store the parser error message (if any) | ||
410 | * @return NULL on error, CHK URI otherwise | ||
411 | */ | ||
412 | static struct GNUNET_FS_Uri * | ||
413 | uri_chk_parse (const char *s, char **emsg) | ||
414 | { | ||
415 | struct GNUNET_FS_Uri *ret; | ||
416 | struct FileIdentifier fi; | ||
417 | unsigned int pos; | ||
418 | unsigned long long flen; | ||
419 | size_t slen; | ||
420 | char h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)]; | ||
421 | char h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)]; | ||
422 | |||
423 | slen = strlen (s); | ||
424 | pos = strlen (GNUNET_FS_URI_CHK_PREFIX); | ||
425 | if ((slen < pos + 2 * sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || | ||
426 | (0 != strncmp (s, GNUNET_FS_URI_CHK_PREFIX, pos))) | ||
427 | return NULL; /* not a CHK URI */ | ||
428 | if ((s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || | ||
429 | (s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) | ||
430 | { | ||
431 | *emsg = GNUNET_strdup (_ ("Malformed CHK URI (wrong syntax)")); | ||
432 | return NULL; | ||
433 | } | ||
434 | GNUNET_memcpy (h1, &s[pos], sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)); | ||
435 | h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; | ||
436 | GNUNET_memcpy (h2, | ||
437 | &s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)], | ||
438 | sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)); | ||
439 | h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; | ||
440 | |||
441 | if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &fi.chk.key)) || | ||
442 | (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &fi.chk.query)) || | ||
443 | (1 != | ||
444 | sscanf (&s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], | ||
445 | "%llu", | ||
446 | &flen))) | ||
447 | { | ||
448 | *emsg = GNUNET_strdup (_ ("Malformed CHK URI (failed to decode CHK)")); | ||
449 | return NULL; | ||
450 | } | ||
451 | fi.file_length = GNUNET_htonll (flen); | ||
452 | ret = GNUNET_new (struct GNUNET_FS_Uri); | ||
453 | ret->type = GNUNET_FS_URI_CHK; | ||
454 | ret->data.chk = fi; | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | |||
459 | GNUNET_NETWORK_STRUCT_BEGIN | ||
460 | /** | ||
461 | * Structure that defines how the contents of a location URI must be | ||
462 | * assembled in memory to create or verify the signature of a location | ||
463 | * URI. | ||
464 | */ | ||
465 | struct LocUriAssembly | ||
466 | { | ||
467 | /** | ||
468 | * What is being signed (rest of this struct). | ||
469 | */ | ||
470 | struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | ||
471 | |||
472 | /** | ||
473 | * Expiration time of the offer. | ||
474 | */ | ||
475 | struct GNUNET_TIME_AbsoluteNBO exptime; | ||
476 | |||
477 | /** | ||
478 | * File being offered. | ||
479 | */ | ||
480 | struct FileIdentifier fi; | ||
481 | |||
482 | /** | ||
483 | * Peer offering the file. | ||
484 | */ | ||
485 | struct GNUNET_PeerIdentity peer; | ||
486 | }; | ||
487 | GNUNET_NETWORK_STRUCT_END | ||
488 | |||
489 | |||
490 | #define GNUNET_FS_URI_LOC_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX | ||
491 | |||
492 | #define SIGNATURE_ASCII_LENGTH 103 | ||
493 | |||
494 | /** | ||
495 | * Parse a LOC URI. | ||
496 | * Also verifies validity of the location URI. | ||
497 | * | ||
498 | * @param s an uri string | ||
499 | * @param emsg where to store the parser error message (if any) | ||
500 | * @return NULL on error, valid LOC URI otherwise | ||
501 | */ | ||
502 | static struct GNUNET_FS_Uri * | ||
503 | uri_loc_parse (const char *s, char **emsg) | ||
504 | { | ||
505 | struct GNUNET_FS_Uri *uri; | ||
506 | char h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)]; | ||
507 | char h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)]; | ||
508 | unsigned int pos; | ||
509 | unsigned int npos; | ||
510 | unsigned long long exptime; | ||
511 | unsigned long long flen; | ||
512 | struct GNUNET_TIME_Absolute et; | ||
513 | struct GNUNET_CRYPTO_EddsaSignature sig; | ||
514 | struct LocUriAssembly ass; | ||
515 | size_t slen; | ||
516 | |||
517 | slen = strlen (s); | ||
518 | pos = strlen (GNUNET_FS_URI_LOC_PREFIX); | ||
519 | if ((slen < pos + 2 * sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || | ||
520 | (0 != strncmp (s, GNUNET_FS_URI_LOC_PREFIX, pos))) | ||
521 | return NULL; /* not a LOC URI */ | ||
522 | if ((s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || | ||
523 | (s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) | ||
524 | { | ||
525 | *emsg = GNUNET_strdup (_ ("LOC URI malformed (wrong syntax)")); | ||
526 | return NULL; | ||
527 | } | ||
528 | GNUNET_memcpy (h1, &s[pos], sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)); | ||
529 | h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; | ||
530 | GNUNET_memcpy (h2, | ||
531 | &s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)], | ||
532 | sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)); | ||
533 | h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; | ||
534 | |||
535 | if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &ass.fi.chk.key)) || | ||
536 | (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &ass.fi.chk.query)) || | ||
537 | (1 != | ||
538 | sscanf (&s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], | ||
539 | "%llu", | ||
540 | &flen))) | ||
541 | { | ||
542 | *emsg = GNUNET_strdup (_ ("LOC URI malformed (no CHK)")); | ||
543 | return NULL; | ||
544 | } | ||
545 | ass.fi.file_length = GNUNET_htonll (flen); | ||
546 | |||
547 | npos = pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2; | ||
548 | while ((s[npos] != '\0') && (s[npos] != '.')) | ||
549 | npos++; | ||
550 | if (s[npos] == '\0') | ||
551 | { | ||
552 | *emsg = GNUNET_strdup (_ ("LOC URI malformed (missing LOC)")); | ||
553 | goto ERR; | ||
554 | } | ||
555 | npos++; | ||
556 | if ((strlen (&s[npos]) <= GNUNET_CRYPTO_PKEY_ASCII_LENGTH + 1) || | ||
557 | ('.' != s[npos + GNUNET_CRYPTO_PKEY_ASCII_LENGTH])) | ||
558 | { | ||
559 | *emsg = | ||
560 | GNUNET_strdup (_ ("LOC URI malformed (wrong syntax for public key)")); | ||
561 | } | ||
562 | if ( | ||
563 | GNUNET_OK != | ||
564 | GNUNET_CRYPTO_eddsa_public_key_from_string (&s[npos], | ||
565 | GNUNET_CRYPTO_PKEY_ASCII_LENGTH, | ||
566 | &ass.peer.public_key)) | ||
567 | { | ||
568 | *emsg = | ||
569 | GNUNET_strdup (_ ("LOC URI malformed (could not decode public key)")); | ||
570 | goto ERR; | ||
571 | } | ||
572 | npos += GNUNET_CRYPTO_PKEY_ASCII_LENGTH; | ||
573 | if (s[npos++] != '.') | ||
574 | { | ||
575 | *emsg = GNUNET_strdup (_ ("LOC URI malformed (could not find signature)")); | ||
576 | goto ERR; | ||
577 | } | ||
578 | if ((strlen (&s[npos]) <= SIGNATURE_ASCII_LENGTH + 1) || | ||
579 | ('.' != s[npos + SIGNATURE_ASCII_LENGTH])) | ||
580 | { | ||
581 | *emsg = | ||
582 | GNUNET_strdup (_ ("LOC URI malformed (wrong syntax for signature)")); | ||
583 | goto ERR; | ||
584 | } | ||
585 | if (GNUNET_OK != | ||
586 | GNUNET_STRINGS_string_to_data (&s[npos], | ||
587 | SIGNATURE_ASCII_LENGTH, | ||
588 | &sig, | ||
589 | sizeof( | ||
590 | struct GNUNET_CRYPTO_EddsaSignature))) | ||
591 | { | ||
592 | *emsg = | ||
593 | GNUNET_strdup (_ ("LOC URI malformed (could not decode signature)")); | ||
594 | goto ERR; | ||
595 | } | ||
596 | npos += SIGNATURE_ASCII_LENGTH; | ||
597 | if (s[npos++] != '.') | ||
598 | { | ||
599 | *emsg = GNUNET_strdup ( | ||
600 | _ ("LOC URI malformed (wrong syntax for expiration time)")); | ||
601 | goto ERR; | ||
602 | } | ||
603 | if (1 != sscanf (&s[npos], "%llu", &exptime)) | ||
604 | { | ||
605 | *emsg = | ||
606 | GNUNET_strdup (_ ("LOC URI malformed (could not parse expiration time)")); | ||
607 | goto ERR; | ||
608 | } | ||
609 | ass.purpose.size = htonl (sizeof(struct LocUriAssembly)); | ||
610 | ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); | ||
611 | et.abs_value_us = exptime * 1000LL * 1000LL; | ||
612 | ass.exptime = GNUNET_TIME_absolute_hton (et); | ||
613 | if (GNUNET_OK != | ||
614 | GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT, | ||
615 | &ass, | ||
616 | &sig, | ||
617 | &ass.peer.public_key)) | ||
618 | { | ||
619 | *emsg = | ||
620 | GNUNET_strdup (_ ("LOC URI malformed (signature failed validation)")); | ||
621 | goto ERR; | ||
622 | } | ||
623 | uri = GNUNET_new (struct GNUNET_FS_Uri); | ||
624 | uri->type = GNUNET_FS_URI_LOC; | ||
625 | uri->data.loc.fi = ass.fi; | ||
626 | uri->data.loc.peer = ass.peer; | ||
627 | uri->data.loc.expirationTime = et; | ||
628 | uri->data.loc.contentSignature = sig; | ||
629 | |||
630 | return uri; | ||
631 | ERR: | ||
632 | return NULL; | ||
633 | } | ||
634 | |||
635 | |||
636 | /** | ||
637 | * Convert a UTF-8 String to a URI. | ||
638 | * | ||
639 | * @param uri string to parse | ||
640 | * @param emsg where to store the parser error message (if any) | ||
641 | * @return NULL on error | ||
642 | */ | ||
643 | struct GNUNET_FS_Uri * | ||
644 | GNUNET_FS_uri_parse (const char *uri, char **emsg) | ||
645 | { | ||
646 | struct GNUNET_FS_Uri *ret; | ||
647 | char *msg; | ||
648 | |||
649 | if (NULL == uri) | ||
650 | { | ||
651 | GNUNET_break (0); | ||
652 | if (NULL != emsg) | ||
653 | *emsg = GNUNET_strdup (_ ("invalid argument")); | ||
654 | return NULL; | ||
655 | } | ||
656 | if (NULL == emsg) | ||
657 | emsg = &msg; | ||
658 | *emsg = NULL; | ||
659 | if ((NULL != (ret = uri_chk_parse (uri, emsg))) || | ||
660 | (NULL != (ret = uri_ksk_parse (uri, emsg))) || | ||
661 | (NULL != (ret = uri_sks_parse (uri, emsg))) || | ||
662 | (NULL != (ret = uri_loc_parse (uri, emsg)))) | ||
663 | return ret; | ||
664 | if (NULL == *emsg) | ||
665 | *emsg = GNUNET_strdup (_ ("Unrecognized URI type")); | ||
666 | if (emsg == &msg) | ||
667 | GNUNET_free (msg); | ||
668 | return NULL; | ||
669 | } | ||
670 | |||
671 | |||
672 | /** | ||
673 | * Free URI. | ||
674 | * | ||
675 | * @param uri uri to free | ||
676 | */ | ||
677 | void | ||
678 | GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri) | ||
679 | { | ||
680 | unsigned int i; | ||
681 | |||
682 | switch (uri->type) | ||
683 | { | ||
684 | case GNUNET_FS_URI_KSK: | ||
685 | for (i = 0; i < uri->data.ksk.keywordCount; i++) | ||
686 | GNUNET_free (uri->data.ksk.keywords[i]); | ||
687 | GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, 0); | ||
688 | break; | ||
689 | |||
690 | case GNUNET_FS_URI_SKS: | ||
691 | GNUNET_free (uri->data.sks.identifier); | ||
692 | break; | ||
693 | |||
694 | case GNUNET_FS_URI_LOC: | ||
695 | break; | ||
696 | |||
697 | default: | ||
698 | /* do nothing */ | ||
699 | break; | ||
700 | } | ||
701 | GNUNET_free (uri); | ||
702 | } | ||
703 | |||
704 | |||
705 | /** | ||
706 | * How many keywords are ANDed in this keyword URI? | ||
707 | * | ||
708 | * @param uri ksk uri to get the number of keywords from | ||
709 | * @return 0 if this is not a keyword URI | ||
710 | */ | ||
711 | unsigned int | ||
712 | GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri) | ||
713 | { | ||
714 | if (uri->type != GNUNET_FS_URI_KSK) | ||
715 | return 0; | ||
716 | return uri->data.ksk.keywordCount; | ||
717 | } | ||
718 | |||
719 | |||
720 | /** | ||
721 | * Iterate over all keywords in this keyword URI. | ||
722 | * | ||
723 | * @param uri ksk uri to get the keywords from | ||
724 | * @param iterator function to call on each keyword | ||
725 | * @param iterator_cls closure for iterator | ||
726 | * @return -1 if this is not a keyword URI, otherwise number of | ||
727 | * keywords iterated over until iterator aborted | ||
728 | */ | ||
729 | int | ||
730 | GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, | ||
731 | GNUNET_FS_KeywordIterator iterator, | ||
732 | void *iterator_cls) | ||
733 | { | ||
734 | unsigned int i; | ||
735 | char *keyword; | ||
736 | |||
737 | if (uri->type != GNUNET_FS_URI_KSK) | ||
738 | return -1; | ||
739 | if (NULL == iterator) | ||
740 | return uri->data.ksk.keywordCount; | ||
741 | for (i = 0; i < uri->data.ksk.keywordCount; i++) | ||
742 | { | ||
743 | keyword = uri->data.ksk.keywords[i]; | ||
744 | /* first character of keyword indicates | ||
745 | * if it is mandatory or not */ | ||
746 | if (GNUNET_OK != iterator (iterator_cls, &keyword[1],(keyword[0] == '+') )) | ||
747 | return i; | ||
748 | } | ||
749 | return i; | ||
750 | } | ||
751 | |||
752 | |||
753 | /** | ||
754 | * Add the given keyword to the set of keywords represented by the URI. | ||
755 | * Does nothing if the keyword is already present. | ||
756 | * | ||
757 | * @param uri ksk uri to modify | ||
758 | * @param keyword keyword to add | ||
759 | * @param is_mandatory is this keyword mandatory? | ||
760 | */ | ||
761 | void | ||
762 | GNUNET_FS_uri_ksk_add_keyword (struct GNUNET_FS_Uri *uri, | ||
763 | const char *keyword, | ||
764 | int is_mandatory) | ||
765 | { | ||
766 | unsigned int i; | ||
767 | const char *old; | ||
768 | char *n; | ||
769 | |||
770 | GNUNET_assert (uri->type == GNUNET_FS_URI_KSK); | ||
771 | for (i = 0; i < uri->data.ksk.keywordCount; i++) | ||
772 | { | ||
773 | old = uri->data.ksk.keywords[i]; | ||
774 | if (0 == strcmp (&old[1], keyword)) | ||
775 | return; | ||
776 | } | ||
777 | GNUNET_asprintf (&n, is_mandatory ? "+%s" : " %s", keyword); | ||
778 | GNUNET_array_append (uri->data.ksk.keywords, uri->data.ksk.keywordCount, n); | ||
779 | } | ||
780 | |||
781 | |||
782 | /** | ||
783 | * Remove the given keyword from the set of keywords represented by the URI. | ||
784 | * Does nothing if the keyword is not present. | ||
785 | * | ||
786 | * @param uri ksk uri to modify | ||
787 | * @param keyword keyword to add | ||
788 | */ | ||
789 | void | ||
790 | GNUNET_FS_uri_ksk_remove_keyword (struct GNUNET_FS_Uri *uri, | ||
791 | const char *keyword) | ||
792 | { | ||
793 | unsigned int i; | ||
794 | char *old; | ||
795 | |||
796 | GNUNET_assert (uri->type == GNUNET_FS_URI_KSK); | ||
797 | for (i = 0; i < uri->data.ksk.keywordCount; i++) | ||
798 | { | ||
799 | old = uri->data.ksk.keywords[i]; | ||
800 | if (0 == strcmp (&old[1], keyword)) | ||
801 | { | ||
802 | uri->data.ksk.keywords[i] = | ||
803 | uri->data.ksk.keywords[uri->data.ksk.keywordCount - 1]; | ||
804 | GNUNET_array_grow (uri->data.ksk.keywords, | ||
805 | uri->data.ksk.keywordCount, | ||
806 | uri->data.ksk.keywordCount - 1); | ||
807 | GNUNET_free (old); | ||
808 | return; | ||
809 | } | ||
810 | } | ||
811 | } | ||
812 | |||
813 | |||
814 | /** | ||
815 | * Obtain the identity of the peer offering the data | ||
816 | * | ||
817 | * @param uri the location URI to inspect | ||
818 | * @param peer where to store the identify of the peer (presumably) offering the content | ||
819 | * @return #GNUNET_SYSERR if this is not a location URI, otherwise #GNUNET_OK | ||
820 | */ | ||
821 | int | ||
822 | GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri, | ||
823 | struct GNUNET_PeerIdentity *peer) | ||
824 | { | ||
825 | if (uri->type != GNUNET_FS_URI_LOC) | ||
826 | return GNUNET_SYSERR; | ||
827 | *peer = uri->data.loc.peer; | ||
828 | return GNUNET_OK; | ||
829 | } | ||
830 | |||
831 | |||
832 | /** | ||
833 | * Obtain the expiration of the LOC URI. | ||
834 | * | ||
835 | * @param uri location URI to get the expiration from | ||
836 | * @return expiration time of the URI | ||
837 | */ | ||
838 | struct GNUNET_TIME_Absolute | ||
839 | GNUNET_FS_uri_loc_get_expiration (const struct GNUNET_FS_Uri *uri) | ||
840 | { | ||
841 | GNUNET_assert (uri->type == GNUNET_FS_URI_LOC); | ||
842 | return uri->data.loc.expirationTime; | ||
843 | } | ||
844 | |||
845 | |||
846 | /** | ||
847 | * Obtain the URI of the content itself. | ||
848 | * | ||
849 | * @param uri location URI to get the content URI from | ||
850 | * @return NULL if argument is not a location URI | ||
851 | */ | ||
852 | struct GNUNET_FS_Uri * | ||
853 | GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri) | ||
854 | { | ||
855 | struct GNUNET_FS_Uri *ret; | ||
856 | |||
857 | if (uri->type != GNUNET_FS_URI_LOC) | ||
858 | return NULL; | ||
859 | ret = GNUNET_new (struct GNUNET_FS_Uri); | ||
860 | ret->type = GNUNET_FS_URI_CHK; | ||
861 | ret->data.chk = uri->data.loc.fi; | ||
862 | return ret; | ||
863 | } | ||
864 | |||
865 | |||
866 | /** | ||
867 | * Construct a location URI (this peer will be used for the location). | ||
868 | * This function should only be called from within gnunet-service-fs, | ||
869 | * as it requires the peer's private key which is generally unavailable | ||
870 | * to processes directly under the user's control. However, for | ||
871 | * testing and as it logically fits under URIs, it is in this API. | ||
872 | * | ||
873 | * @param base_uri content offered by the sender | ||
874 | * @param sign_key private key of the peer | ||
875 | * @param expiration_time how long will the content be offered? | ||
876 | * @return the location URI, NULL on error | ||
877 | */ | ||
878 | struct GNUNET_FS_Uri * | ||
879 | GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *base_uri, | ||
880 | const struct GNUNET_CRYPTO_EddsaPrivateKey *sign_key, | ||
881 | struct GNUNET_TIME_Absolute expiration_time) | ||
882 | { | ||
883 | struct GNUNET_FS_Uri *uri; | ||
884 | struct GNUNET_CRYPTO_EddsaPublicKey my_public_key; | ||
885 | struct LocUriAssembly ass; | ||
886 | struct GNUNET_TIME_Absolute et; | ||
887 | |||
888 | if (GNUNET_FS_URI_CHK != base_uri->type) | ||
889 | return NULL; | ||
890 | /* we round expiration time to full seconds for SKS URIs */ | ||
891 | et.abs_value_us = (expiration_time.abs_value_us / 1000000LL) * 1000000LL; | ||
892 | GNUNET_CRYPTO_eddsa_key_get_public (sign_key, &my_public_key); | ||
893 | ass.purpose.size = htonl (sizeof(struct LocUriAssembly)); | ||
894 | ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); | ||
895 | ass.exptime = GNUNET_TIME_absolute_hton (et); | ||
896 | ass.fi = base_uri->data.chk; | ||
897 | ass.peer.public_key = my_public_key; | ||
898 | uri = GNUNET_new (struct GNUNET_FS_Uri); | ||
899 | uri->type = GNUNET_FS_URI_LOC; | ||
900 | uri->data.loc.fi = base_uri->data.chk; | ||
901 | uri->data.loc.expirationTime = et; | ||
902 | uri->data.loc.peer.public_key = my_public_key; | ||
903 | GNUNET_CRYPTO_eddsa_sign (sign_key, | ||
904 | &ass, | ||
905 | &uri->data.loc.contentSignature); | ||
906 | return uri; | ||
907 | } | ||
908 | |||
909 | |||
910 | /** | ||
911 | * Create an SKS URI from a namespace ID and an identifier. | ||
912 | * | ||
913 | * @param ns namespace ID | ||
914 | * @param id identifier | ||
915 | * @return an FS URI for the given namespace and identifier | ||
916 | */ | ||
917 | struct GNUNET_FS_Uri * | ||
918 | GNUNET_FS_uri_sks_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *ns, | ||
919 | const char *id) | ||
920 | { | ||
921 | struct GNUNET_FS_Uri *ns_uri; | ||
922 | |||
923 | ns_uri = GNUNET_new (struct GNUNET_FS_Uri); | ||
924 | ns_uri->type = GNUNET_FS_URI_SKS; | ||
925 | ns_uri->data.sks.ns = *ns; | ||
926 | ns_uri->data.sks.identifier = GNUNET_strdup (id); | ||
927 | return ns_uri; | ||
928 | } | ||
929 | |||
930 | |||
931 | /** | ||
932 | * Merge the sets of keywords from two KSK URIs. | ||
933 | * (useful for merging the canonicalized keywords with | ||
934 | * the original keywords for sharing). | ||
935 | * | ||
936 | * @param u1 first uri | ||
937 | * @param u2 second uri | ||
938 | * @return merged URI, NULL on error | ||
939 | */ | ||
940 | struct GNUNET_FS_Uri * | ||
941 | GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1, | ||
942 | const struct GNUNET_FS_Uri *u2) | ||
943 | { | ||
944 | struct GNUNET_FS_Uri *ret; | ||
945 | unsigned int kc; | ||
946 | unsigned int i; | ||
947 | unsigned int j; | ||
948 | int found; | ||
949 | const char *kp; | ||
950 | char **kl; | ||
951 | |||
952 | if ((u1 == NULL) && (u2 == NULL)) | ||
953 | return NULL; | ||
954 | if (u1 == NULL) | ||
955 | return GNUNET_FS_uri_dup (u2); | ||
956 | if (u2 == NULL) | ||
957 | return GNUNET_FS_uri_dup (u1); | ||
958 | if ((u1->type != GNUNET_FS_URI_KSK) || (u2->type != GNUNET_FS_URI_KSK)) | ||
959 | { | ||
960 | GNUNET_break (0); | ||
961 | return NULL; | ||
962 | } | ||
963 | kc = u1->data.ksk.keywordCount; | ||
964 | kl = GNUNET_new_array (kc + u2->data.ksk.keywordCount, char *); | ||
965 | for (i = 0; i < u1->data.ksk.keywordCount; i++) | ||
966 | kl[i] = GNUNET_strdup (u1->data.ksk.keywords[i]); | ||
967 | for (i = 0; i < u2->data.ksk.keywordCount; i++) | ||
968 | { | ||
969 | kp = u2->data.ksk.keywords[i]; | ||
970 | found = 0; | ||
971 | for (j = 0; j < u1->data.ksk.keywordCount; j++) | ||
972 | if (0 == strcmp (kp + 1, kl[j] + 1)) | ||
973 | { | ||
974 | found = 1; | ||
975 | if (kp[0] == '+') | ||
976 | kl[j][0] = '+'; | ||
977 | break; | ||
978 | } | ||
979 | if (0 == found) | ||
980 | kl[kc++] = GNUNET_strdup (kp); | ||
981 | } | ||
982 | ret = GNUNET_new (struct GNUNET_FS_Uri); | ||
983 | ret->type = GNUNET_FS_URI_KSK; | ||
984 | ret->data.ksk.keywordCount = kc; | ||
985 | ret->data.ksk.keywords = kl; | ||
986 | return ret; | ||
987 | } | ||
988 | |||
989 | |||
990 | /** | ||
991 | * Duplicate URI. | ||
992 | * | ||
993 | * @param uri the URI to duplicate | ||
994 | * @return copy of the URI | ||
995 | */ | ||
996 | struct GNUNET_FS_Uri * | ||
997 | GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri) | ||
998 | { | ||
999 | struct GNUNET_FS_Uri *ret; | ||
1000 | unsigned int i; | ||
1001 | |||
1002 | if (uri == NULL) | ||
1003 | return NULL; | ||
1004 | ret = GNUNET_new (struct GNUNET_FS_Uri); | ||
1005 | GNUNET_memcpy (ret, uri, sizeof(struct GNUNET_FS_Uri)); | ||
1006 | switch (ret->type) | ||
1007 | { | ||
1008 | case GNUNET_FS_URI_KSK: | ||
1009 | if (ret->data.ksk.keywordCount >= | ||
1010 | GNUNET_MAX_MALLOC_CHECKED / sizeof(char *)) | ||
1011 | { | ||
1012 | GNUNET_break (0); | ||
1013 | GNUNET_free (ret); | ||
1014 | return NULL; | ||
1015 | } | ||
1016 | if (ret->data.ksk.keywordCount > 0) | ||
1017 | { | ||
1018 | ret->data.ksk.keywords = | ||
1019 | GNUNET_new_array (ret->data.ksk.keywordCount, char *); | ||
1020 | for (i = 0; i < ret->data.ksk.keywordCount; i++) | ||
1021 | ret->data.ksk.keywords[i] = GNUNET_strdup (uri->data.ksk.keywords[i]); | ||
1022 | } | ||
1023 | else | ||
1024 | ret->data.ksk.keywords = NULL; /* just to be sure */ | ||
1025 | break; | ||
1026 | |||
1027 | case GNUNET_FS_URI_SKS: | ||
1028 | ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier); | ||
1029 | break; | ||
1030 | |||
1031 | case GNUNET_FS_URI_LOC: | ||
1032 | break; | ||
1033 | |||
1034 | default: | ||
1035 | break; | ||
1036 | } | ||
1037 | return ret; | ||
1038 | } | ||
1039 | |||
1040 | |||
1041 | /** | ||
1042 | * Create an FS URI from a single user-supplied string of keywords. | ||
1043 | * The string is broken up at spaces into individual keywords. | ||
1044 | * Keywords that start with "+" are mandatory. Double-quotes can | ||
1045 | * be used to prevent breaking up strings at spaces (and also | ||
1046 | * to specify non-mandatory keywords starting with "+"). | ||
1047 | * | ||
1048 | * Keywords must contain a balanced number of double quotes and | ||
1049 | * double quotes can not be used in the actual keywords (for | ||
1050 | * example, the string '""foo bar""' will be turned into two | ||
1051 | * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'. | ||
1052 | * | ||
1053 | * @param keywords the keyword string | ||
1054 | * @param emsg where to store an error message | ||
1055 | * @return an FS URI for the given keywords, NULL | ||
1056 | * if keywords is not legal (i.e. empty). | ||
1057 | */ | ||
1058 | struct GNUNET_FS_Uri * | ||
1059 | GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg) | ||
1060 | { | ||
1061 | char **keywordarr; | ||
1062 | unsigned int num_Words; | ||
1063 | int inWord; | ||
1064 | char *pos; | ||
1065 | struct GNUNET_FS_Uri *uri; | ||
1066 | char *searchString; | ||
1067 | int saw_quote; | ||
1068 | |||
1069 | if (keywords == NULL) | ||
1070 | { | ||
1071 | *emsg = GNUNET_strdup (_ ("No keywords specified!\n")); | ||
1072 | GNUNET_break (0); | ||
1073 | return NULL; | ||
1074 | } | ||
1075 | searchString = GNUNET_strdup (keywords); | ||
1076 | num_Words = 0; | ||
1077 | inWord = 0; | ||
1078 | saw_quote = 0; | ||
1079 | pos = searchString; | ||
1080 | while ('\0' != *pos) | ||
1081 | { | ||
1082 | if ((saw_quote == 0) && (isspace ((unsigned char) *pos))) | ||
1083 | { | ||
1084 | inWord = 0; | ||
1085 | } | ||
1086 | else if (0 == inWord) | ||
1087 | { | ||
1088 | inWord = 1; | ||
1089 | ++num_Words; | ||
1090 | } | ||
1091 | if ('"' == *pos) | ||
1092 | saw_quote = (saw_quote + 1) % 2; | ||
1093 | pos++; | ||
1094 | } | ||
1095 | if (num_Words == 0) | ||
1096 | { | ||
1097 | GNUNET_free (searchString); | ||
1098 | *emsg = GNUNET_strdup (_ ("No keywords specified!\n")); | ||
1099 | return NULL; | ||
1100 | } | ||
1101 | if (saw_quote != 0) | ||
1102 | { | ||
1103 | GNUNET_free (searchString); | ||
1104 | *emsg = GNUNET_strdup (_ ("Number of double-quotes not balanced!\n")); | ||
1105 | return NULL; | ||
1106 | } | ||
1107 | keywordarr = GNUNET_new_array (num_Words, char *); | ||
1108 | num_Words = 0; | ||
1109 | inWord = 0; | ||
1110 | pos = searchString; | ||
1111 | while ('\0' != *pos) | ||
1112 | { | ||
1113 | if ((saw_quote == 0) && (isspace ((unsigned char) *pos))) | ||
1114 | { | ||
1115 | inWord = 0; | ||
1116 | *pos = '\0'; | ||
1117 | } | ||
1118 | else if (0 == inWord) | ||
1119 | { | ||
1120 | keywordarr[num_Words] = pos; | ||
1121 | inWord = 1; | ||
1122 | ++num_Words; | ||
1123 | } | ||
1124 | if ('"' == *pos) | ||
1125 | saw_quote = (saw_quote + 1) % 2; | ||
1126 | pos++; | ||
1127 | } | ||
1128 | uri = | ||
1129 | GNUNET_FS_uri_ksk_create_from_args (num_Words, (const char **) keywordarr); | ||
1130 | GNUNET_free (keywordarr); | ||
1131 | GNUNET_free (searchString); | ||
1132 | return uri; | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | /** | ||
1137 | * Create an FS URI from a user-supplied command line of keywords. | ||
1138 | * Arguments should start with "+" to indicate mandatory | ||
1139 | * keywords. | ||
1140 | * | ||
1141 | * @param argc number of keywords | ||
1142 | * @param argv keywords (double quotes are not required for | ||
1143 | * keywords containing spaces; however, double | ||
1144 | * quotes are required for keywords starting with | ||
1145 | * "+"); there is no mechanism for having double | ||
1146 | * quotes in the actual keywords (if the user | ||
1147 | * did specifically specify double quotes, the | ||
1148 | * caller should convert each double quote | ||
1149 | * into two single quotes). | ||
1150 | * @return an FS URI for the given keywords, NULL | ||
1151 | * if keywords is not legal (i.e. empty). | ||
1152 | */ | ||
1153 | struct GNUNET_FS_Uri * | ||
1154 | GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv) | ||
1155 | { | ||
1156 | unsigned int i; | ||
1157 | struct GNUNET_FS_Uri *uri; | ||
1158 | const char *keyword; | ||
1159 | char *val; | ||
1160 | const char *r; | ||
1161 | char *w; | ||
1162 | char *emsg; | ||
1163 | |||
1164 | if (argc == 0) | ||
1165 | return NULL; | ||
1166 | /* allow URI to be given as one and only keyword and | ||
1167 | * handle accordingly */ | ||
1168 | emsg = NULL; | ||
1169 | if ((argc == 1) && (strlen (argv[0]) > strlen (GNUNET_FS_URI_PREFIX)) && | ||
1170 | (0 == strncmp (argv[0], | ||
1171 | GNUNET_FS_URI_PREFIX, | ||
1172 | strlen (GNUNET_FS_URI_PREFIX))) && | ||
1173 | (NULL != (uri = GNUNET_FS_uri_parse (argv[0], &emsg)))) | ||
1174 | return uri; | ||
1175 | GNUNET_free (emsg); | ||
1176 | uri = GNUNET_new (struct GNUNET_FS_Uri); | ||
1177 | uri->type = GNUNET_FS_URI_KSK; | ||
1178 | uri->data.ksk.keywordCount = argc; | ||
1179 | uri->data.ksk.keywords = GNUNET_new_array (argc, char *); | ||
1180 | for (i = 0; i < argc; i++) | ||
1181 | { | ||
1182 | keyword = argv[i]; | ||
1183 | if (keyword[0] == '+') | ||
1184 | val = GNUNET_strdup (keyword); | ||
1185 | else | ||
1186 | GNUNET_asprintf (&val, " %s", keyword); | ||
1187 | r = val; | ||
1188 | w = val; | ||
1189 | while ('\0' != *r) | ||
1190 | { | ||
1191 | if ('"' == *r) | ||
1192 | r++; | ||
1193 | else | ||
1194 | *(w++) = *(r++); | ||
1195 | } | ||
1196 | *w = '\0'; | ||
1197 | uri->data.ksk.keywords[i] = val; | ||
1198 | } | ||
1199 | return uri; | ||
1200 | } | ||
1201 | |||
1202 | |||
1203 | /** | ||
1204 | * Test if two URIs are equal. | ||
1205 | * | ||
1206 | * @param u1 one of the URIs | ||
1207 | * @param u2 the other URI | ||
1208 | * @return #GNUNET_YES if the URIs are equal | ||
1209 | */ | ||
1210 | int | ||
1211 | GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1, | ||
1212 | const struct GNUNET_FS_Uri *u2) | ||
1213 | { | ||
1214 | int ret; | ||
1215 | unsigned int i; | ||
1216 | unsigned int j; | ||
1217 | |||
1218 | GNUNET_assert (u1 != NULL); | ||
1219 | GNUNET_assert (u2 != NULL); | ||
1220 | if (u1->type != u2->type) | ||
1221 | return GNUNET_NO; | ||
1222 | switch (u1->type) | ||
1223 | { | ||
1224 | case GNUNET_FS_URI_CHK: | ||
1225 | if (0 == | ||
1226 | memcmp (&u1->data.chk, &u2->data.chk, sizeof(struct FileIdentifier))) | ||
1227 | return GNUNET_YES; | ||
1228 | return GNUNET_NO; | ||
1229 | |||
1230 | case GNUNET_FS_URI_SKS: | ||
1231 | if ((0 == memcmp (&u1->data.sks.ns, | ||
1232 | &u2->data.sks.ns, | ||
1233 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) && | ||
1234 | (0 == strcmp (u1->data.sks.identifier, u2->data.sks.identifier))) | ||
1235 | |||
1236 | return GNUNET_YES; | ||
1237 | return GNUNET_NO; | ||
1238 | |||
1239 | case GNUNET_FS_URI_KSK: | ||
1240 | if (u1->data.ksk.keywordCount != u2->data.ksk.keywordCount) | ||
1241 | return GNUNET_NO; | ||
1242 | for (i = 0; i < u1->data.ksk.keywordCount; i++) | ||
1243 | { | ||
1244 | ret = GNUNET_NO; | ||
1245 | for (j = 0; j < u2->data.ksk.keywordCount; j++) | ||
1246 | { | ||
1247 | if (0 == strcmp (u1->data.ksk.keywords[i], u2->data.ksk.keywords[j])) | ||
1248 | { | ||
1249 | ret = GNUNET_YES; | ||
1250 | break; | ||
1251 | } | ||
1252 | } | ||
1253 | if (ret == GNUNET_NO) | ||
1254 | return GNUNET_NO; | ||
1255 | } | ||
1256 | return GNUNET_YES; | ||
1257 | |||
1258 | case GNUNET_FS_URI_LOC: | ||
1259 | if (memcmp (&u1->data.loc, | ||
1260 | &u2->data.loc, | ||
1261 | sizeof(struct FileIdentifier) | ||
1262 | + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) | ||
1263 | + sizeof(struct GNUNET_TIME_Absolute) | ||
1264 | + sizeof(unsigned short) + sizeof(unsigned short)) != 0) | ||
1265 | return GNUNET_NO; | ||
1266 | return GNUNET_YES; | ||
1267 | |||
1268 | default: | ||
1269 | return GNUNET_NO; | ||
1270 | } | ||
1271 | } | ||
1272 | |||
1273 | |||
1274 | /** | ||
1275 | * Is this a namespace URI? | ||
1276 | * | ||
1277 | * @param uri the uri to check | ||
1278 | * @return #GNUNET_YES if this is an SKS uri | ||
1279 | */ | ||
1280 | int | ||
1281 | GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri) | ||
1282 | { | ||
1283 | return uri->type == GNUNET_FS_URI_SKS; | ||
1284 | } | ||
1285 | |||
1286 | |||
1287 | /** | ||
1288 | * Get the ID of a namespace from the given | ||
1289 | * namespace URI. | ||
1290 | * | ||
1291 | * @param uri the uri to get the namespace ID from | ||
1292 | * @param pseudonym where to store the ID of the namespace | ||
1293 | * @return #GNUNET_OK on success | ||
1294 | */ | ||
1295 | int | ||
1296 | GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, | ||
1297 | struct GNUNET_CRYPTO_EcdsaPublicKey *pseudonym) | ||
1298 | { | ||
1299 | if (! GNUNET_FS_uri_test_sks (uri)) | ||
1300 | { | ||
1301 | GNUNET_break (0); | ||
1302 | return GNUNET_SYSERR; | ||
1303 | } | ||
1304 | *pseudonym = uri->data.sks.ns; | ||
1305 | return GNUNET_OK; | ||
1306 | } | ||
1307 | |||
1308 | |||
1309 | /** | ||
1310 | * Get the content identifier of an SKS URI. | ||
1311 | * | ||
1312 | * @param uri the sks uri | ||
1313 | * @return NULL on error (not a valid SKS URI) | ||
1314 | */ | ||
1315 | char * | ||
1316 | GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri) | ||
1317 | { | ||
1318 | if (! GNUNET_FS_uri_test_sks (uri)) | ||
1319 | { | ||
1320 | GNUNET_break (0); | ||
1321 | return NULL; | ||
1322 | } | ||
1323 | return GNUNET_strdup (uri->data.sks.identifier); | ||
1324 | } | ||
1325 | |||
1326 | |||
1327 | /** | ||
1328 | * Is this a keyword URI? | ||
1329 | * | ||
1330 | * @param uri the uri | ||
1331 | * @return #GNUNET_YES if this is a KSK uri | ||
1332 | */ | ||
1333 | int | ||
1334 | GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri) | ||
1335 | { | ||
1336 | #if EXTRA_CHECKS | ||
1337 | unsigned int i; | ||
1338 | |||
1339 | if (uri->type == GNUNET_FS_URI_KSK) | ||
1340 | { | ||
1341 | for (i = 0; i < uri->data.ksk.keywordCount; i++) | ||
1342 | GNUNET_assert (uri->data.ksk.keywords[i] != NULL); | ||
1343 | } | ||
1344 | #endif | ||
1345 | return uri->type == GNUNET_FS_URI_KSK; | ||
1346 | } | ||
1347 | |||
1348 | |||
1349 | /** | ||
1350 | * Is this a file (or directory) URI? | ||
1351 | * | ||
1352 | * @param uri the uri to check | ||
1353 | * @return #GNUNET_YES if this is a CHK uri | ||
1354 | */ | ||
1355 | int | ||
1356 | GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri) | ||
1357 | { | ||
1358 | return uri->type == GNUNET_FS_URI_CHK; | ||
1359 | } | ||
1360 | |||
1361 | |||
1362 | /** | ||
1363 | * What is the size of the file that this URI | ||
1364 | * refers to? | ||
1365 | * | ||
1366 | * @param uri the CHK URI to inspect | ||
1367 | * @return size of the file as specified in the CHK URI | ||
1368 | */ | ||
1369 | uint64_t | ||
1370 | GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri *uri) | ||
1371 | { | ||
1372 | switch (uri->type) | ||
1373 | { | ||
1374 | case GNUNET_FS_URI_CHK: | ||
1375 | return GNUNET_ntohll (uri->data.chk.file_length); | ||
1376 | |||
1377 | case GNUNET_FS_URI_LOC: | ||
1378 | return GNUNET_ntohll (uri->data.loc.fi.file_length); | ||
1379 | |||
1380 | default: | ||
1381 | GNUNET_assert (0); | ||
1382 | } | ||
1383 | return 0; /* unreachable */ | ||
1384 | } | ||
1385 | |||
1386 | |||
1387 | /** | ||
1388 | * Is this a location URI? | ||
1389 | * | ||
1390 | * @param uri the uri to check | ||
1391 | * @return #GNUNET_YES if this is a LOC uri | ||
1392 | */ | ||
1393 | int | ||
1394 | GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri) | ||
1395 | { | ||
1396 | return uri->type == GNUNET_FS_URI_LOC; | ||
1397 | } | ||
1398 | |||
1399 | |||
1400 | /** | ||
1401 | * Add a keyword as non-mandatory (with ' '-prefix) to the | ||
1402 | * given keyword list at offset 'index'. The array is | ||
1403 | * guaranteed to be long enough. | ||
1404 | * | ||
1405 | * @param s keyword to add | ||
1406 | * @param array array to add the keyword to | ||
1407 | * @param index offset where to add the keyword | ||
1408 | */ | ||
1409 | static void | ||
1410 | insert_non_mandatory_keyword (const char *s, char **array, int index) | ||
1411 | { | ||
1412 | char *nkword; | ||
1413 | |||
1414 | GNUNET_asprintf (&nkword, | ||
1415 | " %s", /* space to mark as 'non mandatory' */ | ||
1416 | s); | ||
1417 | array[index] = nkword; | ||
1418 | } | ||
1419 | |||
1420 | |||
1421 | /** | ||
1422 | * Test if the given keyword @a s is already present in the | ||
1423 | * given array, ignoring the '+'-mandatory prefix in the array. | ||
1424 | * | ||
1425 | * @param s keyword to test | ||
1426 | * @param array keywords to test against, with ' ' or '+' prefix to ignore | ||
1427 | * @param array_length length of the @a array | ||
1428 | * @return #GNUNET_YES if the keyword exists, #GNUNET_NO if not | ||
1429 | */ | ||
1430 | static int | ||
1431 | find_duplicate (const char *s, const char **array, int array_length) | ||
1432 | { | ||
1433 | int j; | ||
1434 | |||
1435 | for (j = array_length - 1; j >= 0; j--) | ||
1436 | if (0 == strcmp (&array[j][1], s)) | ||
1437 | return GNUNET_YES; | ||
1438 | return GNUNET_NO; | ||
1439 | } | ||
1440 | |||
1441 | |||
1442 | /** | ||
1443 | * FIXME: comment | ||
1444 | */ | ||
1445 | static char * | ||
1446 | normalize_metadata (enum EXTRACTOR_MetaFormat format, | ||
1447 | const char *data, | ||
1448 | size_t data_len) | ||
1449 | { | ||
1450 | uint8_t *free_str = NULL; | ||
1451 | uint8_t *str_to_normalize = (uint8_t *) data; | ||
1452 | uint8_t *normalized; | ||
1453 | size_t r_len; | ||
1454 | |||
1455 | if (str_to_normalize == NULL) | ||
1456 | return NULL; | ||
1457 | /* Don't trust libextractor */ | ||
1458 | if (format == EXTRACTOR_METAFORMAT_UTF8) | ||
1459 | { | ||
1460 | free_str = (uint8_t *) u8_check ((const uint8_t *) data, data_len); | ||
1461 | if (free_str == NULL) | ||
1462 | free_str = NULL; | ||
1463 | else | ||
1464 | format = EXTRACTOR_METAFORMAT_C_STRING; | ||
1465 | } | ||
1466 | if (format == EXTRACTOR_METAFORMAT_C_STRING) | ||
1467 | { | ||
1468 | free_str = u8_strconv_from_encoding (data, | ||
1469 | locale_charset (), | ||
1470 | iconveh_escape_sequence); | ||
1471 | if (free_str == NULL) | ||
1472 | return NULL; | ||
1473 | } | ||
1474 | |||
1475 | normalized = u8_tolower (str_to_normalize, | ||
1476 | strlen ((char *) str_to_normalize), | ||
1477 | NULL, | ||
1478 | UNINORM_NFD, | ||
1479 | NULL, | ||
1480 | &r_len); | ||
1481 | /* free_str is allocated by libunistring internally, use free() */ | ||
1482 | if (free_str != NULL) | ||
1483 | free (free_str); | ||
1484 | if (normalized != NULL) | ||
1485 | { | ||
1486 | /* u8_tolower allocates a non-NULL-terminated string! */ | ||
1487 | free_str = GNUNET_malloc (r_len + 1); | ||
1488 | GNUNET_memcpy (free_str, normalized, r_len); | ||
1489 | free_str[r_len] = '\0'; | ||
1490 | free (normalized); | ||
1491 | normalized = free_str; | ||
1492 | } | ||
1493 | return (char *) normalized; | ||
1494 | } | ||
1495 | |||
1496 | |||
1497 | /** | ||
1498 | * Counts the number of UTF-8 characters (not bytes) in the string, | ||
1499 | * returns that count. | ||
1500 | */ | ||
1501 | static size_t | ||
1502 | u8_strcount (const uint8_t *s) | ||
1503 | { | ||
1504 | size_t count; | ||
1505 | ucs4_t c; | ||
1506 | |||
1507 | GNUNET_assert (s != NULL); | ||
1508 | if (s[0] == 0) | ||
1509 | return 0; | ||
1510 | for (count = 0; s != NULL; count++) | ||
1511 | s = u8_next (&c, s); | ||
1512 | return count - 1; | ||
1513 | } | ||
1514 | |||
1515 | |||
1516 | /** | ||
1517 | * Break the filename up by matching [], () and {} pairs to make | ||
1518 | * keywords. In case of nesting parentheses only the inner pair counts. | ||
1519 | * You can't escape parentheses to scan something like "[blah\{foo]" to | ||
1520 | * make a "blah{foo" keyword, this function is only a heuristic! | ||
1521 | * | ||
1522 | * @param s string to break down. | ||
1523 | * @param array array to fill with enclosed tokens. If NULL, then tokens | ||
1524 | * are only counted. | ||
1525 | * @param index index at which to start filling the array (entries prior | ||
1526 | * to it are used to check for duplicates). ignored if @a array == NULL. | ||
1527 | * @return number of tokens counted (including duplicates), or number of | ||
1528 | * tokens extracted (excluding duplicates). 0 if there are no | ||
1529 | * matching parens in the string (when counting), or when all tokens | ||
1530 | * were duplicates (when extracting). | ||
1531 | */ | ||
1532 | static int | ||
1533 | get_keywords_from_parens (const char *s, char **array, int index) | ||
1534 | { | ||
1535 | int count = 0; | ||
1536 | char *open_paren; | ||
1537 | char *close_paren; | ||
1538 | char *ss; | ||
1539 | char tmp; | ||
1540 | |||
1541 | if (NULL == s) | ||
1542 | return 0; | ||
1543 | ss = GNUNET_strdup (s); | ||
1544 | open_paren = ss - 1; | ||
1545 | while (NULL != (open_paren = strpbrk (open_paren + 1, "[{("))) | ||
1546 | { | ||
1547 | int match = 0; | ||
1548 | |||
1549 | close_paren = strpbrk (open_paren + 1, "]})"); | ||
1550 | if (NULL == close_paren) | ||
1551 | continue; | ||
1552 | switch (open_paren[0]) | ||
1553 | { | ||
1554 | case '[': | ||
1555 | if (']' == close_paren[0]) | ||
1556 | match = 1; | ||
1557 | break; | ||
1558 | |||
1559 | case '{': | ||
1560 | if ('}' == close_paren[0]) | ||
1561 | match = 1; | ||
1562 | break; | ||
1563 | |||
1564 | case '(': | ||
1565 | if (')' == close_paren[0]) | ||
1566 | match = 1; | ||
1567 | break; | ||
1568 | |||
1569 | default: | ||
1570 | break; | ||
1571 | } | ||
1572 | if (match && (close_paren - open_paren > 1)) | ||
1573 | { | ||
1574 | tmp = close_paren[0]; | ||
1575 | close_paren[0] = '\0'; | ||
1576 | /* Keywords must be at least 3 characters long */ | ||
1577 | if (u8_strcount ((const uint8_t *) &open_paren[1]) <= 2) | ||
1578 | { | ||
1579 | close_paren[0] = tmp; | ||
1580 | continue; | ||
1581 | } | ||
1582 | if (NULL != array) | ||
1583 | { | ||
1584 | char *normalized; | ||
1585 | if (GNUNET_NO == find_duplicate ((const char *) &open_paren[1], | ||
1586 | (const char **) array, | ||
1587 | index + count)) | ||
1588 | { | ||
1589 | insert_non_mandatory_keyword ((const char *) &open_paren[1], | ||
1590 | array, | ||
1591 | index + count); | ||
1592 | count++; | ||
1593 | } | ||
1594 | normalized = normalize_metadata (EXTRACTOR_METAFORMAT_UTF8, | ||
1595 | &open_paren[1], | ||
1596 | close_paren - &open_paren[1]); | ||
1597 | if (normalized != NULL) | ||
1598 | { | ||
1599 | if (GNUNET_NO == find_duplicate ((const char *) normalized, | ||
1600 | (const char **) array, | ||
1601 | index + count)) | ||
1602 | { | ||
1603 | insert_non_mandatory_keyword ((const char *) normalized, | ||
1604 | array, | ||
1605 | index + count); | ||
1606 | count++; | ||
1607 | } | ||
1608 | GNUNET_free (normalized); | ||
1609 | } | ||
1610 | } | ||
1611 | else | ||
1612 | count++; | ||
1613 | close_paren[0] = tmp; | ||
1614 | } | ||
1615 | } | ||
1616 | GNUNET_free (ss); | ||
1617 | return count; | ||
1618 | } | ||
1619 | |||
1620 | |||
1621 | /** | ||
1622 | * Where to break up keywords | ||
1623 | */ | ||
1624 | #define TOKENS "_. /-!?#&+@\"\'\\;:,()[]{}$<>|" | ||
1625 | |||
1626 | /** | ||
1627 | * Break the filename up by TOKENS to make | ||
1628 | * keywords. | ||
1629 | * | ||
1630 | * @param s string to break down. | ||
1631 | * @param array array to fill with tokens. If NULL, then tokens are only | ||
1632 | * counted. | ||
1633 | * @param index index at which to start filling the array (entries prior | ||
1634 | * to it are used to check for duplicates). ignored if @a array == NULL. | ||
1635 | * @return number of tokens (>1) counted (including duplicates), or number of | ||
1636 | * tokens extracted (excluding duplicates). 0 if there are no | ||
1637 | * separators in the string (when counting), or when all tokens were | ||
1638 | * duplicates (when extracting). | ||
1639 | */ | ||
1640 | static int | ||
1641 | get_keywords_from_tokens (const char *s, char **array, int index) | ||
1642 | { | ||
1643 | char *p; | ||
1644 | char *ss; | ||
1645 | int seps = 0; | ||
1646 | |||
1647 | ss = GNUNET_strdup (s); | ||
1648 | for (p = strtok (ss, TOKENS); p != NULL; p = strtok (NULL, TOKENS)) | ||
1649 | { | ||
1650 | /* Keywords must be at least 3 characters long */ | ||
1651 | if (u8_strcount ((const uint8_t *) p) <= 2) | ||
1652 | continue; | ||
1653 | if (NULL != array) | ||
1654 | { | ||
1655 | char *normalized; | ||
1656 | if (GNUNET_NO == find_duplicate (p, (const char **) array, index + seps)) | ||
1657 | { | ||
1658 | insert_non_mandatory_keyword (p, array, index + seps); | ||
1659 | seps++; | ||
1660 | } | ||
1661 | normalized = | ||
1662 | normalize_metadata (EXTRACTOR_METAFORMAT_UTF8, p, strlen (p)); | ||
1663 | if (normalized != NULL) | ||
1664 | { | ||
1665 | if (GNUNET_NO == find_duplicate ((const char *) normalized, | ||
1666 | (const char **) array, | ||
1667 | index + seps)) | ||
1668 | { | ||
1669 | insert_non_mandatory_keyword ((const char *) normalized, | ||
1670 | array, | ||
1671 | index + seps); | ||
1672 | seps++; | ||
1673 | } | ||
1674 | GNUNET_free (normalized); | ||
1675 | } | ||
1676 | } | ||
1677 | else | ||
1678 | seps++; | ||
1679 | } | ||
1680 | GNUNET_free (ss); | ||
1681 | return seps; | ||
1682 | } | ||
1683 | |||
1684 | |||
1685 | #undef TOKENS | ||
1686 | |||
1687 | |||
1688 | /** | ||
1689 | * Function called on each value in the meta data. | ||
1690 | * Adds it to the URI. | ||
1691 | * | ||
1692 | * @param cls URI to update | ||
1693 | * @param plugin_name name of the plugin that produced this value; | ||
1694 | * special values can be used (e.g. '<zlib>' for zlib being | ||
1695 | * used in the main libextractor library and yielding | ||
1696 | * meta data). | ||
1697 | * @param type libextractor-type describing the meta data | ||
1698 | * @param format basic format information about data | ||
1699 | * @param data_mime_type mime-type of data (not of the original file); | ||
1700 | * can be NULL (if mime-type is not known) | ||
1701 | * @param data actual meta-data found | ||
1702 | * @param data_len number of bytes in @a data | ||
1703 | * @return 0 (always) | ||
1704 | */ | ||
1705 | static int | ||
1706 | gather_uri_data (void *cls, | ||
1707 | const char *plugin_name, | ||
1708 | enum EXTRACTOR_MetaType type, | ||
1709 | enum EXTRACTOR_MetaFormat format, | ||
1710 | const char *data_mime_type, | ||
1711 | const char *data, | ||
1712 | size_t data_len) | ||
1713 | { | ||
1714 | struct GNUNET_FS_Uri *uri = cls; | ||
1715 | char *normalized_data; | ||
1716 | const char *sep; | ||
1717 | |||
1718 | if ((format != EXTRACTOR_METAFORMAT_UTF8) && | ||
1719 | (format != EXTRACTOR_METAFORMAT_C_STRING)) | ||
1720 | return 0; | ||
1721 | /* Keywords must be at least 3 characters long | ||
1722 | * If given non-utf8 string it will, most likely, find it to be invalid, | ||
1723 | * and will return the length of its valid part, skipping the keyword. | ||
1724 | * If it does - fix the extractor, not this check! | ||
1725 | */if (u8_strcount ((const uint8_t *) data) <= 2) | ||
1726 | return 0; | ||
1727 | if ((EXTRACTOR_METATYPE_MIMETYPE == type) && | ||
1728 | (NULL != (sep = memchr (data, '/', data_len))) && (sep != data)) | ||
1729 | { | ||
1730 | char *xtra; | ||
1731 | |||
1732 | GNUNET_asprintf (&xtra, "mimetype:%.*s", (int) (sep - data), data); | ||
1733 | if (! find_duplicate (xtra, | ||
1734 | (const char **) uri->data.ksk.keywords, | ||
1735 | uri->data.ksk.keywordCount)) | ||
1736 | { | ||
1737 | insert_non_mandatory_keyword (xtra, | ||
1738 | uri->data.ksk.keywords, | ||
1739 | uri->data.ksk.keywordCount); | ||
1740 | uri->data.ksk.keywordCount++; | ||
1741 | } | ||
1742 | GNUNET_free (xtra); | ||
1743 | } | ||
1744 | |||
1745 | normalized_data = normalize_metadata (format, data, data_len); | ||
1746 | if (! find_duplicate (data, | ||
1747 | (const char **) uri->data.ksk.keywords, | ||
1748 | uri->data.ksk.keywordCount)) | ||
1749 | { | ||
1750 | insert_non_mandatory_keyword (data, | ||
1751 | uri->data.ksk.keywords, | ||
1752 | uri->data.ksk.keywordCount); | ||
1753 | uri->data.ksk.keywordCount++; | ||
1754 | } | ||
1755 | if (NULL != normalized_data) | ||
1756 | { | ||
1757 | if (! find_duplicate (normalized_data, | ||
1758 | (const char **) uri->data.ksk.keywords, | ||
1759 | uri->data.ksk.keywordCount)) | ||
1760 | { | ||
1761 | insert_non_mandatory_keyword (normalized_data, | ||
1762 | uri->data.ksk.keywords, | ||
1763 | uri->data.ksk.keywordCount); | ||
1764 | uri->data.ksk.keywordCount++; | ||
1765 | } | ||
1766 | GNUNET_free (normalized_data); | ||
1767 | } | ||
1768 | return 0; | ||
1769 | } | ||
1770 | |||
1771 | |||
1772 | /** | ||
1773 | * Construct a keyword-URI from meta-data (take all entries | ||
1774 | * in the meta-data and construct one large keyword URI | ||
1775 | * that lists all keywords that can be found in the meta-data). | ||
1776 | * | ||
1777 | * @param md metadata to use | ||
1778 | * @return NULL on error, otherwise a KSK URI | ||
1779 | */ | ||
1780 | struct GNUNET_FS_Uri * | ||
1781 | GNUNET_FS_uri_ksk_create_from_meta_data ( | ||
1782 | const struct GNUNET_CONTAINER_MetaData *md) | ||
1783 | { | ||
1784 | struct GNUNET_FS_Uri *ret; | ||
1785 | char *filename; | ||
1786 | char *full_name = NULL; | ||
1787 | char *ss; | ||
1788 | int ent; | ||
1789 | int tok_keywords = 0; | ||
1790 | int paren_keywords = 0; | ||
1791 | |||
1792 | if (NULL == md) | ||
1793 | return NULL; | ||
1794 | ret = GNUNET_new (struct GNUNET_FS_Uri); | ||
1795 | ret->type = GNUNET_FS_URI_KSK; | ||
1796 | ent = GNUNET_CONTAINER_meta_data_iterate (md, NULL, NULL); | ||
1797 | if (ent > 0) | ||
1798 | { | ||
1799 | full_name = GNUNET_CONTAINER_meta_data_get_first_by_types ( | ||
1800 | md, | ||
1801 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, | ||
1802 | -1); | ||
1803 | if (NULL != full_name) | ||
1804 | { | ||
1805 | filename = full_name; | ||
1806 | while (NULL != (ss = strstr (filename, DIR_SEPARATOR_STR))) | ||
1807 | filename = ss + 1; | ||
1808 | tok_keywords = get_keywords_from_tokens (filename, NULL, 0); | ||
1809 | paren_keywords = get_keywords_from_parens (filename, NULL, 0); | ||
1810 | } | ||
1811 | /* x3 because there might be a normalized variant of every keyword, | ||
1812 | plus theoretically one more for mime... */ | ||
1813 | ret->data.ksk.keywords = | ||
1814 | GNUNET_new_array ((ent + tok_keywords + paren_keywords) * 3, char *); | ||
1815 | GNUNET_CONTAINER_meta_data_iterate (md, &gather_uri_data, ret); | ||
1816 | } | ||
1817 | if (tok_keywords > 0) | ||
1818 | ret->data.ksk.keywordCount += | ||
1819 | get_keywords_from_tokens (filename, | ||
1820 | ret->data.ksk.keywords, | ||
1821 | ret->data.ksk.keywordCount); | ||
1822 | if (paren_keywords > 0) | ||
1823 | ret->data.ksk.keywordCount += | ||
1824 | get_keywords_from_parens (filename, | ||
1825 | ret->data.ksk.keywords, | ||
1826 | ret->data.ksk.keywordCount); | ||
1827 | if (ent > 0) | ||
1828 | GNUNET_free (full_name); | ||
1829 | return ret; | ||
1830 | } | ||
1831 | |||
1832 | |||
1833 | /** | ||
1834 | * In URI-encoding, does the given character | ||
1835 | * need to be encoded using %-encoding? | ||
1836 | */ | ||
1837 | static int | ||
1838 | needs_percent (char c) | ||
1839 | { | ||
1840 | return(! ((isalnum ((unsigned char) c)) || (c == '-') || (c == '_') || | ||
1841 | (c == '.') || (c == '~'))); | ||
1842 | } | ||
1843 | |||
1844 | |||
1845 | /** | ||
1846 | * Convert a KSK URI to a string. | ||
1847 | * | ||
1848 | * @param uri the URI to convert | ||
1849 | * @return NULL on error (i.e. keywordCount == 0) | ||
1850 | */ | ||
1851 | static char * | ||
1852 | uri_ksk_to_string (const struct GNUNET_FS_Uri *uri) | ||
1853 | { | ||
1854 | char **keywords; | ||
1855 | unsigned int keywordCount; | ||
1856 | size_t n; | ||
1857 | char *ret; | ||
1858 | unsigned int i; | ||
1859 | unsigned int j; | ||
1860 | unsigned int wpos; | ||
1861 | size_t slen; | ||
1862 | const char *keyword; | ||
1863 | |||
1864 | if (uri->type != GNUNET_FS_URI_KSK) | ||
1865 | return NULL; | ||
1866 | keywords = uri->data.ksk.keywords; | ||
1867 | keywordCount = uri->data.ksk.keywordCount; | ||
1868 | n = keywordCount + strlen (GNUNET_FS_URI_PREFIX) | ||
1869 | + strlen (GNUNET_FS_URI_KSK_INFIX) + 1; | ||
1870 | for (i = 0; i < keywordCount; i++) | ||
1871 | { | ||
1872 | keyword = keywords[i]; | ||
1873 | slen = strlen (keyword); | ||
1874 | n += slen; | ||
1875 | for (j = 0; j < slen; j++) | ||
1876 | { | ||
1877 | if ((j == 0) && (keyword[j] == ' ')) | ||
1878 | { | ||
1879 | n--; | ||
1880 | continue; /* skip leading space */ | ||
1881 | } | ||
1882 | if (needs_percent (keyword[j])) | ||
1883 | n += 2; /* will use %-encoding */ | ||
1884 | } | ||
1885 | } | ||
1886 | ret = GNUNET_malloc (n); | ||
1887 | strcpy (ret, GNUNET_FS_URI_PREFIX); | ||
1888 | strcat (ret, GNUNET_FS_URI_KSK_INFIX); | ||
1889 | wpos = strlen (ret); | ||
1890 | for (i = 0; i < keywordCount; i++) | ||
1891 | { | ||
1892 | keyword = keywords[i]; | ||
1893 | slen = strlen (keyword); | ||
1894 | for (j = 0; j < slen; j++) | ||
1895 | { | ||
1896 | if ((j == 0) && (keyword[j] == ' ')) | ||
1897 | continue; /* skip leading space */ | ||
1898 | if (needs_percent (keyword[j])) | ||
1899 | { | ||
1900 | sprintf (&ret[wpos], "%%%02X", (unsigned char) keyword[j]); | ||
1901 | wpos += 3; | ||
1902 | } | ||
1903 | else | ||
1904 | { | ||
1905 | ret[wpos++] = keyword[j]; | ||
1906 | } | ||
1907 | } | ||
1908 | if (i != keywordCount - 1) | ||
1909 | ret[wpos++] = '+'; | ||
1910 | } | ||
1911 | return ret; | ||
1912 | } | ||
1913 | |||
1914 | |||
1915 | /** | ||
1916 | * Convert SKS URI to a string. | ||
1917 | * | ||
1918 | * @param uri sks uri to convert | ||
1919 | * @return NULL on error | ||
1920 | */ | ||
1921 | static char * | ||
1922 | uri_sks_to_string (const struct GNUNET_FS_Uri *uri) | ||
1923 | { | ||
1924 | char *ret; | ||
1925 | char buf[1024]; | ||
1926 | |||
1927 | if (GNUNET_FS_URI_SKS != uri->type) | ||
1928 | return NULL; | ||
1929 | ret = | ||
1930 | GNUNET_STRINGS_data_to_string (&uri->data.sks.ns, | ||
1931 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey), | ||
1932 | buf, | ||
1933 | sizeof(buf)); | ||
1934 | GNUNET_assert (NULL != ret); | ||
1935 | ret[0] = '\0'; | ||
1936 | GNUNET_asprintf (&ret, | ||
1937 | "%s%s%s/%s", | ||
1938 | GNUNET_FS_URI_PREFIX, | ||
1939 | GNUNET_FS_URI_SKS_INFIX, | ||
1940 | buf, | ||
1941 | uri->data.sks.identifier); | ||
1942 | return ret; | ||
1943 | } | ||
1944 | |||
1945 | |||
1946 | /** | ||
1947 | * Convert a CHK URI to a string. | ||
1948 | * | ||
1949 | * @param uri chk uri to convert | ||
1950 | * @return NULL on error | ||
1951 | */ | ||
1952 | static char * | ||
1953 | uri_chk_to_string (const struct GNUNET_FS_Uri *uri) | ||
1954 | { | ||
1955 | const struct FileIdentifier *fi; | ||
1956 | char *ret; | ||
1957 | struct GNUNET_CRYPTO_HashAsciiEncoded keyhash; | ||
1958 | struct GNUNET_CRYPTO_HashAsciiEncoded queryhash; | ||
1959 | |||
1960 | if (uri->type != GNUNET_FS_URI_CHK) | ||
1961 | return NULL; | ||
1962 | fi = &uri->data.chk; | ||
1963 | GNUNET_CRYPTO_hash_to_enc (&fi->chk.key, &keyhash); | ||
1964 | GNUNET_CRYPTO_hash_to_enc (&fi->chk.query, &queryhash); | ||
1965 | |||
1966 | GNUNET_asprintf (&ret, | ||
1967 | "%s%s%s.%s.%llu", | ||
1968 | GNUNET_FS_URI_PREFIX, | ||
1969 | GNUNET_FS_URI_CHK_INFIX, | ||
1970 | (const char *) &keyhash, | ||
1971 | (const char *) &queryhash, | ||
1972 | (unsigned long long) GNUNET_ntohll (fi->file_length)); | ||
1973 | return ret; | ||
1974 | } | ||
1975 | |||
1976 | |||
1977 | /** | ||
1978 | * Convert a LOC URI to a string. | ||
1979 | * | ||
1980 | * @param uri loc uri to convert | ||
1981 | * @return NULL on error | ||
1982 | */ | ||
1983 | static char * | ||
1984 | uri_loc_to_string (const struct GNUNET_FS_Uri *uri) | ||
1985 | { | ||
1986 | char *ret; | ||
1987 | struct GNUNET_CRYPTO_HashAsciiEncoded keyhash; | ||
1988 | struct GNUNET_CRYPTO_HashAsciiEncoded queryhash; | ||
1989 | char *peer_id; | ||
1990 | char peer_sig[SIGNATURE_ASCII_LENGTH + 1]; | ||
1991 | |||
1992 | GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.key, &keyhash); | ||
1993 | GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.query, &queryhash); | ||
1994 | peer_id = | ||
1995 | GNUNET_CRYPTO_eddsa_public_key_to_string (&uri->data.loc.peer.public_key); | ||
1996 | GNUNET_assert ( | ||
1997 | NULL != | ||
1998 | GNUNET_STRINGS_data_to_string (&uri->data.loc.contentSignature, | ||
1999 | sizeof(struct GNUNET_CRYPTO_EddsaSignature), | ||
2000 | peer_sig, | ||
2001 | sizeof(peer_sig))); | ||
2002 | GNUNET_asprintf (&ret, | ||
2003 | "%s%s%s.%s.%llu.%s.%s.%llu", | ||
2004 | GNUNET_FS_URI_PREFIX, | ||
2005 | GNUNET_FS_URI_LOC_INFIX, | ||
2006 | (const char *) &keyhash, | ||
2007 | (const char *) &queryhash, | ||
2008 | (unsigned long long) GNUNET_ntohll ( | ||
2009 | uri->data.loc.fi.file_length), | ||
2010 | peer_id, | ||
2011 | peer_sig, | ||
2012 | (unsigned long long) | ||
2013 | uri->data.loc.expirationTime.abs_value_us | ||
2014 | / 1000000LL); | ||
2015 | GNUNET_free (peer_id); | ||
2016 | return ret; | ||
2017 | } | ||
2018 | |||
2019 | |||
2020 | /** | ||
2021 | * Convert a URI to a UTF-8 String. | ||
2022 | * | ||
2023 | * @param uri uri to convert to a string | ||
2024 | * @return the UTF-8 string | ||
2025 | */ | ||
2026 | char * | ||
2027 | GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri) | ||
2028 | { | ||
2029 | if (uri == NULL) | ||
2030 | { | ||
2031 | GNUNET_break (0); | ||
2032 | return NULL; | ||
2033 | } | ||
2034 | switch (uri->type) | ||
2035 | { | ||
2036 | case GNUNET_FS_URI_KSK: | ||
2037 | return uri_ksk_to_string (uri); | ||
2038 | |||
2039 | case GNUNET_FS_URI_SKS: | ||
2040 | return uri_sks_to_string (uri); | ||
2041 | |||
2042 | case GNUNET_FS_URI_CHK: | ||
2043 | return uri_chk_to_string (uri); | ||
2044 | |||
2045 | case GNUNET_FS_URI_LOC: | ||
2046 | return uri_loc_to_string (uri); | ||
2047 | |||
2048 | default: | ||
2049 | GNUNET_break (0); | ||
2050 | return NULL; | ||
2051 | } | ||
2052 | } | ||
2053 | |||
2054 | |||
2055 | /* end of fs_uri.c */ | ||
diff --git a/src/fs/gnunet-auto-share.c b/src/fs/gnunet-auto-share.c deleted file mode 100644 index f91e9d00d..000000000 --- a/src/fs/gnunet-auto-share.c +++ /dev/null | |||
@@ -1,791 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001--2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/gnunet-auto-share.c | ||
22 | * @brief automatically publish files on GNUnet | ||
23 | * @author Christian Grothoff | ||
24 | * | ||
25 | * TODO: | ||
26 | * - support loading meta data / keywords from resource file | ||
27 | * - add stability timer (a la buildbot) | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | |||
32 | #define MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) | ||
33 | |||
34 | #define MIN_DELAY GNUNET_TIME_UNIT_MINUTES | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Item in our work queue (or in the set of files/directories | ||
39 | * we have successfully published). | ||
40 | */ | ||
41 | struct WorkItem | ||
42 | { | ||
43 | /** | ||
44 | * PENDING Work is kept in a linked list. | ||
45 | */ | ||
46 | struct WorkItem *prev; | ||
47 | |||
48 | /** | ||
49 | * PENDING Work is kept in a linked list. | ||
50 | */ | ||
51 | struct WorkItem *next; | ||
52 | |||
53 | /** | ||
54 | * Filename of the work item. | ||
55 | */ | ||
56 | char *filename; | ||
57 | |||
58 | /** | ||
59 | * Unique identity for this work item (used to detect | ||
60 | * if we need to do the work again). | ||
61 | */ | ||
62 | struct GNUNET_HashCode id; | ||
63 | }; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Global return value from 'main'. | ||
68 | */ | ||
69 | static int ret; | ||
70 | |||
71 | /** | ||
72 | * Are we running 'verbosely'? | ||
73 | */ | ||
74 | static unsigned int verbose; | ||
75 | |||
76 | /** | ||
77 | * Configuration to use. | ||
78 | */ | ||
79 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
80 | |||
81 | /** | ||
82 | * Name of the configuration file. | ||
83 | */ | ||
84 | static char *cfg_filename; | ||
85 | |||
86 | /** | ||
87 | * Disable extractor option to use for publishing. | ||
88 | */ | ||
89 | static int disable_extractor; | ||
90 | |||
91 | /** | ||
92 | * Disable creation time option to use for publishing. | ||
93 | */ | ||
94 | static int do_disable_creation_time; | ||
95 | |||
96 | /** | ||
97 | * Handle for the main task that does scanning and working. | ||
98 | */ | ||
99 | static struct GNUNET_SCHEDULER_Task *run_task; | ||
100 | |||
101 | /** | ||
102 | * Anonymity level option to use for publishing. | ||
103 | */ | ||
104 | static unsigned int anonymity_level = 1; | ||
105 | |||
106 | /** | ||
107 | * Content priority option to use for publishing. | ||
108 | */ | ||
109 | static unsigned int content_priority = 365; | ||
110 | |||
111 | /** | ||
112 | * Replication level option to use for publishing. | ||
113 | */ | ||
114 | static unsigned int replication_level = 1; | ||
115 | |||
116 | /** | ||
117 | * Top-level directory we monitor to auto-publish. | ||
118 | */ | ||
119 | static const char *dir_name; | ||
120 | |||
121 | /** | ||
122 | * Head of linked list of files still to publish. | ||
123 | */ | ||
124 | static struct WorkItem *work_head; | ||
125 | |||
126 | /** | ||
127 | * Tail of linked list of files still to publish. | ||
128 | */ | ||
129 | static struct WorkItem *work_tail; | ||
130 | |||
131 | /** | ||
132 | * Map from the hash of the filename (!) to a `struct WorkItem` | ||
133 | * that was finished. | ||
134 | */ | ||
135 | static struct GNUNET_CONTAINER_MultiHashMap *work_finished; | ||
136 | |||
137 | /** | ||
138 | * Set to #GNUNET_YES if we are shutting down. | ||
139 | */ | ||
140 | static int do_shutdown; | ||
141 | |||
142 | /** | ||
143 | * Start time of the current round; used to determine how long | ||
144 | * one iteration takes (which influences how fast we schedule | ||
145 | * the next one). | ||
146 | */ | ||
147 | static struct GNUNET_TIME_Absolute start_time; | ||
148 | |||
149 | /** | ||
150 | * Pipe used to communicate 'gnunet-publish' completion (SIGCHLD) via signal. | ||
151 | */ | ||
152 | static struct GNUNET_DISK_PipeHandle *sigpipe; | ||
153 | |||
154 | /** | ||
155 | * Handle to the 'gnunet-publish' process that we executed. | ||
156 | */ | ||
157 | static struct GNUNET_OS_Process *publish_proc; | ||
158 | |||
159 | |||
160 | /** | ||
161 | * Compute the name of the state database file we will use. | ||
162 | */ | ||
163 | static char * | ||
164 | get_state_file () | ||
165 | { | ||
166 | char *ret; | ||
167 | |||
168 | GNUNET_asprintf (&ret, | ||
169 | "%s%s.auto-share", | ||
170 | dir_name, | ||
171 | (DIR_SEPARATOR == dir_name[strlen (dir_name) - 1]) | ||
172 | ? "" | ||
173 | : DIR_SEPARATOR_STR); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | |||
178 | /** | ||
179 | * Load the set of #work_finished items from disk. | ||
180 | */ | ||
181 | static void | ||
182 | load_state () | ||
183 | { | ||
184 | char *fn; | ||
185 | struct GNUNET_BIO_ReadHandle *rh; | ||
186 | uint32_t n; | ||
187 | struct GNUNET_HashCode id; | ||
188 | struct WorkItem *wi; | ||
189 | char *emsg; | ||
190 | |||
191 | emsg = NULL; | ||
192 | fn = get_state_file (); | ||
193 | rh = GNUNET_BIO_read_open_file (fn); | ||
194 | GNUNET_free (fn); | ||
195 | if (NULL == rh) | ||
196 | return; | ||
197 | fn = NULL; | ||
198 | if (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "number of files", | ||
199 | (int32_t *) &n)) | ||
200 | goto error; | ||
201 | while (n-- > 0) | ||
202 | { | ||
203 | struct GNUNET_BIO_ReadSpec rs[] = { | ||
204 | GNUNET_BIO_read_spec_string ("filename", &fn, 1024), | ||
205 | GNUNET_BIO_read_spec_object ("id", &id, sizeof(struct GNUNET_HashCode)), | ||
206 | GNUNET_BIO_read_spec_end (), | ||
207 | }; | ||
208 | if (GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs)) | ||
209 | goto error; | ||
210 | wi = GNUNET_new (struct WorkItem); | ||
211 | wi->id = id; | ||
212 | wi->filename = fn; | ||
213 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
214 | "Loaded serialization ID for `%s' is `%s'\n", | ||
215 | wi->filename, | ||
216 | GNUNET_h2s (&id)); | ||
217 | fn = NULL; | ||
218 | GNUNET_CRYPTO_hash (wi->filename, strlen (wi->filename), &id); | ||
219 | GNUNET_break (GNUNET_OK == | ||
220 | GNUNET_CONTAINER_multihashmap_put ( | ||
221 | work_finished, | ||
222 | &id, | ||
223 | wi, | ||
224 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
225 | } | ||
226 | if (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)) | ||
227 | return; | ||
228 | rh = NULL; | ||
229 | error: | ||
230 | GNUNET_free (fn); | ||
231 | if (NULL != rh) | ||
232 | (void) GNUNET_BIO_read_close (rh, &emsg); | ||
233 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
234 | _ ("Failed to load state: %s\n"), | ||
235 | emsg); | ||
236 | GNUNET_free (emsg); | ||
237 | } | ||
238 | |||
239 | |||
240 | /** | ||
241 | * Write work item from the #work_finished map to the given write handle. | ||
242 | * | ||
243 | * @param cls the `struct GNUNET_BIO_WriteHandle *` | ||
244 | * @param key key of the item in the map (unused) | ||
245 | * @param value the `struct WorkItem` to write | ||
246 | * @return #GNUNET_OK to continue to iterate (if write worked) | ||
247 | */ | ||
248 | static int | ||
249 | write_item (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
250 | { | ||
251 | struct GNUNET_BIO_WriteHandle *wh = cls; | ||
252 | struct WorkItem *wi = value; | ||
253 | |||
254 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
255 | "Saving serialization ID of file `%s' with value `%s'\n", | ||
256 | wi->filename, | ||
257 | GNUNET_h2s (&wi->id)); | ||
258 | struct GNUNET_BIO_WriteSpec ws[] = { | ||
259 | GNUNET_BIO_write_spec_string ("auto-share-write-item-filename", | ||
260 | wi->filename), | ||
261 | GNUNET_BIO_write_spec_object ("id", &wi->id, sizeof(struct | ||
262 | GNUNET_HashCode)), | ||
263 | GNUNET_BIO_write_spec_end (), | ||
264 | }; | ||
265 | if (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws)) | ||
266 | return GNUNET_SYSERR; /* write error, abort iteration */ | ||
267 | return GNUNET_OK; | ||
268 | } | ||
269 | |||
270 | |||
271 | /** | ||
272 | * Save the set of #work_finished items on disk. | ||
273 | */ | ||
274 | static void | ||
275 | save_state () | ||
276 | { | ||
277 | uint32_t n; | ||
278 | struct GNUNET_BIO_WriteHandle *wh; | ||
279 | char *fn; | ||
280 | |||
281 | n = GNUNET_CONTAINER_multihashmap_size (work_finished); | ||
282 | fn = get_state_file (); | ||
283 | wh = GNUNET_BIO_write_open_file (fn); | ||
284 | if (NULL == wh) | ||
285 | { | ||
286 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
287 | _ ("Failed to save state to file %s\n"), | ||
288 | fn); | ||
289 | GNUNET_free (fn); | ||
290 | return; | ||
291 | } | ||
292 | if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, "size of state", n)) | ||
293 | { | ||
294 | (void) GNUNET_BIO_write_close (wh, NULL); | ||
295 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
296 | _ ("Failed to save state to file %s\n"), | ||
297 | fn); | ||
298 | GNUNET_free (fn); | ||
299 | return; | ||
300 | } | ||
301 | (void) GNUNET_CONTAINER_multihashmap_iterate (work_finished, &write_item, wh); | ||
302 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
303 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
304 | _ ("Failed to save state to file %s\n"), | ||
305 | fn); | ||
306 | GNUNET_free (fn); | ||
307 | } | ||
308 | |||
309 | |||
310 | /** | ||
311 | * Task run on shutdown. Serializes our current state to disk. | ||
312 | * | ||
313 | * @param cls closure, unused | ||
314 | */ | ||
315 | static void | ||
316 | do_stop_task (void *cls) | ||
317 | { | ||
318 | do_shutdown = GNUNET_YES; | ||
319 | if (NULL != publish_proc) | ||
320 | { | ||
321 | GNUNET_OS_process_kill (publish_proc, SIGKILL); | ||
322 | return; | ||
323 | } | ||
324 | if (NULL != run_task) | ||
325 | { | ||
326 | GNUNET_SCHEDULER_cancel (run_task); | ||
327 | run_task = NULL; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | |||
332 | /** | ||
333 | * Decide what the next task is (working or scanning) and schedule it. | ||
334 | */ | ||
335 | static void | ||
336 | schedule_next_task (void); | ||
337 | |||
338 | |||
339 | /** | ||
340 | * Task triggered whenever we receive a SIGCHLD (child | ||
341 | * process died). | ||
342 | * | ||
343 | * @param cls the `struct WorkItem` we were working on | ||
344 | */ | ||
345 | static void | ||
346 | maint_child_death (void *cls) | ||
347 | { | ||
348 | struct WorkItem *wi = cls; | ||
349 | struct GNUNET_HashCode key; | ||
350 | enum GNUNET_OS_ProcessStatusType type; | ||
351 | unsigned long code; | ||
352 | int ret; | ||
353 | char c; | ||
354 | const struct GNUNET_DISK_FileHandle *pr; | ||
355 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
356 | |||
357 | run_task = NULL; | ||
358 | pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); | ||
359 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
360 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) | ||
361 | { | ||
362 | /* shutdown scheduled us, someone else will kill child, | ||
363 | we should just try again */ | ||
364 | run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
365 | pr, | ||
366 | &maint_child_death, | ||
367 | wi); | ||
368 | return; | ||
369 | } | ||
370 | /* consume the signal */ | ||
371 | GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c))); | ||
372 | |||
373 | ret = GNUNET_OS_process_status (publish_proc, &type, &code); | ||
374 | GNUNET_assert (GNUNET_SYSERR != ret); | ||
375 | if (GNUNET_NO == ret) | ||
376 | { | ||
377 | /* process still running? Then where did the SIGCHLD come from? | ||
378 | Well, let's declare it spurious (kernel bug?) and keep rolling. | ||
379 | */ | ||
380 | GNUNET_break (0); | ||
381 | run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
382 | pr, | ||
383 | &maint_child_death, | ||
384 | wi); | ||
385 | return; | ||
386 | } | ||
387 | GNUNET_assert (GNUNET_OK == ret); | ||
388 | |||
389 | GNUNET_OS_process_destroy (publish_proc); | ||
390 | publish_proc = NULL; | ||
391 | |||
392 | if (GNUNET_YES == do_shutdown) | ||
393 | { | ||
394 | GNUNET_free (wi->filename); | ||
395 | GNUNET_free (wi); | ||
396 | return; | ||
397 | } | ||
398 | if ((GNUNET_OS_PROCESS_EXITED == type) && (0 == code)) | ||
399 | { | ||
400 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
401 | _ ("Publication of `%s' done\n"), | ||
402 | wi->filename); | ||
403 | GNUNET_CRYPTO_hash (wi->filename, strlen (wi->filename), &key); | ||
404 | GNUNET_break (GNUNET_OK == | ||
405 | GNUNET_CONTAINER_multihashmap_put ( | ||
406 | work_finished, | ||
407 | &key, | ||
408 | wi, | ||
409 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
410 | } | ||
411 | else | ||
412 | { | ||
413 | GNUNET_CONTAINER_DLL_insert_tail (work_head, work_tail, wi); | ||
414 | } | ||
415 | save_state (); | ||
416 | schedule_next_task (); | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
421 | * Signal handler called for SIGCHLD. Triggers the | ||
422 | * respective handler by writing to the trigger pipe. | ||
423 | */ | ||
424 | static void | ||
425 | sighandler_child_death () | ||
426 | { | ||
427 | static char c; | ||
428 | int old_errno = errno; /* back-up errno */ | ||
429 | |||
430 | GNUNET_break ( | ||
431 | 1 == | ||
432 | GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe, | ||
433 | GNUNET_DISK_PIPE_END_WRITE), | ||
434 | &c, | ||
435 | sizeof(c))); | ||
436 | errno = old_errno; /* restore errno */ | ||
437 | } | ||
438 | |||
439 | |||
440 | /** | ||
441 | * Function called to process work items. | ||
442 | * | ||
443 | * @param cls closure, NULL | ||
444 | */ | ||
445 | static void | ||
446 | work (void *cls) | ||
447 | { | ||
448 | static char *argv[14]; | ||
449 | static char anon_level[20]; | ||
450 | static char content_prio[20]; | ||
451 | static char repl_level[20]; | ||
452 | struct WorkItem *wi; | ||
453 | const struct GNUNET_DISK_FileHandle *pr; | ||
454 | int argc; | ||
455 | |||
456 | run_task = NULL; | ||
457 | wi = work_head; | ||
458 | GNUNET_CONTAINER_DLL_remove (work_head, work_tail, wi); | ||
459 | argc = 0; | ||
460 | argv[argc++] = "gnunet-publish"; | ||
461 | if (verbose) | ||
462 | argv[argc++] = "-V"; | ||
463 | if (disable_extractor) | ||
464 | argv[argc++] = "-D"; | ||
465 | if (do_disable_creation_time) | ||
466 | argv[argc++] = "-d"; | ||
467 | argv[argc++] = "-c"; | ||
468 | argv[argc++] = cfg_filename; | ||
469 | GNUNET_snprintf (anon_level, sizeof(anon_level), "%u", anonymity_level); | ||
470 | argv[argc++] = "-a"; | ||
471 | argv[argc++] = anon_level; | ||
472 | GNUNET_snprintf (content_prio, sizeof(content_prio), "%u", content_priority); | ||
473 | argv[argc++] = "-p"; | ||
474 | argv[argc++] = content_prio; | ||
475 | GNUNET_snprintf (repl_level, sizeof(repl_level), "%u", replication_level); | ||
476 | argv[argc++] = "-r"; | ||
477 | argv[argc++] = repl_level; | ||
478 | argv[argc++] = wi->filename; | ||
479 | argv[argc] = NULL; | ||
480 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Publishing `%s'\n"), wi->filename); | ||
481 | GNUNET_assert (NULL == publish_proc); | ||
482 | publish_proc = GNUNET_OS_start_process_vap (GNUNET_OS_USE_PIPE_CONTROL, | ||
483 | NULL, | ||
484 | NULL, | ||
485 | NULL, | ||
486 | "gnunet-publish", | ||
487 | argv); | ||
488 | if (NULL == publish_proc) | ||
489 | { | ||
490 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
491 | _ ("Failed to run `%s'\n"), | ||
492 | "gnunet-publish"); | ||
493 | GNUNET_CONTAINER_DLL_insert (work_head, work_tail, wi); | ||
494 | run_task = | ||
495 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &work, NULL); | ||
496 | return; | ||
497 | } | ||
498 | pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); | ||
499 | run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
500 | pr, | ||
501 | &maint_child_death, | ||
502 | wi); | ||
503 | } | ||
504 | |||
505 | |||
506 | /** | ||
507 | * Recursively scan the given file/directory structure to determine | ||
508 | * a unique ID that represents the current state of the hierarchy. | ||
509 | * | ||
510 | * @param cls where to store the unique ID we are computing | ||
511 | * @param filename file to scan | ||
512 | * @return #GNUNET_OK (always) | ||
513 | */ | ||
514 | static int | ||
515 | determine_id (void *cls, const char *filename) | ||
516 | { | ||
517 | struct GNUNET_HashCode *id = cls; | ||
518 | struct stat sbuf; | ||
519 | struct GNUNET_HashCode fx[2]; | ||
520 | struct GNUNET_HashCode ft; | ||
521 | |||
522 | if (0 != stat (filename, &sbuf)) | ||
523 | { | ||
524 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename); | ||
525 | return GNUNET_OK; | ||
526 | } | ||
527 | GNUNET_CRYPTO_hash (filename, strlen (filename), &fx[0]); | ||
528 | if (! S_ISDIR (sbuf.st_mode)) | ||
529 | { | ||
530 | uint64_t fattr[2]; | ||
531 | |||
532 | fattr[0] = GNUNET_htonll (sbuf.st_size); | ||
533 | fattr[0] = GNUNET_htonll (sbuf.st_mtime); | ||
534 | |||
535 | GNUNET_CRYPTO_hash (fattr, sizeof(fattr), &fx[1]); | ||
536 | } | ||
537 | else | ||
538 | { | ||
539 | memset (&fx[1], 1, sizeof(struct GNUNET_HashCode)); | ||
540 | GNUNET_DISK_directory_scan (filename, &determine_id, &fx[1]); | ||
541 | } | ||
542 | /* use hash here to make hierarchical structure distinct from | ||
543 | all files on the same level */ | ||
544 | GNUNET_CRYPTO_hash (fx, sizeof(fx), &ft); | ||
545 | /* use XOR here so that order of the files in the directory | ||
546 | does not matter! */ | ||
547 | GNUNET_CRYPTO_hash_xor (&ft, id, id); | ||
548 | return GNUNET_OK; | ||
549 | } | ||
550 | |||
551 | |||
552 | /** | ||
553 | * Function called with a filename (or directory name) to publish | ||
554 | * (if it has changed since the last time we published it). This function | ||
555 | * is called for the top-level files only. | ||
556 | * | ||
557 | * @param cls closure, NULL | ||
558 | * @param filename complete filename (absolute path) | ||
559 | * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR during shutdown | ||
560 | */ | ||
561 | static int | ||
562 | add_file (void *cls, const char *filename) | ||
563 | { | ||
564 | struct WorkItem *wi; | ||
565 | struct GNUNET_HashCode key; | ||
566 | struct GNUNET_HashCode id; | ||
567 | |||
568 | if (GNUNET_YES == do_shutdown) | ||
569 | return GNUNET_SYSERR; | ||
570 | if ((NULL != strstr (filename, "/.auto-share")) || | ||
571 | (NULL != strstr (filename, "\\.auto-share"))) | ||
572 | return GNUNET_OK; /* skip internal file */ | ||
573 | GNUNET_CRYPTO_hash (filename, strlen (filename), &key); | ||
574 | wi = GNUNET_CONTAINER_multihashmap_get (work_finished, &key); | ||
575 | memset (&id, 0, sizeof(struct GNUNET_HashCode)); | ||
576 | determine_id (&id, filename); | ||
577 | if (NULL != wi) | ||
578 | { | ||
579 | if (0 == memcmp (&id, &wi->id, sizeof(struct GNUNET_HashCode))) | ||
580 | return GNUNET_OK; /* skip: we did this one already */ | ||
581 | /* contents changed, need to re-do the directory... */ | ||
582 | GNUNET_assert ( | ||
583 | GNUNET_YES == | ||
584 | GNUNET_CONTAINER_multihashmap_remove (work_finished, &key, wi)); | ||
585 | } | ||
586 | else | ||
587 | { | ||
588 | wi = GNUNET_new (struct WorkItem); | ||
589 | wi->filename = GNUNET_strdup (filename); | ||
590 | } | ||
591 | wi->id = id; | ||
592 | GNUNET_CONTAINER_DLL_insert (work_head, work_tail, wi); | ||
593 | if (GNUNET_YES == do_shutdown) | ||
594 | return GNUNET_SYSERR; | ||
595 | return GNUNET_OK; | ||
596 | } | ||
597 | |||
598 | |||
599 | /** | ||
600 | * Periodically run task to update our view of the directory to share. | ||
601 | * | ||
602 | * @param cls NULL | ||
603 | */ | ||
604 | static void | ||
605 | scan (void *cls) | ||
606 | { | ||
607 | run_task = NULL; | ||
608 | start_time = GNUNET_TIME_absolute_get (); | ||
609 | (void) GNUNET_DISK_directory_scan (dir_name, &add_file, NULL); | ||
610 | schedule_next_task (); | ||
611 | } | ||
612 | |||
613 | |||
614 | /** | ||
615 | * Decide what the next task is (working or scanning) and schedule it. | ||
616 | */ | ||
617 | static void | ||
618 | schedule_next_task () | ||
619 | { | ||
620 | struct GNUNET_TIME_Relative delay; | ||
621 | |||
622 | if (GNUNET_YES == do_shutdown) | ||
623 | return; | ||
624 | GNUNET_assert (NULL == run_task); | ||
625 | if (NULL == work_head) | ||
626 | { | ||
627 | /* delay by at most 4h, at least 1s, and otherwise in between depending | ||
628 | on how long it took to scan */ | ||
629 | delay = GNUNET_TIME_absolute_get_duration (start_time); | ||
630 | delay = GNUNET_TIME_relative_saturating_multiply (delay, 100); | ||
631 | delay = GNUNET_TIME_relative_min (delay, MAX_DELAY); | ||
632 | delay = GNUNET_TIME_relative_max (delay, MIN_DELAY); | ||
633 | run_task = GNUNET_SCHEDULER_add_delayed (delay, &scan, NULL); | ||
634 | } | ||
635 | else | ||
636 | { | ||
637 | run_task = GNUNET_SCHEDULER_add_now (&work, NULL); | ||
638 | } | ||
639 | } | ||
640 | |||
641 | |||
642 | /** | ||
643 | * Main function that will be run by the scheduler. | ||
644 | * | ||
645 | * @param cls closure | ||
646 | * @param args remaining command-line arguments | ||
647 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
648 | * @param c configuration | ||
649 | */ | ||
650 | static void | ||
651 | run (void *cls, | ||
652 | char *const *args, | ||
653 | const char *cfgfile, | ||
654 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
655 | { | ||
656 | /* check arguments */ | ||
657 | if ((NULL == args[0]) || (NULL != args[1]) || | ||
658 | (GNUNET_YES != GNUNET_DISK_directory_test (args[0], GNUNET_YES))) | ||
659 | { | ||
660 | printf (_ ( | ||
661 | "You must specify one and only one directory name for automatic publication.\n")); | ||
662 | ret = -1; | ||
663 | return; | ||
664 | } | ||
665 | cfg_filename = GNUNET_strdup (cfgfile); | ||
666 | cfg = c; | ||
667 | dir_name = args[0]; | ||
668 | work_finished = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO); | ||
669 | load_state (); | ||
670 | run_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
671 | &scan, | ||
672 | NULL); | ||
673 | GNUNET_SCHEDULER_add_shutdown (&do_stop_task, NULL); | ||
674 | } | ||
675 | |||
676 | |||
677 | /** | ||
678 | * Free memory associated with the work item from the work_finished map. | ||
679 | * | ||
680 | * @param cls NULL (unused) | ||
681 | * @param key key of the item in the map (unused) | ||
682 | * @param value the `struct WorkItem` to free | ||
683 | * @return #GNUNET_OK to continue to iterate | ||
684 | */ | ||
685 | static int | ||
686 | free_item (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
687 | { | ||
688 | struct WorkItem *wi = value; | ||
689 | |||
690 | GNUNET_free (wi->filename); | ||
691 | GNUNET_free (wi); | ||
692 | return GNUNET_OK; | ||
693 | } | ||
694 | |||
695 | |||
696 | /** | ||
697 | * The main function to automatically publish content to GNUnet. | ||
698 | * | ||
699 | * @param argc number of arguments from the command line | ||
700 | * @param argv command line arguments | ||
701 | * @return 0 ok, 1 on error | ||
702 | */ | ||
703 | int | ||
704 | main (int argc, char *const *argv) | ||
705 | { | ||
706 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
707 | GNUNET_GETOPT_option_uint ('a', | ||
708 | "anonymity", | ||
709 | "LEVEL", | ||
710 | gettext_noop ( | ||
711 | "set the desired LEVEL of sender-anonymity"), | ||
712 | &anonymity_level), | ||
713 | |||
714 | GNUNET_GETOPT_option_flag ( | ||
715 | 'd', | ||
716 | "disable-creation-time", | ||
717 | gettext_noop ( | ||
718 | "disable adding the creation time to the metadata of the uploaded file"), | ||
719 | &do_disable_creation_time), | ||
720 | |||
721 | GNUNET_GETOPT_option_flag ( | ||
722 | 'D', | ||
723 | "disable-extractor", | ||
724 | gettext_noop ("do not use libextractor to add keywords or metadata"), | ||
725 | &disable_extractor), | ||
726 | |||
727 | GNUNET_GETOPT_option_uint ('p', | ||
728 | "priority", | ||
729 | "PRIORITY", | ||
730 | gettext_noop ( | ||
731 | "specify the priority of the content"), | ||
732 | &content_priority), | ||
733 | |||
734 | GNUNET_GETOPT_option_uint ('r', | ||
735 | "replication", | ||
736 | "LEVEL", | ||
737 | gettext_noop ( | ||
738 | "set the desired replication LEVEL"), | ||
739 | &replication_level), | ||
740 | |||
741 | GNUNET_GETOPT_option_verbose (&verbose), | ||
742 | |||
743 | GNUNET_GETOPT_OPTION_END | ||
744 | }; | ||
745 | struct WorkItem *wi; | ||
746 | int ok; | ||
747 | struct GNUNET_SIGNAL_Context *shc_chld; | ||
748 | |||
749 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
750 | return 2; | ||
751 | sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE); | ||
752 | GNUNET_assert (NULL != sigpipe); | ||
753 | shc_chld = | ||
754 | GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); | ||
755 | ok = | ||
756 | (GNUNET_OK == | ||
757 | GNUNET_PROGRAM_run ( | ||
758 | argc, | ||
759 | argv, | ||
760 | "gnunet-auto-share [OPTIONS] FILENAME", | ||
761 | gettext_noop ("Automatically publish files from a directory on GNUnet"), | ||
762 | options, | ||
763 | &run, | ||
764 | NULL)) | ||
765 | ? ret | ||
766 | : 1; | ||
767 | if (NULL != work_finished) | ||
768 | { | ||
769 | (void) GNUNET_CONTAINER_multihashmap_iterate (work_finished, | ||
770 | &free_item, | ||
771 | NULL); | ||
772 | GNUNET_CONTAINER_multihashmap_destroy (work_finished); | ||
773 | } | ||
774 | while (NULL != (wi = work_head)) | ||
775 | { | ||
776 | GNUNET_CONTAINER_DLL_remove (work_head, work_tail, wi); | ||
777 | GNUNET_free (wi->filename); | ||
778 | GNUNET_free (wi); | ||
779 | } | ||
780 | GNUNET_SIGNAL_handler_uninstall (shc_chld); | ||
781 | shc_chld = NULL; | ||
782 | GNUNET_DISK_pipe_close (sigpipe); | ||
783 | sigpipe = NULL; | ||
784 | GNUNET_free (cfg_filename); | ||
785 | cfg_filename = NULL; | ||
786 | GNUNET_free_nz ((void *) argv); | ||
787 | return ok; | ||
788 | } | ||
789 | |||
790 | |||
791 | /* end of gnunet-auto-share.c */ | ||
diff --git a/src/fs/gnunet-daemon-fsprofiler.c b/src/fs/gnunet-daemon-fsprofiler.c deleted file mode 100644 index fbb7c6028..000000000 --- a/src/fs/gnunet-daemon-fsprofiler.c +++ /dev/null | |||
@@ -1,672 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012 Christian Grothoff | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-daemon-fsprofiler.c | ||
23 | * @brief daemon that publishes and downloads (random) files | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - how to signal driver that we're done? | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include "gnunet_fs_service.h" | ||
31 | #include "gnunet_statistics_service.h" | ||
32 | |||
33 | /** | ||
34 | * We use 'patterns' of the form (x,y,t) to specify desired download/publish | ||
35 | * activities of a peer. They are stored in a DLL. | ||
36 | */ | ||
37 | struct Pattern | ||
38 | { | ||
39 | /** | ||
40 | * Kept in a DLL. | ||
41 | */ | ||
42 | struct Pattern *next; | ||
43 | |||
44 | /** | ||
45 | * Kept in a DLL. | ||
46 | */ | ||
47 | struct Pattern *prev; | ||
48 | |||
49 | /** | ||
50 | * Execution context for the pattern (FS-handle to the operation). | ||
51 | */ | ||
52 | void *ctx; | ||
53 | |||
54 | /** | ||
55 | * Secondary execution context for the pattern (FS-handle to the operation). | ||
56 | */ | ||
57 | void *sctx; | ||
58 | |||
59 | /** | ||
60 | * When did the operation start? | ||
61 | */ | ||
62 | struct GNUNET_TIME_Absolute start_time; | ||
63 | |||
64 | /** | ||
65 | * With how much delay should this operation be started? | ||
66 | */ | ||
67 | struct GNUNET_TIME_Relative delay; | ||
68 | |||
69 | /** | ||
70 | * Task to run the operation. | ||
71 | */ | ||
72 | struct GNUNET_SCHEDULER_Task *task; | ||
73 | |||
74 | /** | ||
75 | * Secondary task to run the operation. | ||
76 | */ | ||
77 | struct GNUNET_SCHEDULER_Task *stask; | ||
78 | |||
79 | /** | ||
80 | * X-value. | ||
81 | */ | ||
82 | unsigned long long x; | ||
83 | |||
84 | /** | ||
85 | * Y-value. | ||
86 | */ | ||
87 | unsigned long long y; | ||
88 | }; | ||
89 | |||
90 | |||
91 | /** | ||
92 | * Return value from 'main'. | ||
93 | */ | ||
94 | static int global_ret; | ||
95 | |||
96 | /** | ||
97 | * Configuration we use. | ||
98 | */ | ||
99 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
100 | |||
101 | /** | ||
102 | * Handle to the statistics service. | ||
103 | */ | ||
104 | static struct GNUNET_STATISTICS_Handle *stats_handle; | ||
105 | |||
106 | /** | ||
107 | * Peer's FS handle. | ||
108 | */ | ||
109 | static struct GNUNET_FS_Handle *fs_handle; | ||
110 | |||
111 | /** | ||
112 | * Unique number for this peer in the testbed. | ||
113 | */ | ||
114 | static unsigned long long my_peerid; | ||
115 | |||
116 | /** | ||
117 | * Desired anonymity level. | ||
118 | */ | ||
119 | static unsigned long long anonymity_level; | ||
120 | |||
121 | /** | ||
122 | * Desired replication level. | ||
123 | */ | ||
124 | static unsigned long long replication_level; | ||
125 | |||
126 | /** | ||
127 | * String describing which publishing operations this peer should | ||
128 | * perform. The format is "(SIZE,SEED,TIME)*", for example: | ||
129 | * "(1,5,0)(7,3,13)" means to publish a file with 1 byte and | ||
130 | * seed/keyword 5 immediately and another file with 7 bytes and | ||
131 | * seed/keyword 3 after 13 ms. | ||
132 | */ | ||
133 | static char *publish_pattern; | ||
134 | |||
135 | /** | ||
136 | * Head of the DLL of publish patterns. | ||
137 | */ | ||
138 | static struct Pattern *publish_head; | ||
139 | |||
140 | /** | ||
141 | * Tail of the DLL of publish patterns. | ||
142 | */ | ||
143 | static struct Pattern *publish_tail; | ||
144 | |||
145 | /** | ||
146 | * String describing which download operations this peer should | ||
147 | * perform. The format is "(KEYWORD,SIZE,DELAY)*"; for example, | ||
148 | * "(1,7,3)(3,8,8)" means to download one file of 7 bytes under | ||
149 | * keyword "1" starting the search after 3 ms; and another one of 8 | ||
150 | * bytes under keyword '3' starting after 8 ms. The file size is | ||
151 | * used to determine which search result(s) should be used or ignored. | ||
152 | */ | ||
153 | static char *download_pattern; | ||
154 | |||
155 | /** | ||
156 | * Head of the DLL of publish patterns. | ||
157 | */ | ||
158 | static struct Pattern *download_head; | ||
159 | |||
160 | /** | ||
161 | * Tail of the DLL of publish patterns. | ||
162 | */ | ||
163 | static struct Pattern *download_tail; | ||
164 | |||
165 | |||
166 | /** | ||
167 | * Parse a pattern string and store the corresponding | ||
168 | * 'struct Pattern' in the given head/tail. | ||
169 | * | ||
170 | * @param head where to store the head | ||
171 | * @param tail where to store the tail | ||
172 | * @param pattern pattern to parse | ||
173 | * @return GNUNET_OK on success | ||
174 | */ | ||
175 | static int | ||
176 | parse_pattern (struct Pattern **head, | ||
177 | struct Pattern **tail, | ||
178 | const char *pattern) | ||
179 | { | ||
180 | struct Pattern *p; | ||
181 | unsigned long long x; | ||
182 | unsigned long long y; | ||
183 | unsigned long long t; | ||
184 | |||
185 | while (3 == sscanf (pattern, | ||
186 | "(%llu,%llu,%llu)", | ||
187 | &x, &y, &t)) | ||
188 | { | ||
189 | p = GNUNET_new (struct Pattern); | ||
190 | p->x = x; | ||
191 | p->y = y; | ||
192 | p->delay.rel_value_us = (uint64_t) t; | ||
193 | GNUNET_CONTAINER_DLL_insert (*head, *tail, p); | ||
194 | pattern = strstr (pattern, ")"); | ||
195 | GNUNET_assert (NULL != pattern); | ||
196 | pattern++; | ||
197 | } | ||
198 | return (0 == strlen (pattern)) ? GNUNET_OK : GNUNET_SYSERR; | ||
199 | } | ||
200 | |||
201 | |||
202 | /** | ||
203 | * Create a KSK URI from a number. | ||
204 | * | ||
205 | * @param kval the number | ||
206 | * @return corresponding KSK URI | ||
207 | */ | ||
208 | static struct GNUNET_FS_Uri * | ||
209 | make_keywords (uint64_t kval) | ||
210 | { | ||
211 | char kw[128]; | ||
212 | |||
213 | GNUNET_snprintf (kw, sizeof(kw), | ||
214 | "%llu", (unsigned long long) kval); | ||
215 | return GNUNET_FS_uri_ksk_create (kw, NULL); | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Create a file of the given length with a deterministic amount | ||
221 | * of data to be published under keyword 'kval'. | ||
222 | * | ||
223 | * @param length number of bytes in the file | ||
224 | * @param kval keyword value and seed for the data of the file | ||
225 | * @param ctx context to pass to 'fi' | ||
226 | * @return file information handle for the file | ||
227 | */ | ||
228 | static struct GNUNET_FS_FileInformation * | ||
229 | make_file (uint64_t length, | ||
230 | uint64_t kval, | ||
231 | void *ctx) | ||
232 | { | ||
233 | struct GNUNET_FS_FileInformation *fi; | ||
234 | struct GNUNET_FS_BlockOptions bo; | ||
235 | char *data; | ||
236 | struct GNUNET_FS_Uri *keywords; | ||
237 | unsigned long long i; | ||
238 | uint64_t xor; | ||
239 | |||
240 | data = NULL; /* to make compilers happy */ | ||
241 | if ((0 != length) && | ||
242 | (NULL == (data = GNUNET_malloc_large ((size_t) length)))) | ||
243 | return NULL; | ||
244 | /* initialize data with 'unique' data only depending on 'kval' and 'size', | ||
245 | making sure that blocks do not repeat */ | ||
246 | for (i = 0; i < length; i += 8) | ||
247 | { | ||
248 | xor = length ^ kval ^ (uint64_t) (i / 32 / 1024); | ||
249 | GNUNET_memcpy (&data[i], &xor, GNUNET_MIN (length - i, sizeof(uint64_t))); | ||
250 | } | ||
251 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS); | ||
252 | bo.anonymity_level = (uint32_t) anonymity_level; | ||
253 | bo.content_priority = 128; | ||
254 | bo.replication_level = (uint32_t) replication_level; | ||
255 | keywords = make_keywords (kval); | ||
256 | fi = GNUNET_FS_file_information_create_from_data (fs_handle, | ||
257 | ctx, | ||
258 | length, | ||
259 | data, keywords, | ||
260 | NULL, GNUNET_NO, &bo); | ||
261 | GNUNET_FS_uri_destroy (keywords); | ||
262 | return fi; | ||
263 | } | ||
264 | |||
265 | |||
266 | /** | ||
267 | * Task run during shutdown. | ||
268 | * | ||
269 | * @param cls unused | ||
270 | */ | ||
271 | static void | ||
272 | shutdown_task (void *cls) | ||
273 | { | ||
274 | struct Pattern *p; | ||
275 | |||
276 | while (NULL != (p = publish_head)) | ||
277 | { | ||
278 | if (NULL != p->task) | ||
279 | GNUNET_SCHEDULER_cancel (p->task); | ||
280 | if (NULL != p->ctx) | ||
281 | GNUNET_FS_publish_stop (p->ctx); | ||
282 | GNUNET_CONTAINER_DLL_remove (publish_head, publish_tail, p); | ||
283 | GNUNET_free (p); | ||
284 | } | ||
285 | while (NULL != (p = download_head)) | ||
286 | { | ||
287 | if (NULL != p->task) | ||
288 | GNUNET_SCHEDULER_cancel (p->task); | ||
289 | if (NULL != p->stask) | ||
290 | GNUNET_SCHEDULER_cancel (p->stask); | ||
291 | if (NULL != p->ctx) | ||
292 | GNUNET_FS_download_stop (p->ctx, GNUNET_YES); | ||
293 | if (NULL != p->sctx) | ||
294 | GNUNET_FS_search_stop (p->sctx); | ||
295 | GNUNET_CONTAINER_DLL_remove (download_head, download_tail, p); | ||
296 | GNUNET_free (p); | ||
297 | } | ||
298 | if (NULL != fs_handle) | ||
299 | { | ||
300 | GNUNET_FS_stop (fs_handle); | ||
301 | fs_handle = NULL; | ||
302 | } | ||
303 | if (NULL != stats_handle) | ||
304 | { | ||
305 | GNUNET_STATISTICS_destroy (stats_handle, GNUNET_YES); | ||
306 | stats_handle = NULL; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Task run when a publish operation should be stopped. | ||
313 | * | ||
314 | * @param cls the 'struct Pattern' of the publish operation to stop | ||
315 | */ | ||
316 | static void | ||
317 | publish_stop_task (void *cls) | ||
318 | { | ||
319 | struct Pattern *p = cls; | ||
320 | |||
321 | p->task = NULL; | ||
322 | GNUNET_FS_publish_stop (p->ctx); | ||
323 | } | ||
324 | |||
325 | |||
326 | /** | ||
327 | * Task run when a download operation should be stopped. | ||
328 | * | ||
329 | * @param cls the 'struct Pattern' of the download operation to stop | ||
330 | */ | ||
331 | static void | ||
332 | download_stop_task (void *cls) | ||
333 | { | ||
334 | struct Pattern *p = cls; | ||
335 | |||
336 | p->task = NULL; | ||
337 | GNUNET_FS_download_stop (p->ctx, GNUNET_YES); | ||
338 | } | ||
339 | |||
340 | |||
341 | /** | ||
342 | * Task run when a download operation should be stopped. | ||
343 | * | ||
344 | * @param cls the 'struct Pattern' of the download operation to stop | ||
345 | */ | ||
346 | static void | ||
347 | search_stop_task (void *cls) | ||
348 | { | ||
349 | struct Pattern *p = cls; | ||
350 | |||
351 | p->stask = NULL; | ||
352 | GNUNET_FS_search_stop (p->sctx); | ||
353 | } | ||
354 | |||
355 | |||
356 | /** | ||
357 | * Notification of FS to a client about the progress of an | ||
358 | * operation. Callbacks of this type will be used for uploads, | ||
359 | * downloads and searches. Some of the arguments depend a bit | ||
360 | * in their meaning on the context in which the callback is used. | ||
361 | * | ||
362 | * @param cls closure | ||
363 | * @param info details about the event, specifying the event type | ||
364 | * and various bits about the event | ||
365 | * @return client-context (for the next progress call | ||
366 | * for this operation; should be set to NULL for | ||
367 | * SUSPEND and STOPPED events). The value returned | ||
368 | * will be passed to future callbacks in the respective | ||
369 | * field in the GNUNET_FS_ProgressInfo struct. | ||
370 | */ | ||
371 | static void * | ||
372 | progress_cb (void *cls, | ||
373 | const struct GNUNET_FS_ProgressInfo *info) | ||
374 | { | ||
375 | struct Pattern *p; | ||
376 | const struct GNUNET_FS_Uri *uri; | ||
377 | |||
378 | switch (info->status) | ||
379 | { | ||
380 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
381 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
382 | p = info->value.publish.cctx; | ||
383 | return p; | ||
384 | |||
385 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
386 | p = info->value.publish.cctx; | ||
387 | return p; | ||
388 | |||
389 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
390 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
391 | "Publishing failed\n"); | ||
392 | GNUNET_STATISTICS_update (stats_handle, | ||
393 | "# failed publish operations", 1, GNUNET_NO); | ||
394 | p = info->value.publish.cctx; | ||
395 | p->task = GNUNET_SCHEDULER_add_now (&publish_stop_task, p); | ||
396 | return p; | ||
397 | |||
398 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
399 | p = info->value.publish.cctx; | ||
400 | GNUNET_STATISTICS_update (stats_handle, | ||
401 | "# publishing time (ms)", | ||
402 | (long long) GNUNET_TIME_absolute_get_duration ( | ||
403 | p->start_time).rel_value_us / 1000LL, | ||
404 | GNUNET_NO); | ||
405 | p->task = GNUNET_SCHEDULER_add_now (&publish_stop_task, p); | ||
406 | return p; | ||
407 | |||
408 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
409 | p = info->value.publish.cctx; | ||
410 | p->ctx = NULL; | ||
411 | GNUNET_CONTAINER_DLL_remove (publish_head, publish_tail, p); | ||
412 | GNUNET_free (p); | ||
413 | return NULL; | ||
414 | |||
415 | case GNUNET_FS_STATUS_DOWNLOAD_START: | ||
416 | case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: | ||
417 | case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: | ||
418 | case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: | ||
419 | p = info->value.download.cctx; | ||
420 | return p; | ||
421 | |||
422 | case GNUNET_FS_STATUS_DOWNLOAD_ERROR: | ||
423 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
424 | "Download failed\n"); | ||
425 | GNUNET_STATISTICS_update (stats_handle, | ||
426 | "# failed downloads", 1, GNUNET_NO); | ||
427 | p = info->value.download.cctx; | ||
428 | p->task = GNUNET_SCHEDULER_add_now (&download_stop_task, p); | ||
429 | return p; | ||
430 | |||
431 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: | ||
432 | p = info->value.download.cctx; | ||
433 | GNUNET_STATISTICS_update (stats_handle, | ||
434 | "# download time (ms)", | ||
435 | (long long) GNUNET_TIME_absolute_get_duration ( | ||
436 | p->start_time).rel_value_us / 1000LL, | ||
437 | GNUNET_NO); | ||
438 | p->task = GNUNET_SCHEDULER_add_now (&download_stop_task, p); | ||
439 | return p; | ||
440 | |||
441 | case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: | ||
442 | p = info->value.download.cctx; | ||
443 | p->ctx = NULL; | ||
444 | if (NULL == p->sctx) | ||
445 | { | ||
446 | GNUNET_CONTAINER_DLL_remove (download_head, download_tail, p); | ||
447 | GNUNET_free (p); | ||
448 | } | ||
449 | return NULL; | ||
450 | |||
451 | case GNUNET_FS_STATUS_SEARCH_START: | ||
452 | case GNUNET_FS_STATUS_SEARCH_RESULT_NAMESPACE: | ||
453 | p = info->value.search.cctx; | ||
454 | return p; | ||
455 | |||
456 | case GNUNET_FS_STATUS_SEARCH_RESULT: | ||
457 | p = info->value.search.cctx; | ||
458 | uri = info->value.search.specifics.result.uri; | ||
459 | if (GNUNET_YES != GNUNET_FS_uri_test_chk (uri)) | ||
460 | return NULL; /* not what we want */ | ||
461 | if (p->y != GNUNET_FS_uri_chk_get_file_size (uri)) | ||
462 | return NULL; /* not what we want */ | ||
463 | GNUNET_STATISTICS_update (stats_handle, | ||
464 | "# search time (ms)", | ||
465 | (long long) GNUNET_TIME_absolute_get_duration ( | ||
466 | p->start_time).rel_value_us / 1000LL, | ||
467 | GNUNET_NO); | ||
468 | p->start_time = GNUNET_TIME_absolute_get (); | ||
469 | p->ctx = GNUNET_FS_download_start (fs_handle, uri, | ||
470 | NULL, NULL, NULL, | ||
471 | 0, GNUNET_FS_uri_chk_get_file_size (uri), | ||
472 | anonymity_level, | ||
473 | GNUNET_FS_DOWNLOAD_NO_TEMPORARIES, | ||
474 | p, | ||
475 | NULL); | ||
476 | p->stask = GNUNET_SCHEDULER_add_now (&search_stop_task, p); | ||
477 | return NULL; | ||
478 | |||
479 | case GNUNET_FS_STATUS_SEARCH_UPDATE: | ||
480 | case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: | ||
481 | return NULL; /* don't care */ | ||
482 | |||
483 | case GNUNET_FS_STATUS_SEARCH_ERROR: | ||
484 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
485 | "Search failed\n"); | ||
486 | GNUNET_STATISTICS_update (stats_handle, | ||
487 | "# failed searches", 1, GNUNET_NO); | ||
488 | p = info->value.search.cctx; | ||
489 | p->stask = GNUNET_SCHEDULER_add_now (&search_stop_task, p); | ||
490 | return p; | ||
491 | |||
492 | case GNUNET_FS_STATUS_SEARCH_STOPPED: | ||
493 | p = info->value.search.cctx; | ||
494 | p->sctx = NULL; | ||
495 | if (NULL == p->ctx) | ||
496 | { | ||
497 | GNUNET_CONTAINER_DLL_remove (download_head, download_tail, p); | ||
498 | GNUNET_free (p); | ||
499 | } | ||
500 | return NULL; | ||
501 | |||
502 | default: | ||
503 | /* unexpected event during profiling */ | ||
504 | GNUNET_break (0); | ||
505 | return NULL; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | |||
510 | /** | ||
511 | * Start publish operation. | ||
512 | * | ||
513 | * @param cls the 'struct Pattern' specifying the operation to perform | ||
514 | */ | ||
515 | static void | ||
516 | start_publish (void *cls) | ||
517 | { | ||
518 | struct Pattern *p = cls; | ||
519 | struct GNUNET_FS_FileInformation *fi; | ||
520 | |||
521 | p->task = NULL; | ||
522 | fi = make_file (p->x, p->y, p); | ||
523 | p->start_time = GNUNET_TIME_absolute_get (); | ||
524 | p->ctx = GNUNET_FS_publish_start (fs_handle, | ||
525 | fi, | ||
526 | NULL, NULL, NULL, | ||
527 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
528 | } | ||
529 | |||
530 | |||
531 | /** | ||
532 | * Start download operation. | ||
533 | * | ||
534 | * @param cls the 'struct Pattern' specifying the operation to perform | ||
535 | */ | ||
536 | static void | ||
537 | start_download (void *cls) | ||
538 | { | ||
539 | struct Pattern *p = cls; | ||
540 | struct GNUNET_FS_Uri *keywords; | ||
541 | |||
542 | p->task = NULL; | ||
543 | keywords = make_keywords (p->x); | ||
544 | p->start_time = GNUNET_TIME_absolute_get (); | ||
545 | p->sctx = GNUNET_FS_search_start (fs_handle, keywords, | ||
546 | anonymity_level, | ||
547 | GNUNET_FS_SEARCH_OPTION_NONE, | ||
548 | p); | ||
549 | } | ||
550 | |||
551 | |||
552 | /** | ||
553 | * @brief Main function that will be run by the scheduler. | ||
554 | * | ||
555 | * @param cls closure | ||
556 | * @param args remaining command-line arguments | ||
557 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
558 | * @param cfg_ configuration | ||
559 | */ | ||
560 | static void | ||
561 | run (void *cls, char *const *args GNUNET_UNUSED, | ||
562 | const char *cfgfile GNUNET_UNUSED, | ||
563 | const struct GNUNET_CONFIGURATION_Handle *cfg_) | ||
564 | { | ||
565 | char myoptname[128]; | ||
566 | struct Pattern *p; | ||
567 | |||
568 | cfg = cfg_; | ||
569 | /* Scheduled the task to clean up when shutdown is called */ | ||
570 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
571 | NULL); | ||
572 | |||
573 | if (GNUNET_OK != | ||
574 | GNUNET_CONFIGURATION_get_value_number (cfg, | ||
575 | "TESTBED", "PEERID", | ||
576 | &my_peerid)) | ||
577 | { | ||
578 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
579 | "TESTBED", "PEERID"); | ||
580 | global_ret = GNUNET_SYSERR; | ||
581 | GNUNET_SCHEDULER_shutdown (); | ||
582 | return; | ||
583 | } | ||
584 | if (GNUNET_OK != | ||
585 | GNUNET_CONFIGURATION_get_value_number (cfg, | ||
586 | "FSPROFILER", "ANONYMITY_LEVEL", | ||
587 | &anonymity_level)) | ||
588 | anonymity_level = 1; | ||
589 | if (GNUNET_OK != | ||
590 | GNUNET_CONFIGURATION_get_value_number (cfg, | ||
591 | "FSPROFILER", "REPLICATION_LEVEL", | ||
592 | &replication_level)) | ||
593 | replication_level = 1; | ||
594 | GNUNET_snprintf (myoptname, sizeof(myoptname), | ||
595 | "DOWNLOAD-PATTERN-%llu", my_peerid); | ||
596 | if (GNUNET_OK != | ||
597 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
598 | "FSPROFILER", myoptname, | ||
599 | &download_pattern)) | ||
600 | download_pattern = GNUNET_strdup (""); | ||
601 | GNUNET_snprintf (myoptname, sizeof(myoptname), | ||
602 | "PUBLISH-PATTERN-%llu", my_peerid); | ||
603 | if (GNUNET_OK != | ||
604 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
605 | "FSPROFILER", myoptname, | ||
606 | &publish_pattern)) | ||
607 | publish_pattern = GNUNET_strdup (""); | ||
608 | if ((GNUNET_OK != | ||
609 | parse_pattern (&download_head, | ||
610 | &download_tail, | ||
611 | download_pattern)) || | ||
612 | (GNUNET_OK != | ||
613 | parse_pattern (&publish_head, | ||
614 | &publish_tail, | ||
615 | publish_pattern))) | ||
616 | { | ||
617 | GNUNET_SCHEDULER_shutdown (); | ||
618 | return; | ||
619 | } | ||
620 | |||
621 | stats_handle = GNUNET_STATISTICS_create ("fsprofiler", cfg); | ||
622 | fs_handle = | ||
623 | GNUNET_FS_start (cfg, | ||
624 | "fsprofiler", | ||
625 | &progress_cb, NULL, | ||
626 | GNUNET_FS_FLAGS_NONE, | ||
627 | GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, 1, | ||
628 | GNUNET_FS_OPTIONS_REQUEST_PARALLELISM, 1, | ||
629 | GNUNET_FS_OPTIONS_END); | ||
630 | if (NULL == fs_handle) | ||
631 | { | ||
632 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
633 | "Could not acquire FS handle. Exiting.\n"); | ||
634 | global_ret = GNUNET_SYSERR; | ||
635 | GNUNET_SCHEDULER_shutdown (); | ||
636 | return; | ||
637 | } | ||
638 | for (p = publish_head; NULL != p; p = p->next) | ||
639 | p->task = GNUNET_SCHEDULER_add_delayed (p->delay, | ||
640 | &start_publish, p); | ||
641 | for (p = download_head; NULL != p; p = p->next) | ||
642 | p->task = GNUNET_SCHEDULER_add_delayed (p->delay, | ||
643 | &start_download, p); | ||
644 | } | ||
645 | |||
646 | |||
647 | /** | ||
648 | * Program that performs various "random" FS activities. | ||
649 | * | ||
650 | * @param argc number of arguments from the command line | ||
651 | * @param argv command line arguments | ||
652 | * @return 0 ok, 1 on error | ||
653 | */ | ||
654 | int | ||
655 | main (int argc, char *const *argv) | ||
656 | { | ||
657 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
658 | GNUNET_GETOPT_OPTION_END | ||
659 | }; | ||
660 | |||
661 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
662 | return 2; | ||
663 | return (GNUNET_OK == | ||
664 | GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-fsprofiler", | ||
665 | gettext_noop | ||
666 | ( | ||
667 | "Daemon to use file-sharing to measure its performance."), | ||
668 | options, &run, NULL)) ? global_ret : 1; | ||
669 | } | ||
670 | |||
671 | |||
672 | /* end of gnunet-daemon-fsprofiler.c */ | ||
diff --git a/src/fs/gnunet-directory.c b/src/fs/gnunet-directory.c deleted file mode 100644 index ef5c40ae2..000000000 --- a/src/fs/gnunet-directory.c +++ /dev/null | |||
@@ -1,211 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/gnunet-directory.c | ||
22 | * @brief display content of GNUnet directories | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_fs_service.h" | ||
27 | |||
28 | static int ret; | ||
29 | |||
30 | /** | ||
31 | * Print a meta data entry. | ||
32 | * | ||
33 | * @param cls closure (unused) | ||
34 | * @param plugin_name name of the plugin that generated the meta data | ||
35 | * @param type type of the keyword | ||
36 | * @param format format of data | ||
37 | * @param data_mime_type mime type of data | ||
38 | * @param data value of the meta data | ||
39 | * @param data_size number of bytes in @a data | ||
40 | * @return always 0 (to continue iterating) | ||
41 | */ | ||
42 | static int | ||
43 | item_printer (void *cls, | ||
44 | const char *plugin_name, | ||
45 | enum EXTRACTOR_MetaType type, | ||
46 | enum EXTRACTOR_MetaFormat format, | ||
47 | const char *data_mime_type, | ||
48 | const char *data, | ||
49 | size_t data_size) | ||
50 | { | ||
51 | if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA) | ||
52 | { | ||
53 | printf (_ ("\t<original file embedded in %u bytes of meta data>\n"), | ||
54 | (unsigned int) data_size); | ||
55 | return 0; | ||
56 | } | ||
57 | if ((format != EXTRACTOR_METAFORMAT_UTF8) && | ||
58 | (format != EXTRACTOR_METAFORMAT_C_STRING)) | ||
59 | return 0; | ||
60 | if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) | ||
61 | return 0; | ||
62 | #if HAVE_LIBEXTRACTOR | ||
63 | printf ("\t%20s: %s\n", | ||
64 | dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, | ||
65 | EXTRACTOR_metatype_to_string (type)), | ||
66 | data); | ||
67 | #else | ||
68 | printf ("\t%20d: %s\n", type, data); | ||
69 | #endif | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | |||
74 | /** | ||
75 | * Print an entry in a directory. | ||
76 | * | ||
77 | * @param cls closure (not used) | ||
78 | * @param filename name of the file in the directory | ||
79 | * @param uri URI of the file | ||
80 | * @param meta metadata for the file; metadata for | ||
81 | * the directory if everything else is NULL/zero | ||
82 | * @param length length of the available data for the file | ||
83 | * (of type size_t since data must certainly fit | ||
84 | * into memory; if files are larger than size_t | ||
85 | * permits, then they will certainly not be | ||
86 | * embedded with the directory itself). | ||
87 | * @param data data available for the file (length bytes) | ||
88 | */ | ||
89 | static void | ||
90 | print_entry (void *cls, | ||
91 | const char *filename, | ||
92 | const struct GNUNET_FS_Uri *uri, | ||
93 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
94 | size_t length, | ||
95 | const void *data) | ||
96 | { | ||
97 | char *string; | ||
98 | char *name; | ||
99 | |||
100 | name = GNUNET_CONTAINER_meta_data_get_by_type ( | ||
101 | meta, | ||
102 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); | ||
103 | if (uri == NULL) | ||
104 | { | ||
105 | printf (_ ("Directory `%s' meta data:\n"), name ? name : ""); | ||
106 | GNUNET_CONTAINER_meta_data_iterate (meta, &item_printer, NULL); | ||
107 | printf ("\n"); | ||
108 | printf (_ ("Directory `%s' contents:\n"), name ? name : ""); | ||
109 | GNUNET_free (name); | ||
110 | return; | ||
111 | } | ||
112 | string = GNUNET_FS_uri_to_string (uri); | ||
113 | printf ("%s (%s):\n", name ? name : "", string); | ||
114 | GNUNET_free (string); | ||
115 | GNUNET_CONTAINER_meta_data_iterate (meta, &item_printer, NULL); | ||
116 | printf ("\n"); | ||
117 | GNUNET_free (name); | ||
118 | } | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Main function that will be run by the scheduler. | ||
123 | * | ||
124 | * @param cls closure | ||
125 | * @param args remaining command-line arguments | ||
126 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
127 | * @param cfg configuration | ||
128 | */ | ||
129 | static void | ||
130 | run (void *cls, | ||
131 | char *const *args, | ||
132 | const char *cfgfile, | ||
133 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
134 | { | ||
135 | struct GNUNET_DISK_MapHandle *map; | ||
136 | struct GNUNET_DISK_FileHandle *h; | ||
137 | void *data; | ||
138 | size_t len; | ||
139 | uint64_t size; | ||
140 | const char *filename; | ||
141 | int i; | ||
142 | |||
143 | if (NULL == args[0]) | ||
144 | { | ||
145 | fprintf (stderr, "%s", _ ("You must specify a filename to inspect.\n")); | ||
146 | ret = 1; | ||
147 | return; | ||
148 | } | ||
149 | i = 0; | ||
150 | while (NULL != (filename = args[i++])) | ||
151 | { | ||
152 | if ((GNUNET_OK != | ||
153 | GNUNET_DISK_file_size (filename, &size, GNUNET_YES, GNUNET_YES)) || | ||
154 | (NULL == (h = GNUNET_DISK_file_open (filename, | ||
155 | GNUNET_DISK_OPEN_READ, | ||
156 | GNUNET_DISK_PERM_NONE)))) | ||
157 | { | ||
158 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
159 | _ ("Failed to read directory `%s'\n"), | ||
160 | filename); | ||
161 | ret = 1; | ||
162 | continue; | ||
163 | } | ||
164 | len = (size_t) size; | ||
165 | data = GNUNET_DISK_file_map (h, &map, GNUNET_DISK_MAP_TYPE_READ, len); | ||
166 | GNUNET_assert (NULL != data); | ||
167 | if (GNUNET_OK != | ||
168 | GNUNET_FS_directory_list_contents (len, data, 0, &print_entry, NULL)) | ||
169 | fprintf (stdout, _ ("`%s' is not a GNUnet directory\n"), filename); | ||
170 | else | ||
171 | printf ("\n"); | ||
172 | GNUNET_DISK_file_unmap (map); | ||
173 | GNUNET_DISK_file_close (h); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | |||
178 | /** | ||
179 | * The main function to inspect GNUnet directories. | ||
180 | * | ||
181 | * @param argc number of arguments from the command line | ||
182 | * @param argv command line arguments | ||
183 | * @return 0 ok, 1 on error | ||
184 | */ | ||
185 | int | ||
186 | main (int argc, char *const *argv) | ||
187 | { | ||
188 | static struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
189 | GNUNET_GETOPT_OPTION_END | ||
190 | }; | ||
191 | |||
192 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
193 | return 2; | ||
194 | |||
195 | ret = (GNUNET_OK == | ||
196 | GNUNET_PROGRAM_run (argc, | ||
197 | argv, | ||
198 | "gnunet-directory [OPTIONS] FILENAME", | ||
199 | gettext_noop ( | ||
200 | "Display contents of a GNUnet directory"), | ||
201 | options, | ||
202 | &run, | ||
203 | NULL)) | ||
204 | ? ret | ||
205 | : 1; | ||
206 | GNUNET_free_nz ((void *) argv); | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | |||
211 | /* end of gnunet-directory.c */ | ||
diff --git a/src/fs/gnunet-download.c b/src/fs/gnunet-download.c deleted file mode 100644 index eebf8e993..000000000 --- a/src/fs/gnunet-download.c +++ /dev/null | |||
@@ -1,384 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/gnunet-download.c | ||
22 | * @brief downloading for files on GNUnet | ||
23 | * @author Christian Grothoff | ||
24 | * @author Krista Bennett | ||
25 | * @author James Blackwell | ||
26 | * @author Igor Wronsky | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | static int ret; | ||
32 | |||
33 | static unsigned int verbose; | ||
34 | |||
35 | static int delete_incomplete; | ||
36 | |||
37 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
38 | |||
39 | static struct GNUNET_FS_Handle *ctx; | ||
40 | |||
41 | static struct GNUNET_FS_DownloadContext *dc; | ||
42 | |||
43 | static unsigned int anonymity = 1; | ||
44 | |||
45 | static unsigned int parallelism = 16; | ||
46 | |||
47 | static unsigned int request_parallelism = 4092; | ||
48 | |||
49 | static int do_recursive; | ||
50 | |||
51 | static char *filename; | ||
52 | |||
53 | static int local_only; | ||
54 | |||
55 | |||
56 | static void | ||
57 | cleanup_task (void *cls) | ||
58 | { | ||
59 | GNUNET_FS_stop (ctx); | ||
60 | ctx = NULL; | ||
61 | } | ||
62 | |||
63 | |||
64 | static void | ||
65 | shutdown_task (void *cls) | ||
66 | { | ||
67 | if (NULL != dc) | ||
68 | { | ||
69 | GNUNET_FS_download_stop (dc, delete_incomplete); | ||
70 | dc = NULL; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Display progress bar (if tty). | ||
77 | * | ||
78 | * @param x current position in the download | ||
79 | * @param n total size of the download | ||
80 | * @param w desired number of steps in the progress bar | ||
81 | */ | ||
82 | static void | ||
83 | display_bar (unsigned long long x, unsigned long long n, unsigned int w) | ||
84 | { | ||
85 | char buf[w + 20]; | ||
86 | unsigned int p; | ||
87 | unsigned int endeq; | ||
88 | float ratio_complete; | ||
89 | |||
90 | if (0 == isatty (1)) | ||
91 | return; | ||
92 | ratio_complete = x / (float) n; | ||
93 | endeq = ratio_complete * w; | ||
94 | GNUNET_snprintf (buf, sizeof(buf), "%3d%% [", (int) (ratio_complete * 100)); | ||
95 | for (p = 0; p < endeq; p++) | ||
96 | strcat (buf, "="); | ||
97 | for (p = endeq; p < w; p++) | ||
98 | strcat (buf, " "); | ||
99 | strcat (buf, "]\r"); | ||
100 | printf ("%s", buf); | ||
101 | fflush (stdout); | ||
102 | } | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Called by FS client to give information about the progress of an | ||
107 | * operation. | ||
108 | * | ||
109 | * @param cls closure | ||
110 | * @param info details about the event, specifying the event type | ||
111 | * and various bits about the event | ||
112 | * @return client-context (for the next progress call | ||
113 | * for this operation; should be set to NULL for | ||
114 | * SUSPEND and STOPPED events). The value returned | ||
115 | * will be passed to future callbacks in the respective | ||
116 | * field in the `struct GNUNET_FS_ProgressInfo` | ||
117 | */ | ||
118 | static void * | ||
119 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) | ||
120 | { | ||
121 | char *s; | ||
122 | const char *s2; | ||
123 | char *t; | ||
124 | |||
125 | switch (info->status) | ||
126 | { | ||
127 | case GNUNET_FS_STATUS_DOWNLOAD_START: | ||
128 | if (verbose > 1) | ||
129 | fprintf (stderr, | ||
130 | _ ("Starting download `%s'.\n"), | ||
131 | info->value.download.filename); | ||
132 | break; | ||
133 | |||
134 | case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: | ||
135 | if (verbose) | ||
136 | { | ||
137 | s = GNUNET_strdup ( | ||
138 | GNUNET_STRINGS_relative_time_to_string (info->value.download.eta, | ||
139 | GNUNET_YES)); | ||
140 | if (info->value.download.specifics.progress.block_download_duration | ||
141 | .rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) | ||
142 | s2 = _ ("<unknown time>"); | ||
143 | else | ||
144 | s2 = GNUNET_STRINGS_relative_time_to_string (info->value.download | ||
145 | .specifics.progress | ||
146 | .block_download_duration, | ||
147 | GNUNET_YES); | ||
148 | t = GNUNET_STRINGS_byte_size_fancy ( | ||
149 | info->value.download.completed * 1000LL | ||
150 | / (info->value.download.duration.rel_value_us + 1)); | ||
151 | fprintf ( | ||
152 | stdout, | ||
153 | _ ( | ||
154 | "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"), | ||
155 | info->value.download.filename, | ||
156 | (unsigned long long) info->value.download.completed, | ||
157 | (unsigned long long) info->value.download.size, | ||
158 | s, | ||
159 | t, | ||
160 | s2); | ||
161 | GNUNET_free (s); | ||
162 | GNUNET_free (t); | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | display_bar (info->value.download.completed, | ||
167 | info->value.download.size, | ||
168 | 60); | ||
169 | } | ||
170 | break; | ||
171 | |||
172 | case GNUNET_FS_STATUS_DOWNLOAD_ERROR: | ||
173 | if (0 != isatty (1)) | ||
174 | fprintf (stdout, "\n"); | ||
175 | fprintf (stderr, | ||
176 | _ ("Error downloading: %s.\n"), | ||
177 | info->value.download.specifics.error.message); | ||
178 | GNUNET_SCHEDULER_shutdown (); | ||
179 | break; | ||
180 | |||
181 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: | ||
182 | s = GNUNET_STRINGS_byte_size_fancy ( | ||
183 | info->value.download.completed * 1000 | ||
184 | / (info->value.download.duration.rel_value_us + 1)); | ||
185 | if (0 != isatty (1)) | ||
186 | fprintf (stdout, "\n"); | ||
187 | fprintf (stdout, | ||
188 | _ ("Downloading `%s' done (%s/s).\n"), | ||
189 | info->value.download.filename, | ||
190 | s); | ||
191 | GNUNET_free (s); | ||
192 | if (info->value.download.dc == dc) | ||
193 | GNUNET_SCHEDULER_shutdown (); | ||
194 | break; | ||
195 | |||
196 | case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: | ||
197 | if (info->value.download.dc == dc) | ||
198 | GNUNET_SCHEDULER_add_now (&cleanup_task, NULL); | ||
199 | break; | ||
200 | |||
201 | case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: | ||
202 | case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: | ||
203 | break; | ||
204 | |||
205 | default: | ||
206 | fprintf (stderr, _ ("Unexpected status: %d\n"), info->status); | ||
207 | break; | ||
208 | } | ||
209 | return NULL; | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Main function that will be run by the scheduler. | ||
215 | * | ||
216 | * @param cls closure | ||
217 | * @param args remaining command-line arguments | ||
218 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
219 | * @param c configuration | ||
220 | */ | ||
221 | static void | ||
222 | run (void *cls, | ||
223 | char *const *args, | ||
224 | const char *cfgfile, | ||
225 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
226 | { | ||
227 | struct GNUNET_FS_Uri *uri; | ||
228 | char *emsg; | ||
229 | enum GNUNET_FS_DownloadOptions options; | ||
230 | |||
231 | if (NULL == args[0]) | ||
232 | { | ||
233 | fprintf (stderr, "%s", _ ("You need to specify a URI argument.\n")); | ||
234 | return; | ||
235 | } | ||
236 | uri = GNUNET_FS_uri_parse (args[0], &emsg); | ||
237 | if (NULL == uri) | ||
238 | { | ||
239 | fprintf (stderr, _ ("Failed to parse URI: %s\n"), emsg); | ||
240 | GNUNET_free (emsg); | ||
241 | ret = 1; | ||
242 | return; | ||
243 | } | ||
244 | if ((! GNUNET_FS_uri_test_chk (uri)) && (! GNUNET_FS_uri_test_loc (uri))) | ||
245 | { | ||
246 | fprintf (stderr, "%s", _ ("Only CHK or LOC URIs supported.\n")); | ||
247 | ret = 1; | ||
248 | GNUNET_FS_uri_destroy (uri); | ||
249 | return; | ||
250 | } | ||
251 | if (NULL == filename) | ||
252 | { | ||
253 | fprintf (stderr, "%s", _ ("Target filename must be specified.\n")); | ||
254 | ret = 1; | ||
255 | GNUNET_FS_uri_destroy (uri); | ||
256 | return; | ||
257 | } | ||
258 | cfg = c; | ||
259 | ctx = GNUNET_FS_start (cfg, | ||
260 | "gnunet-download", | ||
261 | &progress_cb, | ||
262 | NULL, | ||
263 | GNUNET_FS_FLAGS_NONE, | ||
264 | GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, | ||
265 | parallelism, | ||
266 | GNUNET_FS_OPTIONS_REQUEST_PARALLELISM, | ||
267 | request_parallelism, | ||
268 | GNUNET_FS_OPTIONS_END); | ||
269 | if (NULL == ctx) | ||
270 | { | ||
271 | fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS"); | ||
272 | GNUNET_FS_uri_destroy (uri); | ||
273 | ret = 1; | ||
274 | return; | ||
275 | } | ||
276 | options = GNUNET_FS_DOWNLOAD_OPTION_NONE; | ||
277 | if (do_recursive) | ||
278 | options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE; | ||
279 | if (local_only) | ||
280 | options |= GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY; | ||
281 | dc = GNUNET_FS_download_start (ctx, | ||
282 | uri, | ||
283 | NULL, | ||
284 | filename, | ||
285 | NULL, | ||
286 | 0, | ||
287 | GNUNET_FS_uri_chk_get_file_size (uri), | ||
288 | anonymity, | ||
289 | options, | ||
290 | NULL, | ||
291 | NULL); | ||
292 | GNUNET_FS_uri_destroy (uri); | ||
293 | if (dc == NULL) | ||
294 | { | ||
295 | GNUNET_FS_stop (ctx); | ||
296 | ctx = NULL; | ||
297 | return; | ||
298 | } | ||
299 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
300 | } | ||
301 | |||
302 | |||
303 | /** | ||
304 | * The main function to download GNUnet. | ||
305 | * | ||
306 | * @param argc number of arguments from the command line | ||
307 | * @param argv command line arguments | ||
308 | * @return 0 ok, 1 on error | ||
309 | */ | ||
310 | int | ||
311 | main (int argc, char *const *argv) | ||
312 | { | ||
313 | struct GNUNET_GETOPT_CommandLineOption options[] = | ||
314 | { GNUNET_GETOPT_option_uint ('a', | ||
315 | "anonymity", | ||
316 | "LEVEL", | ||
317 | gettext_noop ( | ||
318 | "set the desired LEVEL of receiver-anonymity"), | ||
319 | &anonymity), | ||
320 | |||
321 | GNUNET_GETOPT_option_flag ( | ||
322 | 'D', | ||
323 | "delete-incomplete", | ||
324 | gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"), | ||
325 | &delete_incomplete), | ||
326 | |||
327 | GNUNET_GETOPT_option_flag ( | ||
328 | 'n', | ||
329 | "no-network", | ||
330 | gettext_noop ("only search the local peer (no P2P network search)"), | ||
331 | &local_only), | ||
332 | GNUNET_GETOPT_option_string ('o', | ||
333 | "output", | ||
334 | "FILENAME", | ||
335 | gettext_noop ("write the file to FILENAME"), | ||
336 | &filename), | ||
337 | GNUNET_GETOPT_option_uint ( | ||
338 | 'p', | ||
339 | "parallelism", | ||
340 | "DOWNLOADS", | ||
341 | gettext_noop ( | ||
342 | "set the maximum number of parallel downloads that is allowed"), | ||
343 | ¶llelism), | ||
344 | GNUNET_GETOPT_option_uint ( | ||
345 | 'r', | ||
346 | "request-parallelism", | ||
347 | "REQUESTS", | ||
348 | gettext_noop ( | ||
349 | "set the maximum number of parallel requests for blocks that is allowed"), | ||
350 | &request_parallelism), | ||
351 | GNUNET_GETOPT_option_flag ('R', | ||
352 | "recursive", | ||
353 | gettext_noop ( | ||
354 | "download a GNUnet directory recursively"), | ||
355 | &do_recursive), | ||
356 | GNUNET_GETOPT_option_increment_uint ( | ||
357 | 'V', | ||
358 | "verbose", | ||
359 | gettext_noop ("be verbose (print progress information)"), | ||
360 | &verbose), | ||
361 | GNUNET_GETOPT_OPTION_END }; | ||
362 | |||
363 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
364 | return 2; | ||
365 | |||
366 | ret = | ||
367 | (GNUNET_OK == | ||
368 | GNUNET_PROGRAM_run ( | ||
369 | argc, | ||
370 | argv, | ||
371 | "gnunet-download [OPTIONS] URI", | ||
372 | gettext_noop ( | ||
373 | "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/chk/...)"), | ||
374 | options, | ||
375 | &run, | ||
376 | NULL)) | ||
377 | ? ret | ||
378 | : 1; | ||
379 | GNUNET_free_nz ((void *) argv); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | |||
384 | /* end of gnunet-download.c */ | ||
diff --git a/src/fs/gnunet-fs-profiler.c b/src/fs/gnunet-fs-profiler.c deleted file mode 100644 index 62da46834..000000000 --- a/src/fs/gnunet-fs-profiler.c +++ /dev/null | |||
@@ -1,245 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-fs-profiler.c | ||
23 | * @brief tool to benchmark/profile file-sharing | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testbed_service.h" | ||
29 | |||
30 | /** | ||
31 | * Final status code. | ||
32 | */ | ||
33 | static int ret; | ||
34 | |||
35 | /** | ||
36 | * Data file with the hosts for the testbed. | ||
37 | */ | ||
38 | static char *host_filename; | ||
39 | |||
40 | /** | ||
41 | * Number of peers to run in the experiment. | ||
42 | */ | ||
43 | static unsigned int num_peers; | ||
44 | |||
45 | /** | ||
46 | * After how long do we abort the test? | ||
47 | */ | ||
48 | static struct GNUNET_TIME_Relative timeout; | ||
49 | |||
50 | /** | ||
51 | * Handle to the task run during termination. | ||
52 | */ | ||
53 | static struct GNUNET_SCHEDULER_Task *terminate_taskid; | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Function called after we've collected the statistics. | ||
58 | * | ||
59 | * @param cls NULL | ||
60 | * @param op the operation that has been finished | ||
61 | * @param emsg error message in case the operation has failed; will be NULL if | ||
62 | * operation has executed successfully. | ||
63 | */ | ||
64 | static void | ||
65 | shutdown_task (void *cls, | ||
66 | struct GNUNET_TESTBED_Operation *op, | ||
67 | const char *emsg) | ||
68 | { | ||
69 | if (NULL != emsg) | ||
70 | fprintf (stderr, | ||
71 | "Error collecting statistics: %s\n", | ||
72 | emsg); | ||
73 | GNUNET_SCHEDULER_shutdown (); | ||
74 | } | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Callback function to process statistic values from all peers. | ||
79 | * Prints them out. | ||
80 | * | ||
81 | * @param cls closure | ||
82 | * @param peer the peer the statistic belong to | ||
83 | * @param subsystem name of subsystem that created the statistic | ||
84 | * @param name the name of the datum | ||
85 | * @param value the current value | ||
86 | * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not | ||
87 | * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration | ||
88 | */ | ||
89 | static int | ||
90 | process_stats (void *cls, | ||
91 | const struct GNUNET_TESTBED_Peer *peer, | ||
92 | const char *subsystem, | ||
93 | const char *name, | ||
94 | uint64_t value, | ||
95 | int is_persistent) | ||
96 | { | ||
97 | fprintf (stdout, | ||
98 | "%p-%s: %s = %llu\n", | ||
99 | peer, | ||
100 | subsystem, | ||
101 | name, | ||
102 | (unsigned long long) value); | ||
103 | return GNUNET_OK; | ||
104 | } | ||
105 | |||
106 | |||
107 | /** | ||
108 | * Task run on shutdown to terminate. Triggers printing out | ||
109 | * all statistics. | ||
110 | * | ||
111 | * @param cls NULL | ||
112 | */ | ||
113 | static void | ||
114 | terminate_task (void *cls) | ||
115 | { | ||
116 | if (NULL != terminate_taskid) | ||
117 | { | ||
118 | GNUNET_SCHEDULER_cancel (terminate_taskid); | ||
119 | terminate_taskid = NULL; | ||
120 | } | ||
121 | GNUNET_TESTBED_get_statistics (0, NULL, | ||
122 | NULL, NULL, | ||
123 | &process_stats, | ||
124 | &shutdown_task, | ||
125 | NULL); | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * Task run on timeout to terminate. Triggers printing out | ||
131 | * all statistics. | ||
132 | * | ||
133 | * @param cls NULL | ||
134 | */ | ||
135 | static void | ||
136 | timeout_task (void *cls) | ||
137 | { | ||
138 | terminate_taskid = NULL; | ||
139 | GNUNET_SCHEDULER_shutdown (); | ||
140 | } | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Signature of a main function for a testcase. | ||
145 | * | ||
146 | * @param cls closure | ||
147 | * @param h the run handle | ||
148 | * @param num_peers number of peers in 'peers' | ||
149 | * @param peers handle to peers run in the testbed | ||
150 | * @param links_succeeded the number of overlay link connection attempts that | ||
151 | * succeeded | ||
152 | * @param links_failed the number of overlay link connection attempts that | ||
153 | * failed | ||
154 | */ | ||
155 | static void | ||
156 | test_master (void *cls, | ||
157 | struct GNUNET_TESTBED_RunHandle *h, | ||
158 | unsigned int num_peers, | ||
159 | struct GNUNET_TESTBED_Peer **peers, | ||
160 | unsigned int links_succeeded, | ||
161 | unsigned int links_failed) | ||
162 | { | ||
163 | // const struct GNUNET_CONFIGURATION_Handle *cfg = cls; | ||
164 | // FIXME: enable clients to signal 'completion' before timeout; | ||
165 | // in that case, run the 'terminate_task' "immediately" | ||
166 | |||
167 | if (0 != timeout.rel_value_us) | ||
168 | terminate_taskid = GNUNET_SCHEDULER_add_delayed (timeout, | ||
169 | &timeout_task, | ||
170 | NULL); | ||
171 | GNUNET_SCHEDULER_add_shutdown (&terminate_task, | ||
172 | NULL); | ||
173 | } | ||
174 | |||
175 | |||
176 | /** | ||
177 | * Main function that will be run by the scheduler. | ||
178 | * | ||
179 | * @param cls closure | ||
180 | * @param args remaining command-line arguments | ||
181 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
182 | * @param cfg configuration | ||
183 | */ | ||
184 | static void | ||
185 | run (void *cls, char *const *args, const char *cfgfile, | ||
186 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
187 | { | ||
188 | GNUNET_TESTBED_run (host_filename, | ||
189 | cfg, | ||
190 | num_peers, | ||
191 | 0, NULL, NULL, | ||
192 | &test_master, (void *) cfg); | ||
193 | } | ||
194 | |||
195 | |||
196 | /** | ||
197 | * Program to run a file-sharing testbed. | ||
198 | * | ||
199 | * @param argc number of arguments from the command line | ||
200 | * @param argv command line arguments | ||
201 | * @return 0 ok, 1 on error | ||
202 | */ | ||
203 | int | ||
204 | main (int argc, char *const *argv) | ||
205 | { | ||
206 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
207 | GNUNET_GETOPT_option_uint ('n', | ||
208 | "num-peers", | ||
209 | "COUNT", | ||
210 | gettext_noop ( | ||
211 | "run the experiment with COUNT peers"), | ||
212 | &num_peers), | ||
213 | |||
214 | GNUNET_GETOPT_option_string ('H', | ||
215 | "hosts", | ||
216 | "HOSTFILE", | ||
217 | gettext_noop ( | ||
218 | "specifies name of a file with the HOSTS the testbed should use"), | ||
219 | &host_filename), | ||
220 | |||
221 | GNUNET_GETOPT_option_relative_time ('t', | ||
222 | "timeout", | ||
223 | "DELAY", | ||
224 | gettext_noop ( | ||
225 | "automatically terminate experiment after DELAY"), | ||
226 | &timeout), | ||
227 | |||
228 | GNUNET_GETOPT_OPTION_END | ||
229 | }; | ||
230 | |||
231 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
232 | return 2; | ||
233 | |||
234 | ret = (GNUNET_OK == | ||
235 | GNUNET_PROGRAM_run (argc, argv, "gnunet-fs-profiler", | ||
236 | gettext_noop ( | ||
237 | "run a testbed to measure file-sharing performance"), | ||
238 | options, &run, | ||
239 | NULL)) ? ret : 1; | ||
240 | GNUNET_free_nz ((void *) argv); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | |||
245 | /* end of gnunet-fs-profiler.c */ | ||
diff --git a/src/fs/gnunet-fs.c b/src/fs/gnunet-fs.c deleted file mode 100644 index 70a0034a0..000000000 --- a/src/fs/gnunet-fs.c +++ /dev/null | |||
@@ -1,152 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/gnunet-fs.c | ||
22 | * @brief special file-sharing functions | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_fs_service.h" | ||
27 | |||
28 | /** | ||
29 | * Return value. | ||
30 | */ | ||
31 | static int ret; | ||
32 | |||
33 | /** | ||
34 | * Handle to FS service. | ||
35 | */ | ||
36 | static struct GNUNET_FS_Handle *fs; | ||
37 | |||
38 | /** | ||
39 | * Option -i given? | ||
40 | */ | ||
41 | static int list_indexed_files; | ||
42 | |||
43 | /** | ||
44 | * Option -v given? | ||
45 | */ | ||
46 | static unsigned int verbose; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Print indexed filenames to stdout. | ||
51 | * | ||
52 | * @param cls closure | ||
53 | * @param filename the name of the file | ||
54 | * @param file_id hash of the contents of the indexed file | ||
55 | * @return GNUNET_OK to continue iteration | ||
56 | */ | ||
57 | static int | ||
58 | print_indexed (void *cls, | ||
59 | const char *filename, | ||
60 | const struct GNUNET_HashCode *file_id) | ||
61 | { | ||
62 | if (NULL == filename) | ||
63 | { | ||
64 | GNUNET_FS_stop (fs); | ||
65 | fs = NULL; | ||
66 | return GNUNET_OK; | ||
67 | } | ||
68 | if (verbose) | ||
69 | fprintf (stdout, "%s: %s\n", GNUNET_h2s (file_id), filename); | ||
70 | else | ||
71 | fprintf (stdout, "%s\n", filename); | ||
72 | return GNUNET_OK; | ||
73 | } | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Main function that will be run by the scheduler. | ||
78 | * | ||
79 | * @param cls closure | ||
80 | * @param args remaining command-line arguments | ||
81 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
82 | * @param cfg configuration | ||
83 | */ | ||
84 | static void | ||
85 | run (void *cls, | ||
86 | char *const *args, | ||
87 | const char *cfgfile, | ||
88 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
89 | { | ||
90 | if (list_indexed_files) | ||
91 | { | ||
92 | fs = GNUNET_FS_start (cfg, | ||
93 | "gnunet-fs", | ||
94 | NULL, | ||
95 | NULL, | ||
96 | GNUNET_FS_FLAGS_NONE, | ||
97 | GNUNET_FS_OPTIONS_END); | ||
98 | if (NULL == fs) | ||
99 | { | ||
100 | ret = 1; | ||
101 | return; | ||
102 | } | ||
103 | if (NULL == GNUNET_FS_get_indexed_files (fs, &print_indexed, NULL)) | ||
104 | { | ||
105 | ret = 2; | ||
106 | GNUNET_FS_stop (fs); | ||
107 | fs = NULL; | ||
108 | return; | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | |||
114 | /** | ||
115 | * The main function to access special file-sharing functions. | ||
116 | * | ||
117 | * @param argc number of arguments from the command line | ||
118 | * @param argv command line arguments | ||
119 | * @return 0 ok, 1 on error | ||
120 | */ | ||
121 | int | ||
122 | main (int argc, char *const *argv) | ||
123 | { | ||
124 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
125 | GNUNET_GETOPT_option_flag ('i', | ||
126 | "list-indexed", | ||
127 | gettext_noop ( | ||
128 | "print a list of all indexed files"), | ||
129 | &list_indexed_files), | ||
130 | |||
131 | GNUNET_GETOPT_option_verbose (&verbose), | ||
132 | GNUNET_GETOPT_OPTION_END | ||
133 | }; | ||
134 | |||
135 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
136 | return 2; | ||
137 | ret = (GNUNET_OK == | ||
138 | GNUNET_PROGRAM_run (argc, | ||
139 | argv, | ||
140 | "gnunet-fs [OPTIONS]", | ||
141 | gettext_noop ("Special file-sharing operations"), | ||
142 | options, | ||
143 | &run, | ||
144 | NULL)) | ||
145 | ? ret | ||
146 | : 1; | ||
147 | GNUNET_free_nz ((void *) argv); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | |||
152 | /* end of gnunet-fs.c */ | ||
diff --git a/src/fs/gnunet-helper-fs-publish.c b/src/fs/gnunet-helper-fs-publish.c deleted file mode 100644 index ef1a9ce4b..000000000 --- a/src/fs/gnunet-helper-fs-publish.c +++ /dev/null | |||
@@ -1,578 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file src/fs/gnunet-helper-fs-publish.c | ||
23 | * @brief Tool to help extract meta data asynchronously | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * This program will scan a directory for files with meta data | ||
27 | * and report the results to stdout. | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include "gnunet_fs_service.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * A node of a directory tree. | ||
35 | */ | ||
36 | struct ScanTreeNode | ||
37 | { | ||
38 | /** | ||
39 | * This is a doubly-linked list | ||
40 | */ | ||
41 | struct ScanTreeNode *next; | ||
42 | |||
43 | /** | ||
44 | * This is a doubly-linked list | ||
45 | */ | ||
46 | struct ScanTreeNode *prev; | ||
47 | |||
48 | /** | ||
49 | * Parent of this node, NULL for top-level entries. | ||
50 | */ | ||
51 | struct ScanTreeNode *parent; | ||
52 | |||
53 | /** | ||
54 | * This is a doubly-linked tree | ||
55 | * NULL for files and empty directories | ||
56 | */ | ||
57 | struct ScanTreeNode *children_head; | ||
58 | |||
59 | /** | ||
60 | * This is a doubly-linked tree | ||
61 | * NULL for files and empty directories | ||
62 | */ | ||
63 | struct ScanTreeNode *children_tail; | ||
64 | |||
65 | /** | ||
66 | * Name of the file/directory | ||
67 | */ | ||
68 | char *filename; | ||
69 | |||
70 | /** | ||
71 | * Size of the file (if it is a file), in bytes. | ||
72 | * At the moment it is set to 0 for directories. | ||
73 | */ | ||
74 | uint64_t file_size; | ||
75 | |||
76 | /** | ||
77 | * #GNUNET_YES if this is a directory | ||
78 | */ | ||
79 | int is_directory; | ||
80 | }; | ||
81 | |||
82 | |||
83 | #if HAVE_LIBEXTRACTOR | ||
84 | /** | ||
85 | * List of libextractor plugins to use for extracting. | ||
86 | */ | ||
87 | static struct EXTRACTOR_PluginList *plugins; | ||
88 | #endif | ||
89 | |||
90 | /** | ||
91 | * File descriptor we use for IPC with the parent. | ||
92 | */ | ||
93 | static int output_stream; | ||
94 | |||
95 | |||
96 | #if HAVE_LIBEXTRACTOR | ||
97 | /** | ||
98 | * Add meta data that libextractor finds to our meta data | ||
99 | * container. | ||
100 | * | ||
101 | * @param cls closure, our meta data container | ||
102 | * @param plugin_name name of the plugin that produced this value; | ||
103 | * special values can be used (e.g. '<zlib>' for zlib being | ||
104 | * used in the main libextractor library and yielding | ||
105 | * meta data). | ||
106 | * @param type libextractor-type describing the meta data | ||
107 | * @param format basic format information about data | ||
108 | * @param data_mime_type mime-type of data (not of the original file); | ||
109 | * can be NULL (if mime-type is not known) | ||
110 | * @param data actual meta-data found | ||
111 | * @param data_len number of bytes in @a data | ||
112 | * @return always 0 to continue extracting | ||
113 | */ | ||
114 | static int | ||
115 | add_to_md (void *cls, | ||
116 | const char *plugin_name, | ||
117 | enum EXTRACTOR_MetaType type, | ||
118 | enum EXTRACTOR_MetaFormat format, | ||
119 | const char *data_mime_type, | ||
120 | const char *data, | ||
121 | size_t data_len) | ||
122 | { | ||
123 | struct GNUNET_CONTAINER_MetaData *md = cls; | ||
124 | |||
125 | if (((EXTRACTOR_METAFORMAT_UTF8 == format) || | ||
126 | (EXTRACTOR_METAFORMAT_C_STRING == format)) && | ||
127 | ('\0' != data[data_len - 1])) | ||
128 | { | ||
129 | char zdata[data_len + 1]; | ||
130 | GNUNET_memcpy (zdata, data, data_len); | ||
131 | zdata[data_len] = '\0'; | ||
132 | (void) GNUNET_CONTAINER_meta_data_insert (md, | ||
133 | plugin_name, | ||
134 | type, | ||
135 | format, | ||
136 | data_mime_type, | ||
137 | zdata, | ||
138 | data_len + 1); | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | (void) GNUNET_CONTAINER_meta_data_insert (md, | ||
143 | plugin_name, | ||
144 | type, | ||
145 | format, | ||
146 | data_mime_type, | ||
147 | data, | ||
148 | data_len); | ||
149 | } | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | |||
154 | #endif | ||
155 | |||
156 | |||
157 | /** | ||
158 | * Free memory of the @a tree structure | ||
159 | * | ||
160 | * @param tree tree to free | ||
161 | */ | ||
162 | static void | ||
163 | free_tree (struct ScanTreeNode *tree) | ||
164 | { | ||
165 | struct ScanTreeNode *pos; | ||
166 | |||
167 | while (NULL != (pos = tree->children_head)) | ||
168 | free_tree (pos); | ||
169 | if (NULL != tree->parent) | ||
170 | GNUNET_CONTAINER_DLL_remove (tree->parent->children_head, | ||
171 | tree->parent->children_tail, | ||
172 | tree); | ||
173 | GNUNET_free (tree->filename); | ||
174 | GNUNET_free (tree); | ||
175 | } | ||
176 | |||
177 | |||
178 | /** | ||
179 | * Write @a size bytes from @a buf into the #output_stream. | ||
180 | * | ||
181 | * @param buf buffer with data to write | ||
182 | * @param size number of bytes to write | ||
183 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
184 | */ | ||
185 | static int | ||
186 | write_all (const void *buf, size_t size) | ||
187 | { | ||
188 | const char *cbuf = buf; | ||
189 | size_t total; | ||
190 | ssize_t wr; | ||
191 | |||
192 | total = 0; | ||
193 | do | ||
194 | { | ||
195 | wr = write (output_stream, &cbuf[total], size - total); | ||
196 | if (wr > 0) | ||
197 | total += wr; | ||
198 | } | ||
199 | while ((wr > 0) && (total < size)); | ||
200 | if (wr <= 0) | ||
201 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
202 | "Failed to write to stdout: %s\n", | ||
203 | strerror (errno)); | ||
204 | return (total == size) ? GNUNET_OK : GNUNET_SYSERR; | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Write message to the master process. | ||
210 | * | ||
211 | * @param message_type message type to use | ||
212 | * @param data data to append, NULL for none | ||
213 | * @param data_length number of bytes in @a data | ||
214 | * @return #GNUNET_SYSERR to stop scanning (the pipe was broken somehow) | ||
215 | */ | ||
216 | static int | ||
217 | write_message (uint16_t message_type, const char *data, size_t data_length) | ||
218 | { | ||
219 | struct GNUNET_MessageHeader hdr; | ||
220 | |||
221 | #if 0 | ||
222 | fprintf (stderr, | ||
223 | "Helper sends %u-byte message of type %u\n", | ||
224 | (unsigned int) (sizeof(struct GNUNET_MessageHeader) + data_length), | ||
225 | (unsigned int) message_type); | ||
226 | #endif | ||
227 | hdr.type = htons (message_type); | ||
228 | hdr.size = htons (sizeof(struct GNUNET_MessageHeader) + data_length); | ||
229 | if ((GNUNET_OK != write_all (&hdr, sizeof(hdr))) || | ||
230 | (GNUNET_OK != write_all (data, data_length))) | ||
231 | return GNUNET_SYSERR; | ||
232 | return GNUNET_OK; | ||
233 | } | ||
234 | |||
235 | |||
236 | /** | ||
237 | * Function called to (recursively) add all of the files in the | ||
238 | * directory to the tree. Called by the directory scanner to initiate | ||
239 | * the scan. Does NOT yet add any metadata. | ||
240 | * | ||
241 | * @param filename file or directory to scan | ||
242 | * @param dst where to store the resulting share tree item; | ||
243 | * NULL is stored in @a dst upon recoverable errors (#GNUNET_OK is returned) | ||
244 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
245 | */ | ||
246 | static int | ||
247 | preprocess_file (const char *filename, struct ScanTreeNode **dst); | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Closure for the 'scan_callback' | ||
252 | */ | ||
253 | struct RecursionContext | ||
254 | { | ||
255 | /** | ||
256 | * Parent to add the files to. | ||
257 | */ | ||
258 | struct ScanTreeNode *parent; | ||
259 | |||
260 | /** | ||
261 | * Flag to set to GNUNET_YES on serious errors. | ||
262 | */ | ||
263 | int stop; | ||
264 | }; | ||
265 | |||
266 | |||
267 | /** | ||
268 | * Function called by the directory iterator to (recursively) add all | ||
269 | * of the files in the directory to the tree. Called by the directory | ||
270 | * scanner to initiate the scan. Does NOT yet add any metadata. | ||
271 | * | ||
272 | * @param cls the `struct RecursionContext` | ||
273 | * @param filename file or directory to scan | ||
274 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
275 | */ | ||
276 | static int | ||
277 | scan_callback (void *cls, const char *filename) | ||
278 | { | ||
279 | struct RecursionContext *rc = cls; | ||
280 | struct ScanTreeNode *chld; | ||
281 | |||
282 | if (GNUNET_OK != preprocess_file (filename, &chld)) | ||
283 | { | ||
284 | rc->stop = GNUNET_YES; | ||
285 | return GNUNET_SYSERR; | ||
286 | } | ||
287 | if (NULL == chld) | ||
288 | return GNUNET_OK; | ||
289 | chld->parent = rc->parent; | ||
290 | GNUNET_CONTAINER_DLL_insert (rc->parent->children_head, | ||
291 | rc->parent->children_tail, | ||
292 | chld); | ||
293 | return GNUNET_OK; | ||
294 | } | ||
295 | |||
296 | |||
297 | /** | ||
298 | * Function called to (recursively) add all of the files in the | ||
299 | * directory to the tree. Called by the directory scanner to initiate | ||
300 | * the scan. Does NOT yet add any metadata. | ||
301 | * | ||
302 | * @param filename file or directory to scan | ||
303 | * @param dst where to store the resulting share tree item; | ||
304 | * NULL is stored in @a dst upon recoverable errors (#GNUNET_OK is returned) | ||
305 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
306 | */ | ||
307 | static int | ||
308 | preprocess_file (const char *filename, struct ScanTreeNode **dst) | ||
309 | { | ||
310 | struct ScanTreeNode *item; | ||
311 | struct stat sbuf; | ||
312 | uint64_t fsize = 0; | ||
313 | |||
314 | if ((0 != stat (filename, &sbuf)) || | ||
315 | ((! S_ISDIR (sbuf.st_mode)) && | ||
316 | (GNUNET_OK != | ||
317 | GNUNET_DISK_file_size (filename, &fsize, GNUNET_NO, GNUNET_YES)))) | ||
318 | { | ||
319 | /* If the file doesn't exist (or is not stat-able for any other reason) | ||
320 | skip it (but report it), but do continue. */ | ||
321 | if (GNUNET_OK != | ||
322 | write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE, | ||
323 | filename, | ||
324 | strlen (filename) + 1)) | ||
325 | return GNUNET_SYSERR; | ||
326 | /* recoverable error, store 'NULL' in *dst */ | ||
327 | *dst = NULL; | ||
328 | return GNUNET_OK; | ||
329 | } | ||
330 | |||
331 | /* Report the progress */ | ||
332 | if ( | ||
333 | GNUNET_OK != | ||
334 | write_message (S_ISDIR (sbuf.st_mode) | ||
335 | ? GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY | ||
336 | : GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE, | ||
337 | filename, | ||
338 | strlen (filename) + 1)) | ||
339 | return GNUNET_SYSERR; | ||
340 | item = GNUNET_new (struct ScanTreeNode); | ||
341 | item->filename = GNUNET_strdup (filename); | ||
342 | item->is_directory = (S_ISDIR (sbuf.st_mode)) ? GNUNET_YES : GNUNET_NO; | ||
343 | item->file_size = fsize; | ||
344 | if (GNUNET_YES == item->is_directory) | ||
345 | { | ||
346 | struct RecursionContext rc; | ||
347 | |||
348 | rc.parent = item; | ||
349 | rc.stop = GNUNET_NO; | ||
350 | GNUNET_DISK_directory_scan (filename, &scan_callback, &rc); | ||
351 | if ( | ||
352 | (GNUNET_YES == rc.stop) || | ||
353 | (GNUNET_OK != | ||
354 | write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY, | ||
355 | "..", | ||
356 | 3))) | ||
357 | { | ||
358 | free_tree (item); | ||
359 | return GNUNET_SYSERR; | ||
360 | } | ||
361 | } | ||
362 | *dst = item; | ||
363 | return GNUNET_OK; | ||
364 | } | ||
365 | |||
366 | |||
367 | /** | ||
368 | * Extract metadata from files. | ||
369 | * | ||
370 | * @param item entry we are processing | ||
371 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on fatal errors | ||
372 | */ | ||
373 | static int | ||
374 | extract_files (struct ScanTreeNode *item) | ||
375 | { | ||
376 | struct GNUNET_CONTAINER_MetaData *meta; | ||
377 | ssize_t size; | ||
378 | size_t slen; | ||
379 | |||
380 | if (GNUNET_YES == item->is_directory) | ||
381 | { | ||
382 | /* for directories, we simply only descent, no extraction, no | ||
383 | progress reporting */ | ||
384 | struct ScanTreeNode *pos; | ||
385 | |||
386 | for (pos = item->children_head; NULL != pos; pos = pos->next) | ||
387 | if (GNUNET_OK != extract_files (pos)) | ||
388 | return GNUNET_SYSERR; | ||
389 | return GNUNET_OK; | ||
390 | } | ||
391 | |||
392 | /* this is the expensive operation, *afterwards* we'll check for aborts */ | ||
393 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
394 | #if HAVE_LIBEXTRACTOR | ||
395 | EXTRACTOR_extract (plugins, item->filename, NULL, 0, &add_to_md, meta); | ||
396 | #endif | ||
397 | slen = strlen (item->filename) + 1; | ||
398 | size = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); | ||
399 | if (-1 == size) | ||
400 | { | ||
401 | /* no meta data */ | ||
402 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
403 | if (GNUNET_OK != | ||
404 | write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA, | ||
405 | item->filename, | ||
406 | slen)) | ||
407 | return GNUNET_SYSERR; | ||
408 | return GNUNET_OK; | ||
409 | } | ||
410 | else if (size > (UINT16_MAX - sizeof(struct GNUNET_MessageHeader) - slen)) | ||
411 | { | ||
412 | /* We can't transfer more than 64k bytes in one message. */ | ||
413 | size = UINT16_MAX - sizeof(struct GNUNET_MessageHeader) - slen; | ||
414 | } | ||
415 | { | ||
416 | char buf[size + slen]; | ||
417 | char *dst = &buf[slen]; | ||
418 | |||
419 | GNUNET_memcpy (buf, item->filename, slen); | ||
420 | size = GNUNET_CONTAINER_meta_data_serialize ( | ||
421 | meta, | ||
422 | &dst, | ||
423 | size, | ||
424 | GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); | ||
425 | if (size < 0) | ||
426 | { | ||
427 | GNUNET_break (0); | ||
428 | size = 0; | ||
429 | } | ||
430 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
431 | if (GNUNET_OK != | ||
432 | write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA, | ||
433 | buf, | ||
434 | slen + size)) | ||
435 | return GNUNET_SYSERR; | ||
436 | } | ||
437 | return GNUNET_OK; | ||
438 | } | ||
439 | |||
440 | |||
441 | /** | ||
442 | * Install a signal handler to ignore SIGPIPE. | ||
443 | */ | ||
444 | static void | ||
445 | ignore_sigpipe () | ||
446 | { | ||
447 | struct sigaction oldsig; | ||
448 | struct sigaction sig; | ||
449 | |||
450 | memset (&sig, 0, sizeof(struct sigaction)); | ||
451 | sig.sa_handler = SIG_IGN; | ||
452 | sigemptyset (&sig.sa_mask); | ||
453 | #ifdef SA_INTERRUPT | ||
454 | sig.sa_flags = SA_INTERRUPT; /* SunOS */ | ||
455 | #else | ||
456 | sig.sa_flags = SA_RESTART; | ||
457 | #endif | ||
458 | if (0 != sigaction (SIGPIPE, &sig, &oldsig)) | ||
459 | fprintf (stderr, | ||
460 | "Failed to install SIGPIPE handler: %s\n", | ||
461 | strerror (errno)); | ||
462 | } | ||
463 | |||
464 | |||
465 | /** | ||
466 | * Turn the given file descriptor in to '/dev/null'. | ||
467 | * | ||
468 | * @param fd fd to bind to /dev/null | ||
469 | * @param flags flags to use (O_RDONLY or O_WRONLY) | ||
470 | */ | ||
471 | static void | ||
472 | make_dev_zero (int fd, int flags) | ||
473 | { | ||
474 | int z; | ||
475 | |||
476 | GNUNET_assert (0 == close (fd)); | ||
477 | z = open ("/dev/null", flags); | ||
478 | GNUNET_assert (-1 != z); | ||
479 | if (z == fd) | ||
480 | return; | ||
481 | GNUNET_break (fd == dup2 (z, fd)); | ||
482 | GNUNET_assert (0 == close (z)); | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * Main function of the helper process to extract meta data. | ||
488 | * | ||
489 | * @param argc should be 3 | ||
490 | * @param argv [0] our binary name | ||
491 | * [1] name of the file or directory to process | ||
492 | * [2] "-" to disable extraction, NULL for defaults, | ||
493 | * otherwise custom plugins to load from LE | ||
494 | * @return 0 on success | ||
495 | */ | ||
496 | int | ||
497 | main (int argc, char *const *argv) | ||
498 | { | ||
499 | const char *filename_expanded; | ||
500 | const char *ex; | ||
501 | struct ScanTreeNode *root; | ||
502 | |||
503 | ignore_sigpipe (); | ||
504 | /* move stdout to some other FD for IPC, bind | ||
505 | stdout/stderr to /dev/null */ | ||
506 | output_stream = dup (1); | ||
507 | make_dev_zero (1, O_WRONLY); | ||
508 | make_dev_zero (2, O_WRONLY); | ||
509 | |||
510 | /* parse command line */ | ||
511 | if ((3 != argc) && (2 != argc)) | ||
512 | { | ||
513 | fprintf (stderr, | ||
514 | "%s", | ||
515 | "gnunet-helper-fs-publish needs exactly one or two arguments\n"); | ||
516 | return 1; | ||
517 | } | ||
518 | filename_expanded = argv[1]; | ||
519 | ex = argv[2]; | ||
520 | if ((NULL == ex) || (0 != strcmp (ex, "-"))) | ||
521 | { | ||
522 | #if HAVE_LIBEXTRACTOR | ||
523 | plugins = EXTRACTOR_plugin_add_defaults (EXTRACTOR_OPTION_DEFAULT_POLICY); | ||
524 | if (NULL != ex) | ||
525 | plugins = EXTRACTOR_plugin_add_config (plugins, | ||
526 | ex, | ||
527 | EXTRACTOR_OPTION_DEFAULT_POLICY); | ||
528 | #endif | ||
529 | } | ||
530 | |||
531 | /* scan tree to find out how much work there is to be done */ | ||
532 | if (GNUNET_OK != preprocess_file (filename_expanded, &root)) | ||
533 | { | ||
534 | (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0); | ||
535 | #if HAVE_LIBEXTRACTOR | ||
536 | EXTRACTOR_plugin_remove_all (plugins); | ||
537 | #endif | ||
538 | return 2; | ||
539 | } | ||
540 | /* signal that we're done counting files, so that a percentage of | ||
541 | progress can now be calculated */ | ||
542 | if (GNUNET_OK != | ||
543 | write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE, | ||
544 | NULL, | ||
545 | 0)) | ||
546 | { | ||
547 | #if HAVE_LIBEXTRACTOR | ||
548 | EXTRACTOR_plugin_remove_all (plugins); | ||
549 | #endif | ||
550 | return 3; | ||
551 | } | ||
552 | if (NULL != root) | ||
553 | { | ||
554 | if (GNUNET_OK != extract_files (root)) | ||
555 | { | ||
556 | (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, | ||
557 | NULL, | ||
558 | 0); | ||
559 | free_tree (root); | ||
560 | #if HAVE_LIBEXTRACTOR | ||
561 | EXTRACTOR_plugin_remove_all (plugins); | ||
562 | #endif | ||
563 | return 4; | ||
564 | } | ||
565 | free_tree (root); | ||
566 | } | ||
567 | /* enable "clean" shutdown by telling parent that we are done */ | ||
568 | (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED, | ||
569 | NULL, | ||
570 | 0); | ||
571 | #if HAVE_LIBEXTRACTOR | ||
572 | EXTRACTOR_plugin_remove_all (plugins); | ||
573 | #endif | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | |||
578 | /* end of gnunet-helper-fs-publish.c */ | ||
diff --git a/src/fs/gnunet-publish.c b/src/fs/gnunet-publish.c deleted file mode 100644 index c62edcd61..000000000 --- a/src/fs/gnunet-publish.c +++ /dev/null | |||
@@ -1,1008 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/gnunet-publish.c | ||
22 | * @brief publishing files on GNUnet | ||
23 | * @author Christian Grothoff | ||
24 | * @author Krista Bennett | ||
25 | * @author James Blackwell | ||
26 | * @author Igor Wronsky | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | #include "gnunet_identity_service.h" | ||
31 | |||
32 | /** | ||
33 | * Global return value from #main(). | ||
34 | */ | ||
35 | static int ret; | ||
36 | |||
37 | /** | ||
38 | * Command line option 'verbose' set | ||
39 | */ | ||
40 | static unsigned int verbose; | ||
41 | |||
42 | /** | ||
43 | * Handle to our configuration. | ||
44 | */ | ||
45 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
46 | |||
47 | /** | ||
48 | * Handle for interaction with file-sharing service. | ||
49 | */ | ||
50 | static struct GNUNET_FS_Handle *ctx; | ||
51 | |||
52 | /** | ||
53 | * Handle to FS-publishing operation. | ||
54 | */ | ||
55 | static struct GNUNET_FS_PublishContext *pc; | ||
56 | |||
57 | /** | ||
58 | * Meta-data provided via command-line option. | ||
59 | */ | ||
60 | static struct GNUNET_CONTAINER_MetaData *meta; | ||
61 | |||
62 | /** | ||
63 | * Keywords provided via command-line option. | ||
64 | */ | ||
65 | static struct GNUNET_FS_Uri *topKeywords; | ||
66 | |||
67 | /** | ||
68 | * Options we set for published blocks. | ||
69 | */ | ||
70 | static struct GNUNET_FS_BlockOptions bo = { { 0LL }, 1, 365, 1 }; | ||
71 | |||
72 | /** | ||
73 | * Value of URI provided on command-line (when not publishing | ||
74 | * a file but just creating UBlocks to refer to an existing URI). | ||
75 | */ | ||
76 | static char *uri_string; | ||
77 | |||
78 | /** | ||
79 | * Value of URI provided on command-line (when not publishing | ||
80 | * a file but just creating UBlocks to refer to an existing URI); | ||
81 | * parsed version of 'uri_string'. | ||
82 | */ | ||
83 | static struct GNUNET_FS_Uri *uri; | ||
84 | |||
85 | /** | ||
86 | * Command-line option for namespace publishing: identifier for updates | ||
87 | * to this publication. | ||
88 | */ | ||
89 | static char *next_id; | ||
90 | |||
91 | /** | ||
92 | * Command-line option for namespace publishing: identifier for this | ||
93 | * publication. | ||
94 | */ | ||
95 | static char *this_id; | ||
96 | |||
97 | /** | ||
98 | * Command-line option identifying the pseudonym to use for the publication. | ||
99 | */ | ||
100 | static char *pseudonym; | ||
101 | |||
102 | /** | ||
103 | * Command-line option for 'inserting' | ||
104 | */ | ||
105 | static int do_insert; | ||
106 | |||
107 | /** | ||
108 | * Command-line option to disable meta data extraction. | ||
109 | */ | ||
110 | static int disable_extractor; | ||
111 | |||
112 | /** | ||
113 | * Command-line option to merely simulate publishing operation. | ||
114 | */ | ||
115 | static int do_simulate; | ||
116 | |||
117 | /** | ||
118 | * Command-line option to only perform meta data extraction, but not publish. | ||
119 | */ | ||
120 | static int extract_only; | ||
121 | |||
122 | /** | ||
123 | * Command-line option to disable adding creation time. | ||
124 | */ | ||
125 | static int enable_creation_time; | ||
126 | |||
127 | /** | ||
128 | * Handle to the directory scanner (for recursive insertions). | ||
129 | */ | ||
130 | static struct GNUNET_FS_DirScanner *ds; | ||
131 | |||
132 | /** | ||
133 | * Which namespace do we publish to? NULL if we do not publish to | ||
134 | * a namespace. | ||
135 | */ | ||
136 | static struct GNUNET_IDENTITY_Ego *namespace; | ||
137 | |||
138 | /** | ||
139 | * Handle to identity service. | ||
140 | */ | ||
141 | static struct GNUNET_IDENTITY_Handle *identity; | ||
142 | |||
143 | |||
144 | /** | ||
145 | * We are finished with the publishing operation, clean up all | ||
146 | * FS state. | ||
147 | * | ||
148 | * @param cls NULL | ||
149 | */ | ||
150 | static void | ||
151 | do_stop_task (void *cls) | ||
152 | { | ||
153 | struct GNUNET_FS_PublishContext *p; | ||
154 | |||
155 | if (NULL != ds) | ||
156 | { | ||
157 | GNUNET_FS_directory_scan_abort (ds); | ||
158 | ds = NULL; | ||
159 | } | ||
160 | if (NULL != identity) | ||
161 | { | ||
162 | GNUNET_IDENTITY_disconnect (identity); | ||
163 | identity = NULL; | ||
164 | } | ||
165 | if (NULL != pc) | ||
166 | { | ||
167 | p = pc; | ||
168 | pc = NULL; | ||
169 | GNUNET_FS_publish_stop (p); | ||
170 | } | ||
171 | if (NULL != ctx) | ||
172 | { | ||
173 | GNUNET_FS_stop (ctx); | ||
174 | ctx = NULL; | ||
175 | } | ||
176 | if (NULL != meta) | ||
177 | { | ||
178 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
179 | meta = NULL; | ||
180 | } | ||
181 | if (NULL != uri) | ||
182 | { | ||
183 | GNUNET_FS_uri_destroy (uri); | ||
184 | uri = NULL; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | |||
189 | /** | ||
190 | * Called by FS client to give information about the progress of an | ||
191 | * operation. | ||
192 | * | ||
193 | * @param cls closure | ||
194 | * @param info details about the event, specifying the event type | ||
195 | * and various bits about the event | ||
196 | * @return client-context (for the next progress call | ||
197 | * for this operation; should be set to NULL for | ||
198 | * SUSPEND and STOPPED events). The value returned | ||
199 | * will be passed to future callbacks in the respective | ||
200 | * field in the GNUNET_FS_ProgressInfo struct. | ||
201 | */ | ||
202 | static void * | ||
203 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) | ||
204 | { | ||
205 | const char *s; | ||
206 | char *suri; | ||
207 | |||
208 | switch (info->status) | ||
209 | { | ||
210 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
211 | break; | ||
212 | |||
213 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
214 | if (verbose) | ||
215 | { | ||
216 | s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.eta, | ||
217 | GNUNET_YES); | ||
218 | fprintf (stdout, | ||
219 | _ ("Publishing `%s' at %llu/%llu (%s remaining)\n"), | ||
220 | info->value.publish.filename, | ||
221 | (unsigned long long) info->value.publish.completed, | ||
222 | (unsigned long long) info->value.publish.size, | ||
223 | s); | ||
224 | } | ||
225 | break; | ||
226 | |||
227 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
228 | if (verbose) | ||
229 | { | ||
230 | s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.specifics | ||
231 | .progress_directory.eta, | ||
232 | GNUNET_YES); | ||
233 | fprintf (stdout, | ||
234 | _ ("Publishing `%s' at %llu/%llu (%s remaining)\n"), | ||
235 | info->value.publish.filename, | ||
236 | (unsigned long long) | ||
237 | info->value.publish.specifics.progress_directory.completed, | ||
238 | (unsigned long long) | ||
239 | info->value.publish.specifics.progress_directory.total, | ||
240 | s); | ||
241 | } | ||
242 | break; | ||
243 | |||
244 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
245 | fprintf (stderr, | ||
246 | _ ("Error publishing: %s.\n"), | ||
247 | info->value.publish.specifics.error.message); | ||
248 | ret = 1; | ||
249 | GNUNET_SCHEDULER_shutdown (); | ||
250 | break; | ||
251 | |||
252 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
253 | fprintf (stdout, | ||
254 | _ ("Publishing `%s' done.\n"), | ||
255 | info->value.publish.filename); | ||
256 | suri = | ||
257 | GNUNET_FS_uri_to_string (info->value.publish.specifics.completed.chk_uri); | ||
258 | fprintf (stdout, _ ("URI is `%s'.\n"), suri); | ||
259 | GNUNET_free (suri); | ||
260 | if (NULL != info->value.publish.specifics.completed.sks_uri) | ||
261 | { | ||
262 | suri = GNUNET_FS_uri_to_string ( | ||
263 | info->value.publish.specifics.completed.sks_uri); | ||
264 | fprintf (stdout, _ ("Namespace URI is `%s'.\n"), suri); | ||
265 | GNUNET_free (suri); | ||
266 | } | ||
267 | if (NULL == info->value.publish.pctx) | ||
268 | { | ||
269 | ret = 0; | ||
270 | GNUNET_SCHEDULER_shutdown (); | ||
271 | } | ||
272 | break; | ||
273 | |||
274 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
275 | GNUNET_break (NULL == pc); | ||
276 | return NULL; | ||
277 | |||
278 | case GNUNET_FS_STATUS_UNINDEX_START: | ||
279 | fprintf (stderr, "%s", _ ("Starting cleanup after abort\n")); | ||
280 | return NULL; | ||
281 | |||
282 | case GNUNET_FS_STATUS_UNINDEX_PROGRESS: | ||
283 | return NULL; | ||
284 | |||
285 | case GNUNET_FS_STATUS_UNINDEX_COMPLETED: | ||
286 | fprintf (stderr, "%s", _ ("Cleanup after abort completed.\n")); | ||
287 | GNUNET_FS_unindex_stop (info->value.unindex.uc); | ||
288 | return NULL; | ||
289 | |||
290 | case GNUNET_FS_STATUS_UNINDEX_ERROR: | ||
291 | fprintf (stderr, "%s", _ ("Cleanup after abort failed.\n")); | ||
292 | GNUNET_FS_unindex_stop (info->value.unindex.uc); | ||
293 | return NULL; | ||
294 | |||
295 | case GNUNET_FS_STATUS_UNINDEX_STOPPED: | ||
296 | return NULL; | ||
297 | |||
298 | default: | ||
299 | fprintf (stderr, _ ("Unexpected status: %d\n"), info->status); | ||
300 | return NULL; | ||
301 | } | ||
302 | return ""; /* non-null */ | ||
303 | } | ||
304 | |||
305 | |||
306 | /** | ||
307 | * Print metadata entries (except binary | ||
308 | * metadata and the filename). | ||
309 | * | ||
310 | * @param cls closure | ||
311 | * @param plugin_name name of the plugin that generated the meta data | ||
312 | * @param type type of the meta data | ||
313 | * @param format format of data | ||
314 | * @param data_mime_type mime type of @a data | ||
315 | * @param data value of the meta data | ||
316 | * @param data_size number of bytes in @a data | ||
317 | * @return always 0 | ||
318 | */ | ||
319 | static int | ||
320 | meta_printer (void *cls, | ||
321 | const char *plugin_name, | ||
322 | enum EXTRACTOR_MetaType type, | ||
323 | enum EXTRACTOR_MetaFormat format, | ||
324 | const char *data_mime_type, | ||
325 | const char *data, | ||
326 | size_t data_size) | ||
327 | { | ||
328 | if ((EXTRACTOR_METAFORMAT_UTF8 != format) && | ||
329 | (EXTRACTOR_METAFORMAT_C_STRING != format)) | ||
330 | return 0; | ||
331 | if (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type) | ||
332 | return 0; | ||
333 | #if HAVE_LIBEXTRACTOR | ||
334 | fprintf (stdout, "\t%s - %s\n", EXTRACTOR_metatype_to_string (type), data); | ||
335 | #else | ||
336 | fprintf (stdout, "\t%d - %s\n", type, data); | ||
337 | #endif | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Iterator printing keywords | ||
344 | * | ||
345 | * @param cls closure | ||
346 | * @param keyword the keyword | ||
347 | * @param is_mandatory is the keyword mandatory (in a search) | ||
348 | * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to abort | ||
349 | */ | ||
350 | static int | ||
351 | keyword_printer (void *cls, const char *keyword, int is_mandatory) | ||
352 | { | ||
353 | fprintf (stdout, "\t%s\n", keyword); | ||
354 | return GNUNET_OK; | ||
355 | } | ||
356 | |||
357 | |||
358 | /** | ||
359 | * Function called on all entries before the publication. This is | ||
360 | * where we perform modifications to the default based on command-line | ||
361 | * options. | ||
362 | * | ||
363 | * @param cls closure | ||
364 | * @param fi the entry in the publish-structure | ||
365 | * @param length length of the file or directory | ||
366 | * @param m metadata for the file or directory (can be modified) | ||
367 | * @param uri pointer to the keywords that will be used for this entry (can be modified) | ||
368 | * @param bo block options | ||
369 | * @param do_index should we index? | ||
370 | * @param client_info pointer to client context set upon creation (can be modified) | ||
371 | * @return #GNUNET_OK to continue, #GNUNET_NO to remove | ||
372 | * this entry from the directory, #GNUNET_SYSERR | ||
373 | * to abort the iteration | ||
374 | */ | ||
375 | static int | ||
376 | publish_inspector (void *cls, | ||
377 | struct GNUNET_FS_FileInformation *fi, | ||
378 | uint64_t length, | ||
379 | struct GNUNET_CONTAINER_MetaData *m, | ||
380 | struct GNUNET_FS_Uri **uri, | ||
381 | struct GNUNET_FS_BlockOptions *bo, | ||
382 | int *do_index, | ||
383 | void **client_info) | ||
384 | { | ||
385 | char *fn; | ||
386 | char *fs; | ||
387 | struct GNUNET_FS_Uri *new_uri; | ||
388 | |||
389 | if (cls == fi) | ||
390 | return GNUNET_OK; | ||
391 | if ((disable_extractor) && (NULL != *uri)) | ||
392 | { | ||
393 | GNUNET_FS_uri_destroy (*uri); | ||
394 | *uri = NULL; | ||
395 | } | ||
396 | if (NULL != topKeywords) | ||
397 | { | ||
398 | if (NULL != *uri) | ||
399 | { | ||
400 | new_uri = GNUNET_FS_uri_ksk_merge (topKeywords, *uri); | ||
401 | GNUNET_FS_uri_destroy (*uri); | ||
402 | *uri = new_uri; | ||
403 | GNUNET_FS_uri_destroy (topKeywords); | ||
404 | } | ||
405 | else | ||
406 | { | ||
407 | *uri = topKeywords; | ||
408 | } | ||
409 | topKeywords = NULL; | ||
410 | } | ||
411 | if (NULL != meta) | ||
412 | { | ||
413 | GNUNET_CONTAINER_meta_data_merge (m, meta); | ||
414 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
415 | meta = NULL; | ||
416 | } | ||
417 | if (enable_creation_time) | ||
418 | GNUNET_CONTAINER_meta_data_add_publication_date (m); | ||
419 | if (extract_only) | ||
420 | { | ||
421 | fn = GNUNET_CONTAINER_meta_data_get_by_type ( | ||
422 | m, | ||
423 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); | ||
424 | fs = GNUNET_STRINGS_byte_size_fancy (length); | ||
425 | fprintf (stdout, _ ("Meta data for file `%s' (%s)\n"), fn, fs); | ||
426 | GNUNET_CONTAINER_meta_data_iterate (m, &meta_printer, NULL); | ||
427 | fprintf (stdout, _ ("Keywords for file `%s' (%s)\n"), fn, fs); | ||
428 | GNUNET_free (fn); | ||
429 | GNUNET_free (fs); | ||
430 | if (NULL != *uri) | ||
431 | GNUNET_FS_uri_ksk_get_keywords (*uri, &keyword_printer, NULL); | ||
432 | fprintf (stdout, "%s", "\n"); | ||
433 | } | ||
434 | if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (m)) | ||
435 | GNUNET_FS_file_information_inspect (fi, &publish_inspector, fi); | ||
436 | return GNUNET_OK; | ||
437 | } | ||
438 | |||
439 | |||
440 | /** | ||
441 | * Function called upon completion of the publishing | ||
442 | * of the UBLOCK for the SKS URI. As this is the last | ||
443 | * step, stop our interaction with FS (clean up). | ||
444 | * | ||
445 | * @param cls NULL (closure) | ||
446 | * @param sks_uri URI for the block that was published | ||
447 | * @param emsg error message, NULL on success | ||
448 | */ | ||
449 | static void | ||
450 | uri_sks_continuation (void *cls, | ||
451 | const struct GNUNET_FS_Uri *sks_uri, | ||
452 | const char *emsg) | ||
453 | { | ||
454 | if (NULL != emsg) | ||
455 | { | ||
456 | fprintf (stderr, "%s\n", emsg); | ||
457 | ret = 1; | ||
458 | } | ||
459 | GNUNET_SCHEDULER_shutdown (); | ||
460 | } | ||
461 | |||
462 | |||
463 | /** | ||
464 | * Function called upon completion of the publishing | ||
465 | * of the UBLOCK for the KSK URI. Continue with | ||
466 | * publishing the SKS URI (if applicable) or clean up. | ||
467 | * | ||
468 | * @param cls NULL (closure) | ||
469 | * @param ksk_uri URI for the block that was published | ||
470 | * @param emsg error message, NULL on success | ||
471 | */ | ||
472 | static void | ||
473 | uri_ksk_continuation (void *cls, | ||
474 | const struct GNUNET_FS_Uri *ksk_uri, | ||
475 | const char *emsg) | ||
476 | { | ||
477 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv; | ||
478 | const struct GNUNET_IDENTITY_PrivateKey *pk; | ||
479 | |||
480 | if (NULL != emsg) | ||
481 | { | ||
482 | fprintf (stderr, "%s\n", emsg); | ||
483 | ret = 1; | ||
484 | } | ||
485 | if (NULL == namespace) | ||
486 | { | ||
487 | GNUNET_SCHEDULER_shutdown (); | ||
488 | return; | ||
489 | } | ||
490 | pk = GNUNET_IDENTITY_ego_get_private_key (namespace); | ||
491 | if (GNUNET_IDENTITY_TYPE_ECDSA != ntohl (pk->type)) | ||
492 | return; | ||
493 | priv = &pk->ecdsa_key; | ||
494 | GNUNET_FS_publish_sks (ctx, | ||
495 | priv, | ||
496 | this_id, | ||
497 | next_id, | ||
498 | meta, | ||
499 | uri, | ||
500 | &bo, | ||
501 | GNUNET_FS_PUBLISH_OPTION_NONE, | ||
502 | &uri_sks_continuation, | ||
503 | NULL); | ||
504 | } | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Iterate over the results from the directory scan and extract | ||
509 | * the desired information for the publishing operation. | ||
510 | * | ||
511 | * @param item root with the data from the directory scan | ||
512 | * @return handle with the information for the publishing operation | ||
513 | */ | ||
514 | static struct GNUNET_FS_FileInformation * | ||
515 | get_file_information (struct GNUNET_FS_ShareTreeItem *item) | ||
516 | { | ||
517 | struct GNUNET_FS_FileInformation *fi; | ||
518 | struct GNUNET_FS_FileInformation *fic; | ||
519 | struct GNUNET_FS_ShareTreeItem *child; | ||
520 | |||
521 | if (GNUNET_YES == item->is_directory) | ||
522 | { | ||
523 | if (NULL == item->meta) | ||
524 | item->meta = GNUNET_CONTAINER_meta_data_create (); | ||
525 | GNUNET_CONTAINER_meta_data_delete (item->meta, | ||
526 | EXTRACTOR_METATYPE_MIMETYPE, | ||
527 | NULL, | ||
528 | 0); | ||
529 | GNUNET_FS_meta_data_make_directory (item->meta); | ||
530 | if (NULL == item->ksk_uri) | ||
531 | { | ||
532 | const char *mime = GNUNET_FS_DIRECTORY_MIME; | ||
533 | item->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &mime); | ||
534 | } | ||
535 | else | ||
536 | GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri, | ||
537 | GNUNET_FS_DIRECTORY_MIME, | ||
538 | GNUNET_NO); | ||
539 | fi = GNUNET_FS_file_information_create_empty_directory (ctx, | ||
540 | NULL, | ||
541 | item->ksk_uri, | ||
542 | item->meta, | ||
543 | &bo, | ||
544 | item->filename); | ||
545 | for (child = item->children_head; child; child = child->next) | ||
546 | { | ||
547 | fic = get_file_information (child); | ||
548 | GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic)); | ||
549 | } | ||
550 | } | ||
551 | else | ||
552 | { | ||
553 | fi = GNUNET_FS_file_information_create_from_file (ctx, | ||
554 | NULL, | ||
555 | item->filename, | ||
556 | item->ksk_uri, | ||
557 | item->meta, | ||
558 | ! do_insert, | ||
559 | &bo); | ||
560 | } | ||
561 | return fi; | ||
562 | } | ||
563 | |||
564 | |||
565 | /** | ||
566 | * We've finished scanning the directory and optimized the meta data. | ||
567 | * Begin the publication process. | ||
568 | * | ||
569 | * @param directory_scan_result result from the directory scan, freed in this function | ||
570 | */ | ||
571 | static void | ||
572 | directory_trim_complete (struct GNUNET_FS_ShareTreeItem *directory_scan_result) | ||
573 | { | ||
574 | struct GNUNET_FS_FileInformation *fi; | ||
575 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv; | ||
576 | const struct GNUNET_IDENTITY_PrivateKey *pk; | ||
577 | |||
578 | fi = get_file_information (directory_scan_result); | ||
579 | GNUNET_FS_share_tree_free (directory_scan_result); | ||
580 | if (NULL == fi) | ||
581 | { | ||
582 | fprintf (stderr, "%s", _ ("Could not publish\n")); | ||
583 | ret = 1; | ||
584 | GNUNET_SCHEDULER_shutdown (); | ||
585 | return; | ||
586 | } | ||
587 | GNUNET_FS_file_information_inspect (fi, &publish_inspector, NULL); | ||
588 | if (extract_only) | ||
589 | { | ||
590 | GNUNET_FS_file_information_destroy (fi, NULL, NULL); | ||
591 | GNUNET_SCHEDULER_shutdown (); | ||
592 | return; | ||
593 | } | ||
594 | priv = NULL; | ||
595 | if (NULL != namespace) | ||
596 | { | ||
597 | pk = GNUNET_IDENTITY_ego_get_private_key (namespace); | ||
598 | GNUNET_assert (GNUNET_IDENTITY_TYPE_ECDSA == ntohl (pk->type)); | ||
599 | priv = &pk->ecdsa_key; | ||
600 | } | ||
601 | pc = GNUNET_FS_publish_start (ctx, | ||
602 | fi, | ||
603 | priv, | ||
604 | this_id, | ||
605 | next_id, | ||
606 | (do_simulate) | ||
607 | ? GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY | ||
608 | : GNUNET_FS_PUBLISH_OPTION_NONE); | ||
609 | if (NULL == pc) | ||
610 | { | ||
611 | fprintf (stderr, "%s", _ ("Could not start publishing.\n")); | ||
612 | ret = 1; | ||
613 | GNUNET_SCHEDULER_shutdown (); | ||
614 | return; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | |||
619 | /** | ||
620 | * Function called by the directory scanner as we build the tree | ||
621 | * that we will need to publish later. | ||
622 | * | ||
623 | * @param cls closure | ||
624 | * @param filename which file we are making progress on | ||
625 | * @param is_directory #GNUNET_YES if this is a directory, | ||
626 | * #GNUNET_NO if this is a file | ||
627 | * #GNUNET_SYSERR if it is neither (or unknown) | ||
628 | * @param reason kind of progress we are making | ||
629 | */ | ||
630 | static void | ||
631 | directory_scan_cb (void *cls, | ||
632 | const char *filename, | ||
633 | int is_directory, | ||
634 | enum GNUNET_FS_DirScannerProgressUpdateReason reason) | ||
635 | { | ||
636 | struct GNUNET_FS_ShareTreeItem *directory_scan_result; | ||
637 | |||
638 | switch (reason) | ||
639 | { | ||
640 | case GNUNET_FS_DIRSCANNER_FILE_START: | ||
641 | if (verbose > 1) | ||
642 | { | ||
643 | if (is_directory == GNUNET_YES) | ||
644 | fprintf (stdout, _ ("Scanning directory `%s'.\n"), filename); | ||
645 | else | ||
646 | fprintf (stdout, _ ("Scanning file `%s'.\n"), filename); | ||
647 | } | ||
648 | break; | ||
649 | |||
650 | case GNUNET_FS_DIRSCANNER_FILE_IGNORED: | ||
651 | fprintf (stderr, | ||
652 | _ ("There was trouble processing file `%s', skipping it.\n"), | ||
653 | filename); | ||
654 | break; | ||
655 | |||
656 | case GNUNET_FS_DIRSCANNER_ALL_COUNTED: | ||
657 | if (verbose) | ||
658 | fprintf (stdout, "%s", _ ("Preprocessing complete.\n")); | ||
659 | break; | ||
660 | |||
661 | case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED: | ||
662 | if (verbose > 2) | ||
663 | fprintf (stdout, | ||
664 | _ ("Extracting meta data from file `%s' complete.\n"), | ||
665 | filename); | ||
666 | break; | ||
667 | |||
668 | case GNUNET_FS_DIRSCANNER_FINISHED: | ||
669 | if (verbose > 1) | ||
670 | fprintf (stdout, "%s", _ ("Meta data extraction has finished.\n")); | ||
671 | directory_scan_result = GNUNET_FS_directory_scan_get_result (ds); | ||
672 | ds = NULL; | ||
673 | GNUNET_FS_share_tree_trim (directory_scan_result); | ||
674 | directory_trim_complete (directory_scan_result); | ||
675 | break; | ||
676 | |||
677 | case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR: | ||
678 | fprintf (stdout, "%s", _ ("Error scanning directory.\n")); | ||
679 | ret = 1; | ||
680 | GNUNET_SCHEDULER_shutdown (); | ||
681 | break; | ||
682 | |||
683 | default: | ||
684 | GNUNET_assert (0); | ||
685 | break; | ||
686 | } | ||
687 | fflush (stdout); | ||
688 | } | ||
689 | |||
690 | |||
691 | /** | ||
692 | * Continuation proceeding with initialization after identity subsystem | ||
693 | * has been initialized. | ||
694 | * | ||
695 | * @param args0 filename to publish | ||
696 | */ | ||
697 | static void | ||
698 | identity_continuation (const char *args0) | ||
699 | { | ||
700 | char *ex; | ||
701 | char *emsg; | ||
702 | |||
703 | if ((NULL != pseudonym) && (NULL == namespace)) | ||
704 | { | ||
705 | fprintf (stderr, _ ("Selected pseudonym `%s' unknown\n"), pseudonym); | ||
706 | ret = 1; | ||
707 | GNUNET_SCHEDULER_shutdown (); | ||
708 | return; | ||
709 | } | ||
710 | if (NULL != uri_string) | ||
711 | { | ||
712 | emsg = NULL; | ||
713 | if (NULL == (uri = GNUNET_FS_uri_parse (uri_string, &emsg))) | ||
714 | { | ||
715 | fprintf (stderr, _ ("Failed to parse URI: %s\n"), emsg); | ||
716 | GNUNET_free (emsg); | ||
717 | ret = 1; | ||
718 | GNUNET_SCHEDULER_shutdown (); | ||
719 | return; | ||
720 | } | ||
721 | GNUNET_FS_publish_ksk (ctx, | ||
722 | topKeywords, | ||
723 | meta, | ||
724 | uri, | ||
725 | &bo, | ||
726 | GNUNET_FS_PUBLISH_OPTION_NONE, | ||
727 | &uri_ksk_continuation, | ||
728 | NULL); | ||
729 | return; | ||
730 | } | ||
731 | if (GNUNET_OK != | ||
732 | GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS", &ex)) | ||
733 | ex = NULL; | ||
734 | if (0 != access (args0, R_OK)) | ||
735 | { | ||
736 | fprintf (stderr, | ||
737 | _ ("Failed to access `%s': %s\n"), | ||
738 | args0, | ||
739 | strerror (errno)); | ||
740 | GNUNET_free (ex); | ||
741 | return; | ||
742 | } | ||
743 | ds = GNUNET_FS_directory_scan_start (args0, | ||
744 | disable_extractor, | ||
745 | ex, | ||
746 | &directory_scan_cb, | ||
747 | NULL); | ||
748 | if (NULL == ds) | ||
749 | { | ||
750 | fprintf ( | ||
751 | stderr, | ||
752 | "%s", | ||
753 | _ ( | ||
754 | "Failed to start meta directory scanner. Is gnunet-helper-publish-fs installed?\n")); | ||
755 | GNUNET_free (ex); | ||
756 | return; | ||
757 | } | ||
758 | GNUNET_free (ex); | ||
759 | } | ||
760 | |||
761 | |||
762 | /** | ||
763 | * Function called by identity service with known pseudonyms. | ||
764 | * | ||
765 | * @param cls closure with 'const char *' of filename to publish | ||
766 | * @param ego ego handle | ||
767 | * @param ctx context for application to store data for this ego | ||
768 | * (during the lifetime of this process, initially NULL) | ||
769 | * @param name name assigned by the user for this ego, | ||
770 | * NULL if the user just deleted the ego and it | ||
771 | * must thus no longer be used | ||
772 | */ | ||
773 | static void | ||
774 | identity_cb (void *cls, | ||
775 | struct GNUNET_IDENTITY_Ego *ego, | ||
776 | void **ctx, | ||
777 | const char *name) | ||
778 | { | ||
779 | const char *args0 = cls; | ||
780 | |||
781 | if (NULL == ego) | ||
782 | { | ||
783 | identity_continuation (args0); | ||
784 | return; | ||
785 | } | ||
786 | if (NULL == name) | ||
787 | return; | ||
788 | if (0 == strcmp (name, pseudonym)) | ||
789 | namespace = ego; | ||
790 | } | ||
791 | |||
792 | |||
793 | /** | ||
794 | * Main function that will be run by the scheduler. | ||
795 | * | ||
796 | * @param cls closure | ||
797 | * @param args remaining command-line arguments | ||
798 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
799 | * @param c configuration | ||
800 | */ | ||
801 | static void | ||
802 | run (void *cls, | ||
803 | char *const *args, | ||
804 | const char *cfgfile, | ||
805 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
806 | { | ||
807 | /* check arguments */ | ||
808 | if ((NULL != uri_string) && (extract_only)) | ||
809 | { | ||
810 | printf (_ ("Cannot extract metadata from a URI!\n")); | ||
811 | ret = -1; | ||
812 | return; | ||
813 | } | ||
814 | if (((NULL == uri_string) || (extract_only)) && | ||
815 | ((NULL == args[0]) || (NULL != args[1]))) | ||
816 | { | ||
817 | printf (_ ("You must specify one and only one filename for insertion.\n")); | ||
818 | ret = -1; | ||
819 | return; | ||
820 | } | ||
821 | if ((NULL != uri_string) && (NULL != args[0])) | ||
822 | { | ||
823 | printf (_ ("You must NOT specify an URI and a filename.\n")); | ||
824 | ret = -1; | ||
825 | return; | ||
826 | } | ||
827 | if (NULL != pseudonym) | ||
828 | { | ||
829 | if (NULL == this_id) | ||
830 | { | ||
831 | fprintf (stderr, | ||
832 | _ ("Option `%s' is required when using option `%s'.\n"), | ||
833 | "-t", | ||
834 | "-P"); | ||
835 | ret = -1; | ||
836 | return; | ||
837 | } | ||
838 | } | ||
839 | else | ||
840 | { /* ordinary insertion checks */ | ||
841 | if (NULL != next_id) | ||
842 | { | ||
843 | fprintf (stderr, | ||
844 | _ ("Option `%s' makes no sense without option `%s'.\n"), | ||
845 | "-N", | ||
846 | "-P"); | ||
847 | ret = -1; | ||
848 | return; | ||
849 | } | ||
850 | if (NULL != this_id) | ||
851 | { | ||
852 | fprintf (stderr, | ||
853 | _ ("Option `%s' makes no sense without option `%s'.\n"), | ||
854 | "-t", | ||
855 | "-P"); | ||
856 | ret = -1; | ||
857 | return; | ||
858 | } | ||
859 | } | ||
860 | cfg = c; | ||
861 | ctx = GNUNET_FS_start (cfg, | ||
862 | "gnunet-publish", | ||
863 | &progress_cb, | ||
864 | NULL, | ||
865 | GNUNET_FS_FLAGS_NONE, | ||
866 | GNUNET_FS_OPTIONS_END); | ||
867 | if (NULL == ctx) | ||
868 | { | ||
869 | fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS"); | ||
870 | ret = 1; | ||
871 | return; | ||
872 | } | ||
873 | GNUNET_SCHEDULER_add_shutdown (&do_stop_task, NULL); | ||
874 | if (NULL != pseudonym) | ||
875 | identity = GNUNET_IDENTITY_connect (cfg, &identity_cb, args[0]); | ||
876 | else | ||
877 | identity_continuation (args[0]); | ||
878 | } | ||
879 | |||
880 | |||
881 | /** | ||
882 | * The main function to publish content to GNUnet. | ||
883 | * | ||
884 | * @param argc number of arguments from the command line | ||
885 | * @param argv command line arguments | ||
886 | * @return 0 ok, 1 on error | ||
887 | */ | ||
888 | int | ||
889 | main (int argc, char *const *argv) | ||
890 | { | ||
891 | struct GNUNET_GETOPT_CommandLineOption options[] = | ||
892 | { GNUNET_GETOPT_option_uint ('a', | ||
893 | "anonymity", | ||
894 | "LEVEL", | ||
895 | gettext_noop ( | ||
896 | "set the desired LEVEL of sender-anonymity"), | ||
897 | &bo.anonymity_level), | ||
898 | GNUNET_GETOPT_option_flag ( | ||
899 | 'D', | ||
900 | "disable-extractor", | ||
901 | gettext_noop ("do not use libextractor to add keywords or metadata"), | ||
902 | &disable_extractor), | ||
903 | GNUNET_GETOPT_option_flag ('E', | ||
904 | "enable-creation-time", | ||
905 | gettext_noop ( | ||
906 | "enable adding the creation time to the " | ||
907 | "metadata of the uploaded file"), | ||
908 | &enable_creation_time), | ||
909 | GNUNET_GETOPT_option_flag ('e', | ||
910 | "extract", | ||
911 | gettext_noop ( | ||
912 | "print list of extracted keywords that would " | ||
913 | "be used, but do not perform upload"), | ||
914 | &extract_only), | ||
915 | GNUNET_FS_GETOPT_KEYWORDS ( | ||
916 | 'k', | ||
917 | "key", | ||
918 | "KEYWORD", | ||
919 | gettext_noop ( | ||
920 | "add an additional keyword for the top-level " | ||
921 | "file or directory (this option can be specified multiple times)"), | ||
922 | &topKeywords), | ||
923 | GNUNET_FS_GETOPT_METADATA ( | ||
924 | 'm', | ||
925 | "meta", | ||
926 | "TYPE:VALUE", | ||
927 | gettext_noop ("set the meta-data for the given TYPE to the given VALUE"), | ||
928 | &meta), | ||
929 | GNUNET_GETOPT_option_flag ( | ||
930 | 'n', | ||
931 | "noindex", | ||
932 | gettext_noop ("do not index, perform full insertion (stores " | ||
933 | "entire file in encrypted form in GNUnet database)"), | ||
934 | &do_insert), | ||
935 | GNUNET_GETOPT_option_string ( | ||
936 | 'N', | ||
937 | "next", | ||
938 | "ID", | ||
939 | gettext_noop ("specify ID of an updated version to be " | ||
940 | "published in the future (for namespace insertions only)"), | ||
941 | &next_id), | ||
942 | GNUNET_GETOPT_option_uint ('p', | ||
943 | "priority", | ||
944 | "PRIORITY", | ||
945 | gettext_noop ( | ||
946 | "specify the priority of the content"), | ||
947 | &bo.content_priority), | ||
948 | GNUNET_GETOPT_option_string ('P', | ||
949 | "pseudonym", | ||
950 | "NAME", | ||
951 | gettext_noop ( | ||
952 | "publish the files under the pseudonym " | ||
953 | "NAME (place file into namespace)"), | ||
954 | &pseudonym), | ||
955 | GNUNET_GETOPT_option_uint ('r', | ||
956 | "replication", | ||
957 | "LEVEL", | ||
958 | gettext_noop ( | ||
959 | "set the desired replication LEVEL"), | ||
960 | &bo.replication_level), | ||
961 | GNUNET_GETOPT_option_flag ('s', | ||
962 | "simulate-only", | ||
963 | gettext_noop ( | ||
964 | "only simulate the process but do not do " | ||
965 | "any actual publishing (useful to compute URIs)"), | ||
966 | &do_simulate), | ||
967 | GNUNET_GETOPT_option_string ('t', | ||
968 | "this", | ||
969 | "ID", | ||
970 | gettext_noop ( | ||
971 | "set the ID of this version of the publication " | ||
972 | "(for namespace insertions only)"), | ||
973 | &this_id), | ||
974 | GNUNET_GETOPT_option_string ( | ||
975 | 'u', | ||
976 | "uri", | ||
977 | "URI", | ||
978 | gettext_noop ( | ||
979 | "URI to be published (can be used instead of passing a " | ||
980 | "file to add keywords to the file with the respective URI)"), | ||
981 | &uri_string), | ||
982 | |||
983 | GNUNET_GETOPT_option_verbose (&verbose), | ||
984 | |||
985 | GNUNET_GETOPT_OPTION_END }; | ||
986 | |||
987 | bo.expiration_time = | ||
988 | GNUNET_TIME_year_to_time (GNUNET_TIME_get_current_year () + 2); | ||
989 | |||
990 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
991 | return 2; | ||
992 | ret = | ||
993 | (GNUNET_OK == | ||
994 | GNUNET_PROGRAM_run (argc, | ||
995 | argv, | ||
996 | "gnunet-publish [OPTIONS] FILENAME", | ||
997 | gettext_noop ("Publish a file or directory on GNUnet"), | ||
998 | options, | ||
999 | &run, | ||
1000 | NULL)) | ||
1001 | ? ret | ||
1002 | : 1; | ||
1003 | GNUNET_free_nz ((void *) argv); | ||
1004 | return ret; | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | /* end of gnunet-publish.c */ | ||
diff --git a/src/fs/gnunet-search.c b/src/fs/gnunet-search.c deleted file mode 100644 index 3bf013650..000000000 --- a/src/fs/gnunet-search.c +++ /dev/null | |||
@@ -1,382 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/gnunet-search.c | ||
22 | * @brief searching for files on GNUnet | ||
23 | * @author Christian Grothoff | ||
24 | * @author Krista Bennett | ||
25 | * @author James Blackwell | ||
26 | * @author Igor Wronsky | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | static int ret; | ||
32 | |||
33 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
34 | |||
35 | static struct GNUNET_FS_Handle *ctx; | ||
36 | |||
37 | static struct GNUNET_FS_SearchContext *sc; | ||
38 | |||
39 | static char *output_filename; | ||
40 | |||
41 | static struct GNUNET_FS_DirectoryBuilder *db; | ||
42 | |||
43 | static unsigned int anonymity = 1; | ||
44 | |||
45 | /** | ||
46 | * Timeout for the search, 0 means to wait for CTRL-C. | ||
47 | */ | ||
48 | static struct GNUNET_TIME_Relative timeout; | ||
49 | |||
50 | static unsigned int results_limit; | ||
51 | |||
52 | static unsigned int results; | ||
53 | |||
54 | static unsigned int verbose; | ||
55 | |||
56 | static int local_only; | ||
57 | |||
58 | static struct GNUNET_SCHEDULER_Task *tt; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Type of a function that libextractor calls for each | ||
63 | * meta data item found. | ||
64 | * | ||
65 | * @param cls closure (user-defined, unused) | ||
66 | * @param plugin_name name of the plugin that produced this value; | ||
67 | * special values can be used (e.g. '<zlib>' for zlib being | ||
68 | * used in the main libextractor library and yielding | ||
69 | * meta data). | ||
70 | * @param type libextractor-type describing the meta data | ||
71 | * @param format basic format information about data | ||
72 | * @param data_mime_type mime-type of data (not of the original file); | ||
73 | * can be NULL (if mime-type is not known) | ||
74 | * @param data actual meta-data found | ||
75 | * @param data_size number of bytes in @a data | ||
76 | * @return 0 to continue extracting, 1 to abort | ||
77 | */ | ||
78 | static int | ||
79 | item_printer (void *cls, | ||
80 | const char *plugin_name, | ||
81 | enum EXTRACTOR_MetaType type, | ||
82 | enum EXTRACTOR_MetaFormat format, | ||
83 | const char *data_mime_type, | ||
84 | const char *data, | ||
85 | size_t data_size) | ||
86 | { | ||
87 | if ((format != EXTRACTOR_METAFORMAT_UTF8) && | ||
88 | (format != EXTRACTOR_METAFORMAT_C_STRING)) | ||
89 | return 0; | ||
90 | if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) | ||
91 | return 0; | ||
92 | #if HAVE_LIBEXTRACTOR | ||
93 | printf ("\t%20s: %s\n", | ||
94 | dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, | ||
95 | EXTRACTOR_metatype_to_string (type)), | ||
96 | data); | ||
97 | #else | ||
98 | printf ("\t%20d: %s\n", type, data); | ||
99 | #endif | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | |||
104 | static void | ||
105 | clean_task (void *cls) | ||
106 | { | ||
107 | size_t dsize; | ||
108 | void *ddata; | ||
109 | |||
110 | GNUNET_FS_stop (ctx); | ||
111 | ctx = NULL; | ||
112 | if (output_filename == NULL) | ||
113 | return; | ||
114 | if (GNUNET_OK != | ||
115 | GNUNET_FS_directory_builder_finish (db, &dsize, &ddata)) | ||
116 | { | ||
117 | GNUNET_break (0); | ||
118 | GNUNET_free (output_filename); | ||
119 | return; | ||
120 | } | ||
121 | (void) GNUNET_DISK_directory_remove (output_filename); | ||
122 | if (GNUNET_OK != | ||
123 | GNUNET_DISK_fn_write (output_filename, | ||
124 | ddata, | ||
125 | dsize, | ||
126 | GNUNET_DISK_PERM_USER_READ | ||
127 | | GNUNET_DISK_PERM_USER_WRITE)) | ||
128 | { | ||
129 | fprintf (stderr, | ||
130 | _ ("Failed to write directory with search results to `%s'\n"), | ||
131 | output_filename); | ||
132 | } | ||
133 | GNUNET_free (ddata); | ||
134 | GNUNET_free (output_filename); | ||
135 | } | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Called by FS client to give information about the progress of an | ||
140 | * operation. | ||
141 | * | ||
142 | * @param cls closure | ||
143 | * @param info details about the event, specifying the event type | ||
144 | * and various bits about the event | ||
145 | * @return client-context (for the next progress call | ||
146 | * for this operation; should be set to NULL for | ||
147 | * SUSPEND and STOPPED events). The value returned | ||
148 | * will be passed to future callbacks in the respective | ||
149 | * field in the GNUNET_FS_ProgressInfo struct. | ||
150 | */ | ||
151 | static void * | ||
152 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) | ||
153 | { | ||
154 | static unsigned int cnt; | ||
155 | int is_directory; | ||
156 | char *uri; | ||
157 | char *filename; | ||
158 | |||
159 | switch (info->status) | ||
160 | { | ||
161 | case GNUNET_FS_STATUS_SEARCH_START: | ||
162 | break; | ||
163 | |||
164 | case GNUNET_FS_STATUS_SEARCH_RESULT: | ||
165 | if (db != NULL) | ||
166 | GNUNET_FS_directory_builder_add (db, | ||
167 | info->value.search.specifics.result.uri, | ||
168 | info->value.search.specifics.result.meta, | ||
169 | NULL); | ||
170 | uri = GNUNET_FS_uri_to_string (info->value.search.specifics.result.uri); | ||
171 | printf ("#%u:\n", ++cnt); | ||
172 | filename = GNUNET_CONTAINER_meta_data_get_by_type ( | ||
173 | info->value.search.specifics.result.meta, | ||
174 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); | ||
175 | is_directory = GNUNET_FS_meta_data_test_for_directory ( | ||
176 | info->value.search.specifics.result.meta); | ||
177 | if (NULL != filename) | ||
178 | { | ||
179 | while ((filename[0] != '\0') && ('/' == filename[strlen (filename) - 1])) | ||
180 | filename[strlen (filename) - 1] = '\0'; | ||
181 | GNUNET_DISK_filename_canonicalize (filename); | ||
182 | if (GNUNET_YES == is_directory) | ||
183 | printf ("gnunet-download -o \"%s%s\" -R %s\n", | ||
184 | filename, | ||
185 | GNUNET_FS_DIRECTORY_EXT, | ||
186 | uri); | ||
187 | else | ||
188 | printf ("gnunet-download -o \"%s\" %s\n", filename, uri); | ||
189 | } | ||
190 | else if (GNUNET_YES == is_directory) | ||
191 | printf ("gnunet-download -o \"collection%s\" -R %s\n", | ||
192 | GNUNET_FS_DIRECTORY_EXT, | ||
193 | uri); | ||
194 | else | ||
195 | printf ("gnunet-download %s\n", uri); | ||
196 | if (verbose) | ||
197 | GNUNET_CONTAINER_meta_data_iterate (info->value.search.specifics.result | ||
198 | .meta, | ||
199 | &item_printer, | ||
200 | NULL); | ||
201 | printf ("\n"); | ||
202 | fflush (stdout); | ||
203 | GNUNET_free (filename); | ||
204 | GNUNET_free (uri); | ||
205 | results++; | ||
206 | if ((results_limit > 0) && (results >= results_limit)) | ||
207 | GNUNET_SCHEDULER_shutdown (); | ||
208 | break; | ||
209 | |||
210 | case GNUNET_FS_STATUS_SEARCH_UPDATE: | ||
211 | break; | ||
212 | |||
213 | case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: | ||
214 | /* ignore */ | ||
215 | break; | ||
216 | |||
217 | case GNUNET_FS_STATUS_SEARCH_ERROR: | ||
218 | fprintf (stderr, | ||
219 | _ ("Error searching: %s.\n"), | ||
220 | info->value.search.specifics.error.message); | ||
221 | GNUNET_SCHEDULER_shutdown (); | ||
222 | break; | ||
223 | |||
224 | case GNUNET_FS_STATUS_SEARCH_STOPPED: | ||
225 | GNUNET_SCHEDULER_add_now (&clean_task, NULL); | ||
226 | break; | ||
227 | |||
228 | default: | ||
229 | fprintf (stderr, _ ("Unexpected status: %d\n"), info->status); | ||
230 | break; | ||
231 | } | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | |||
236 | static void | ||
237 | shutdown_task (void *cls) | ||
238 | { | ||
239 | if (sc != NULL) | ||
240 | { | ||
241 | GNUNET_FS_search_stop (sc); | ||
242 | sc = NULL; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | |||
247 | static void | ||
248 | timeout_task (void *cls) | ||
249 | { | ||
250 | tt = NULL; | ||
251 | GNUNET_SCHEDULER_shutdown (); | ||
252 | } | ||
253 | |||
254 | |||
255 | /** | ||
256 | * Main function that will be run by the scheduler. | ||
257 | * | ||
258 | * @param cls closure | ||
259 | * @param args remaining command-line arguments | ||
260 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
261 | * @param c configuration | ||
262 | */ | ||
263 | static void | ||
264 | run (void *cls, | ||
265 | char *const *args, | ||
266 | const char *cfgfile, | ||
267 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
268 | { | ||
269 | struct GNUNET_FS_Uri *uri; | ||
270 | unsigned int argc; | ||
271 | enum GNUNET_FS_SearchOptions options; | ||
272 | |||
273 | argc = 0; | ||
274 | while (NULL != args[argc]) | ||
275 | argc++; | ||
276 | uri = GNUNET_FS_uri_ksk_create_from_args (argc, (const char **) args); | ||
277 | if (NULL == uri) | ||
278 | { | ||
279 | fprintf (stderr, | ||
280 | "%s", | ||
281 | _ ("Could not create keyword URI from arguments.\n")); | ||
282 | ret = 1; | ||
283 | return; | ||
284 | } | ||
285 | cfg = c; | ||
286 | ctx = GNUNET_FS_start (cfg, | ||
287 | "gnunet-search", | ||
288 | &progress_cb, | ||
289 | NULL, | ||
290 | GNUNET_FS_FLAGS_NONE, | ||
291 | GNUNET_FS_OPTIONS_END); | ||
292 | if (NULL == ctx) | ||
293 | { | ||
294 | fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS"); | ||
295 | GNUNET_FS_uri_destroy (uri); | ||
296 | ret = 1; | ||
297 | return; | ||
298 | } | ||
299 | if (output_filename != NULL) | ||
300 | db = GNUNET_FS_directory_builder_create (NULL); | ||
301 | options = GNUNET_FS_SEARCH_OPTION_NONE; | ||
302 | if (local_only) | ||
303 | options |= GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY; | ||
304 | sc = GNUNET_FS_search_start (ctx, uri, anonymity, options, NULL); | ||
305 | GNUNET_FS_uri_destroy (uri); | ||
306 | if (NULL == sc) | ||
307 | { | ||
308 | fprintf (stderr, "%s", _ ("Could not start searching.\n")); | ||
309 | GNUNET_FS_stop (ctx); | ||
310 | ret = 1; | ||
311 | return; | ||
312 | } | ||
313 | if (0 != timeout.rel_value_us) | ||
314 | tt = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_task, NULL); | ||
315 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
316 | } | ||
317 | |||
318 | |||
319 | /** | ||
320 | * The main function to search GNUnet. | ||
321 | * | ||
322 | * @param argc number of arguments from the command line | ||
323 | * @param argv command line arguments | ||
324 | * @return 0 ok, 1 on error | ||
325 | */ | ||
326 | int | ||
327 | main (int argc, char *const *argv) | ||
328 | { | ||
329 | struct GNUNET_GETOPT_CommandLineOption options[] = | ||
330 | { GNUNET_GETOPT_option_uint ('a', | ||
331 | "anonymity", | ||
332 | "LEVEL", | ||
333 | gettext_noop ( | ||
334 | "set the desired LEVEL of receiver-anonymity"), | ||
335 | &anonymity), | ||
336 | GNUNET_GETOPT_option_flag ( | ||
337 | 'n', | ||
338 | "no-network", | ||
339 | gettext_noop ("only search the local peer (no P2P network search)"), | ||
340 | &local_only), | ||
341 | GNUNET_GETOPT_option_string ( | ||
342 | 'o', | ||
343 | "output", | ||
344 | "PREFIX", | ||
345 | gettext_noop ("write search results to file starting with PREFIX"), | ||
346 | &output_filename), | ||
347 | GNUNET_GETOPT_option_relative_time ( | ||
348 | 't', | ||
349 | "timeout", | ||
350 | "DELAY", | ||
351 | gettext_noop ("automatically terminate search after DELAY"), | ||
352 | &timeout), | ||
353 | GNUNET_GETOPT_option_verbose (&verbose), | ||
354 | GNUNET_GETOPT_option_uint ('N', | ||
355 | "results", | ||
356 | "VALUE", | ||
357 | gettext_noop ("automatically terminate search " | ||
358 | "after VALUE results are found"), | ||
359 | &results_limit), | ||
360 | GNUNET_GETOPT_OPTION_END }; | ||
361 | |||
362 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
363 | return 2; | ||
364 | |||
365 | ret = | ||
366 | (GNUNET_OK == | ||
367 | GNUNET_PROGRAM_run (argc, | ||
368 | argv, | ||
369 | "gnunet-search [OPTIONS] KEYWORD", | ||
370 | gettext_noop ( | ||
371 | "Search GNUnet for files that were published on GNUnet"), | ||
372 | options, | ||
373 | &run, | ||
374 | NULL)) | ||
375 | ? ret | ||
376 | : 1; | ||
377 | GNUNET_free_nz ((void *) argv); | ||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | |||
382 | /* end of gnunet-search.c */ | ||
diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c deleted file mode 100644 index 8c6c39885..000000000 --- a/src/fs/gnunet-service-fs.c +++ /dev/null | |||
@@ -1,1425 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2014, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs.c | ||
23 | * @brief gnunet anonymity protocol implementation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include <float.h> | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_core_service.h" | ||
30 | #include "gnunet_dht_service.h" | ||
31 | #include "gnunet_datastore_service.h" | ||
32 | #include "gnunet_load_lib.h" | ||
33 | #include "gnunet_peer_lib.h" | ||
34 | #include "gnunet_protocols.h" | ||
35 | #include "gnunet_signatures.h" | ||
36 | #include "gnunet_statistics_service.h" | ||
37 | #include "gnunet_transport_service.h" | ||
38 | #include "gnunet_util_lib.h" | ||
39 | #include "gnunet-service-fs_cp.h" | ||
40 | #include "gnunet-service-fs_indexing.h" | ||
41 | #include "gnunet-service-fs_pe.h" | ||
42 | #include "gnunet-service-fs_pr.h" | ||
43 | #include "gnunet-service-fs_push.h" | ||
44 | #include "gnunet-service-fs_put.h" | ||
45 | #include "gnunet-service-fs_cadet.h" | ||
46 | #include "fs.h" | ||
47 | #include "fs_api.h" | ||
48 | |||
49 | /** | ||
50 | * Size for the hash map for DHT requests from the FS | ||
51 | * service. Should be about the number of concurrent | ||
52 | * DHT requests we plan to make. | ||
53 | */ | ||
54 | #define FS_DHT_HT_SIZE 1024 | ||
55 | |||
56 | |||
57 | /** | ||
58 | * How quickly do we age cover traffic? At the given | ||
59 | * time interval, remaining cover traffic counters are | ||
60 | * decremented by 1/16th. | ||
61 | */ | ||
62 | #define COVER_AGE_FREQUENCY GNUNET_TIME_relative_multiply ( \ | ||
63 | GNUNET_TIME_UNIT_SECONDS, 5) | ||
64 | |||
65 | /** | ||
66 | * Collect an instance number of statistics? May cause excessive IPC. | ||
67 | */ | ||
68 | #define INSANE_STATISTICS GNUNET_NO | ||
69 | |||
70 | |||
71 | /** | ||
72 | * Doubly-linked list of requests we are performing | ||
73 | * on behalf of the same client. | ||
74 | */ | ||
75 | struct ClientRequest | ||
76 | { | ||
77 | /** | ||
78 | * This is a doubly-linked list. | ||
79 | */ | ||
80 | struct ClientRequest *next; | ||
81 | |||
82 | /** | ||
83 | * This is a doubly-linked list. | ||
84 | */ | ||
85 | struct ClientRequest *prev; | ||
86 | |||
87 | /** | ||
88 | * Request this entry represents. | ||
89 | */ | ||
90 | struct GSF_PendingRequest *pr; | ||
91 | |||
92 | /** | ||
93 | * Client list this request belongs to. | ||
94 | */ | ||
95 | struct GSF_LocalClient *lc; | ||
96 | |||
97 | /** | ||
98 | * Task scheduled to destroy the request. | ||
99 | */ | ||
100 | struct GNUNET_SCHEDULER_Task *kill_task; | ||
101 | }; | ||
102 | |||
103 | |||
104 | /** | ||
105 | * Replies to be transmitted to the client. The actual | ||
106 | * response message is allocated after this struct. | ||
107 | */ | ||
108 | struct ClientResponse | ||
109 | { | ||
110 | /** | ||
111 | * This is a doubly-linked list. | ||
112 | */ | ||
113 | struct ClientResponse *next; | ||
114 | |||
115 | /** | ||
116 | * This is a doubly-linked list. | ||
117 | */ | ||
118 | struct ClientResponse *prev; | ||
119 | |||
120 | /** | ||
121 | * Client list entry this response belongs to. | ||
122 | */ | ||
123 | struct GSF_LocalClient *lc; | ||
124 | |||
125 | /** | ||
126 | * Number of bytes in the response. | ||
127 | */ | ||
128 | size_t msize; | ||
129 | }; | ||
130 | |||
131 | |||
132 | /** | ||
133 | * Information we track while handling an index | ||
134 | * start request from a client. | ||
135 | */ | ||
136 | struct IndexStartContext | ||
137 | { | ||
138 | /** | ||
139 | * This is a doubly linked list. | ||
140 | */ | ||
141 | struct IndexStartContext *next; | ||
142 | |||
143 | /** | ||
144 | * This is a doubly linked list. | ||
145 | */ | ||
146 | struct IndexStartContext *prev; | ||
147 | |||
148 | /** | ||
149 | * Name of the indexed file. | ||
150 | */ | ||
151 | char *filename; | ||
152 | |||
153 | /** | ||
154 | * Context for transmitting confirmation to client. | ||
155 | */ | ||
156 | struct GSF_LocalClient *lc; | ||
157 | |||
158 | /** | ||
159 | * Context for hashing of the file. | ||
160 | */ | ||
161 | struct GNUNET_CRYPTO_FileHashContext *fhc; | ||
162 | |||
163 | /** | ||
164 | * Hash of the contents of the file. | ||
165 | */ | ||
166 | struct GNUNET_HashCode file_id; | ||
167 | }; | ||
168 | |||
169 | |||
170 | /** | ||
171 | * A local client. | ||
172 | */ | ||
173 | struct GSF_LocalClient | ||
174 | { | ||
175 | /** | ||
176 | * ID of the client. | ||
177 | */ | ||
178 | struct GNUNET_SERVICE_Client *client; | ||
179 | |||
180 | /** | ||
181 | * Queue for sending replies. | ||
182 | */ | ||
183 | struct GNUNET_MQ_Handle *mq; | ||
184 | |||
185 | /** | ||
186 | * Head of list of requests performed on behalf | ||
187 | * of this client right now. | ||
188 | */ | ||
189 | struct ClientRequest *cr_head; | ||
190 | |||
191 | /** | ||
192 | * Tail of list of requests performed on behalf | ||
193 | * of this client right now. | ||
194 | */ | ||
195 | struct ClientRequest *cr_tail; | ||
196 | |||
197 | /** | ||
198 | * This is a doubly linked list. | ||
199 | */ | ||
200 | struct IndexStartContext *isc_head; | ||
201 | |||
202 | /** | ||
203 | * This is a doubly linked list. | ||
204 | */ | ||
205 | struct IndexStartContext *isc_tail; | ||
206 | |||
207 | /** | ||
208 | * Head of linked list of responses. | ||
209 | */ | ||
210 | struct ClientResponse *res_head; | ||
211 | |||
212 | /** | ||
213 | * Tail of linked list of responses. | ||
214 | */ | ||
215 | struct ClientResponse *res_tail; | ||
216 | }; | ||
217 | |||
218 | |||
219 | /* ****************************** globals ****************************** */ | ||
220 | |||
221 | /** | ||
222 | * Our connection to the datastore. | ||
223 | */ | ||
224 | struct GNUNET_DATASTORE_Handle *GSF_dsh; | ||
225 | |||
226 | /** | ||
227 | * Our configuration. | ||
228 | */ | ||
229 | const struct GNUNET_CONFIGURATION_Handle *GSF_cfg; | ||
230 | |||
231 | /** | ||
232 | * Handle for reporting statistics. | ||
233 | */ | ||
234 | struct GNUNET_STATISTICS_Handle *GSF_stats; | ||
235 | |||
236 | /** | ||
237 | * Handle for DHT operations. | ||
238 | */ | ||
239 | struct GNUNET_DHT_Handle *GSF_dht; | ||
240 | |||
241 | /** | ||
242 | * How long do requests typically stay in the routing table? | ||
243 | */ | ||
244 | struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime; | ||
245 | |||
246 | /** | ||
247 | * Running average of the observed latency to other peers (round trip). | ||
248 | * Initialized to 5s as the initial default. | ||
249 | */ | ||
250 | struct GNUNET_TIME_Relative GSF_avg_latency = { 500 }; | ||
251 | |||
252 | /** | ||
253 | * Handle to ATS service. | ||
254 | */ | ||
255 | struct GNUNET_ATS_PerformanceHandle *GSF_ats; | ||
256 | |||
257 | |||
258 | /** | ||
259 | * Typical priorities we're seeing from other peers right now. Since | ||
260 | * most priorities will be zero, this value is the weighted average of | ||
261 | * non-zero priorities seen "recently". In order to ensure that new | ||
262 | * values do not dramatically change the ratio, values are first | ||
263 | * "capped" to a reasonable range (+N of the current value) and then | ||
264 | * averaged into the existing value by a ratio of 1:N. Hence | ||
265 | * receiving the largest possible priority can still only raise our | ||
266 | * "current_priorities" by at most 1. | ||
267 | */ | ||
268 | double GSF_current_priorities; | ||
269 | |||
270 | /** | ||
271 | * Size of the datastore queue we assume for common requests. | ||
272 | */ | ||
273 | unsigned int GSF_datastore_queue_size; | ||
274 | |||
275 | /** | ||
276 | * How many query messages have we received 'recently' that | ||
277 | * have not yet been claimed as cover traffic? | ||
278 | */ | ||
279 | unsigned int GSF_cover_query_count; | ||
280 | |||
281 | /** | ||
282 | * How many content messages have we received 'recently' that | ||
283 | * have not yet been claimed as cover traffic? | ||
284 | */ | ||
285 | unsigned int GSF_cover_content_count; | ||
286 | |||
287 | /** | ||
288 | * Our block context. | ||
289 | */ | ||
290 | struct GNUNET_BLOCK_Context *GSF_block_ctx; | ||
291 | |||
292 | /** | ||
293 | * Pointer to handle to the core service (points to NULL until we've | ||
294 | * connected to it). | ||
295 | */ | ||
296 | struct GNUNET_CORE_Handle *GSF_core; | ||
297 | |||
298 | /** | ||
299 | * Are we introducing randomized delays for better anonymity? | ||
300 | */ | ||
301 | int GSF_enable_randomized_delays; | ||
302 | |||
303 | /** | ||
304 | * Identity of this peer. | ||
305 | */ | ||
306 | struct GNUNET_PeerIdentity GSF_my_id; | ||
307 | |||
308 | /* ***************************** locals ******************************* */ | ||
309 | |||
310 | /** | ||
311 | * Configuration for block library. | ||
312 | */ | ||
313 | static struct GNUNET_CONFIGURATION_Handle *block_cfg; | ||
314 | |||
315 | /** | ||
316 | * Private key of this peer. Used to sign LOC URI requests. | ||
317 | */ | ||
318 | static struct GNUNET_CRYPTO_EddsaPrivateKey pk; | ||
319 | |||
320 | /** | ||
321 | * ID of our task that we use to age the cover counters. | ||
322 | */ | ||
323 | static struct GNUNET_SCHEDULER_Task *cover_age_task; | ||
324 | |||
325 | /** | ||
326 | * Datastore 'GET' load tracking. | ||
327 | */ | ||
328 | static struct GNUNET_LOAD_Value *datastore_get_load; | ||
329 | |||
330 | |||
331 | /** | ||
332 | * Creates a fresh local client handle. | ||
333 | * | ||
334 | * @param cls NULL | ||
335 | * @param client handle of the client | ||
336 | * @param mq message queue for @a client | ||
337 | * @return handle to local client entry | ||
338 | */ | ||
339 | static void * | ||
340 | client_connect_cb (void *cls, | ||
341 | struct GNUNET_SERVICE_Client *client, | ||
342 | struct GNUNET_MQ_Handle *mq) | ||
343 | { | ||
344 | struct GSF_LocalClient *pos; | ||
345 | |||
346 | pos = GNUNET_new (struct GSF_LocalClient); | ||
347 | pos->client = client; | ||
348 | pos->mq = mq; | ||
349 | return pos; | ||
350 | } | ||
351 | |||
352 | |||
353 | /** | ||
354 | * Free the given client request. | ||
355 | * | ||
356 | * @param cls the client request to free | ||
357 | */ | ||
358 | static void | ||
359 | client_request_destroy (void *cls) | ||
360 | { | ||
361 | struct ClientRequest *cr = cls; | ||
362 | struct GSF_LocalClient *lc = cr->lc; | ||
363 | |||
364 | cr->kill_task = NULL; | ||
365 | GNUNET_CONTAINER_DLL_remove (lc->cr_head, | ||
366 | lc->cr_tail, | ||
367 | cr); | ||
368 | GSF_pending_request_cancel_ (cr->pr, | ||
369 | GNUNET_YES); | ||
370 | GNUNET_STATISTICS_update (GSF_stats, | ||
371 | gettext_noop ("# client searches active"), | ||
372 | -1, | ||
373 | GNUNET_NO); | ||
374 | GNUNET_free (cr); | ||
375 | } | ||
376 | |||
377 | |||
378 | /** | ||
379 | * Handle a reply to a pending request. Also called if a request | ||
380 | * expires (then with data == NULL). The handler may be called | ||
381 | * many times (depending on the request type), but will not be | ||
382 | * called during or after a call to #GSF_pending_request_cancel() | ||
383 | * and will also not be called anymore after a call signalling | ||
384 | * expiration. | ||
385 | * | ||
386 | * @param cls user-specified closure | ||
387 | * @param eval evaluation of the result | ||
388 | * @param pr handle to the original pending request | ||
389 | * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" | ||
390 | * @param expiration when does @a data expire? | ||
391 | * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown) | ||
392 | * @param type type of the block | ||
393 | * @param data response data, NULL on request expiration | ||
394 | * @param data_len number of bytes in @a data | ||
395 | */ | ||
396 | static void | ||
397 | client_response_handler (void *cls, | ||
398 | enum GNUNET_BLOCK_ReplyEvaluationResult eval, | ||
399 | struct GSF_PendingRequest *pr, | ||
400 | uint32_t reply_anonymity_level, | ||
401 | struct GNUNET_TIME_Absolute expiration, | ||
402 | struct GNUNET_TIME_Absolute last_transmission, | ||
403 | enum GNUNET_BLOCK_Type type, | ||
404 | const void *data, | ||
405 | size_t data_len) | ||
406 | { | ||
407 | struct ClientRequest *cr = cls; | ||
408 | struct GSF_LocalClient *lc; | ||
409 | struct GNUNET_MQ_Envelope *env; | ||
410 | struct ClientPutMessage *pm; | ||
411 | const struct GSF_PendingRequestData *prd; | ||
412 | |||
413 | if (NULL == data) | ||
414 | { | ||
415 | /* local-only request, with no result, clean up. */ | ||
416 | if (NULL == cr->kill_task) | ||
417 | cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, | ||
418 | cr); | ||
419 | return; | ||
420 | } | ||
421 | prd = GSF_pending_request_get_data_ (pr); | ||
422 | GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY); | ||
423 | if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY)) | ||
424 | { | ||
425 | GNUNET_break (0); | ||
426 | return; | ||
427 | } | ||
428 | GNUNET_STATISTICS_update (GSF_stats, | ||
429 | gettext_noop | ||
430 | ("# replies received for local clients"), 1, | ||
431 | GNUNET_NO); | ||
432 | GNUNET_assert (pr == cr->pr); | ||
433 | lc = cr->lc; | ||
434 | env = GNUNET_MQ_msg_extra (pm, | ||
435 | data_len, | ||
436 | GNUNET_MESSAGE_TYPE_FS_PUT); | ||
437 | pm->type = htonl (type); | ||
438 | pm->expiration = GNUNET_TIME_absolute_hton (expiration); | ||
439 | pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission); | ||
440 | pm->num_transmissions = htonl (prd->num_transmissions); | ||
441 | pm->respect_offered = htonl (prd->respect_offered); | ||
442 | GNUNET_memcpy (&pm[1], | ||
443 | data, | ||
444 | data_len); | ||
445 | GNUNET_MQ_send (lc->mq, | ||
446 | env); | ||
447 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
448 | "Queued reply to query `%s' for local client\n", | ||
449 | GNUNET_h2s (&prd->query)); | ||
450 | if (GNUNET_BLOCK_REPLY_OK_LAST != eval) | ||
451 | { | ||
452 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
453 | "Evaluation %d - keeping query alive\n", | ||
454 | (int) eval); | ||
455 | return; | ||
456 | } | ||
457 | if (NULL == cr->kill_task) | ||
458 | cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, | ||
459 | cr); | ||
460 | } | ||
461 | |||
462 | |||
463 | /** | ||
464 | * A client disconnected from us. Tear down the local client | ||
465 | * record. | ||
466 | * | ||
467 | * @param cls unused | ||
468 | * @param client handle of the client | ||
469 | * @param app_ctx the `struct GSF_LocalClient` | ||
470 | */ | ||
471 | static void | ||
472 | client_disconnect_cb (void *cls, | ||
473 | struct GNUNET_SERVICE_Client *client, | ||
474 | void *app_ctx) | ||
475 | { | ||
476 | struct GSF_LocalClient *lc = app_ctx; | ||
477 | struct IndexStartContext *isc; | ||
478 | struct ClientRequest *cr; | ||
479 | struct ClientResponse *res; | ||
480 | |||
481 | while (NULL != (cr = lc->cr_head)) | ||
482 | { | ||
483 | if (NULL != cr->kill_task) | ||
484 | GNUNET_SCHEDULER_cancel (cr->kill_task); | ||
485 | client_request_destroy (cr); | ||
486 | } | ||
487 | while (NULL != (res = lc->res_head)) | ||
488 | { | ||
489 | GNUNET_CONTAINER_DLL_remove (lc->res_head, | ||
490 | lc->res_tail, | ||
491 | res); | ||
492 | GNUNET_free (res); | ||
493 | } | ||
494 | while (NULL != (isc = lc->isc_head)) | ||
495 | { | ||
496 | GNUNET_CONTAINER_DLL_remove (lc->isc_head, | ||
497 | lc->isc_tail, | ||
498 | isc); | ||
499 | GNUNET_CRYPTO_hash_file_cancel (isc->fhc); | ||
500 | GNUNET_free (isc); | ||
501 | } | ||
502 | GNUNET_free (lc); | ||
503 | } | ||
504 | |||
505 | |||
506 | /** | ||
507 | * Task that periodically ages our cover traffic statistics. | ||
508 | * | ||
509 | * @param cls unused closure | ||
510 | */ | ||
511 | static void | ||
512 | age_cover_counters (void *cls) | ||
513 | { | ||
514 | GSF_cover_content_count = (GSF_cover_content_count * 15) / 16; | ||
515 | GSF_cover_query_count = (GSF_cover_query_count * 15) / 16; | ||
516 | cover_age_task = | ||
517 | GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY, | ||
518 | &age_cover_counters, | ||
519 | NULL); | ||
520 | } | ||
521 | |||
522 | |||
523 | /** | ||
524 | * We've just now completed a datastore request. Update our | ||
525 | * datastore load calculations. | ||
526 | * | ||
527 | * @param start time when the datastore request was issued | ||
528 | */ | ||
529 | void | ||
530 | GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start) | ||
531 | { | ||
532 | struct GNUNET_TIME_Relative delay; | ||
533 | |||
534 | delay = GNUNET_TIME_absolute_get_duration (start); | ||
535 | GNUNET_LOAD_update (datastore_get_load, delay.rel_value_us); | ||
536 | } | ||
537 | |||
538 | |||
539 | /** | ||
540 | * Test if the DATABASE (GET) load on this peer is too high | ||
541 | * to even consider processing the query at | ||
542 | * all. | ||
543 | * | ||
544 | * @param priority priority of the request (used as a reference point to compare with the load) | ||
545 | * @return #GNUNET_YES if the load is too high to do anything (load high) | ||
546 | * #GNUNET_NO to process normally (load normal) | ||
547 | * #GNUNET_SYSERR to process for free (load low) | ||
548 | */ | ||
549 | int | ||
550 | GSF_test_get_load_too_high_ (uint32_t priority) | ||
551 | { | ||
552 | double ld; | ||
553 | |||
554 | ld = GNUNET_LOAD_get_load (datastore_get_load); | ||
555 | if (ld < 1) | ||
556 | return GNUNET_SYSERR; | ||
557 | if (ld <= priority) | ||
558 | return GNUNET_NO; | ||
559 | return GNUNET_YES; | ||
560 | } | ||
561 | |||
562 | |||
563 | /** | ||
564 | * We've received peer performance information. Update | ||
565 | * our running average for the P2P latency. | ||
566 | * | ||
567 | * @param cls closure | ||
568 | * @param address the address | ||
569 | * @param active is this address in active use | ||
570 | * @param bandwidth_out assigned outbound bandwidth for the connection | ||
571 | * @param bandwidth_in assigned inbound bandwidth for the connection | ||
572 | * @param prop performance data for the address (as far as known) | ||
573 | */ | ||
574 | static void | ||
575 | update_latencies (void *cls, | ||
576 | const struct GNUNET_HELLO_Address *address, | ||
577 | int active, | ||
578 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, | ||
579 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, | ||
580 | const struct GNUNET_ATS_Properties *prop) | ||
581 | { | ||
582 | if (NULL == address) | ||
583 | { | ||
584 | /* ATS service temporarily disconnected */ | ||
585 | return; | ||
586 | } | ||
587 | |||
588 | if (GNUNET_YES != active) | ||
589 | return; | ||
590 | GSF_update_peer_latency_ (&address->peer, | ||
591 | prop->delay); | ||
592 | GSF_avg_latency.rel_value_us = | ||
593 | (GSF_avg_latency.rel_value_us * 31 | ||
594 | + GNUNET_MIN (5000, prop->delay.rel_value_us)) / 32; | ||
595 | GNUNET_STATISTICS_set (GSF_stats, | ||
596 | gettext_noop ("# running average P2P latency (ms)"), | ||
597 | GSF_avg_latency.rel_value_us / 1000LL, | ||
598 | GNUNET_NO); | ||
599 | } | ||
600 | |||
601 | |||
602 | /** | ||
603 | * Check P2P "PUT" message. | ||
604 | * | ||
605 | * @param cls closure with the `struct GSF_ConnectedPeer` | ||
606 | * @param message the actual message | ||
607 | * @return #GNUNET_OK to keep the connection open, | ||
608 | * #GNUNET_SYSERR to close it (signal serious error) | ||
609 | */ | ||
610 | static int | ||
611 | check_p2p_put (void *cls, | ||
612 | const struct PutMessage *put) | ||
613 | { | ||
614 | enum GNUNET_BLOCK_Type type; | ||
615 | |||
616 | type = ntohl (put->type); | ||
617 | if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type) | ||
618 | { | ||
619 | GNUNET_break_op (0); | ||
620 | return GNUNET_SYSERR; | ||
621 | } | ||
622 | return GNUNET_OK; | ||
623 | } | ||
624 | |||
625 | |||
626 | /** | ||
627 | * We have a new request, consider forwarding it to the given | ||
628 | * peer. | ||
629 | * | ||
630 | * @param cls the `struct GSF_PendingRequest` | ||
631 | * @param peer identity of the peer | ||
632 | * @param cp handle to the connected peer record | ||
633 | * @param ppd peer performance data | ||
634 | */ | ||
635 | static void | ||
636 | consider_request_for_forwarding (void *cls, | ||
637 | const struct GNUNET_PeerIdentity *peer, | ||
638 | struct GSF_ConnectedPeer *cp, | ||
639 | const struct GSF_PeerPerformanceData *ppd) | ||
640 | { | ||
641 | struct GSF_PendingRequest *pr = cls; | ||
642 | |||
643 | if (GNUNET_YES != | ||
644 | GSF_pending_request_test_target_ (pr, peer)) | ||
645 | { | ||
646 | #if INSANE_STATISTICS | ||
647 | GNUNET_STATISTICS_update (GSF_stats, | ||
648 | gettext_noop ("# Loopback routes suppressed"), 1, | ||
649 | GNUNET_NO); | ||
650 | #endif | ||
651 | return; | ||
652 | } | ||
653 | GSF_plan_add_ (cp, | ||
654 | pr); | ||
655 | } | ||
656 | |||
657 | |||
658 | /** | ||
659 | * Function to be called after we're done processing | ||
660 | * replies from the local lookup. If the result status | ||
661 | * code indicates that there may be more replies, plan | ||
662 | * forwarding the request. | ||
663 | * | ||
664 | * @param cls closure (NULL) | ||
665 | * @param pr the pending request we were processing | ||
666 | * @param result final datastore lookup result | ||
667 | */ | ||
668 | void | ||
669 | GSF_consider_forwarding (void *cls, | ||
670 | struct GSF_PendingRequest *pr, | ||
671 | enum GNUNET_BLOCK_ReplyEvaluationResult result) | ||
672 | { | ||
673 | if (GNUNET_BLOCK_REPLY_OK_LAST == result) | ||
674 | return; /* we're done... */ | ||
675 | if (GNUNET_YES != | ||
676 | GSF_pending_request_test_active_ (pr)) | ||
677 | return; /* request is not actually active, skip! */ | ||
678 | GSF_iterate_connected_peers_ (&consider_request_for_forwarding, | ||
679 | pr); | ||
680 | } | ||
681 | |||
682 | |||
683 | /** | ||
684 | * Check P2P "GET" request. | ||
685 | * | ||
686 | * @param cls closure | ||
687 | * @param gm the actual message | ||
688 | * @return #GNUNET_OK to keep the connection open, | ||
689 | * #GNUNET_SYSERR to close it (signal serious error) | ||
690 | */ | ||
691 | static int | ||
692 | check_p2p_get (void *cls, | ||
693 | const struct GetMessage *gm) | ||
694 | { | ||
695 | size_t msize; | ||
696 | unsigned int bm; | ||
697 | unsigned int bits; | ||
698 | size_t bfsize; | ||
699 | |||
700 | msize = ntohs (gm->header.size); | ||
701 | bm = ntohl (gm->hash_bitmap); | ||
702 | bits = 0; | ||
703 | while (bm > 0) | ||
704 | { | ||
705 | if (1 == (bm & 1)) | ||
706 | bits++; | ||
707 | bm >>= 1; | ||
708 | } | ||
709 | if (msize < sizeof(struct GetMessage) + bits * sizeof(struct | ||
710 | GNUNET_PeerIdentity)) | ||
711 | { | ||
712 | GNUNET_break_op (0); | ||
713 | return GNUNET_SYSERR; | ||
714 | } | ||
715 | bfsize = msize - sizeof(struct GetMessage) - bits * sizeof(struct | ||
716 | GNUNET_PeerIdentity); | ||
717 | /* bfsize must be power of 2, check! */ | ||
718 | if (0 != ((bfsize - 1) & bfsize)) | ||
719 | { | ||
720 | GNUNET_break_op (0); | ||
721 | return GNUNET_SYSERR; | ||
722 | } | ||
723 | return GNUNET_OK; | ||
724 | } | ||
725 | |||
726 | |||
727 | /** | ||
728 | * We're done with the local lookup, now consider | ||
729 | * P2P processing (depending on request options and | ||
730 | * result status). Also signal that we can now | ||
731 | * receive more request information from the client. | ||
732 | * | ||
733 | * @param cls the client doing the request (`struct GSF_LocalClient`) | ||
734 | * @param pr the pending request we were processing | ||
735 | * @param result final datastore lookup result | ||
736 | */ | ||
737 | static void | ||
738 | start_p2p_processing (void *cls, | ||
739 | struct GSF_PendingRequest *pr, | ||
740 | enum GNUNET_BLOCK_ReplyEvaluationResult result) | ||
741 | { | ||
742 | struct GSF_LocalClient *lc = cls; | ||
743 | struct GSF_PendingRequestData *prd; | ||
744 | |||
745 | GNUNET_SERVICE_client_continue (lc->client); | ||
746 | if (GNUNET_BLOCK_REPLY_OK_LAST == result) | ||
747 | return; /* we're done, 'pr' was already destroyed... */ | ||
748 | prd = GSF_pending_request_get_data_ (pr); | ||
749 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
750 | "Finished database lookup for local request `%s' with result %d\n", | ||
751 | GNUNET_h2s (&prd->query), | ||
752 | result); | ||
753 | if (0 == prd->anonymity_level) | ||
754 | { | ||
755 | switch (prd->type) | ||
756 | { | ||
757 | case GNUNET_BLOCK_TYPE_FS_DBLOCK: | ||
758 | case GNUNET_BLOCK_TYPE_FS_IBLOCK: | ||
759 | /* the above block types MAY be available via 'cadet' */ | ||
760 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
761 | "Considering cadet-based download for block\n"); | ||
762 | GSF_cadet_lookup_ (pr); | ||
763 | break; | ||
764 | |||
765 | case GNUNET_BLOCK_TYPE_FS_UBLOCK: | ||
766 | /* the above block types are in the DHT */ | ||
767 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
768 | "Considering DHT-based search for block\n"); | ||
769 | GSF_dht_lookup_ (pr); | ||
770 | break; | ||
771 | |||
772 | default: | ||
773 | GNUNET_break (0); | ||
774 | break; | ||
775 | } | ||
776 | } | ||
777 | GSF_consider_forwarding (NULL, | ||
778 | pr, | ||
779 | result); | ||
780 | } | ||
781 | |||
782 | |||
783 | /** | ||
784 | * Check #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request | ||
785 | * from client). | ||
786 | * | ||
787 | * @param cls identification of the client | ||
788 | * @param sm the actual message | ||
789 | * @return #GNUNET_OK if @a sm is well-formed | ||
790 | */ | ||
791 | static int | ||
792 | check_client_start_search (void *cls, | ||
793 | const struct SearchMessage *sm) | ||
794 | { | ||
795 | uint16_t msize; | ||
796 | |||
797 | msize = ntohs (sm->header.size) - sizeof(struct SearchMessage); | ||
798 | if (0 != msize % sizeof(struct GNUNET_HashCode)) | ||
799 | { | ||
800 | GNUNET_break (0); | ||
801 | return GNUNET_SYSERR; | ||
802 | } | ||
803 | return GNUNET_OK; | ||
804 | } | ||
805 | |||
806 | |||
807 | /** | ||
808 | * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request | ||
809 | * from client). | ||
810 | * | ||
811 | * Responsible for creating the request entry itself and setting | ||
812 | * up reply callback and cancellation on client disconnect. | ||
813 | * | ||
814 | * @param cls identification of the client | ||
815 | * @param sm the actual message | ||
816 | */ | ||
817 | static void | ||
818 | handle_client_start_search (void *cls, | ||
819 | const struct SearchMessage *sm) | ||
820 | { | ||
821 | static struct GNUNET_PeerIdentity all_zeros; | ||
822 | struct GSF_LocalClient *lc = cls; | ||
823 | struct ClientRequest *cr; | ||
824 | struct GSF_PendingRequestData *prd; | ||
825 | uint16_t msize; | ||
826 | unsigned int sc; | ||
827 | enum GNUNET_BLOCK_Type type; | ||
828 | enum GSF_PendingRequestOptions options; | ||
829 | |||
830 | GNUNET_STATISTICS_update (GSF_stats, | ||
831 | gettext_noop ("# client searches received"), | ||
832 | 1, | ||
833 | GNUNET_NO); | ||
834 | msize = ntohs (sm->header.size) - sizeof(struct SearchMessage); | ||
835 | sc = msize / sizeof(struct GNUNET_HashCode); | ||
836 | type = ntohl (sm->type); | ||
837 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
838 | "Received request for `%s' of type %u from local client\n", | ||
839 | GNUNET_h2s (&sm->query), | ||
840 | (unsigned int) type); | ||
841 | cr = NULL; | ||
842 | /* detect duplicate UBLOCK requests */ | ||
843 | if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) || | ||
844 | (type == GNUNET_BLOCK_TYPE_ANY)) | ||
845 | { | ||
846 | cr = lc->cr_head; | ||
847 | while (NULL != cr) | ||
848 | { | ||
849 | prd = GSF_pending_request_get_data_ (cr->pr); | ||
850 | /* only unify with queries that hae not yet started local processing | ||
851 | (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a | ||
852 | matching query and type */ | ||
853 | if ((GNUNET_YES != prd->has_started) && | ||
854 | (0 != memcmp (&prd->query, | ||
855 | &sm->query, | ||
856 | sizeof(struct GNUNET_HashCode))) && | ||
857 | (prd->type == type)) | ||
858 | break; | ||
859 | cr = cr->next; | ||
860 | } | ||
861 | } | ||
862 | if (NULL != cr) | ||
863 | { | ||
864 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
865 | "Have existing request, merging content-seen lists.\n"); | ||
866 | GSF_pending_request_update_ (cr->pr, | ||
867 | (const struct GNUNET_HashCode *) &sm[1], | ||
868 | sc); | ||
869 | GNUNET_STATISTICS_update (GSF_stats, | ||
870 | gettext_noop ( | ||
871 | "# client searches updated (merged content seen list)"), | ||
872 | 1, | ||
873 | GNUNET_NO); | ||
874 | } | ||
875 | else | ||
876 | { | ||
877 | GNUNET_STATISTICS_update (GSF_stats, | ||
878 | gettext_noop ("# client searches active"), | ||
879 | 1, | ||
880 | GNUNET_NO); | ||
881 | cr = GNUNET_new (struct ClientRequest); | ||
882 | cr->lc = lc; | ||
883 | GNUNET_CONTAINER_DLL_insert (lc->cr_head, | ||
884 | lc->cr_tail, | ||
885 | cr); | ||
886 | options = GSF_PRO_LOCAL_REQUEST; | ||
887 | if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options))) | ||
888 | options |= GSF_PRO_LOCAL_ONLY; | ||
889 | cr->pr = GSF_pending_request_create_ (options, type, | ||
890 | &sm->query, | ||
891 | (0 != | ||
892 | memcmp (&sm->target, | ||
893 | &all_zeros, | ||
894 | sizeof(struct | ||
895 | GNUNET_PeerIdentity))) | ||
896 | ? &sm->target : NULL, NULL, 0, | ||
897 | 0 /* bf */, | ||
898 | ntohl (sm->anonymity_level), | ||
899 | 0 /* priority */, | ||
900 | 0 /* ttl */, | ||
901 | 0 /* sender PID */, | ||
902 | 0 /* origin PID */, | ||
903 | (const struct | ||
904 | GNUNET_HashCode *) &sm[1], sc, | ||
905 | &client_response_handler, | ||
906 | cr); | ||
907 | } | ||
908 | if (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options))) | ||
909 | { | ||
910 | GNUNET_SERVICE_client_continue (lc->client); | ||
911 | return; | ||
912 | } | ||
913 | GSF_pending_request_get_data_ (cr->pr)->has_started = GNUNET_YES; | ||
914 | GSF_local_lookup_ (cr->pr, | ||
915 | &start_p2p_processing, | ||
916 | lc); | ||
917 | } | ||
918 | |||
919 | |||
920 | /** | ||
921 | * Handle request to sign a LOC URI (from client). | ||
922 | * | ||
923 | * @param cls identification of the client | ||
924 | * @param msg the actual message | ||
925 | */ | ||
926 | static void | ||
927 | handle_client_loc_sign (void *cls, | ||
928 | const struct RequestLocSignatureMessage *msg) | ||
929 | { | ||
930 | struct GSF_LocalClient *lc = cls; | ||
931 | struct GNUNET_FS_Uri base; | ||
932 | struct GNUNET_FS_Uri *loc; | ||
933 | struct GNUNET_MQ_Envelope *env; | ||
934 | struct ResponseLocSignatureMessage *resp; | ||
935 | |||
936 | GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT == | ||
937 | ntohl (msg->purpose)); | ||
938 | base.type = GNUNET_FS_URI_CHK; | ||
939 | base.data.chk.chk = msg->chk; | ||
940 | base.data.chk.file_length = GNUNET_ntohll (msg->file_length); | ||
941 | loc = GNUNET_FS_uri_loc_create (&base, | ||
942 | &pk, | ||
943 | GNUNET_TIME_absolute_ntoh ( | ||
944 | msg->expiration_time)); | ||
945 | env = GNUNET_MQ_msg (resp, | ||
946 | GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE); | ||
947 | resp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); | ||
948 | resp->expiration_time = GNUNET_TIME_absolute_hton ( | ||
949 | loc->data.loc.expirationTime); | ||
950 | resp->signature = loc->data.loc.contentSignature; | ||
951 | resp->peer = loc->data.loc.peer; | ||
952 | GNUNET_FS_uri_destroy (loc); | ||
953 | GNUNET_MQ_send (lc->mq, | ||
954 | env); | ||
955 | GNUNET_SERVICE_client_continue (lc->client); | ||
956 | } | ||
957 | |||
958 | |||
959 | /** | ||
960 | * Check INDEX_START-message. | ||
961 | * | ||
962 | * @param cls identification of the client | ||
963 | * @param ism the actual message | ||
964 | * @return #GNUNET_OK if @a ism is well-formed | ||
965 | */ | ||
966 | static int | ||
967 | check_client_index_start (void *cls, | ||
968 | const struct IndexStartMessage *ism) | ||
969 | { | ||
970 | char *fn; | ||
971 | |||
972 | GNUNET_MQ_check_zero_termination (ism); | ||
973 | if (0 != ism->reserved) | ||
974 | { | ||
975 | GNUNET_break (0); | ||
976 | return GNUNET_SYSERR; | ||
977 | } | ||
978 | fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]); | ||
979 | if (NULL == fn) | ||
980 | { | ||
981 | GNUNET_break (0); | ||
982 | return GNUNET_SYSERR; | ||
983 | } | ||
984 | GNUNET_free (fn); | ||
985 | return GNUNET_OK; | ||
986 | } | ||
987 | |||
988 | |||
989 | /** | ||
990 | * We've validated the hash of the file we're about to index. Signal | ||
991 | * success to the client and update our internal data structures. | ||
992 | * | ||
993 | * @param isc the data about the index info entry for the request | ||
994 | */ | ||
995 | static void | ||
996 | signal_index_ok (struct IndexStartContext *isc) | ||
997 | { | ||
998 | struct GSF_LocalClient *lc = isc->lc; | ||
999 | struct GNUNET_MQ_Envelope *env; | ||
1000 | struct GNUNET_MessageHeader *msg; | ||
1001 | |||
1002 | GNUNET_FS_add_to_index (isc->filename, | ||
1003 | &isc->file_id); | ||
1004 | env = GNUNET_MQ_msg (msg, | ||
1005 | GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); | ||
1006 | GNUNET_MQ_send (lc->mq, | ||
1007 | env); | ||
1008 | GNUNET_free (isc->filename); | ||
1009 | GNUNET_free (isc); | ||
1010 | GNUNET_SERVICE_client_continue (lc->client); | ||
1011 | } | ||
1012 | |||
1013 | |||
1014 | /** | ||
1015 | * Function called once the hash computation over an | ||
1016 | * indexed file has completed. | ||
1017 | * | ||
1018 | * @param cls closure, our publishing context | ||
1019 | * @param res resulting hash, NULL on error | ||
1020 | */ | ||
1021 | static void | ||
1022 | hash_for_index_val (void *cls, | ||
1023 | const struct GNUNET_HashCode *res) | ||
1024 | { | ||
1025 | struct IndexStartContext *isc = cls; | ||
1026 | struct GSF_LocalClient *lc = isc->lc; | ||
1027 | struct GNUNET_MQ_Envelope *env; | ||
1028 | struct GNUNET_MessageHeader *msg; | ||
1029 | |||
1030 | GNUNET_CONTAINER_DLL_remove (lc->isc_head, | ||
1031 | lc->isc_tail, | ||
1032 | isc); | ||
1033 | isc->fhc = NULL; | ||
1034 | if ((NULL == res) || | ||
1035 | (0 != memcmp (res, | ||
1036 | &isc->file_id, | ||
1037 | sizeof(struct GNUNET_HashCode)))) | ||
1038 | { | ||
1039 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1040 | _ ( | ||
1041 | "Hash mismatch trying to index file `%s' which does not have hash `%s'\n"), | ||
1042 | isc->filename, | ||
1043 | GNUNET_h2s (&isc->file_id)); | ||
1044 | env = GNUNET_MQ_msg (msg, | ||
1045 | GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED); | ||
1046 | GNUNET_MQ_send (lc->mq, | ||
1047 | env); | ||
1048 | GNUNET_SERVICE_client_continue (lc->client); | ||
1049 | GNUNET_free (isc); | ||
1050 | return; | ||
1051 | } | ||
1052 | signal_index_ok (isc); | ||
1053 | } | ||
1054 | |||
1055 | |||
1056 | /** | ||
1057 | * Handle INDEX_START-message. | ||
1058 | * | ||
1059 | * @param cls identification of the client | ||
1060 | * @param message the actual message | ||
1061 | */ | ||
1062 | static void | ||
1063 | handle_client_index_start (void *cls, | ||
1064 | const struct IndexStartMessage *ism) | ||
1065 | { | ||
1066 | struct GSF_LocalClient *lc = cls; | ||
1067 | struct IndexStartContext *isc; | ||
1068 | char *fn; | ||
1069 | uint64_t dev; | ||
1070 | uint64_t ino; | ||
1071 | uint64_t mydev; | ||
1072 | uint64_t myino; | ||
1073 | |||
1074 | fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]); | ||
1075 | GNUNET_assert (NULL != fn); | ||
1076 | dev = GNUNET_ntohll (ism->device); | ||
1077 | ino = GNUNET_ntohll (ism->inode); | ||
1078 | isc = GNUNET_new (struct IndexStartContext); | ||
1079 | isc->filename = fn; | ||
1080 | isc->file_id = ism->file_id; | ||
1081 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1082 | "Received START_INDEX message for file `%s'\n", | ||
1083 | isc->filename); | ||
1084 | isc->lc = lc; | ||
1085 | mydev = 0; | ||
1086 | myino = 0; | ||
1087 | if (((dev != 0) || | ||
1088 | (ino != 0)) && | ||
1089 | (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn, | ||
1090 | &mydev, | ||
1091 | &myino)) && | ||
1092 | (dev == mydev) && | ||
1093 | (ino == myino)) | ||
1094 | { | ||
1095 | /* fast validation OK! */ | ||
1096 | signal_index_ok (isc); | ||
1097 | return; | ||
1098 | } | ||
1099 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1100 | "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n", | ||
1101 | (unsigned long long) ino, | ||
1102 | (unsigned long long) myino, | ||
1103 | (unsigned int) dev, | ||
1104 | (unsigned int) mydev); | ||
1105 | /* slow validation, need to hash full file (again) */ | ||
1106 | GNUNET_CONTAINER_DLL_insert (lc->isc_head, | ||
1107 | lc->isc_tail, | ||
1108 | isc); | ||
1109 | isc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
1110 | isc->filename, | ||
1111 | HASHING_BLOCKSIZE, | ||
1112 | &hash_for_index_val, | ||
1113 | isc); | ||
1114 | if (NULL == isc->fhc) | ||
1115 | hash_for_index_val (isc, | ||
1116 | NULL); | ||
1117 | } | ||
1118 | |||
1119 | |||
1120 | /** | ||
1121 | * Handle INDEX_LIST_GET-message. | ||
1122 | * | ||
1123 | * @param cls closure | ||
1124 | * @param message the actual message | ||
1125 | */ | ||
1126 | static void | ||
1127 | handle_client_index_list_get (void *cls, | ||
1128 | const struct GNUNET_MessageHeader *message) | ||
1129 | { | ||
1130 | struct GSF_LocalClient *lc = cls; | ||
1131 | |||
1132 | GNUNET_FS_indexing_send_list (lc->mq); | ||
1133 | GNUNET_SERVICE_client_continue (lc->client); | ||
1134 | } | ||
1135 | |||
1136 | |||
1137 | /** | ||
1138 | * Handle UNINDEX-message. | ||
1139 | * | ||
1140 | * @param cls identification of the client | ||
1141 | * @param message the actual message | ||
1142 | */ | ||
1143 | static void | ||
1144 | handle_client_unindex (void *cls, | ||
1145 | const struct UnindexMessage *um) | ||
1146 | { | ||
1147 | struct GSF_LocalClient *lc = cls; | ||
1148 | struct GNUNET_MQ_Envelope *env; | ||
1149 | struct GNUNET_MessageHeader *msg; | ||
1150 | int found; | ||
1151 | |||
1152 | GNUNET_break (0 == um->reserved); | ||
1153 | found = GNUNET_FS_indexing_do_unindex (&um->file_id); | ||
1154 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1155 | "Client requested unindexing of file `%s': %s\n", | ||
1156 | GNUNET_h2s (&um->file_id), | ||
1157 | found ? "found" : "not found"); | ||
1158 | env = GNUNET_MQ_msg (msg, | ||
1159 | GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK); | ||
1160 | GNUNET_MQ_send (lc->mq, | ||
1161 | env); | ||
1162 | GNUNET_SERVICE_client_continue (lc->client); | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | /** | ||
1167 | * Task run during shutdown. | ||
1168 | * | ||
1169 | * @param cls unused | ||
1170 | */ | ||
1171 | static void | ||
1172 | shutdown_task (void *cls) | ||
1173 | { | ||
1174 | GSF_cadet_stop_server (); | ||
1175 | if (NULL != GSF_core) | ||
1176 | { | ||
1177 | GNUNET_CORE_disconnect (GSF_core); | ||
1178 | GSF_core = NULL; | ||
1179 | } | ||
1180 | if (NULL != GSF_ats) | ||
1181 | { | ||
1182 | GNUNET_ATS_performance_done (GSF_ats); | ||
1183 | GSF_ats = NULL; | ||
1184 | } | ||
1185 | GSF_put_done_ (); | ||
1186 | GSF_push_done_ (); | ||
1187 | GSF_pending_request_done_ (); | ||
1188 | GSF_plan_done (); | ||
1189 | GSF_connected_peer_done_ (); | ||
1190 | GNUNET_DATASTORE_disconnect (GSF_dsh, | ||
1191 | GNUNET_NO); | ||
1192 | GSF_dsh = NULL; | ||
1193 | GNUNET_DHT_disconnect (GSF_dht); | ||
1194 | GSF_dht = NULL; | ||
1195 | GNUNET_BLOCK_context_destroy (GSF_block_ctx); | ||
1196 | GSF_block_ctx = NULL; | ||
1197 | GNUNET_CONFIGURATION_destroy (block_cfg); | ||
1198 | block_cfg = NULL; | ||
1199 | GNUNET_STATISTICS_destroy (GSF_stats, GNUNET_NO); | ||
1200 | GSF_stats = NULL; | ||
1201 | if (NULL != cover_age_task) | ||
1202 | { | ||
1203 | GNUNET_SCHEDULER_cancel (cover_age_task); | ||
1204 | cover_age_task = NULL; | ||
1205 | } | ||
1206 | GNUNET_FS_indexing_done (); | ||
1207 | GNUNET_LOAD_value_free (datastore_get_load); | ||
1208 | datastore_get_load = NULL; | ||
1209 | GNUNET_LOAD_value_free (GSF_rt_entry_lifetime); | ||
1210 | GSF_rt_entry_lifetime = NULL; | ||
1211 | } | ||
1212 | |||
1213 | |||
1214 | /** | ||
1215 | * Function called after GNUNET_CORE_connect has succeeded | ||
1216 | * (or failed for good). Note that the private key of the | ||
1217 | * peer is intentionally not exposed here; if you need it, | ||
1218 | * your process should try to read the private key file | ||
1219 | * directly (which should work if you are authorized...). | ||
1220 | * | ||
1221 | * @param cls closure | ||
1222 | * @param my_identity ID of this peer, NULL if we failed | ||
1223 | */ | ||
1224 | static void | ||
1225 | peer_init_handler (void *cls, | ||
1226 | const struct GNUNET_PeerIdentity *my_identity) | ||
1227 | { | ||
1228 | if (0 != GNUNET_memcmp (&GSF_my_id, | ||
1229 | my_identity)) | ||
1230 | { | ||
1231 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1232 | "Peer identity mismatch, refusing to start!\n"); | ||
1233 | GNUNET_SCHEDULER_shutdown (); | ||
1234 | } | ||
1235 | } | ||
1236 | |||
1237 | |||
1238 | /** | ||
1239 | * Process fs requests. | ||
1240 | * | ||
1241 | * @param c configuration to use | ||
1242 | */ | ||
1243 | static int | ||
1244 | main_init (const struct GNUNET_CONFIGURATION_Handle *c) | ||
1245 | { | ||
1246 | struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = { | ||
1247 | GNUNET_MQ_handler_end () | ||
1248 | }; | ||
1249 | struct GNUNET_MQ_MessageHandler p2p_handlers[] = { | ||
1250 | GNUNET_MQ_hd_var_size (p2p_get, | ||
1251 | GNUNET_MESSAGE_TYPE_FS_GET, | ||
1252 | struct GetMessage, | ||
1253 | NULL), | ||
1254 | GNUNET_MQ_hd_var_size (p2p_put, | ||
1255 | GNUNET_MESSAGE_TYPE_FS_PUT, | ||
1256 | struct PutMessage, | ||
1257 | NULL), | ||
1258 | GNUNET_MQ_hd_fixed_size (p2p_migration_stop, | ||
1259 | GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP, | ||
1260 | struct MigrationStopMessage, | ||
1261 | NULL), | ||
1262 | GNUNET_MQ_handler_end () | ||
1263 | }; | ||
1264 | int anon_p2p_off; | ||
1265 | char *keyfile; | ||
1266 | |||
1267 | /* this option is really only for testcases that need to disable | ||
1268 | _anonymous_ file-sharing for some reason */ | ||
1269 | anon_p2p_off = (GNUNET_YES == | ||
1270 | GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg, | ||
1271 | "fs", | ||
1272 | "DISABLE_ANON_TRANSFER")); | ||
1273 | |||
1274 | if (GNUNET_OK != | ||
1275 | GNUNET_CONFIGURATION_get_value_filename (GSF_cfg, | ||
1276 | "PEER", | ||
1277 | "PRIVATE_KEY", | ||
1278 | &keyfile)) | ||
1279 | { | ||
1280 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1281 | _ ( | ||
1282 | "FS service is lacking HOSTKEY configuration setting. Exiting.\n")); | ||
1283 | GNUNET_SCHEDULER_shutdown (); | ||
1284 | return GNUNET_SYSERR; | ||
1285 | } | ||
1286 | if (GNUNET_SYSERR == | ||
1287 | GNUNET_CRYPTO_eddsa_key_from_file (keyfile, | ||
1288 | GNUNET_YES, | ||
1289 | &pk)) | ||
1290 | { | ||
1291 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1292 | "Failed to setup peer's private key\n"); | ||
1293 | GNUNET_SCHEDULER_shutdown (); | ||
1294 | GNUNET_free (keyfile); | ||
1295 | return GNUNET_SYSERR; | ||
1296 | } | ||
1297 | GNUNET_free (keyfile); | ||
1298 | GNUNET_CRYPTO_eddsa_key_get_public (&pk, | ||
1299 | &GSF_my_id.public_key); | ||
1300 | |||
1301 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1302 | "I am peer %s\n", | ||
1303 | GNUNET_i2s (&GSF_my_id)); | ||
1304 | GSF_core | ||
1305 | = GNUNET_CORE_connect (GSF_cfg, | ||
1306 | NULL, | ||
1307 | &peer_init_handler, | ||
1308 | &GSF_peer_connect_handler, | ||
1309 | &GSF_peer_disconnect_handler, | ||
1310 | (GNUNET_YES == anon_p2p_off) | ||
1311 | ? no_p2p_handlers | ||
1312 | : p2p_handlers); | ||
1313 | if (NULL == GSF_core) | ||
1314 | { | ||
1315 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1316 | _ ("Failed to connect to `%s' service.\n"), | ||
1317 | "core"); | ||
1318 | return GNUNET_SYSERR; | ||
1319 | } | ||
1320 | cover_age_task = | ||
1321 | GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY, | ||
1322 | &age_cover_counters, | ||
1323 | NULL); | ||
1324 | datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE); | ||
1325 | GSF_cadet_start_server (); | ||
1326 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1327 | NULL); | ||
1328 | return GNUNET_OK; | ||
1329 | } | ||
1330 | |||
1331 | |||
1332 | /** | ||
1333 | * Process fs requests. | ||
1334 | * | ||
1335 | * @param cls closure | ||
1336 | * @param cfg configuration to use | ||
1337 | * @param service the initialized service | ||
1338 | */ | ||
1339 | static void | ||
1340 | run (void *cls, | ||
1341 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1342 | struct GNUNET_SERVICE_Handle *service) | ||
1343 | { | ||
1344 | unsigned long long dqs; | ||
1345 | |||
1346 | GSF_cfg = cfg; | ||
1347 | if (GNUNET_OK != | ||
1348 | GNUNET_CONFIGURATION_get_value_size (GSF_cfg, | ||
1349 | "fs", | ||
1350 | "DATASTORE_QUEUE_SIZE", | ||
1351 | &dqs)) | ||
1352 | { | ||
1353 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO, | ||
1354 | "fs", | ||
1355 | "DATASTORE_QUEUE_SIZE"); | ||
1356 | dqs = 32; | ||
1357 | } | ||
1358 | GSF_datastore_queue_size = (unsigned int) dqs; | ||
1359 | GSF_enable_randomized_delays = | ||
1360 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "fs", "DELAY"); | ||
1361 | GSF_dsh = GNUNET_DATASTORE_connect (cfg); | ||
1362 | if (NULL == GSF_dsh) | ||
1363 | { | ||
1364 | GNUNET_SCHEDULER_shutdown (); | ||
1365 | return; | ||
1366 | } | ||
1367 | GSF_rt_entry_lifetime = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_FOREVER_REL); | ||
1368 | GSF_stats = GNUNET_STATISTICS_create ("fs", cfg); | ||
1369 | block_cfg = GNUNET_CONFIGURATION_create (); | ||
1370 | GSF_block_ctx = GNUNET_BLOCK_context_create (block_cfg); | ||
1371 | GNUNET_assert (NULL != GSF_block_ctx); | ||
1372 | GSF_dht = GNUNET_DHT_connect (cfg, FS_DHT_HT_SIZE); | ||
1373 | GSF_plan_init (); | ||
1374 | GSF_pending_request_init_ (); | ||
1375 | GSF_connected_peer_init_ (); | ||
1376 | GSF_ats = GNUNET_ATS_performance_init (GSF_cfg, | ||
1377 | &update_latencies, | ||
1378 | NULL); | ||
1379 | GSF_push_init_ (); | ||
1380 | GSF_put_init_ (); | ||
1381 | if ((GNUNET_OK != GNUNET_FS_indexing_init (cfg, | ||
1382 | GSF_dsh)) || | ||
1383 | (GNUNET_OK != main_init (cfg))) | ||
1384 | { | ||
1385 | GNUNET_SCHEDULER_shutdown (); | ||
1386 | shutdown_task (NULL); | ||
1387 | return; | ||
1388 | } | ||
1389 | } | ||
1390 | |||
1391 | |||
1392 | /** | ||
1393 | * Define "main" method using service macro. | ||
1394 | */ | ||
1395 | GNUNET_SERVICE_MAIN | ||
1396 | ("fs", | ||
1397 | GNUNET_SERVICE_OPTION_NONE, | ||
1398 | &run, | ||
1399 | &client_connect_cb, | ||
1400 | &client_disconnect_cb, | ||
1401 | NULL, | ||
1402 | GNUNET_MQ_hd_var_size (client_index_start, | ||
1403 | GNUNET_MESSAGE_TYPE_FS_INDEX_START, | ||
1404 | struct IndexStartMessage, | ||
1405 | NULL), | ||
1406 | GNUNET_MQ_hd_fixed_size (client_index_list_get, | ||
1407 | GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET, | ||
1408 | struct GNUNET_MessageHeader, | ||
1409 | NULL), | ||
1410 | GNUNET_MQ_hd_fixed_size (client_unindex, | ||
1411 | GNUNET_MESSAGE_TYPE_FS_UNINDEX, | ||
1412 | struct UnindexMessage, | ||
1413 | NULL), | ||
1414 | GNUNET_MQ_hd_var_size (client_start_search, | ||
1415 | GNUNET_MESSAGE_TYPE_FS_START_SEARCH, | ||
1416 | struct SearchMessage, | ||
1417 | NULL), | ||
1418 | GNUNET_MQ_hd_fixed_size (client_loc_sign, | ||
1419 | GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN, | ||
1420 | struct RequestLocSignatureMessage, | ||
1421 | NULL), | ||
1422 | GNUNET_MQ_handler_end ()); | ||
1423 | |||
1424 | |||
1425 | /* end of gnunet-service-fs.c */ | ||
diff --git a/src/fs/gnunet-service-fs.h b/src/fs/gnunet-service-fs.h deleted file mode 100644 index a6b73db09..000000000 --- a/src/fs/gnunet-service-fs.h +++ /dev/null | |||
@@ -1,310 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs.h | ||
23 | * @brief shared data structures of gnunet-service-fs.c | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_FS_H | ||
27 | #define GNUNET_SERVICE_FS_H | ||
28 | |||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include "gnunet_transport_service.h" | ||
32 | #include "gnunet_core_service.h" | ||
33 | #include "gnunet_block_lib.h" | ||
34 | #include "gnunet_ats_service.h" | ||
35 | #include "fs.h" | ||
36 | |||
37 | |||
38 | /** | ||
39 | * By which amount do we decrement the TTL for simple forwarding / | ||
40 | * indirection of the query; in milli-seconds. Set somewhat in | ||
41 | * accordance to your network latency (above the time it'll take you | ||
42 | * to send a packet and get a reply). | ||
43 | */ | ||
44 | #define TTL_DECREMENT 5000 | ||
45 | |||
46 | /** | ||
47 | * At what frequency should our datastore load decrease | ||
48 | * automatically (since if we don't use it, clearly the | ||
49 | * load must be going down). | ||
50 | */ | ||
51 | #define DATASTORE_LOAD_AUTODECLINE GNUNET_TIME_relative_multiply ( \ | ||
52 | GNUNET_TIME_UNIT_MILLISECONDS, 250) | ||
53 | |||
54 | /** | ||
55 | * Only the (mandatory) query is included. | ||
56 | */ | ||
57 | #define GET_MESSAGE_BIT_QUERY_ONLY 0 | ||
58 | |||
59 | /** | ||
60 | * The peer identity of a peer waiting for the | ||
61 | * reply is included (used if the response | ||
62 | * should be transmitted to someone other than | ||
63 | * the sender of the GET). | ||
64 | */ | ||
65 | #define GET_MESSAGE_BIT_RETURN_TO 1 | ||
66 | |||
67 | /** | ||
68 | * The peer identity of a peer that had claimed to have the content | ||
69 | * previously is included (can be used if responder-anonymity is not | ||
70 | * desired; note that the precursor presumably lacked a direct | ||
71 | * connection to the specified peer; still, the receiver is in no way | ||
72 | * required to limit forwarding only to the specified peer, it should | ||
73 | * only prefer it somewhat if possible). | ||
74 | */ | ||
75 | #define GET_MESSAGE_BIT_TRANSMIT_TO 4 | ||
76 | |||
77 | |||
78 | GNUNET_NETWORK_STRUCT_BEGIN | ||
79 | |||
80 | /** | ||
81 | * Message sent between peers asking for FS-content. | ||
82 | */ | ||
83 | struct GetMessage | ||
84 | { | ||
85 | /** | ||
86 | * Message type will be #GNUNET_MESSAGE_TYPE_FS_GET. | ||
87 | */ | ||
88 | struct GNUNET_MessageHeader header; | ||
89 | |||
90 | /** | ||
91 | * Type of the query (block type). | ||
92 | */ | ||
93 | uint32_t type GNUNET_PACKED; | ||
94 | |||
95 | /** | ||
96 | * How important is this request (network byte order) | ||
97 | */ | ||
98 | uint32_t priority GNUNET_PACKED; | ||
99 | |||
100 | /** | ||
101 | * Relative time to live in MILLISECONDS (network byte order) | ||
102 | */ | ||
103 | int32_t ttl GNUNET_PACKED; | ||
104 | |||
105 | /** | ||
106 | * The content hash should be mutated using this value | ||
107 | * before checking against the bloomfilter (used to | ||
108 | * get many different filters for the same hash codes). | ||
109 | * The number should be in big-endian format when used | ||
110 | * for mingling. | ||
111 | */ | ||
112 | uint32_t filter_mutator GNUNET_PACKED; | ||
113 | |||
114 | /** | ||
115 | * Which of the optional hash codes are present at the end of the | ||
116 | * message? See GET_MESSAGE_BIT_xx constants. For each bit that is | ||
117 | * set, an additional `struct GNUNET_HashCode` with the respective content | ||
118 | * (in order of the bits) will be appended to the end of the GET | ||
119 | * message. | ||
120 | */ | ||
121 | uint32_t hash_bitmap GNUNET_PACKED; | ||
122 | |||
123 | /** | ||
124 | * Hashcodes of the file(s) we're looking for. | ||
125 | * Details depend on the query type. | ||
126 | */ | ||
127 | struct GNUNET_HashCode query; | ||
128 | |||
129 | /* this is followed by PeerIdentities as specified in the "hash_bitmap"; | ||
130 | * after that, an optional bloomfilter (with bits set for replies | ||
131 | * that should be suppressed) can be present */ | ||
132 | }; | ||
133 | |||
134 | |||
135 | /** | ||
136 | * Message send by a peer that wants to be excluded | ||
137 | * from migration for a while. | ||
138 | */ | ||
139 | struct MigrationStopMessage | ||
140 | { | ||
141 | /** | ||
142 | * Message type will be | ||
143 | * GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP. | ||
144 | */ | ||
145 | struct GNUNET_MessageHeader header; | ||
146 | |||
147 | /** | ||
148 | * Always zero. | ||
149 | */ | ||
150 | uint32_t reserved GNUNET_PACKED; | ||
151 | |||
152 | /** | ||
153 | * How long should the block last? | ||
154 | */ | ||
155 | struct GNUNET_TIME_RelativeNBO duration; | ||
156 | }; | ||
157 | GNUNET_NETWORK_STRUCT_END | ||
158 | |||
159 | /** | ||
160 | * A connected peer. | ||
161 | */ | ||
162 | struct GSF_ConnectedPeer; | ||
163 | |||
164 | /** | ||
165 | * An active request. | ||
166 | */ | ||
167 | struct GSF_PendingRequest; | ||
168 | |||
169 | /** | ||
170 | * A local client. | ||
171 | */ | ||
172 | struct GSF_LocalClient; | ||
173 | |||
174 | /** | ||
175 | * Information kept per plan per request ('pe' module). | ||
176 | */ | ||
177 | struct GSF_RequestPlan; | ||
178 | |||
179 | /** | ||
180 | * Bijection between request plans and pending requests. | ||
181 | */ | ||
182 | struct GSF_PendingRequestPlanBijection; | ||
183 | |||
184 | /** | ||
185 | * Our connection to the datastore. | ||
186 | */ | ||
187 | extern struct GNUNET_DATASTORE_Handle *GSF_dsh; | ||
188 | |||
189 | /** | ||
190 | * Our configuration. | ||
191 | */ | ||
192 | extern const struct GNUNET_CONFIGURATION_Handle *GSF_cfg; | ||
193 | |||
194 | /** | ||
195 | * Handle for reporting statistics. | ||
196 | */ | ||
197 | extern struct GNUNET_STATISTICS_Handle *GSF_stats; | ||
198 | |||
199 | /** | ||
200 | * Pointer to handle to the core service (points to NULL until we've | ||
201 | * connected to it). | ||
202 | */ | ||
203 | extern struct GNUNET_CORE_Handle *GSF_core; | ||
204 | |||
205 | /** | ||
206 | * Handle for DHT operations. | ||
207 | */ | ||
208 | extern struct GNUNET_DHT_Handle *GSF_dht; | ||
209 | |||
210 | /** | ||
211 | * How long do requests typically stay in the routing table? | ||
212 | */ | ||
213 | extern struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime; | ||
214 | |||
215 | /** | ||
216 | * Running average of the observed latency to other peers (round trip). | ||
217 | */ | ||
218 | extern struct GNUNET_TIME_Relative GSF_avg_latency; | ||
219 | |||
220 | /** | ||
221 | * Handle to ATS service. | ||
222 | */ | ||
223 | extern struct GNUNET_ATS_PerformanceHandle *GSF_ats; | ||
224 | |||
225 | /** | ||
226 | * Identity of this peer. | ||
227 | */ | ||
228 | extern struct GNUNET_PeerIdentity GSF_my_id; | ||
229 | |||
230 | /** | ||
231 | * Typical priorities we're seeing from other peers right now. Since | ||
232 | * most priorities will be zero, this value is the weighted average of | ||
233 | * non-zero priorities seen "recently". In order to ensure that new | ||
234 | * values do not dramatically change the ratio, values are first | ||
235 | * "capped" to a reasonable range (+N of the current value) and then | ||
236 | * averaged into the existing value by a ratio of 1:N. Hence | ||
237 | * receiving the largest possible priority can still only raise our | ||
238 | * "current_priorities" by at most 1. | ||
239 | */ | ||
240 | extern double GSF_current_priorities; | ||
241 | |||
242 | /** | ||
243 | * How many query messages have we received 'recently' that | ||
244 | * have not yet been claimed as cover traffic? | ||
245 | */ | ||
246 | extern unsigned int GSF_cover_query_count; | ||
247 | |||
248 | /** | ||
249 | * How many content messages have we received 'recently' that | ||
250 | * have not yet been claimed as cover traffic? | ||
251 | */ | ||
252 | extern unsigned int GSF_cover_content_count; | ||
253 | |||
254 | /** | ||
255 | * Our block context. | ||
256 | */ | ||
257 | extern struct GNUNET_BLOCK_Context *GSF_block_ctx; | ||
258 | |||
259 | /** | ||
260 | * Are we introducing randomized delays for better anonymity? | ||
261 | */ | ||
262 | extern int GSF_enable_randomized_delays; | ||
263 | |||
264 | /** | ||
265 | * Size of the datastore queue we assume for common requests. | ||
266 | */ | ||
267 | extern unsigned int GSF_datastore_queue_size; | ||
268 | |||
269 | |||
270 | /** | ||
271 | * Function to be called after we're done processing | ||
272 | * replies from the local lookup. If the result status | ||
273 | * code indicates that there may be more replies, plan | ||
274 | * forwarding the request. | ||
275 | * | ||
276 | * @param cls closure (NULL) | ||
277 | * @param pr the pending request we were processing | ||
278 | * @param result final datastore lookup result | ||
279 | */ | ||
280 | void | ||
281 | GSF_consider_forwarding (void *cls, | ||
282 | struct GSF_PendingRequest *pr, | ||
283 | enum GNUNET_BLOCK_ReplyEvaluationResult result); | ||
284 | |||
285 | |||
286 | /** | ||
287 | * Test if the DATABASE (GET) load on this peer is too high | ||
288 | * to even consider processing the query at | ||
289 | * all. | ||
290 | * | ||
291 | * @return #GNUNET_YES if the load is too high to do anything (load high) | ||
292 | * #GNUNET_NO to process normally (load normal) | ||
293 | * #GNUNET_SYSERR to process for free (load low) | ||
294 | */ | ||
295 | int | ||
296 | GSF_test_get_load_too_high_ (uint32_t priority); | ||
297 | |||
298 | |||
299 | /** | ||
300 | * We've just now completed a datastore request. Update our | ||
301 | * datastore load calculations. | ||
302 | * | ||
303 | * @param start time when the datastore request was issued | ||
304 | */ | ||
305 | void | ||
306 | GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start); | ||
307 | |||
308 | |||
309 | #endif | ||
310 | /* end of gnunet-service-fs.h */ | ||
diff --git a/src/fs/gnunet-service-fs_cadet.h b/src/fs/gnunet-service-fs_cadet.h deleted file mode 100644 index c02021a0d..000000000 --- a/src/fs/gnunet-service-fs_cadet.h +++ /dev/null | |||
@@ -1,168 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_cadet.h | ||
23 | * @brief non-anonymous file-transfer | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_FS_CADET_H | ||
27 | #define GNUNET_SERVICE_FS_CADET_H | ||
28 | |||
29 | /** | ||
30 | * Handle for a request that is going out via cadet API. | ||
31 | */ | ||
32 | struct GSF_CadetRequest; | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Function called with a reply from the cadet. | ||
37 | * | ||
38 | * @param cls closure | ||
39 | * @param type type of the block, ANY on error | ||
40 | * @param expiration expiration time for the block | ||
41 | * @param data_size number of bytes in @a data, 0 on error | ||
42 | * @param data reply block data, NULL on error | ||
43 | */ | ||
44 | typedef void | ||
45 | (*GSF_CadetReplyProcessor)(void *cls, | ||
46 | enum GNUNET_BLOCK_Type type, | ||
47 | struct GNUNET_TIME_Absolute expiration, | ||
48 | size_t data_size, | ||
49 | const void *data); | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Look for a block by directly contacting a particular peer. | ||
54 | * | ||
55 | * @param target peer that should have the block | ||
56 | * @param query hash to query for the block | ||
57 | * @param type desired type for the block | ||
58 | * @param proc function to call with result | ||
59 | * @param proc_cls closure for @a proc | ||
60 | * @return handle to cancel the operation | ||
61 | */ | ||
62 | struct GSF_CadetRequest * | ||
63 | GSF_cadet_query (const struct GNUNET_PeerIdentity *target, | ||
64 | const struct GNUNET_HashCode *query, | ||
65 | enum GNUNET_BLOCK_Type type, | ||
66 | GSF_CadetReplyProcessor proc, | ||
67 | void *proc_cls); | ||
68 | |||
69 | /** | ||
70 | * Function called on each active cadets to shut them down. | ||
71 | * | ||
72 | * @param cls NULL | ||
73 | * @param key target peer, unused | ||
74 | * @param value the `struct CadetHandle` to destroy | ||
75 | * @return #GNUNET_YES (continue to iterate) | ||
76 | */ | ||
77 | int | ||
78 | GSF_cadet_release_clients (void *cls, | ||
79 | const struct GNUNET_PeerIdentity *key, | ||
80 | void *value); | ||
81 | |||
82 | |||
83 | /** | ||
84 | * Cancel an active request; must not be called after 'proc' | ||
85 | * was called. | ||
86 | * | ||
87 | * @param sr request to cancel | ||
88 | */ | ||
89 | void | ||
90 | GSF_cadet_query_cancel (struct GSF_CadetRequest *sr); | ||
91 | |||
92 | |||
93 | /** | ||
94 | * Initialize subsystem for non-anonymous file-sharing. | ||
95 | */ | ||
96 | void | ||
97 | GSF_cadet_start_server (void); | ||
98 | |||
99 | |||
100 | /** | ||
101 | * Shutdown subsystem for non-anonymous file-sharing. | ||
102 | */ | ||
103 | void | ||
104 | GSF_cadet_stop_server (void); | ||
105 | |||
106 | /** | ||
107 | * Cadet channel for creating outbound channels. | ||
108 | */ | ||
109 | extern struct GNUNET_CADET_Handle *cadet_handle; | ||
110 | |||
111 | /** | ||
112 | * Map from peer identities to 'struct CadetHandles' with cadet | ||
113 | * channels to those peers. | ||
114 | */ | ||
115 | extern struct GNUNET_CONTAINER_MultiPeerMap *cadet_map; | ||
116 | |||
117 | |||
118 | GNUNET_NETWORK_STRUCT_BEGIN | ||
119 | |||
120 | /** | ||
121 | * Query from one peer, asking the other for CHK-data. | ||
122 | */ | ||
123 | struct CadetQueryMessage | ||
124 | { | ||
125 | /** | ||
126 | * Type is GNUNET_MESSAGE_TYPE_FS_CADET_QUERY. | ||
127 | */ | ||
128 | struct GNUNET_MessageHeader header; | ||
129 | |||
130 | /** | ||
131 | * Block type must be DBLOCK or IBLOCK. | ||
132 | */ | ||
133 | uint32_t type GNUNET_PACKED; | ||
134 | |||
135 | /** | ||
136 | * Query hash from CHK (hash of encrypted block). | ||
137 | */ | ||
138 | struct GNUNET_HashCode query; | ||
139 | }; | ||
140 | |||
141 | |||
142 | /** | ||
143 | * Reply to a CadetQueryMessage. | ||
144 | */ | ||
145 | struct CadetReplyMessage | ||
146 | { | ||
147 | /** | ||
148 | * Type is GNUNET_MESSAGE_TYPE_FS_CADET_REPLY. | ||
149 | */ | ||
150 | struct GNUNET_MessageHeader header; | ||
151 | |||
152 | /** | ||
153 | * Block type must be DBLOCK or IBLOCK. | ||
154 | */ | ||
155 | uint32_t type GNUNET_PACKED; | ||
156 | |||
157 | /** | ||
158 | * Expiration time for the block. | ||
159 | */ | ||
160 | struct GNUNET_TIME_AbsoluteNBO expiration; | ||
161 | |||
162 | /* followed by the encrypted block */ | ||
163 | }; | ||
164 | |||
165 | GNUNET_NETWORK_STRUCT_END | ||
166 | |||
167 | |||
168 | #endif | ||
diff --git a/src/fs/gnunet-service-fs_cadet_client.c b/src/fs/gnunet-service-fs_cadet_client.c deleted file mode 100644 index 398fcd604..000000000 --- a/src/fs/gnunet-service-fs_cadet_client.c +++ /dev/null | |||
@@ -1,728 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_cadet_client.c | ||
23 | * @brief non-anonymous file-transfer | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - PORT is set to old application type, unsure if we should keep | ||
28 | * it that way (fine for now) | ||
29 | */ | ||
30 | #include "platform.h" | ||
31 | #include "gnunet_constants.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_cadet_service.h" | ||
34 | #include "gnunet_protocols.h" | ||
35 | #include "gnunet_applications.h" | ||
36 | #include "gnunet-service-fs.h" | ||
37 | #include "gnunet-service-fs_indexing.h" | ||
38 | #include "gnunet-service-fs_cadet.h" | ||
39 | |||
40 | |||
41 | /** | ||
42 | * After how long do we reset connections without replies? | ||
43 | */ | ||
44 | #define CLIENT_RETRY_TIMEOUT \ | ||
45 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
46 | |||
47 | |||
48 | /** | ||
49 | * Handle for a cadet to another peer. | ||
50 | */ | ||
51 | struct CadetHandle; | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Handle for a request that is going out via cadet API. | ||
56 | */ | ||
57 | struct GSF_CadetRequest | ||
58 | { | ||
59 | /** | ||
60 | * DLL. | ||
61 | */ | ||
62 | struct GSF_CadetRequest *next; | ||
63 | |||
64 | /** | ||
65 | * DLL. | ||
66 | */ | ||
67 | struct GSF_CadetRequest *prev; | ||
68 | |||
69 | /** | ||
70 | * Which cadet is this request associated with? | ||
71 | */ | ||
72 | struct CadetHandle *mh; | ||
73 | |||
74 | /** | ||
75 | * Function to call with the result. | ||
76 | */ | ||
77 | GSF_CadetReplyProcessor proc; | ||
78 | |||
79 | /** | ||
80 | * Closure for @e proc | ||
81 | */ | ||
82 | void *proc_cls; | ||
83 | |||
84 | /** | ||
85 | * Query to transmit to the other peer. | ||
86 | */ | ||
87 | struct GNUNET_HashCode query; | ||
88 | |||
89 | /** | ||
90 | * Desired type for the reply. | ||
91 | */ | ||
92 | enum GNUNET_BLOCK_Type type; | ||
93 | |||
94 | /** | ||
95 | * Did we transmit this request already? #GNUNET_YES if we are | ||
96 | * in the 'waiting_map', #GNUNET_NO if we are in the 'pending' DLL. | ||
97 | */ | ||
98 | int was_transmitted; | ||
99 | }; | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Handle for a cadet to another peer. | ||
104 | */ | ||
105 | struct CadetHandle | ||
106 | { | ||
107 | /** | ||
108 | * Head of DLL of pending requests on this cadet. | ||
109 | */ | ||
110 | struct GSF_CadetRequest *pending_head; | ||
111 | |||
112 | /** | ||
113 | * Tail of DLL of pending requests on this cadet. | ||
114 | */ | ||
115 | struct GSF_CadetRequest *pending_tail; | ||
116 | |||
117 | /** | ||
118 | * Map from query to `struct GSF_CadetRequest`s waiting for | ||
119 | * a reply. | ||
120 | */ | ||
121 | struct GNUNET_CONTAINER_MultiHashMap *waiting_map; | ||
122 | |||
123 | /** | ||
124 | * Channel to the other peer. | ||
125 | */ | ||
126 | struct GNUNET_CADET_Channel *channel; | ||
127 | |||
128 | /** | ||
129 | * Which peer does this cadet go to? | ||
130 | */ | ||
131 | struct GNUNET_PeerIdentity target; | ||
132 | |||
133 | /** | ||
134 | * Task to kill inactive cadets (we keep them around for | ||
135 | * a few seconds to give the application a chance to give | ||
136 | * us another query). | ||
137 | */ | ||
138 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
139 | |||
140 | /** | ||
141 | * Task to reset cadets that had errors (asynchronously, | ||
142 | * as we may not be able to do it immediately during a | ||
143 | * callback from the cadet API). | ||
144 | */ | ||
145 | struct GNUNET_SCHEDULER_Task *reset_task; | ||
146 | }; | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Cadet channel for creating outbound channels. | ||
151 | */ | ||
152 | struct GNUNET_CADET_Handle *cadet_handle; | ||
153 | |||
154 | /** | ||
155 | * Map from peer identities to 'struct CadetHandles' with cadet | ||
156 | * channels to those peers. | ||
157 | */ | ||
158 | struct GNUNET_CONTAINER_MultiPeerMap *cadet_map; | ||
159 | |||
160 | |||
161 | /* ********************* client-side code ************************* */ | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Transmit pending requests via the cadet. | ||
166 | * | ||
167 | * @param cls `struct CadetHandle` to process | ||
168 | */ | ||
169 | static void | ||
170 | transmit_pending (void *cls); | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Iterator called on each entry in a waiting map to | ||
175 | * move it back to the pending list. | ||
176 | * | ||
177 | * @param cls the `struct CadetHandle` | ||
178 | * @param key the key of the entry in the map (the query) | ||
179 | * @param value the `struct GSF_CadetRequest` to move to pending | ||
180 | * @return #GNUNET_YES (continue to iterate) | ||
181 | */ | ||
182 | static int | ||
183 | move_to_pending (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
184 | { | ||
185 | struct CadetHandle *mh = cls; | ||
186 | struct GSF_CadetRequest *sr = value; | ||
187 | |||
188 | GNUNET_assert ( | ||
189 | GNUNET_YES == | ||
190 | GNUNET_CONTAINER_multihashmap_remove (mh->waiting_map, key, value)); | ||
191 | GNUNET_CONTAINER_DLL_insert (mh->pending_head, mh->pending_tail, sr); | ||
192 | sr->was_transmitted = GNUNET_NO; | ||
193 | return GNUNET_YES; | ||
194 | } | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Functions with this signature are called whenever a complete reply | ||
199 | * is received. | ||
200 | * | ||
201 | * @param cls closure with the `struct CadetHandle` | ||
202 | * @param srm the actual message | ||
203 | * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing | ||
204 | */ | ||
205 | static int | ||
206 | check_reply (void *cls, const struct CadetReplyMessage *srm) | ||
207 | { | ||
208 | /* We check later... */ | ||
209 | return GNUNET_OK; | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Task called when it is time to reset an cadet. | ||
215 | * | ||
216 | * @param cls the `struct CadetHandle` to tear down | ||
217 | */ | ||
218 | static void | ||
219 | reset_cadet_task (void *cls); | ||
220 | |||
221 | |||
222 | /** | ||
223 | * We had a serious error, tear down and re-create cadet from scratch, | ||
224 | * but do so asynchronously. | ||
225 | * | ||
226 | * @param mh cadet to reset | ||
227 | */ | ||
228 | static void | ||
229 | reset_cadet_async (struct CadetHandle *mh) | ||
230 | { | ||
231 | if (NULL != mh->reset_task) | ||
232 | GNUNET_SCHEDULER_cancel (mh->reset_task); | ||
233 | mh->reset_task = GNUNET_SCHEDULER_add_now (&reset_cadet_task, mh); | ||
234 | } | ||
235 | |||
236 | |||
237 | /** | ||
238 | * Closure for handle_reply(). | ||
239 | */ | ||
240 | struct HandleReplyClosure | ||
241 | { | ||
242 | /** | ||
243 | * Reply payload. | ||
244 | */ | ||
245 | const void *data; | ||
246 | |||
247 | /** | ||
248 | * Expiration time for the block. | ||
249 | */ | ||
250 | struct GNUNET_TIME_Absolute expiration; | ||
251 | |||
252 | /** | ||
253 | * Number of bytes in @e data. | ||
254 | */ | ||
255 | size_t data_size; | ||
256 | |||
257 | /** | ||
258 | * Type of the block. | ||
259 | */ | ||
260 | enum GNUNET_BLOCK_Type type; | ||
261 | |||
262 | /** | ||
263 | * Did we have a matching query? | ||
264 | */ | ||
265 | int found; | ||
266 | }; | ||
267 | |||
268 | |||
269 | /** | ||
270 | * Iterator called on each entry in a waiting map to | ||
271 | * process a result. | ||
272 | * | ||
273 | * @param cls the `struct HandleReplyClosure` | ||
274 | * @param key the key of the entry in the map (the query) | ||
275 | * @param value the `struct GSF_CadetRequest` to handle result for | ||
276 | * @return #GNUNET_YES (continue to iterate) | ||
277 | */ | ||
278 | static int | ||
279 | process_reply (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
280 | { | ||
281 | struct HandleReplyClosure *hrc = cls; | ||
282 | struct GSF_CadetRequest *sr = value; | ||
283 | |||
284 | sr->proc (sr->proc_cls, | ||
285 | hrc->type, | ||
286 | hrc->expiration, | ||
287 | hrc->data_size, | ||
288 | hrc->data); | ||
289 | sr->proc = NULL; | ||
290 | GSF_cadet_query_cancel (sr); | ||
291 | hrc->found = GNUNET_YES; | ||
292 | return GNUNET_YES; | ||
293 | } | ||
294 | |||
295 | |||
296 | /** | ||
297 | * Iterator called on each entry in a waiting map to | ||
298 | * call the 'proc' continuation and release associated | ||
299 | * resources. | ||
300 | * | ||
301 | * @param cls the `struct CadetHandle` | ||
302 | * @param key the key of the entry in the map (the query) | ||
303 | * @param value the `struct GSF_CadetRequest` to clean up | ||
304 | * @return #GNUNET_YES (continue to iterate) | ||
305 | */ | ||
306 | static int | ||
307 | free_waiting_entry (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
308 | { | ||
309 | struct GSF_CadetRequest *sr = value; | ||
310 | |||
311 | GSF_cadet_query_cancel (sr); | ||
312 | return GNUNET_YES; | ||
313 | } | ||
314 | |||
315 | |||
316 | /** | ||
317 | * Functions with this signature are called whenever a complete reply | ||
318 | * is received. | ||
319 | * | ||
320 | * @param cls closure with the `struct CadetHandle` | ||
321 | * @param srm the actual message | ||
322 | */ | ||
323 | static void | ||
324 | handle_reply (void *cls, const struct CadetReplyMessage *srm) | ||
325 | { | ||
326 | struct CadetHandle *mh = cls; | ||
327 | struct HandleReplyClosure hrc; | ||
328 | uint16_t msize; | ||
329 | enum GNUNET_BLOCK_Type type; | ||
330 | struct GNUNET_HashCode query; | ||
331 | |||
332 | msize = ntohs (srm->header.size) - sizeof(struct CadetReplyMessage); | ||
333 | type = (enum GNUNET_BLOCK_Type) ntohl (srm->type); | ||
334 | if (GNUNET_YES != | ||
335 | GNUNET_BLOCK_get_key (GSF_block_ctx, type, &srm[1], msize, &query)) | ||
336 | { | ||
337 | GNUNET_break_op (0); | ||
338 | GNUNET_log ( | ||
339 | GNUNET_ERROR_TYPE_WARNING, | ||
340 | "Received bogus reply of type %u with %u bytes via cadet from peer %s\n", | ||
341 | type, | ||
342 | msize, | ||
343 | GNUNET_i2s (&mh->target)); | ||
344 | reset_cadet_async (mh); | ||
345 | return; | ||
346 | } | ||
347 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
348 | "Received reply `%s' via cadet from peer %s\n", | ||
349 | GNUNET_h2s (&query), | ||
350 | GNUNET_i2s (&mh->target)); | ||
351 | GNUNET_CADET_receive_done (mh->channel); | ||
352 | GNUNET_STATISTICS_update (GSF_stats, | ||
353 | gettext_noop ("# replies received via cadet"), | ||
354 | 1, | ||
355 | GNUNET_NO); | ||
356 | hrc.data = &srm[1]; | ||
357 | hrc.data_size = msize; | ||
358 | hrc.expiration = GNUNET_TIME_absolute_ntoh (srm->expiration); | ||
359 | hrc.type = type; | ||
360 | hrc.found = GNUNET_NO; | ||
361 | GNUNET_CONTAINER_multihashmap_get_multiple (mh->waiting_map, | ||
362 | &query, | ||
363 | &process_reply, | ||
364 | &hrc); | ||
365 | if (GNUNET_NO == hrc.found) | ||
366 | { | ||
367 | GNUNET_STATISTICS_update (GSF_stats, | ||
368 | gettext_noop ( | ||
369 | "# replies received via cadet dropped"), | ||
370 | 1, | ||
371 | GNUNET_NO); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | |||
376 | /** | ||
377 | * Function called by cadet when a client disconnects. | ||
378 | * Cleans up our `struct CadetClient` of that channel. | ||
379 | * | ||
380 | * @param cls our `struct CadetClient` | ||
381 | * @param channel channel of the disconnecting client | ||
382 | */ | ||
383 | static void | ||
384 | disconnect_cb (void *cls, const struct GNUNET_CADET_Channel *channel) | ||
385 | { | ||
386 | struct CadetHandle *mh = cls; | ||
387 | struct GSF_CadetRequest *sr; | ||
388 | |||
389 | if (NULL == mh->channel) | ||
390 | return; /* being destroyed elsewhere */ | ||
391 | GNUNET_assert (channel == mh->channel); | ||
392 | mh->channel = NULL; | ||
393 | while (NULL != (sr = mh->pending_head)) | ||
394 | GSF_cadet_query_cancel (sr); | ||
395 | /* first remove `mh` from the `cadet_map`, so that if the | ||
396 | callback from `free_waiting_entry()` happens to re-issue | ||
397 | the request, we don't immediately have it back in the | ||
398 | `waiting_map`. */ | ||
399 | GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (cadet_map, | ||
400 | &mh->target, | ||
401 | mh)); | ||
402 | GNUNET_CONTAINER_multihashmap_iterate (mh->waiting_map, | ||
403 | &free_waiting_entry, | ||
404 | mh); | ||
405 | if (NULL != mh->timeout_task) | ||
406 | GNUNET_SCHEDULER_cancel (mh->timeout_task); | ||
407 | if (NULL != mh->reset_task) | ||
408 | GNUNET_SCHEDULER_cancel (mh->reset_task); | ||
409 | GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (mh->waiting_map)); | ||
410 | GNUNET_CONTAINER_multihashmap_destroy (mh->waiting_map); | ||
411 | GNUNET_free (mh); | ||
412 | } | ||
413 | |||
414 | |||
415 | /** | ||
416 | * Function called whenever an MQ-channel's transmission window size changes. | ||
417 | * | ||
418 | * The first callback in an outgoing channel will be with a non-zero value | ||
419 | * and will mean the channel is connected to the destination. | ||
420 | * | ||
421 | * For an incoming channel it will be called immediately after the | ||
422 | * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value. | ||
423 | * | ||
424 | * @param cls Channel closure. | ||
425 | * @param channel Connection to the other end (henceforth invalid). | ||
426 | * @param window_size New window size. If the is more messages than buffer size | ||
427 | * this value will be negative.. | ||
428 | */ | ||
429 | static void | ||
430 | window_change_cb (void *cls, | ||
431 | const struct GNUNET_CADET_Channel *channel, | ||
432 | int window_size) | ||
433 | { | ||
434 | /* FIXME: for flow control, implement? */ | ||
435 | #if 0 | ||
436 | /* Something like this instead of the GNUNET_MQ_notify_sent() in | ||
437 | transmit_pending() might be good (once the window change CB works...) */ | ||
438 | if (0 < window_size) /* test needed? */ | ||
439 | transmit_pending (mh); | ||
440 | #endif | ||
441 | } | ||
442 | |||
443 | |||
444 | /** | ||
445 | * We had a serious error, tear down and re-create cadet from scratch. | ||
446 | * | ||
447 | * @param mh cadet to reset | ||
448 | */ | ||
449 | static void | ||
450 | reset_cadet (struct CadetHandle *mh) | ||
451 | { | ||
452 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
453 | "Resetting cadet channel to %s\n", | ||
454 | GNUNET_i2s (&mh->target)); | ||
455 | if (NULL != mh->channel) | ||
456 | { | ||
457 | GNUNET_CADET_channel_destroy (mh->channel); | ||
458 | mh->channel = NULL; | ||
459 | } | ||
460 | GNUNET_CONTAINER_multihashmap_iterate (mh->waiting_map, &move_to_pending, mh); | ||
461 | { | ||
462 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
463 | { GNUNET_MQ_hd_var_size (reply, | ||
464 | GNUNET_MESSAGE_TYPE_FS_CADET_REPLY, | ||
465 | struct CadetReplyMessage, | ||
466 | mh), | ||
467 | GNUNET_MQ_handler_end () }; | ||
468 | struct GNUNET_HashCode port; | ||
469 | |||
470 | GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER, | ||
471 | strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER), | ||
472 | &port); | ||
473 | mh->channel = GNUNET_CADET_channel_create (cadet_handle, | ||
474 | mh, | ||
475 | &mh->target, | ||
476 | &port, | ||
477 | &window_change_cb, | ||
478 | &disconnect_cb, | ||
479 | handlers); | ||
480 | } | ||
481 | transmit_pending (mh); | ||
482 | } | ||
483 | |||
484 | |||
485 | /** | ||
486 | * Task called when it is time to destroy an inactive cadet channel. | ||
487 | * | ||
488 | * @param cls the `struct CadetHandle` to tear down | ||
489 | */ | ||
490 | static void | ||
491 | cadet_timeout (void *cls) | ||
492 | { | ||
493 | struct CadetHandle *mh = cls; | ||
494 | struct GNUNET_CADET_Channel *tun; | ||
495 | |||
496 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
497 | "Timeout on cadet channel to %s\n", | ||
498 | GNUNET_i2s (&mh->target)); | ||
499 | mh->timeout_task = NULL; | ||
500 | tun = mh->channel; | ||
501 | mh->channel = NULL; | ||
502 | if (NULL != tun) | ||
503 | GNUNET_CADET_channel_destroy (tun); | ||
504 | } | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Task called when it is time to reset an cadet. | ||
509 | * | ||
510 | * @param cls the `struct CadetHandle` to tear down | ||
511 | */ | ||
512 | static void | ||
513 | reset_cadet_task (void *cls) | ||
514 | { | ||
515 | struct CadetHandle *mh = cls; | ||
516 | |||
517 | mh->reset_task = NULL; | ||
518 | reset_cadet (mh); | ||
519 | } | ||
520 | |||
521 | |||
522 | /** | ||
523 | * Transmit pending requests via the cadet. | ||
524 | * | ||
525 | * @param cls `struct CadetHandle` to process | ||
526 | */ | ||
527 | static void | ||
528 | transmit_pending (void *cls) | ||
529 | { | ||
530 | struct CadetHandle *mh = cls; | ||
531 | struct GNUNET_MQ_Handle *mq = GNUNET_CADET_get_mq (mh->channel); | ||
532 | struct GSF_CadetRequest *sr; | ||
533 | struct GNUNET_MQ_Envelope *env; | ||
534 | struct CadetQueryMessage *sqm; | ||
535 | |||
536 | if ((0 != GNUNET_MQ_get_length (mq)) || (NULL == (sr = mh->pending_head))) | ||
537 | return; | ||
538 | GNUNET_CONTAINER_DLL_remove (mh->pending_head, mh->pending_tail, sr); | ||
539 | GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put ( | ||
540 | mh->waiting_map, | ||
541 | &sr->query, | ||
542 | sr, | ||
543 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
544 | sr->was_transmitted = GNUNET_YES; | ||
545 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
546 | "Sending query for %s via cadet to %s\n", | ||
547 | GNUNET_h2s (&sr->query), | ||
548 | GNUNET_i2s (&mh->target)); | ||
549 | env = GNUNET_MQ_msg (sqm, GNUNET_MESSAGE_TYPE_FS_CADET_QUERY); | ||
550 | GNUNET_MQ_env_set_options (env, | ||
551 | GNUNET_MQ_PREF_GOODPUT | ||
552 | | GNUNET_MQ_PREF_CORK_ALLOWED | ||
553 | | GNUNET_MQ_PREF_OUT_OF_ORDER); | ||
554 | sqm->type = htonl (sr->type); | ||
555 | sqm->query = sr->query; | ||
556 | GNUNET_MQ_notify_sent (env, &transmit_pending, mh); | ||
557 | GNUNET_MQ_send (mq, env); | ||
558 | } | ||
559 | |||
560 | |||
561 | /** | ||
562 | * Get (or create) a cadet to talk to the given peer. | ||
563 | * | ||
564 | * @param target peer we want to communicate with | ||
565 | */ | ||
566 | static struct CadetHandle * | ||
567 | get_cadet (const struct GNUNET_PeerIdentity *target) | ||
568 | { | ||
569 | struct CadetHandle *mh; | ||
570 | |||
571 | mh = GNUNET_CONTAINER_multipeermap_get (cadet_map, target); | ||
572 | if (NULL != mh) | ||
573 | { | ||
574 | if (NULL != mh->timeout_task) | ||
575 | { | ||
576 | GNUNET_SCHEDULER_cancel (mh->timeout_task); | ||
577 | mh->timeout_task = NULL; | ||
578 | } | ||
579 | return mh; | ||
580 | } | ||
581 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
582 | "Creating cadet channel to %s\n", | ||
583 | GNUNET_i2s (target)); | ||
584 | mh = GNUNET_new (struct CadetHandle); | ||
585 | mh->reset_task = | ||
586 | GNUNET_SCHEDULER_add_delayed (CLIENT_RETRY_TIMEOUT, &reset_cadet_task, mh); | ||
587 | mh->waiting_map = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES); | ||
588 | mh->target = *target; | ||
589 | GNUNET_assert (GNUNET_OK == | ||
590 | GNUNET_CONTAINER_multipeermap_put ( | ||
591 | cadet_map, | ||
592 | &mh->target, | ||
593 | mh, | ||
594 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
595 | { | ||
596 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
597 | { GNUNET_MQ_hd_var_size (reply, | ||
598 | GNUNET_MESSAGE_TYPE_FS_CADET_REPLY, | ||
599 | struct CadetReplyMessage, | ||
600 | mh), | ||
601 | GNUNET_MQ_handler_end () }; | ||
602 | struct GNUNET_HashCode port; | ||
603 | |||
604 | GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER, | ||
605 | strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER), | ||
606 | &port); | ||
607 | mh->channel = GNUNET_CADET_channel_create (cadet_handle, | ||
608 | mh, | ||
609 | &mh->target, | ||
610 | &port, | ||
611 | &window_change_cb, | ||
612 | &disconnect_cb, | ||
613 | handlers); | ||
614 | } | ||
615 | return mh; | ||
616 | } | ||
617 | |||
618 | |||
619 | /** | ||
620 | * Look for a block by directly contacting a particular peer. | ||
621 | * | ||
622 | * @param target peer that should have the block | ||
623 | * @param query hash to query for the block | ||
624 | * @param type desired type for the block | ||
625 | * @param proc function to call with result | ||
626 | * @param proc_cls closure for @a proc | ||
627 | * @return handle to cancel the operation | ||
628 | */ | ||
629 | struct GSF_CadetRequest * | ||
630 | GSF_cadet_query (const struct GNUNET_PeerIdentity *target, | ||
631 | const struct GNUNET_HashCode *query, | ||
632 | enum GNUNET_BLOCK_Type type, | ||
633 | GSF_CadetReplyProcessor proc, | ||
634 | void *proc_cls) | ||
635 | { | ||
636 | struct CadetHandle *mh; | ||
637 | struct GSF_CadetRequest *sr; | ||
638 | |||
639 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
640 | "Preparing to send query for %s via cadet to %s\n", | ||
641 | GNUNET_h2s (query), | ||
642 | GNUNET_i2s (target)); | ||
643 | mh = get_cadet (target); | ||
644 | sr = GNUNET_new (struct GSF_CadetRequest); | ||
645 | sr->mh = mh; | ||
646 | sr->proc = proc; | ||
647 | sr->proc_cls = proc_cls; | ||
648 | sr->type = type; | ||
649 | sr->query = *query; | ||
650 | GNUNET_CONTAINER_DLL_insert (mh->pending_head, mh->pending_tail, sr); | ||
651 | transmit_pending (mh); | ||
652 | return sr; | ||
653 | } | ||
654 | |||
655 | |||
656 | /** | ||
657 | * Cancel an active request; must not be called after 'proc' | ||
658 | * was called. | ||
659 | * | ||
660 | * @param sr request to cancel | ||
661 | */ | ||
662 | void | ||
663 | GSF_cadet_query_cancel (struct GSF_CadetRequest *sr) | ||
664 | { | ||
665 | struct CadetHandle *mh = sr->mh; | ||
666 | GSF_CadetReplyProcessor p; | ||
667 | |||
668 | p = sr->proc; | ||
669 | sr->proc = NULL; | ||
670 | if (NULL != p) | ||
671 | { | ||
672 | /* signal failure / cancellation to callback */ | ||
673 | p (sr->proc_cls, GNUNET_BLOCK_TYPE_ANY, GNUNET_TIME_UNIT_ZERO_ABS, 0, NULL); | ||
674 | } | ||
675 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
676 | "Cancelled query for %s via cadet to %s\n", | ||
677 | GNUNET_h2s (&sr->query), | ||
678 | GNUNET_i2s (&sr->mh->target)); | ||
679 | if (GNUNET_YES == sr->was_transmitted) | ||
680 | GNUNET_assert ( | ||
681 | GNUNET_OK == | ||
682 | GNUNET_CONTAINER_multihashmap_remove (mh->waiting_map, &sr->query, sr)); | ||
683 | else | ||
684 | GNUNET_CONTAINER_DLL_remove (mh->pending_head, mh->pending_tail, sr); | ||
685 | GNUNET_free (sr); | ||
686 | if ((0 == GNUNET_CONTAINER_multihashmap_size (mh->waiting_map)) && | ||
687 | (NULL == mh->pending_head)) | ||
688 | mh->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
689 | &cadet_timeout, | ||
690 | mh); | ||
691 | } | ||
692 | |||
693 | |||
694 | /** | ||
695 | * Function called on each active cadets to shut them down. | ||
696 | * | ||
697 | * @param cls NULL | ||
698 | * @param key target peer, unused | ||
699 | * @param value the `struct CadetHandle` to destroy | ||
700 | * @return #GNUNET_YES (continue to iterate) | ||
701 | */ | ||
702 | int | ||
703 | GSF_cadet_release_clients (void *cls, | ||
704 | const struct GNUNET_PeerIdentity *key, | ||
705 | void *value) | ||
706 | { | ||
707 | struct CadetHandle *mh = value; | ||
708 | |||
709 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
710 | "Timeout on cadet channel to %s\n", | ||
711 | GNUNET_i2s (&mh->target)); | ||
712 | if (NULL != mh->channel) | ||
713 | { | ||
714 | struct GNUNET_CADET_Channel *channel = mh->channel; | ||
715 | |||
716 | mh->channel = NULL; | ||
717 | GNUNET_CADET_channel_destroy (channel); | ||
718 | } | ||
719 | if (NULL != mh->reset_task) | ||
720 | { | ||
721 | GNUNET_SCHEDULER_cancel (mh->reset_task); | ||
722 | mh->reset_task = NULL; | ||
723 | } | ||
724 | return GNUNET_YES; | ||
725 | } | ||
726 | |||
727 | |||
728 | /* end of gnunet-service-fs_cadet_client.c */ | ||
diff --git a/src/fs/gnunet-service-fs_cadet_server.c b/src/fs/gnunet-service-fs_cadet_server.c deleted file mode 100644 index 395842ebb..000000000 --- a/src/fs/gnunet-service-fs_cadet_server.c +++ /dev/null | |||
@@ -1,546 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2013, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_cadet_server.c | ||
23 | * @brief non-anonymous file-transfer | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - PORT is set to old application type, unsure if we should keep | ||
28 | * it that way (fine for now) | ||
29 | */ | ||
30 | #include "platform.h" | ||
31 | #include "gnunet_constants.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_cadet_service.h" | ||
34 | #include "gnunet_protocols.h" | ||
35 | #include "gnunet_applications.h" | ||
36 | #include "gnunet-service-fs.h" | ||
37 | #include "gnunet-service-fs_indexing.h" | ||
38 | #include "gnunet-service-fs_cadet.h" | ||
39 | |||
40 | /** | ||
41 | * After how long do we termiante idle connections? | ||
42 | */ | ||
43 | #define IDLE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) | ||
44 | |||
45 | |||
46 | /** | ||
47 | * A message in the queue to be written to the cadet. | ||
48 | */ | ||
49 | struct WriteQueueItem | ||
50 | { | ||
51 | /** | ||
52 | * Kept in a DLL. | ||
53 | */ | ||
54 | struct WriteQueueItem *next; | ||
55 | |||
56 | /** | ||
57 | * Kept in a DLL. | ||
58 | */ | ||
59 | struct WriteQueueItem *prev; | ||
60 | |||
61 | /** | ||
62 | * Number of bytes of payload, allocated at the end of this struct. | ||
63 | */ | ||
64 | size_t msize; | ||
65 | }; | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Information we keep around for each active cadeting client. | ||
70 | */ | ||
71 | struct CadetClient | ||
72 | { | ||
73 | /** | ||
74 | * DLL | ||
75 | */ | ||
76 | struct CadetClient *next; | ||
77 | |||
78 | /** | ||
79 | * DLL | ||
80 | */ | ||
81 | struct CadetClient *prev; | ||
82 | |||
83 | /** | ||
84 | * Channel for communication. | ||
85 | */ | ||
86 | struct GNUNET_CADET_Channel *channel; | ||
87 | |||
88 | /** | ||
89 | * Head of write queue. | ||
90 | */ | ||
91 | struct WriteQueueItem *wqi_head; | ||
92 | |||
93 | /** | ||
94 | * Tail of write queue. | ||
95 | */ | ||
96 | struct WriteQueueItem *wqi_tail; | ||
97 | |||
98 | /** | ||
99 | * Current active request to the datastore, if we have one pending. | ||
100 | */ | ||
101 | struct GNUNET_DATASTORE_QueueEntry *qe; | ||
102 | |||
103 | /** | ||
104 | * Task that is scheduled to asynchronously terminate the connection. | ||
105 | */ | ||
106 | struct GNUNET_SCHEDULER_Task *terminate_task; | ||
107 | |||
108 | /** | ||
109 | * Task that is scheduled to terminate idle connections. | ||
110 | */ | ||
111 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
112 | |||
113 | /** | ||
114 | * Size of the last write that was initiated. | ||
115 | */ | ||
116 | size_t reply_size; | ||
117 | }; | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Listen port for incoming requests. | ||
122 | */ | ||
123 | static struct GNUNET_CADET_Port *cadet_port; | ||
124 | |||
125 | /** | ||
126 | * Head of DLL of cadet clients. | ||
127 | */ | ||
128 | static struct CadetClient *sc_head; | ||
129 | |||
130 | /** | ||
131 | * Tail of DLL of cadet clients. | ||
132 | */ | ||
133 | static struct CadetClient *sc_tail; | ||
134 | |||
135 | /** | ||
136 | * Number of active cadet clients in the 'sc_*'-DLL. | ||
137 | */ | ||
138 | static unsigned int sc_count; | ||
139 | |||
140 | /** | ||
141 | * Maximum allowed number of cadet clients. | ||
142 | */ | ||
143 | static unsigned long long sc_count_max; | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Task run to asynchronously terminate the cadet due to timeout. | ||
148 | * | ||
149 | * @param cls the 'struct CadetClient' | ||
150 | */ | ||
151 | static void | ||
152 | timeout_cadet_task (void *cls) | ||
153 | { | ||
154 | struct CadetClient *sc = cls; | ||
155 | struct GNUNET_CADET_Channel *tun; | ||
156 | |||
157 | sc->timeout_task = NULL; | ||
158 | tun = sc->channel; | ||
159 | sc->channel = NULL; | ||
160 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
161 | "Timeout for inactive cadet client %p\n", | ||
162 | sc); | ||
163 | GNUNET_CADET_channel_destroy (tun); | ||
164 | } | ||
165 | |||
166 | |||
167 | /** | ||
168 | * Reset the timeout for the cadet client (due to activity). | ||
169 | * | ||
170 | * @param sc client handle to reset timeout for | ||
171 | */ | ||
172 | static void | ||
173 | refresh_timeout_task (struct CadetClient *sc) | ||
174 | { | ||
175 | if (NULL != sc->timeout_task) | ||
176 | GNUNET_SCHEDULER_cancel (sc->timeout_task); | ||
177 | sc->timeout_task = GNUNET_SCHEDULER_add_delayed (IDLE_TIMEOUT, | ||
178 | &timeout_cadet_task, | ||
179 | sc); | ||
180 | } | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Check if we are done with the write queue, and if so tell CADET | ||
185 | * that we are ready to read more. | ||
186 | * | ||
187 | * @param cls where to process the write queue | ||
188 | */ | ||
189 | static void | ||
190 | continue_writing (void *cls) | ||
191 | { | ||
192 | struct CadetClient *sc = cls; | ||
193 | struct GNUNET_MQ_Handle *mq; | ||
194 | |||
195 | mq = GNUNET_CADET_get_mq (sc->channel); | ||
196 | if (0 != GNUNET_MQ_get_length (mq)) | ||
197 | { | ||
198 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
199 | "Write pending, waiting for it to complete\n"); | ||
200 | return; | ||
201 | } | ||
202 | refresh_timeout_task (sc); | ||
203 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
204 | "Finished processing cadet request from client %p, ready to receive the next one\n", | ||
205 | sc); | ||
206 | GNUNET_CADET_receive_done (sc->channel); | ||
207 | } | ||
208 | |||
209 | |||
210 | /** | ||
211 | * Process a datum that was stored in the datastore. | ||
212 | * | ||
213 | * @param cls closure with the `struct CadetClient` which sent the query | ||
214 | * @param key key for the content | ||
215 | * @param size number of bytes in @a data | ||
216 | * @param data content stored | ||
217 | * @param type type of the content | ||
218 | * @param priority priority of the content | ||
219 | * @param anonymity anonymity-level for the content | ||
220 | * @param replication replication-level for the content | ||
221 | * @param expiration expiration time for the content | ||
222 | * @param uid unique identifier for the datum; | ||
223 | * maybe 0 if no unique identifier is available | ||
224 | */ | ||
225 | static void | ||
226 | handle_datastore_reply (void *cls, | ||
227 | const struct GNUNET_HashCode *key, | ||
228 | size_t size, | ||
229 | const void *data, | ||
230 | enum GNUNET_BLOCK_Type type, | ||
231 | uint32_t priority, | ||
232 | uint32_t anonymity, | ||
233 | uint32_t replication, | ||
234 | struct GNUNET_TIME_Absolute expiration, | ||
235 | uint64_t uid) | ||
236 | { | ||
237 | struct CadetClient *sc = cls; | ||
238 | size_t msize = size + sizeof(struct CadetReplyMessage); | ||
239 | struct GNUNET_MQ_Envelope *env; | ||
240 | struct CadetReplyMessage *srm; | ||
241 | |||
242 | sc->qe = NULL; | ||
243 | if (NULL == data) | ||
244 | { | ||
245 | /* no result, this should not really happen, as for | ||
246 | non-anonymous routing only peers that HAVE the | ||
247 | answers should be queried; OTOH, this is not a | ||
248 | hard error as we might have had the answer in the | ||
249 | past and the user might have unindexed it. Hence | ||
250 | we log at level "INFO" for now. */if (NULL == key) | ||
251 | { | ||
252 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
253 | "Have no answer and the query was NULL\n"); | ||
254 | } | ||
255 | else | ||
256 | { | ||
257 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
258 | "Have no answer for query `%s'\n", | ||
259 | GNUNET_h2s (key)); | ||
260 | } | ||
261 | GNUNET_STATISTICS_update (GSF_stats, | ||
262 | gettext_noop ( | ||
263 | "# queries received via CADET not answered"), | ||
264 | 1, | ||
265 | GNUNET_NO); | ||
266 | continue_writing (sc); | ||
267 | return; | ||
268 | } | ||
269 | if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type) | ||
270 | { | ||
271 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
272 | "Performing on-demand encoding for query %s\n", | ||
273 | GNUNET_h2s (key)); | ||
274 | if (GNUNET_OK != | ||
275 | GNUNET_FS_handle_on_demand_block (key, | ||
276 | size, | ||
277 | data, | ||
278 | type, | ||
279 | priority, | ||
280 | anonymity, | ||
281 | replication, | ||
282 | expiration, | ||
283 | uid, | ||
284 | &handle_datastore_reply, | ||
285 | sc)) | ||
286 | { | ||
287 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
288 | "On-demand encoding request failed\n"); | ||
289 | continue_writing (sc); | ||
290 | } | ||
291 | return; | ||
292 | } | ||
293 | if (msize > GNUNET_MAX_MESSAGE_SIZE) | ||
294 | { | ||
295 | GNUNET_break (0); | ||
296 | continue_writing (sc); | ||
297 | return; | ||
298 | } | ||
299 | GNUNET_break (GNUNET_BLOCK_TYPE_ANY != type); | ||
300 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
301 | "Starting transmission of %u byte reply of type %d for query `%s' via cadet to %p\n", | ||
302 | (unsigned int) size, | ||
303 | (unsigned int) type, | ||
304 | GNUNET_h2s (key), | ||
305 | sc); | ||
306 | env = GNUNET_MQ_msg_extra (srm, | ||
307 | size, | ||
308 | GNUNET_MESSAGE_TYPE_FS_CADET_REPLY); | ||
309 | srm->type = htonl (type); | ||
310 | srm->expiration = GNUNET_TIME_absolute_hton (expiration); | ||
311 | GNUNET_memcpy (&srm[1], | ||
312 | data, | ||
313 | size); | ||
314 | GNUNET_MQ_notify_sent (env, | ||
315 | &continue_writing, | ||
316 | sc); | ||
317 | GNUNET_STATISTICS_update (GSF_stats, | ||
318 | gettext_noop ("# Blocks transferred via cadet"), | ||
319 | 1, | ||
320 | GNUNET_NO); | ||
321 | GNUNET_MQ_send (GNUNET_CADET_get_mq (sc->channel), | ||
322 | env); | ||
323 | } | ||
324 | |||
325 | |||
326 | /** | ||
327 | * Functions with this signature are called whenever a | ||
328 | * complete query message is received. | ||
329 | * | ||
330 | * @param cls closure with the `struct CadetClient` | ||
331 | * @param sqm the actual message | ||
332 | */ | ||
333 | static void | ||
334 | handle_request (void *cls, | ||
335 | const struct CadetQueryMessage *sqm) | ||
336 | { | ||
337 | struct CadetClient *sc = cls; | ||
338 | |||
339 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
340 | "Received query for `%s' via cadet from client %p\n", | ||
341 | GNUNET_h2s (&sqm->query), | ||
342 | sc); | ||
343 | GNUNET_STATISTICS_update (GSF_stats, | ||
344 | gettext_noop ("# queries received via cadet"), | ||
345 | 1, | ||
346 | GNUNET_NO); | ||
347 | refresh_timeout_task (sc); | ||
348 | sc->qe = GNUNET_DATASTORE_get_key (GSF_dsh, | ||
349 | 0 /* next_uid */, | ||
350 | false /* random */, | ||
351 | &sqm->query, | ||
352 | ntohl (sqm->type), | ||
353 | 0 /* priority */, | ||
354 | GSF_datastore_queue_size, | ||
355 | &handle_datastore_reply, | ||
356 | sc); | ||
357 | if (NULL == sc->qe) | ||
358 | { | ||
359 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
360 | "Queueing request with datastore failed (queue full?)\n"); | ||
361 | continue_writing (sc); | ||
362 | } | ||
363 | } | ||
364 | |||
365 | |||
366 | /** | ||
367 | * Functions of this type are called upon new cadet connection from other peers. | ||
368 | * | ||
369 | * @param cls the closure from GNUNET_CADET_connect | ||
370 | * @param channel the channel representing the cadet | ||
371 | * @param initiator the identity of the peer who wants to establish a cadet | ||
372 | * with us; NULL on binding error | ||
373 | * @return initial channel context (our `struct CadetClient`) | ||
374 | */ | ||
375 | static void * | ||
376 | connect_cb (void *cls, | ||
377 | struct GNUNET_CADET_Channel *channel, | ||
378 | const struct GNUNET_PeerIdentity *initiator) | ||
379 | { | ||
380 | struct CadetClient *sc; | ||
381 | |||
382 | GNUNET_assert (NULL != channel); | ||
383 | if (sc_count >= sc_count_max) | ||
384 | { | ||
385 | GNUNET_STATISTICS_update (GSF_stats, | ||
386 | gettext_noop ( | ||
387 | "# cadet client connections rejected"), | ||
388 | 1, | ||
389 | GNUNET_NO); | ||
390 | GNUNET_CADET_channel_destroy (channel); | ||
391 | return NULL; | ||
392 | } | ||
393 | GNUNET_STATISTICS_update (GSF_stats, | ||
394 | gettext_noop ("# cadet connections active"), | ||
395 | 1, | ||
396 | GNUNET_NO); | ||
397 | sc = GNUNET_new (struct CadetClient); | ||
398 | sc->channel = channel; | ||
399 | GNUNET_CONTAINER_DLL_insert (sc_head, | ||
400 | sc_tail, | ||
401 | sc); | ||
402 | sc_count++; | ||
403 | refresh_timeout_task (sc); | ||
404 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
405 | "Accepting inbound cadet connection from `%s' as client %p\n", | ||
406 | GNUNET_i2s (initiator), | ||
407 | sc); | ||
408 | return sc; | ||
409 | } | ||
410 | |||
411 | |||
412 | /** | ||
413 | * Function called by cadet when a client disconnects. | ||
414 | * Cleans up our `struct CadetClient` of that channel. | ||
415 | * | ||
416 | * @param cls our `struct CadetClient` | ||
417 | * @param channel channel of the disconnecting client | ||
418 | * @param channel_ctx | ||
419 | */ | ||
420 | static void | ||
421 | disconnect_cb (void *cls, | ||
422 | const struct GNUNET_CADET_Channel *channel) | ||
423 | { | ||
424 | struct CadetClient *sc = cls; | ||
425 | struct WriteQueueItem *wqi; | ||
426 | |||
427 | if (NULL == sc) | ||
428 | return; | ||
429 | sc->channel = NULL; | ||
430 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
431 | "Terminating cadet connection with client %p\n", | ||
432 | sc); | ||
433 | GNUNET_STATISTICS_update (GSF_stats, | ||
434 | gettext_noop ("# cadet connections active"), -1, | ||
435 | GNUNET_NO); | ||
436 | if (NULL != sc->terminate_task) | ||
437 | GNUNET_SCHEDULER_cancel (sc->terminate_task); | ||
438 | if (NULL != sc->timeout_task) | ||
439 | GNUNET_SCHEDULER_cancel (sc->timeout_task); | ||
440 | if (NULL != sc->qe) | ||
441 | GNUNET_DATASTORE_cancel (sc->qe); | ||
442 | while (NULL != (wqi = sc->wqi_head)) | ||
443 | { | ||
444 | GNUNET_CONTAINER_DLL_remove (sc->wqi_head, | ||
445 | sc->wqi_tail, | ||
446 | wqi); | ||
447 | GNUNET_free (wqi); | ||
448 | } | ||
449 | GNUNET_CONTAINER_DLL_remove (sc_head, | ||
450 | sc_tail, | ||
451 | sc); | ||
452 | sc_count--; | ||
453 | GNUNET_free (sc); | ||
454 | } | ||
455 | |||
456 | |||
457 | /** | ||
458 | * Function called whenever an MQ-channel's transmission window size changes. | ||
459 | * | ||
460 | * The first callback in an outgoing channel will be with a non-zero value | ||
461 | * and will mean the channel is connected to the destination. | ||
462 | * | ||
463 | * For an incoming channel it will be called immediately after the | ||
464 | * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value. | ||
465 | * | ||
466 | * @param cls Channel closure. | ||
467 | * @param channel Connection to the other end (henceforth invalid). | ||
468 | * @param window_size New window size. If the is more messages than buffer size | ||
469 | * this value will be negative.. | ||
470 | */ | ||
471 | static void | ||
472 | window_change_cb (void *cls, | ||
473 | const struct GNUNET_CADET_Channel *channel, | ||
474 | int window_size) | ||
475 | { | ||
476 | /* FIXME: could do flow control here... */ | ||
477 | } | ||
478 | |||
479 | |||
480 | /** | ||
481 | * Initialize subsystem for non-anonymous file-sharing. | ||
482 | */ | ||
483 | void | ||
484 | GSF_cadet_start_server () | ||
485 | { | ||
486 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
487 | GNUNET_MQ_hd_fixed_size (request, | ||
488 | GNUNET_MESSAGE_TYPE_FS_CADET_QUERY, | ||
489 | struct CadetQueryMessage, | ||
490 | NULL), | ||
491 | GNUNET_MQ_handler_end () | ||
492 | }; | ||
493 | struct GNUNET_HashCode port; | ||
494 | |||
495 | if (GNUNET_YES != | ||
496 | GNUNET_CONFIGURATION_get_value_number (GSF_cfg, | ||
497 | "fs", | ||
498 | "MAX_CADET_CLIENTS", | ||
499 | &sc_count_max)) | ||
500 | return; | ||
501 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
502 | "Initializing cadet FS server with a limit of %llu connections\n", | ||
503 | sc_count_max); | ||
504 | cadet_map = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES); | ||
505 | cadet_handle = GNUNET_CADET_connect (GSF_cfg); | ||
506 | GNUNET_assert (NULL != cadet_handle); | ||
507 | GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER, | ||
508 | strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER), | ||
509 | &port); | ||
510 | cadet_port = GNUNET_CADET_open_port (cadet_handle, | ||
511 | &port, | ||
512 | &connect_cb, | ||
513 | NULL, | ||
514 | &window_change_cb, | ||
515 | &disconnect_cb, | ||
516 | handlers); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * Shutdown subsystem for non-anonymous file-sharing. | ||
522 | */ | ||
523 | void | ||
524 | GSF_cadet_stop_server () | ||
525 | { | ||
526 | GNUNET_CONTAINER_multipeermap_iterate (cadet_map, | ||
527 | &GSF_cadet_release_clients, | ||
528 | NULL); | ||
529 | GNUNET_CONTAINER_multipeermap_destroy (cadet_map); | ||
530 | cadet_map = NULL; | ||
531 | if (NULL != cadet_port) | ||
532 | { | ||
533 | GNUNET_CADET_close_port (cadet_port); | ||
534 | cadet_port = NULL; | ||
535 | } | ||
536 | if (NULL != cadet_handle) | ||
537 | { | ||
538 | GNUNET_CADET_disconnect (cadet_handle); | ||
539 | cadet_handle = NULL; | ||
540 | } | ||
541 | GNUNET_assert (NULL == sc_head); | ||
542 | GNUNET_assert (0 == sc_count); | ||
543 | } | ||
544 | |||
545 | |||
546 | /* end of gnunet-service-fs_cadet.c */ | ||
diff --git a/src/fs/gnunet-service-fs_cp.c b/src/fs/gnunet-service-fs_cp.c deleted file mode 100644 index 5476aa2be..000000000 --- a/src/fs/gnunet-service-fs_cp.c +++ /dev/null | |||
@@ -1,1827 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/gnunet-service-fs_cp.c | ||
22 | * @brief API to handle 'connected peers' | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_load_lib.h" | ||
28 | #include "gnunet-service-fs.h" | ||
29 | #include "gnunet-service-fs_cp.h" | ||
30 | #include "gnunet-service-fs_pe.h" | ||
31 | #include "gnunet-service-fs_pr.h" | ||
32 | #include "gnunet-service-fs_push.h" | ||
33 | #include "gnunet_peerstore_service.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Ratio for moving average delay calculation. The previous | ||
38 | * average goes in with a factor of (n-1) into the calculation. | ||
39 | * Must be > 0. | ||
40 | */ | ||
41 | #define RUNAVG_DELAY_N 16 | ||
42 | |||
43 | /** | ||
44 | * How often do we flush respect values to disk? | ||
45 | */ | ||
46 | #define RESPECT_FLUSH_FREQ GNUNET_TIME_relative_multiply ( \ | ||
47 | GNUNET_TIME_UNIT_MINUTES, 5) | ||
48 | |||
49 | /** | ||
50 | * After how long do we discard a reply? | ||
51 | */ | ||
52 | #define REPLY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, \ | ||
53 | 2) | ||
54 | |||
55 | /** | ||
56 | * Collect an instance number of statistics? May cause excessive IPC. | ||
57 | */ | ||
58 | #define INSANE_STATISTICS GNUNET_NO | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Handle to cancel a transmission request. | ||
63 | */ | ||
64 | struct GSF_PeerTransmitHandle | ||
65 | { | ||
66 | /** | ||
67 | * Kept in a doubly-linked list. | ||
68 | */ | ||
69 | struct GSF_PeerTransmitHandle *next; | ||
70 | |||
71 | /** | ||
72 | * Kept in a doubly-linked list. | ||
73 | */ | ||
74 | struct GSF_PeerTransmitHandle *prev; | ||
75 | |||
76 | /** | ||
77 | * Time when this transmission request was issued. | ||
78 | */ | ||
79 | struct GNUNET_TIME_Absolute transmission_request_start_time; | ||
80 | |||
81 | /** | ||
82 | * Envelope with the actual message. | ||
83 | */ | ||
84 | struct GNUNET_MQ_Envelope *env; | ||
85 | |||
86 | /** | ||
87 | * Peer this request targets. | ||
88 | */ | ||
89 | struct GSF_ConnectedPeer *cp; | ||
90 | |||
91 | /** | ||
92 | * #GNUNET_YES if this is a query, #GNUNET_NO for content. | ||
93 | */ | ||
94 | int is_query; | ||
95 | |||
96 | /** | ||
97 | * Did we get a reservation already? | ||
98 | */ | ||
99 | int was_reserved; | ||
100 | |||
101 | /** | ||
102 | * Priority of this request. | ||
103 | */ | ||
104 | uint32_t priority; | ||
105 | }; | ||
106 | |||
107 | |||
108 | /** | ||
109 | * Handle for an entry in our delay list. | ||
110 | */ | ||
111 | struct GSF_DelayedHandle | ||
112 | { | ||
113 | /** | ||
114 | * Kept in a doubly-linked list. | ||
115 | */ | ||
116 | struct GSF_DelayedHandle *next; | ||
117 | |||
118 | /** | ||
119 | * Kept in a doubly-linked list. | ||
120 | */ | ||
121 | struct GSF_DelayedHandle *prev; | ||
122 | |||
123 | /** | ||
124 | * Peer this transmission belongs to. | ||
125 | */ | ||
126 | struct GSF_ConnectedPeer *cp; | ||
127 | |||
128 | /** | ||
129 | * Envelope of the message that was delayed. | ||
130 | */ | ||
131 | struct GNUNET_MQ_Envelope *env; | ||
132 | |||
133 | /** | ||
134 | * Task for the delay. | ||
135 | */ | ||
136 | struct GNUNET_SCHEDULER_Task *delay_task; | ||
137 | |||
138 | /** | ||
139 | * Size of the message. | ||
140 | */ | ||
141 | size_t msize; | ||
142 | }; | ||
143 | |||
144 | |||
145 | /** | ||
146 | * Information per peer and request. | ||
147 | */ | ||
148 | struct PeerRequest | ||
149 | { | ||
150 | /** | ||
151 | * Handle to generic request (generic: from peer or local client). | ||
152 | */ | ||
153 | struct GSF_PendingRequest *pr; | ||
154 | |||
155 | /** | ||
156 | * Which specific peer issued this request? | ||
157 | */ | ||
158 | struct GSF_ConnectedPeer *cp; | ||
159 | |||
160 | /** | ||
161 | * Task for asynchronous stopping of this request. | ||
162 | */ | ||
163 | struct GNUNET_SCHEDULER_Task *kill_task; | ||
164 | }; | ||
165 | |||
166 | |||
167 | /** | ||
168 | * A connected peer. | ||
169 | */ | ||
170 | struct GSF_ConnectedPeer | ||
171 | { | ||
172 | /** | ||
173 | * Performance data for this peer. | ||
174 | */ | ||
175 | struct GSF_PeerPerformanceData ppd; | ||
176 | |||
177 | /** | ||
178 | * Time until when we blocked this peer from migrating | ||
179 | * data to us. | ||
180 | */ | ||
181 | struct GNUNET_TIME_Absolute last_migration_block; | ||
182 | |||
183 | /** | ||
184 | * Task scheduled to revive migration to this peer. | ||
185 | */ | ||
186 | struct GNUNET_SCHEDULER_Task *mig_revive_task; | ||
187 | |||
188 | /** | ||
189 | * Messages (replies, queries, content migration) we would like to | ||
190 | * send to this peer in the near future. Sorted by priority, head. | ||
191 | */ | ||
192 | struct GSF_PeerTransmitHandle *pth_head; | ||
193 | |||
194 | /** | ||
195 | * Messages (replies, queries, content migration) we would like to | ||
196 | * send to this peer in the near future. Sorted by priority, tail. | ||
197 | */ | ||
198 | struct GSF_PeerTransmitHandle *pth_tail; | ||
199 | |||
200 | /** | ||
201 | * Messages (replies, queries, content migration) we would like to | ||
202 | * send to this peer in the near future. Sorted by priority, head. | ||
203 | */ | ||
204 | struct GSF_DelayedHandle *delayed_head; | ||
205 | |||
206 | /** | ||
207 | * Messages (replies, queries, content migration) we would like to | ||
208 | * send to this peer in the near future. Sorted by priority, tail. | ||
209 | */ | ||
210 | struct GSF_DelayedHandle *delayed_tail; | ||
211 | |||
212 | /** | ||
213 | * Context of our GNUNET_ATS_reserve_bandwidth call (or NULL). | ||
214 | */ | ||
215 | struct GNUNET_ATS_ReservationContext *rc; | ||
216 | |||
217 | /** | ||
218 | * Task scheduled if we need to retry bandwidth reservation later. | ||
219 | */ | ||
220 | struct GNUNET_SCHEDULER_Task *rc_delay_task; | ||
221 | |||
222 | /** | ||
223 | * Active requests from this neighbour, map of query to `struct PeerRequest`. | ||
224 | */ | ||
225 | struct GNUNET_CONTAINER_MultiHashMap *request_map; | ||
226 | |||
227 | /** | ||
228 | * Handle for an active request for transmission to this | ||
229 | * peer. | ||
230 | */ | ||
231 | struct GNUNET_MQ_Handle *mq; | ||
232 | |||
233 | /** | ||
234 | * Increase in traffic preference still to be submitted | ||
235 | * to the core service for this peer. | ||
236 | */ | ||
237 | uint64_t inc_preference; | ||
238 | |||
239 | /** | ||
240 | * Number of entries in @e delayed_head DLL. | ||
241 | */ | ||
242 | unsigned int delay_queue_size; | ||
243 | |||
244 | /** | ||
245 | * Respect rating for this peer on disk. | ||
246 | */ | ||
247 | uint32_t disk_respect; | ||
248 | |||
249 | /** | ||
250 | * Which offset in @e last_p2p_replies will be updated next? | ||
251 | * (we go round-robin). | ||
252 | */ | ||
253 | unsigned int last_p2p_replies_woff; | ||
254 | |||
255 | /** | ||
256 | * Which offset in @e last_client_replies will be updated next? | ||
257 | * (we go round-robin). | ||
258 | */ | ||
259 | unsigned int last_client_replies_woff; | ||
260 | |||
261 | /** | ||
262 | * Current offset into @e last_request_times ring buffer. | ||
263 | */ | ||
264 | unsigned int last_request_times_off; | ||
265 | |||
266 | /** | ||
267 | * #GNUNET_YES if we did successfully reserve 32k bandwidth, | ||
268 | * #GNUNET_NO if not. | ||
269 | */ | ||
270 | int did_reserve; | ||
271 | |||
272 | /** | ||
273 | * Handle to the PEERSTORE iterate request for peer respect value | ||
274 | */ | ||
275 | struct GNUNET_PEERSTORE_IterateContext *respect_iterate_req; | ||
276 | }; | ||
277 | |||
278 | |||
279 | /** | ||
280 | * Map from peer identities to `struct GSF_ConnectPeer` entries. | ||
281 | */ | ||
282 | static struct GNUNET_CONTAINER_MultiPeerMap *cp_map; | ||
283 | |||
284 | /** | ||
285 | * Handle to peerstore service. | ||
286 | */ | ||
287 | static struct GNUNET_PEERSTORE_Handle *peerstore; | ||
288 | |||
289 | /** | ||
290 | * Task used to flush respect values to disk. | ||
291 | */ | ||
292 | static struct GNUNET_SCHEDULER_Task *fr_task; | ||
293 | |||
294 | |||
295 | /** | ||
296 | * Update the latency information kept for the given peer. | ||
297 | * | ||
298 | * @param id peer record to update | ||
299 | * @param latency current latency value | ||
300 | */ | ||
301 | void | ||
302 | GSF_update_peer_latency_ (const struct GNUNET_PeerIdentity *id, | ||
303 | struct GNUNET_TIME_Relative latency) | ||
304 | { | ||
305 | struct GSF_ConnectedPeer *cp; | ||
306 | |||
307 | cp = GSF_peer_get_ (id); | ||
308 | if (NULL == cp) | ||
309 | return; /* we're not yet connected at the core level, ignore */ | ||
310 | GNUNET_LOAD_value_set_decline (cp->ppd.transmission_delay, | ||
311 | latency); | ||
312 | } | ||
313 | |||
314 | |||
315 | /** | ||
316 | * Return the performance data record for the given peer | ||
317 | * | ||
318 | * @param cp peer to query | ||
319 | * @return performance data record for the peer | ||
320 | */ | ||
321 | struct GSF_PeerPerformanceData * | ||
322 | GSF_get_peer_performance_data_ (struct GSF_ConnectedPeer *cp) | ||
323 | { | ||
324 | return &cp->ppd; | ||
325 | } | ||
326 | |||
327 | |||
328 | /** | ||
329 | * Core is ready to transmit to a peer, get the message. | ||
330 | * | ||
331 | * @param cp which peer to send a message to | ||
332 | */ | ||
333 | static void | ||
334 | peer_transmit (struct GSF_ConnectedPeer *cp); | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Function called by core upon success or failure of our bandwidth reservation request. | ||
339 | * | ||
340 | * @param cls the `struct GSF_ConnectedPeer` of the peer for which we made the request | ||
341 | * @param peer identifies the peer | ||
342 | * @param amount set to the amount that was actually reserved or unreserved; | ||
343 | * either the full requested amount or zero (no partial reservations) | ||
344 | * @param res_delay if the reservation could not be satisfied (amount was 0), how | ||
345 | * long should the client wait until re-trying? | ||
346 | */ | ||
347 | static void | ||
348 | ats_reserve_callback (void *cls, | ||
349 | const struct GNUNET_PeerIdentity *peer, | ||
350 | int32_t amount, | ||
351 | struct GNUNET_TIME_Relative res_delay); | ||
352 | |||
353 | |||
354 | /** | ||
355 | * If ready (bandwidth reserved), try to schedule transmission via | ||
356 | * core for the given handle. | ||
357 | * | ||
358 | * @param pth transmission handle to schedule | ||
359 | */ | ||
360 | static void | ||
361 | schedule_transmission (struct GSF_PeerTransmitHandle *pth) | ||
362 | { | ||
363 | struct GSF_ConnectedPeer *cp; | ||
364 | struct GNUNET_PeerIdentity target; | ||
365 | |||
366 | cp = pth->cp; | ||
367 | GNUNET_assert (0 != cp->ppd.pid); | ||
368 | GNUNET_PEER_resolve (cp->ppd.pid, &target); | ||
369 | |||
370 | if (0 != cp->inc_preference) | ||
371 | { | ||
372 | GNUNET_ATS_performance_change_preference (GSF_ats, | ||
373 | &target, | ||
374 | GNUNET_ATS_PREFERENCE_BANDWIDTH, | ||
375 | (double) cp->inc_preference, | ||
376 | GNUNET_ATS_PREFERENCE_END); | ||
377 | cp->inc_preference = 0; | ||
378 | } | ||
379 | |||
380 | if ((GNUNET_YES == pth->is_query) && | ||
381 | (GNUNET_YES != pth->was_reserved)) | ||
382 | { | ||
383 | /* query, need reservation */ | ||
384 | if (GNUNET_YES != cp->did_reserve) | ||
385 | return; /* not ready */ | ||
386 | cp->did_reserve = GNUNET_NO; | ||
387 | /* reservation already done! */ | ||
388 | pth->was_reserved = GNUNET_YES; | ||
389 | cp->rc = GNUNET_ATS_reserve_bandwidth (GSF_ats, | ||
390 | &target, | ||
391 | DBLOCK_SIZE, | ||
392 | &ats_reserve_callback, | ||
393 | cp); | ||
394 | return; | ||
395 | } | ||
396 | peer_transmit (cp); | ||
397 | } | ||
398 | |||
399 | |||
400 | /** | ||
401 | * Core is ready to transmit to a peer, get the message. | ||
402 | * | ||
403 | * @param cp which peer to send a message to | ||
404 | */ | ||
405 | static void | ||
406 | peer_transmit (struct GSF_ConnectedPeer *cp) | ||
407 | { | ||
408 | struct GSF_PeerTransmitHandle *pth = cp->pth_head; | ||
409 | struct GSF_PeerTransmitHandle *pos; | ||
410 | |||
411 | if (NULL == pth) | ||
412 | return; | ||
413 | GNUNET_CONTAINER_DLL_remove (cp->pth_head, | ||
414 | cp->pth_tail, | ||
415 | pth); | ||
416 | if (GNUNET_YES == pth->is_query) | ||
417 | { | ||
418 | cp->ppd.last_request_times[(cp->last_request_times_off++) | ||
419 | % MAX_QUEUE_PER_PEER] = | ||
420 | GNUNET_TIME_absolute_get (); | ||
421 | GNUNET_assert (0 < cp->ppd.pending_queries--); | ||
422 | } | ||
423 | else if (GNUNET_NO == pth->is_query) | ||
424 | { | ||
425 | GNUNET_assert (0 < cp->ppd.pending_replies--); | ||
426 | } | ||
427 | GNUNET_LOAD_update (cp->ppd.transmission_delay, | ||
428 | GNUNET_TIME_absolute_get_duration | ||
429 | (pth->transmission_request_start_time).rel_value_us); | ||
430 | GNUNET_MQ_send (cp->mq, | ||
431 | pth->env); | ||
432 | GNUNET_free (pth); | ||
433 | if (NULL != (pos = cp->pth_head)) | ||
434 | { | ||
435 | GNUNET_assert (pos != pth); | ||
436 | schedule_transmission (pos); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | |||
441 | /** | ||
442 | * (re)try to reserve bandwidth from the given peer. | ||
443 | * | ||
444 | * @param cls the `struct GSF_ConnectedPeer` to reserve from | ||
445 | */ | ||
446 | static void | ||
447 | retry_reservation (void *cls) | ||
448 | { | ||
449 | struct GSF_ConnectedPeer *cp = cls; | ||
450 | struct GNUNET_PeerIdentity target; | ||
451 | |||
452 | GNUNET_PEER_resolve (cp->ppd.pid, &target); | ||
453 | cp->rc_delay_task = NULL; | ||
454 | cp->rc = | ||
455 | GNUNET_ATS_reserve_bandwidth (GSF_ats, | ||
456 | &target, | ||
457 | DBLOCK_SIZE, | ||
458 | &ats_reserve_callback, cp); | ||
459 | } | ||
460 | |||
461 | |||
462 | /** | ||
463 | * Function called by core upon success or failure of our bandwidth reservation request. | ||
464 | * | ||
465 | * @param cls the `struct GSF_ConnectedPeer` of the peer for which we made the request | ||
466 | * @param peer identifies the peer | ||
467 | * @param amount set to the amount that was actually reserved or unreserved; | ||
468 | * either the full requested amount or zero (no partial reservations) | ||
469 | * @param res_delay if the reservation could not be satisfied (amount was 0), how | ||
470 | * long should the client wait until re-trying? | ||
471 | */ | ||
472 | static void | ||
473 | ats_reserve_callback (void *cls, | ||
474 | const struct GNUNET_PeerIdentity *peer, | ||
475 | int32_t amount, | ||
476 | struct GNUNET_TIME_Relative res_delay) | ||
477 | { | ||
478 | struct GSF_ConnectedPeer *cp = cls; | ||
479 | struct GSF_PeerTransmitHandle *pth; | ||
480 | |||
481 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
482 | "Reserved %d bytes / need to wait %s for reservation\n", | ||
483 | (int) amount, | ||
484 | GNUNET_STRINGS_relative_time_to_string (res_delay, GNUNET_YES)); | ||
485 | cp->rc = NULL; | ||
486 | if (0 == amount) | ||
487 | { | ||
488 | cp->rc_delay_task = | ||
489 | GNUNET_SCHEDULER_add_delayed (res_delay, | ||
490 | &retry_reservation, | ||
491 | cp); | ||
492 | return; | ||
493 | } | ||
494 | cp->did_reserve = GNUNET_YES; | ||
495 | pth = cp->pth_head; | ||
496 | if (NULL != pth) | ||
497 | { | ||
498 | /* reservation success, try transmission now! */ | ||
499 | peer_transmit (cp); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | |||
504 | /** | ||
505 | * Function called by PEERSTORE with peer respect record | ||
506 | * | ||
507 | * @param cls handle to connected peer entry | ||
508 | * @param record peerstore record information | ||
509 | * @param emsg error message, or NULL if no errors | ||
510 | */ | ||
511 | static void | ||
512 | peer_respect_cb (void *cls, | ||
513 | const struct GNUNET_PEERSTORE_Record *record, | ||
514 | const char *emsg) | ||
515 | { | ||
516 | struct GSF_ConnectedPeer *cp = cls; | ||
517 | |||
518 | GNUNET_assert (NULL != cp->respect_iterate_req); | ||
519 | if ((NULL != record) && | ||
520 | (sizeof(cp->disk_respect) == record->value_size)) | ||
521 | { | ||
522 | cp->disk_respect = *((uint32_t *) record->value); | ||
523 | cp->ppd.respect += *((uint32_t *) record->value); | ||
524 | } | ||
525 | GSF_push_start_ (cp); | ||
526 | if (NULL != record) | ||
527 | GNUNET_PEERSTORE_iterate_cancel (cp->respect_iterate_req); | ||
528 | cp->respect_iterate_req = NULL; | ||
529 | } | ||
530 | |||
531 | |||
532 | /** | ||
533 | * Function called for each pending request whenever a new | ||
534 | * peer connects, giving us a chance to decide about submitting | ||
535 | * the existing request to the new peer. | ||
536 | * | ||
537 | * @param cls the `struct GSF_ConnectedPeer` of the new peer | ||
538 | * @param key query for the request | ||
539 | * @param pr handle to the pending request | ||
540 | * @return #GNUNET_YES to continue to iterate | ||
541 | */ | ||
542 | static int | ||
543 | consider_peer_for_forwarding (void *cls, | ||
544 | const struct GNUNET_HashCode *key, | ||
545 | struct GSF_PendingRequest *pr) | ||
546 | { | ||
547 | struct GSF_ConnectedPeer *cp = cls; | ||
548 | struct GNUNET_PeerIdentity pid; | ||
549 | |||
550 | if (GNUNET_YES != | ||
551 | GSF_pending_request_test_active_ (pr)) | ||
552 | return GNUNET_YES; /* request is not actually active, skip! */ | ||
553 | GSF_connected_peer_get_identity_ (cp, &pid); | ||
554 | if (GNUNET_YES != | ||
555 | GSF_pending_request_test_target_ (pr, &pid)) | ||
556 | { | ||
557 | GNUNET_STATISTICS_update (GSF_stats, | ||
558 | gettext_noop ("# Loopback routes suppressed"), | ||
559 | 1, | ||
560 | GNUNET_NO); | ||
561 | return GNUNET_YES; | ||
562 | } | ||
563 | GSF_plan_add_ (cp, pr); | ||
564 | return GNUNET_YES; | ||
565 | } | ||
566 | |||
567 | |||
568 | /** | ||
569 | * A peer connected to us. Setup the connected peer | ||
570 | * records. | ||
571 | * | ||
572 | * @param cls NULL | ||
573 | * @param peer identity of peer that connected | ||
574 | * @param mq message queue for talking to @a peer | ||
575 | * @return our internal handle for the peer | ||
576 | */ | ||
577 | void * | ||
578 | GSF_peer_connect_handler (void *cls, | ||
579 | const struct GNUNET_PeerIdentity *peer, | ||
580 | struct GNUNET_MQ_Handle *mq) | ||
581 | { | ||
582 | struct GSF_ConnectedPeer *cp; | ||
583 | |||
584 | if (0 == | ||
585 | GNUNET_memcmp (&GSF_my_id, | ||
586 | peer)) | ||
587 | return NULL; | ||
588 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
589 | "Connected to peer %s\n", | ||
590 | GNUNET_i2s (peer)); | ||
591 | cp = GNUNET_new (struct GSF_ConnectedPeer); | ||
592 | cp->ppd.pid = GNUNET_PEER_intern (peer); | ||
593 | cp->ppd.peer = peer; | ||
594 | cp->mq = mq; | ||
595 | cp->ppd.transmission_delay = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_ZERO); | ||
596 | cp->rc = | ||
597 | GNUNET_ATS_reserve_bandwidth (GSF_ats, | ||
598 | peer, | ||
599 | DBLOCK_SIZE, | ||
600 | &ats_reserve_callback, cp); | ||
601 | cp->request_map = GNUNET_CONTAINER_multihashmap_create (128, | ||
602 | GNUNET_YES); | ||
603 | GNUNET_break (GNUNET_OK == | ||
604 | GNUNET_CONTAINER_multipeermap_put (cp_map, | ||
605 | GSF_connected_peer_get_identity2_ ( | ||
606 | cp), | ||
607 | cp, | ||
608 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
609 | GNUNET_STATISTICS_set (GSF_stats, | ||
610 | gettext_noop ("# peers connected"), | ||
611 | GNUNET_CONTAINER_multipeermap_size (cp_map), | ||
612 | GNUNET_NO); | ||
613 | cp->respect_iterate_req | ||
614 | = GNUNET_PEERSTORE_iterate (peerstore, | ||
615 | "fs", | ||
616 | peer, | ||
617 | "respect", | ||
618 | &peer_respect_cb, | ||
619 | cp); | ||
620 | GSF_iterate_pending_requests_ (&consider_peer_for_forwarding, | ||
621 | cp); | ||
622 | return cp; | ||
623 | } | ||
624 | |||
625 | |||
626 | /** | ||
627 | * It may be time to re-start migrating content to this | ||
628 | * peer. Check, and if so, restart migration. | ||
629 | * | ||
630 | * @param cls the `struct GSF_ConnectedPeer` | ||
631 | */ | ||
632 | static void | ||
633 | revive_migration (void *cls) | ||
634 | { | ||
635 | struct GSF_ConnectedPeer *cp = cls; | ||
636 | struct GNUNET_TIME_Relative bt; | ||
637 | |||
638 | cp->mig_revive_task = NULL; | ||
639 | bt = GNUNET_TIME_absolute_get_remaining (cp->ppd.migration_blocked_until); | ||
640 | if (0 != bt.rel_value_us) | ||
641 | { | ||
642 | /* still time left... */ | ||
643 | cp->mig_revive_task = | ||
644 | GNUNET_SCHEDULER_add_delayed (bt, &revive_migration, cp); | ||
645 | return; | ||
646 | } | ||
647 | GSF_push_start_ (cp); | ||
648 | } | ||
649 | |||
650 | |||
651 | /** | ||
652 | * Get a handle for a connected peer. | ||
653 | * | ||
654 | * @param peer peer's identity | ||
655 | * @return NULL if the peer is not currently connected | ||
656 | */ | ||
657 | struct GSF_ConnectedPeer * | ||
658 | GSF_peer_get_ (const struct GNUNET_PeerIdentity *peer) | ||
659 | { | ||
660 | if (NULL == cp_map) | ||
661 | return NULL; | ||
662 | return GNUNET_CONTAINER_multipeermap_get (cp_map, peer); | ||
663 | } | ||
664 | |||
665 | |||
666 | /** | ||
667 | * Handle P2P #GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP message. | ||
668 | * | ||
669 | * @param cls closure, the `struct GSF_ConnectedPeer` | ||
670 | * @param msm the actual message | ||
671 | */ | ||
672 | void | ||
673 | handle_p2p_migration_stop (void *cls, | ||
674 | const struct MigrationStopMessage *msm) | ||
675 | { | ||
676 | struct GSF_ConnectedPeer *cp = cls; | ||
677 | struct GNUNET_TIME_Relative bt; | ||
678 | |||
679 | GNUNET_STATISTICS_update (GSF_stats, | ||
680 | gettext_noop ("# migration stop messages received"), | ||
681 | 1, GNUNET_NO); | ||
682 | bt = GNUNET_TIME_relative_ntoh (msm->duration); | ||
683 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
684 | _ ("Migration of content to peer `%s' blocked for %s\n"), | ||
685 | GNUNET_i2s (cp->ppd.peer), | ||
686 | GNUNET_STRINGS_relative_time_to_string (bt, GNUNET_YES)); | ||
687 | cp->ppd.migration_blocked_until = GNUNET_TIME_relative_to_absolute (bt); | ||
688 | if ((NULL == cp->mig_revive_task) && | ||
689 | (NULL == cp->respect_iterate_req)) | ||
690 | { | ||
691 | GSF_push_stop_ (cp); | ||
692 | cp->mig_revive_task = | ||
693 | GNUNET_SCHEDULER_add_delayed (bt, | ||
694 | &revive_migration, cp); | ||
695 | } | ||
696 | } | ||
697 | |||
698 | |||
699 | /** | ||
700 | * Free resources associated with the given peer request. | ||
701 | * | ||
702 | * @param peerreq request to free | ||
703 | */ | ||
704 | static void | ||
705 | free_pending_request (struct PeerRequest *peerreq) | ||
706 | { | ||
707 | struct GSF_ConnectedPeer *cp = peerreq->cp; | ||
708 | struct GSF_PendingRequestData *prd; | ||
709 | |||
710 | prd = GSF_pending_request_get_data_ (peerreq->pr); | ||
711 | if (NULL != peerreq->kill_task) | ||
712 | { | ||
713 | GNUNET_SCHEDULER_cancel (peerreq->kill_task); | ||
714 | peerreq->kill_task = NULL; | ||
715 | } | ||
716 | GNUNET_STATISTICS_update (GSF_stats, | ||
717 | gettext_noop ("# P2P searches active"), | ||
718 | -1, | ||
719 | GNUNET_NO); | ||
720 | GNUNET_break (GNUNET_YES == | ||
721 | GNUNET_CONTAINER_multihashmap_remove (cp->request_map, | ||
722 | &prd->query, | ||
723 | peerreq)); | ||
724 | GNUNET_free (peerreq); | ||
725 | } | ||
726 | |||
727 | |||
728 | /** | ||
729 | * Cancel all requests associated with the peer. | ||
730 | * | ||
731 | * @param cls unused | ||
732 | * @param query hash code of the request | ||
733 | * @param value the `struct GSF_PendingRequest` | ||
734 | * @return #GNUNET_YES (continue to iterate) | ||
735 | */ | ||
736 | static int | ||
737 | cancel_pending_request (void *cls, | ||
738 | const struct GNUNET_HashCode *query, | ||
739 | void *value) | ||
740 | { | ||
741 | struct PeerRequest *peerreq = value; | ||
742 | struct GSF_PendingRequest *pr = peerreq->pr; | ||
743 | |||
744 | free_pending_request (peerreq); | ||
745 | GSF_pending_request_cancel_ (pr, | ||
746 | GNUNET_NO); | ||
747 | return GNUNET_OK; | ||
748 | } | ||
749 | |||
750 | |||
751 | /** | ||
752 | * Free the given request. | ||
753 | * | ||
754 | * @param cls the request to free | ||
755 | */ | ||
756 | static void | ||
757 | peer_request_destroy (void *cls) | ||
758 | { | ||
759 | struct PeerRequest *peerreq = cls; | ||
760 | struct GSF_PendingRequest *pr = peerreq->pr; | ||
761 | struct GSF_PendingRequestData *prd; | ||
762 | |||
763 | peerreq->kill_task = NULL; | ||
764 | prd = GSF_pending_request_get_data_ (pr); | ||
765 | cancel_pending_request (NULL, | ||
766 | &prd->query, | ||
767 | peerreq); | ||
768 | } | ||
769 | |||
770 | |||
771 | /** | ||
772 | * The artificial delay is over, transmit the message now. | ||
773 | * | ||
774 | * @param cls the `struct GSF_DelayedHandle` with the message | ||
775 | */ | ||
776 | static void | ||
777 | transmit_delayed_now (void *cls) | ||
778 | { | ||
779 | struct GSF_DelayedHandle *dh = cls; | ||
780 | struct GSF_ConnectedPeer *cp = dh->cp; | ||
781 | |||
782 | GNUNET_CONTAINER_DLL_remove (cp->delayed_head, | ||
783 | cp->delayed_tail, | ||
784 | dh); | ||
785 | cp->delay_queue_size--; | ||
786 | GSF_peer_transmit_ (cp, | ||
787 | GNUNET_NO, | ||
788 | UINT32_MAX, | ||
789 | dh->env); | ||
790 | GNUNET_free (dh); | ||
791 | } | ||
792 | |||
793 | |||
794 | /** | ||
795 | * Get the randomized delay a response should be subjected to. | ||
796 | * | ||
797 | * @return desired delay | ||
798 | */ | ||
799 | static struct GNUNET_TIME_Relative | ||
800 | get_randomized_delay () | ||
801 | { | ||
802 | struct GNUNET_TIME_Relative ret; | ||
803 | |||
804 | ret = | ||
805 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, | ||
806 | GNUNET_CRYPTO_random_u32 | ||
807 | (GNUNET_CRYPTO_QUALITY_WEAK, | ||
808 | 2 * GSF_avg_latency.rel_value_us + 1)); | ||
809 | #if INSANE_STATISTICS | ||
810 | GNUNET_STATISTICS_update (GSF_stats, | ||
811 | gettext_noop | ||
812 | ("# artificial delays introduced (ms)"), | ||
813 | ret.rel_value_us / 1000LL, GNUNET_NO); | ||
814 | #endif | ||
815 | return ret; | ||
816 | } | ||
817 | |||
818 | |||
819 | /** | ||
820 | * Handle a reply to a pending request. Also called if a request | ||
821 | * expires (then with data == NULL). The handler may be called | ||
822 | * many times (depending on the request type), but will not be | ||
823 | * called during or after a call to GSF_pending_request_cancel | ||
824 | * and will also not be called anymore after a call signalling | ||
825 | * expiration. | ||
826 | * | ||
827 | * @param cls `struct PeerRequest` this is an answer for | ||
828 | * @param eval evaluation of the result | ||
829 | * @param pr handle to the original pending request | ||
830 | * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" | ||
831 | * @param expiration when does @a data expire? | ||
832 | * @param last_transmission when did we last transmit a request for this block | ||
833 | * @param type type of the block | ||
834 | * @param data response data, NULL on request expiration | ||
835 | * @param data_len number of bytes in @a data | ||
836 | */ | ||
837 | static void | ||
838 | handle_p2p_reply (void *cls, | ||
839 | enum GNUNET_BLOCK_ReplyEvaluationResult eval, | ||
840 | struct GSF_PendingRequest *pr, | ||
841 | uint32_t reply_anonymity_level, | ||
842 | struct GNUNET_TIME_Absolute expiration, | ||
843 | struct GNUNET_TIME_Absolute last_transmission, | ||
844 | enum GNUNET_BLOCK_Type type, | ||
845 | const void *data, | ||
846 | size_t data_len) | ||
847 | { | ||
848 | struct PeerRequest *peerreq = cls; | ||
849 | struct GSF_ConnectedPeer *cp = peerreq->cp; | ||
850 | struct GSF_PendingRequestData *prd; | ||
851 | struct GNUNET_MQ_Envelope *env; | ||
852 | struct PutMessage *pm; | ||
853 | size_t msize; | ||
854 | |||
855 | GNUNET_assert (data_len + sizeof(struct PutMessage) < | ||
856 | GNUNET_MAX_MESSAGE_SIZE); | ||
857 | GNUNET_assert (peerreq->pr == pr); | ||
858 | prd = GSF_pending_request_get_data_ (pr); | ||
859 | if (NULL == data) | ||
860 | { | ||
861 | free_pending_request (peerreq); | ||
862 | return; | ||
863 | } | ||
864 | GNUNET_break (GNUNET_BLOCK_TYPE_ANY != type); | ||
865 | if ( (prd->type != type) && | ||
866 | (GNUNET_BLOCK_TYPE_ANY != prd->type) ) | ||
867 | { | ||
868 | GNUNET_STATISTICS_update (GSF_stats, | ||
869 | "# replies dropped due to type mismatch", | ||
870 | 1, GNUNET_NO); | ||
871 | return; | ||
872 | } | ||
873 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
874 | "Transmitting result for query `%s' to peer\n", | ||
875 | GNUNET_h2s (&prd->query)); | ||
876 | GNUNET_STATISTICS_update (GSF_stats, | ||
877 | "# replies received for other peers", | ||
878 | 1, | ||
879 | GNUNET_NO); | ||
880 | msize = sizeof(struct PutMessage) + data_len; | ||
881 | if (msize >= GNUNET_MAX_MESSAGE_SIZE) | ||
882 | { | ||
883 | GNUNET_break (0); | ||
884 | return; | ||
885 | } | ||
886 | if ( (UINT32_MAX != reply_anonymity_level) && | ||
887 | (reply_anonymity_level > 1) ) | ||
888 | { | ||
889 | if (reply_anonymity_level - 1 > GSF_cover_content_count) | ||
890 | { | ||
891 | GNUNET_STATISTICS_update (GSF_stats, | ||
892 | "# replies dropped due to insufficient cover traffic", | ||
893 | 1, GNUNET_NO); | ||
894 | return; | ||
895 | } | ||
896 | GSF_cover_content_count -= (reply_anonymity_level - 1); | ||
897 | } | ||
898 | |||
899 | env = GNUNET_MQ_msg_extra (pm, | ||
900 | data_len, | ||
901 | GNUNET_MESSAGE_TYPE_FS_PUT); | ||
902 | pm->type = htonl (type); | ||
903 | pm->expiration = GNUNET_TIME_absolute_hton (expiration); | ||
904 | GNUNET_memcpy (&pm[1], | ||
905 | data, | ||
906 | data_len); | ||
907 | if ((UINT32_MAX != reply_anonymity_level) && | ||
908 | (0 != reply_anonymity_level) && | ||
909 | (GNUNET_YES == GSF_enable_randomized_delays)) | ||
910 | { | ||
911 | struct GSF_DelayedHandle *dh; | ||
912 | |||
913 | dh = GNUNET_new (struct GSF_DelayedHandle); | ||
914 | dh->cp = cp; | ||
915 | dh->env = env; | ||
916 | dh->msize = msize; | ||
917 | GNUNET_CONTAINER_DLL_insert (cp->delayed_head, | ||
918 | cp->delayed_tail, | ||
919 | dh); | ||
920 | cp->delay_queue_size++; | ||
921 | dh->delay_task = | ||
922 | GNUNET_SCHEDULER_add_delayed (get_randomized_delay (), | ||
923 | &transmit_delayed_now, | ||
924 | dh); | ||
925 | } | ||
926 | else | ||
927 | { | ||
928 | GSF_peer_transmit_ (cp, | ||
929 | GNUNET_NO, | ||
930 | UINT32_MAX, | ||
931 | env); | ||
932 | } | ||
933 | if (GNUNET_BLOCK_REPLY_OK_LAST != eval) | ||
934 | return; | ||
935 | if (NULL == peerreq->kill_task) | ||
936 | { | ||
937 | GNUNET_STATISTICS_update (GSF_stats, | ||
938 | "# P2P searches destroyed due to ultimate reply", | ||
939 | 1, | ||
940 | GNUNET_NO); | ||
941 | peerreq->kill_task = | ||
942 | GNUNET_SCHEDULER_add_now (&peer_request_destroy, | ||
943 | peerreq); | ||
944 | } | ||
945 | } | ||
946 | |||
947 | |||
948 | /** | ||
949 | * Increase the peer's respect by a value. | ||
950 | * | ||
951 | * @param cp which peer to change the respect value on | ||
952 | * @param value is the int value by which the | ||
953 | * peer's credit is to be increased or decreased | ||
954 | * @returns the actual change in respect (positive or negative) | ||
955 | */ | ||
956 | static int | ||
957 | change_peer_respect (struct GSF_ConnectedPeer *cp, int value) | ||
958 | { | ||
959 | if (0 == value) | ||
960 | return 0; | ||
961 | GNUNET_assert (NULL != cp); | ||
962 | if (value > 0) | ||
963 | { | ||
964 | if (cp->ppd.respect + value < cp->ppd.respect) | ||
965 | { | ||
966 | value = UINT32_MAX - cp->ppd.respect; | ||
967 | cp->ppd.respect = UINT32_MAX; | ||
968 | } | ||
969 | else | ||
970 | cp->ppd.respect += value; | ||
971 | } | ||
972 | else | ||
973 | { | ||
974 | if (cp->ppd.respect < -value) | ||
975 | { | ||
976 | value = -cp->ppd.respect; | ||
977 | cp->ppd.respect = 0; | ||
978 | } | ||
979 | else | ||
980 | cp->ppd.respect += value; | ||
981 | } | ||
982 | return value; | ||
983 | } | ||
984 | |||
985 | |||
986 | /** | ||
987 | * We've received a request with the specified priority. Bound it | ||
988 | * according to how much we respect the given peer. | ||
989 | * | ||
990 | * @param prio_in requested priority | ||
991 | * @param cp the peer making the request | ||
992 | * @return effective priority | ||
993 | */ | ||
994 | static int32_t | ||
995 | bound_priority (uint32_t prio_in, | ||
996 | struct GSF_ConnectedPeer *cp) | ||
997 | { | ||
998 | #define N ((double) 128.0) | ||
999 | uint32_t ret; | ||
1000 | double rret; | ||
1001 | int ld; | ||
1002 | |||
1003 | ld = GSF_test_get_load_too_high_ (0); | ||
1004 | if (GNUNET_SYSERR == ld) | ||
1005 | { | ||
1006 | #if INSANE_STATISTICS | ||
1007 | GNUNET_STATISTICS_update (GSF_stats, | ||
1008 | gettext_noop | ||
1009 | ("# requests done for free (low load)"), 1, | ||
1010 | GNUNET_NO); | ||
1011 | #endif | ||
1012 | return 0; /* excess resources */ | ||
1013 | } | ||
1014 | if (prio_in > INT32_MAX) | ||
1015 | prio_in = INT32_MAX; | ||
1016 | ret = -change_peer_respect (cp, -(int) prio_in); | ||
1017 | if (ret > 0) | ||
1018 | { | ||
1019 | if (ret > GSF_current_priorities + N) | ||
1020 | rret = GSF_current_priorities + N; | ||
1021 | else | ||
1022 | rret = ret; | ||
1023 | GSF_current_priorities = (GSF_current_priorities * (N - 1) + rret) / N; | ||
1024 | } | ||
1025 | if ((GNUNET_YES == ld) && (ret > 0)) | ||
1026 | { | ||
1027 | /* try with charging */ | ||
1028 | ld = GSF_test_get_load_too_high_ (ret); | ||
1029 | } | ||
1030 | if (GNUNET_YES == ld) | ||
1031 | { | ||
1032 | GNUNET_STATISTICS_update (GSF_stats, | ||
1033 | gettext_noop | ||
1034 | ("# request dropped, priority insufficient"), 1, | ||
1035 | GNUNET_NO); | ||
1036 | /* undo charge */ | ||
1037 | change_peer_respect (cp, (int) ret); | ||
1038 | return -1; /* not enough resources */ | ||
1039 | } | ||
1040 | else | ||
1041 | { | ||
1042 | GNUNET_STATISTICS_update (GSF_stats, | ||
1043 | gettext_noop | ||
1044 | ("# requests done for a price (normal load)"), | ||
1045 | 1, | ||
1046 | GNUNET_NO); | ||
1047 | } | ||
1048 | #undef N | ||
1049 | return ret; | ||
1050 | } | ||
1051 | |||
1052 | |||
1053 | /** | ||
1054 | * The priority level imposes a bound on the maximum | ||
1055 | * value for the ttl that can be requested. | ||
1056 | * | ||
1057 | * @param ttl_in requested ttl | ||
1058 | * @param prio given priority | ||
1059 | * @return @a ttl_in if @a ttl_in is below the limit, | ||
1060 | * otherwise the ttl-limit for the given @a prio | ||
1061 | */ | ||
1062 | static int32_t | ||
1063 | bound_ttl (int32_t ttl_in, | ||
1064 | uint32_t prio) | ||
1065 | { | ||
1066 | unsigned long long allowed; | ||
1067 | |||
1068 | if (ttl_in <= 0) | ||
1069 | return ttl_in; | ||
1070 | allowed = ((unsigned long long) prio) * TTL_DECREMENT / 1000; | ||
1071 | if (ttl_in > allowed) | ||
1072 | { | ||
1073 | if (allowed >= (1 << 30)) | ||
1074 | return 1 << 30; | ||
1075 | return allowed; | ||
1076 | } | ||
1077 | return ttl_in; | ||
1078 | } | ||
1079 | |||
1080 | |||
1081 | /** | ||
1082 | * Closure for #test_exist_cb(). | ||
1083 | */ | ||
1084 | struct TestExistClosure | ||
1085 | { | ||
1086 | /** | ||
1087 | * Priority of the incoming request. | ||
1088 | */ | ||
1089 | int32_t priority; | ||
1090 | |||
1091 | /** | ||
1092 | * Relative TTL of the incoming request. | ||
1093 | */ | ||
1094 | int32_t ttl; | ||
1095 | |||
1096 | /** | ||
1097 | * Type of the incoming request. | ||
1098 | */ | ||
1099 | enum GNUNET_BLOCK_Type type; | ||
1100 | |||
1101 | /** | ||
1102 | * Set to #GNUNET_YES if we are done handling the query. | ||
1103 | */ | ||
1104 | int finished; | ||
1105 | }; | ||
1106 | |||
1107 | |||
1108 | /** | ||
1109 | * Test if the query already exists. If so, merge it, otherwise | ||
1110 | * keep `finished` at #GNUNET_NO. | ||
1111 | * | ||
1112 | * @param cls our `struct TestExistClosure` | ||
1113 | * @param hc the key of the query | ||
1114 | * @param value the existing `struct PeerRequest`. | ||
1115 | * @return #GNUNET_YES to continue to iterate, | ||
1116 | * #GNUNET_NO if we successfully merged | ||
1117 | */ | ||
1118 | static int | ||
1119 | test_exist_cb (void *cls, | ||
1120 | const struct GNUNET_HashCode *hc, | ||
1121 | void *value) | ||
1122 | { | ||
1123 | struct TestExistClosure *tec = cls; | ||
1124 | struct PeerRequest *peerreq = value; | ||
1125 | struct GSF_PendingRequest *pr; | ||
1126 | struct GSF_PendingRequestData *prd; | ||
1127 | |||
1128 | pr = peerreq->pr; | ||
1129 | prd = GSF_pending_request_get_data_ (pr); | ||
1130 | if (prd->type != tec->type) | ||
1131 | return GNUNET_YES; | ||
1132 | if (prd->ttl.abs_value_us >= | ||
1133 | GNUNET_TIME_absolute_get ().abs_value_us + tec->ttl * 1000LL) | ||
1134 | { | ||
1135 | /* existing request has higher TTL, drop new one! */ | ||
1136 | prd->priority += tec->priority; | ||
1137 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1138 | "Have existing request with higher TTL, dropping new request.\n"); | ||
1139 | GNUNET_STATISTICS_update (GSF_stats, | ||
1140 | gettext_noop | ||
1141 | ("# requests dropped due to higher-TTL request"), | ||
1142 | 1, GNUNET_NO); | ||
1143 | tec->finished = GNUNET_YES; | ||
1144 | return GNUNET_NO; | ||
1145 | } | ||
1146 | /* existing request has lower TTL, drop old one! */ | ||
1147 | tec->priority += prd->priority; | ||
1148 | free_pending_request (peerreq); | ||
1149 | GSF_pending_request_cancel_ (pr, | ||
1150 | GNUNET_YES); | ||
1151 | return GNUNET_NO; | ||
1152 | } | ||
1153 | |||
1154 | |||
1155 | /** | ||
1156 | * Handle P2P "QUERY" message. Creates the pending request entry | ||
1157 | * and sets up all of the data structures to that we will | ||
1158 | * process replies properly. Does not initiate forwarding or | ||
1159 | * local database lookups. | ||
1160 | * | ||
1161 | * @param cls the other peer involved (sender of the message) | ||
1162 | * @param gm the GET message | ||
1163 | */ | ||
1164 | void | ||
1165 | handle_p2p_get (void *cls, | ||
1166 | const struct GetMessage *gm) | ||
1167 | { | ||
1168 | struct GSF_ConnectedPeer *cps = cls; | ||
1169 | struct PeerRequest *peerreq; | ||
1170 | struct GSF_PendingRequest *pr; | ||
1171 | struct GSF_ConnectedPeer *cp; | ||
1172 | const struct GNUNET_PeerIdentity *target; | ||
1173 | enum GSF_PendingRequestOptions options; | ||
1174 | uint16_t msize; | ||
1175 | unsigned int bits; | ||
1176 | const struct GNUNET_PeerIdentity *opt; | ||
1177 | uint32_t bm; | ||
1178 | size_t bfsize; | ||
1179 | uint32_t ttl_decrement; | ||
1180 | struct TestExistClosure tec; | ||
1181 | GNUNET_PEER_Id spid; | ||
1182 | const struct GSF_PendingRequestData *prd; | ||
1183 | |||
1184 | msize = ntohs (gm->header.size); | ||
1185 | tec.type = ntohl (gm->type); | ||
1186 | bm = ntohl (gm->hash_bitmap); | ||
1187 | bits = 0; | ||
1188 | while (bm > 0) | ||
1189 | { | ||
1190 | if (1 == (bm & 1)) | ||
1191 | bits++; | ||
1192 | bm >>= 1; | ||
1193 | } | ||
1194 | opt = (const struct GNUNET_PeerIdentity *) &gm[1]; | ||
1195 | bfsize = msize - sizeof(struct GetMessage) - bits * sizeof(struct | ||
1196 | GNUNET_PeerIdentity); | ||
1197 | GNUNET_STATISTICS_update (GSF_stats, | ||
1198 | gettext_noop | ||
1199 | ("# GET requests received (from other peers)"), | ||
1200 | 1, | ||
1201 | GNUNET_NO); | ||
1202 | GSF_cover_query_count++; | ||
1203 | bm = ntohl (gm->hash_bitmap); | ||
1204 | bits = 0; | ||
1205 | if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO)) | ||
1206 | cp = GSF_peer_get_ (&opt[bits++]); | ||
1207 | else | ||
1208 | cp = cps; | ||
1209 | if (NULL == cp) | ||
1210 | { | ||
1211 | if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO)) | ||
1212 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1213 | "Failed to find RETURN-TO peer `%s' in connection set. Dropping query.\n", | ||
1214 | GNUNET_i2s (&opt[bits - 1])); | ||
1215 | |||
1216 | else | ||
1217 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1218 | "Failed to find peer `%s' in connection set. Dropping query.\n", | ||
1219 | GNUNET_i2s (cps->ppd.peer)); | ||
1220 | GNUNET_STATISTICS_update (GSF_stats, | ||
1221 | gettext_noop | ||
1222 | ( | ||
1223 | "# requests dropped due to missing reverse route"), | ||
1224 | 1, | ||
1225 | GNUNET_NO); | ||
1226 | return; | ||
1227 | } | ||
1228 | unsigned int queue_size = GNUNET_MQ_get_length (cp->mq); | ||
1229 | queue_size += cp->ppd.pending_replies + cp->delay_queue_size; | ||
1230 | if (queue_size > MAX_QUEUE_PER_PEER) | ||
1231 | { | ||
1232 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1233 | "Peer `%s' has too many replies queued already. Dropping query.\n", | ||
1234 | GNUNET_i2s (cps->ppd.peer)); | ||
1235 | GNUNET_STATISTICS_update (GSF_stats, | ||
1236 | gettext_noop ( | ||
1237 | "# requests dropped due to full reply queue"), | ||
1238 | 1, | ||
1239 | GNUNET_NO); | ||
1240 | return; | ||
1241 | } | ||
1242 | /* note that we can really only check load here since otherwise | ||
1243 | * peers could find out that we are overloaded by not being | ||
1244 | * disconnected after sending us a malformed query... */ | ||
1245 | tec.priority = bound_priority (ntohl (gm->priority), | ||
1246 | cps); | ||
1247 | if (tec.priority < 0) | ||
1248 | { | ||
1249 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1250 | "Dropping query from `%s', this peer is too busy.\n", | ||
1251 | GNUNET_i2s (cps->ppd.peer)); | ||
1252 | return; | ||
1253 | } | ||
1254 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1255 | "Received request for `%s' of type %u from peer `%s' with flags %u\n", | ||
1256 | GNUNET_h2s (&gm->query), | ||
1257 | (unsigned int) tec.type, | ||
1258 | GNUNET_i2s (cps->ppd.peer), | ||
1259 | (unsigned int) bm); | ||
1260 | target = | ||
1261 | (0 != | ||
1262 | (bm & GET_MESSAGE_BIT_TRANSMIT_TO)) ? (&opt[bits++]) : NULL; | ||
1263 | options = GSF_PRO_DEFAULTS; | ||
1264 | spid = 0; | ||
1265 | if ((GNUNET_LOAD_get_load (cp->ppd.transmission_delay) > 3 * (1 | ||
1266 | + tec.priority)) | ||
1267 | || (GNUNET_LOAD_get_average (cp->ppd.transmission_delay) > | ||
1268 | GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value_us * 2 | ||
1269 | + GNUNET_LOAD_get_average (GSF_rt_entry_lifetime))) | ||
1270 | { | ||
1271 | /* don't have BW to send to peer, or would likely take longer than we have for it, | ||
1272 | * so at best indirect the query */ | ||
1273 | tec.priority = 0; | ||
1274 | options |= GSF_PRO_FORWARD_ONLY; | ||
1275 | spid = GNUNET_PEER_intern (cps->ppd.peer); | ||
1276 | GNUNET_assert (0 != spid); | ||
1277 | } | ||
1278 | tec.ttl = bound_ttl (ntohl (gm->ttl), | ||
1279 | tec.priority); | ||
1280 | /* decrement ttl (always) */ | ||
1281 | ttl_decrement = | ||
1282 | 2 * TTL_DECREMENT + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1283 | TTL_DECREMENT); | ||
1284 | if ((tec.ttl < 0) && | ||
1285 | (((int32_t) (tec.ttl - ttl_decrement)) > 0)) | ||
1286 | { | ||
1287 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1288 | "Dropping query from `%s' due to TTL underflow (%d - %u).\n", | ||
1289 | GNUNET_i2s (cps->ppd.peer), | ||
1290 | tec.ttl, | ||
1291 | ttl_decrement); | ||
1292 | GNUNET_STATISTICS_update (GSF_stats, | ||
1293 | gettext_noop | ||
1294 | ("# requests dropped due TTL underflow"), 1, | ||
1295 | GNUNET_NO); | ||
1296 | /* integer underflow => drop (should be very rare)! */ | ||
1297 | return; | ||
1298 | } | ||
1299 | tec.ttl -= ttl_decrement; | ||
1300 | |||
1301 | /* test if the request already exists */ | ||
1302 | tec.finished = GNUNET_NO; | ||
1303 | GNUNET_CONTAINER_multihashmap_get_multiple (cp->request_map, | ||
1304 | &gm->query, | ||
1305 | &test_exist_cb, | ||
1306 | &tec); | ||
1307 | if (GNUNET_YES == tec.finished) | ||
1308 | return; /* merged into existing request, we're done */ | ||
1309 | |||
1310 | peerreq = GNUNET_new (struct PeerRequest); | ||
1311 | peerreq->cp = cp; | ||
1312 | pr = GSF_pending_request_create_ (options, | ||
1313 | tec.type, | ||
1314 | &gm->query, | ||
1315 | target, | ||
1316 | (bfsize > 0) | ||
1317 | ? (const char *) &opt[bits] | ||
1318 | : NULL, | ||
1319 | bfsize, | ||
1320 | ntohl (gm->filter_mutator), | ||
1321 | 1 /* anonymity */, | ||
1322 | (uint32_t) tec.priority, | ||
1323 | tec.ttl, | ||
1324 | spid, | ||
1325 | GNUNET_PEER_intern (cps->ppd.peer), | ||
1326 | NULL, 0, /* replies_seen */ | ||
1327 | &handle_p2p_reply, | ||
1328 | peerreq); | ||
1329 | GNUNET_assert (NULL != pr); | ||
1330 | prd = GSF_pending_request_get_data_ (pr); | ||
1331 | peerreq->pr = pr; | ||
1332 | GNUNET_break (GNUNET_OK == | ||
1333 | GNUNET_CONTAINER_multihashmap_put (cp->request_map, | ||
1334 | &prd->query, | ||
1335 | peerreq, | ||
1336 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
1337 | GNUNET_STATISTICS_update (GSF_stats, | ||
1338 | gettext_noop ( | ||
1339 | "# P2P query messages received and processed"), | ||
1340 | 1, | ||
1341 | GNUNET_NO); | ||
1342 | GNUNET_STATISTICS_update (GSF_stats, | ||
1343 | gettext_noop ("# P2P searches active"), | ||
1344 | 1, | ||
1345 | GNUNET_NO); | ||
1346 | GSF_pending_request_get_data_ (pr)->has_started = GNUNET_YES; | ||
1347 | GSF_local_lookup_ (pr, | ||
1348 | &GSF_consider_forwarding, | ||
1349 | NULL); | ||
1350 | } | ||
1351 | |||
1352 | |||
1353 | /** | ||
1354 | * Transmit a message to the given peer as soon as possible. | ||
1355 | * If the peer disconnects before the transmission can happen, | ||
1356 | * the callback is invoked with a `NULL` @a buffer. | ||
1357 | * | ||
1358 | * @param cp target peer | ||
1359 | * @param is_query is this a query (#GNUNET_YES) or content (#GNUNET_NO) or neither (#GNUNET_SYSERR) | ||
1360 | * @param priority how important is this request? | ||
1361 | * @param timeout when does this request timeout | ||
1362 | * @param size number of bytes we would like to send to the peer | ||
1363 | * @param env message to send | ||
1364 | */ | ||
1365 | void | ||
1366 | GSF_peer_transmit_ (struct GSF_ConnectedPeer *cp, | ||
1367 | int is_query, | ||
1368 | uint32_t priority, | ||
1369 | struct GNUNET_MQ_Envelope *env) | ||
1370 | { | ||
1371 | struct GSF_PeerTransmitHandle *pth; | ||
1372 | struct GSF_PeerTransmitHandle *pos; | ||
1373 | struct GSF_PeerTransmitHandle *prev; | ||
1374 | |||
1375 | pth = GNUNET_new (struct GSF_PeerTransmitHandle); | ||
1376 | pth->transmission_request_start_time = GNUNET_TIME_absolute_get (); | ||
1377 | pth->env = env; | ||
1378 | pth->is_query = is_query; | ||
1379 | pth->priority = priority; | ||
1380 | pth->cp = cp; | ||
1381 | /* insertion sort (by priority, descending) */ | ||
1382 | prev = NULL; | ||
1383 | pos = cp->pth_head; | ||
1384 | while ((NULL != pos) && (pos->priority > priority)) | ||
1385 | { | ||
1386 | prev = pos; | ||
1387 | pos = pos->next; | ||
1388 | } | ||
1389 | GNUNET_CONTAINER_DLL_insert_after (cp->pth_head, | ||
1390 | cp->pth_tail, | ||
1391 | prev, | ||
1392 | pth); | ||
1393 | if (GNUNET_YES == is_query) | ||
1394 | cp->ppd.pending_queries++; | ||
1395 | else if (GNUNET_NO == is_query) | ||
1396 | cp->ppd.pending_replies++; | ||
1397 | schedule_transmission (pth); | ||
1398 | } | ||
1399 | |||
1400 | |||
1401 | /** | ||
1402 | * Report on receiving a reply; update the performance record of the given peer. | ||
1403 | * | ||
1404 | * @param cp responding peer (will be updated) | ||
1405 | * @param request_time time at which the original query was transmitted | ||
1406 | * @param request_priority priority of the original request | ||
1407 | */ | ||
1408 | void | ||
1409 | GSF_peer_update_performance_ (struct GSF_ConnectedPeer *cp, | ||
1410 | struct GNUNET_TIME_Absolute request_time, | ||
1411 | uint32_t request_priority) | ||
1412 | { | ||
1413 | struct GNUNET_TIME_Relative delay; | ||
1414 | |||
1415 | delay = GNUNET_TIME_absolute_get_duration (request_time); | ||
1416 | cp->ppd.avg_reply_delay.rel_value_us = | ||
1417 | (cp->ppd.avg_reply_delay.rel_value_us * (RUNAVG_DELAY_N - 1) | ||
1418 | + delay.rel_value_us) / RUNAVG_DELAY_N; | ||
1419 | cp->ppd.avg_priority = | ||
1420 | (cp->ppd.avg_priority * (RUNAVG_DELAY_N - 1) | ||
1421 | + request_priority) / RUNAVG_DELAY_N; | ||
1422 | } | ||
1423 | |||
1424 | |||
1425 | /** | ||
1426 | * Report on receiving a reply in response to an initiating client. | ||
1427 | * Remember that this peer is good for this client. | ||
1428 | * | ||
1429 | * @param cp responding peer (will be updated) | ||
1430 | * @param initiator_client local client on responsible for query | ||
1431 | */ | ||
1432 | void | ||
1433 | GSF_peer_update_responder_client_ (struct GSF_ConnectedPeer *cp, | ||
1434 | struct GSF_LocalClient *initiator_client) | ||
1435 | { | ||
1436 | cp->ppd.last_client_replies[cp->last_client_replies_woff++ | ||
1437 | % CS2P_SUCCESS_LIST_SIZE] = initiator_client; | ||
1438 | } | ||
1439 | |||
1440 | |||
1441 | /** | ||
1442 | * Report on receiving a reply in response to an initiating peer. | ||
1443 | * Remember that this peer is good for this initiating peer. | ||
1444 | * | ||
1445 | * @param cp responding peer (will be updated) | ||
1446 | * @param initiator_peer other peer responsible for query | ||
1447 | */ | ||
1448 | void | ||
1449 | GSF_peer_update_responder_peer_ (struct GSF_ConnectedPeer *cp, | ||
1450 | const struct GSF_ConnectedPeer *initiator_peer) | ||
1451 | { | ||
1452 | unsigned int woff; | ||
1453 | |||
1454 | woff = cp->last_p2p_replies_woff % P2P_SUCCESS_LIST_SIZE; | ||
1455 | GNUNET_PEER_change_rc (cp->ppd.last_p2p_replies[woff], -1); | ||
1456 | cp->ppd.last_p2p_replies[woff] = initiator_peer->ppd.pid; | ||
1457 | GNUNET_PEER_change_rc (initiator_peer->ppd.pid, 1); | ||
1458 | cp->last_p2p_replies_woff = (woff + 1) % P2P_SUCCESS_LIST_SIZE; | ||
1459 | } | ||
1460 | |||
1461 | |||
1462 | /** | ||
1463 | * Write peer-respect information to a file - flush the buffer entry! | ||
1464 | * | ||
1465 | * @param cls unused | ||
1466 | * @param key peer identity | ||
1467 | * @param value the `struct GSF_ConnectedPeer` to flush | ||
1468 | * @return #GNUNET_OK to continue iteration | ||
1469 | */ | ||
1470 | static int | ||
1471 | flush_respect (void *cls, | ||
1472 | const struct GNUNET_PeerIdentity *key, | ||
1473 | void *value) | ||
1474 | { | ||
1475 | struct GSF_ConnectedPeer *cp = value; | ||
1476 | struct GNUNET_PeerIdentity pid; | ||
1477 | |||
1478 | if (cp->ppd.respect == cp->disk_respect) | ||
1479 | return GNUNET_OK; /* unchanged */ | ||
1480 | GNUNET_assert (0 != cp->ppd.pid); | ||
1481 | GNUNET_PEER_resolve (cp->ppd.pid, &pid); | ||
1482 | GNUNET_PEERSTORE_store (peerstore, "fs", &pid, "respect", &cp->ppd.respect, | ||
1483 | sizeof(cp->ppd.respect), | ||
1484 | GNUNET_TIME_UNIT_FOREVER_ABS, | ||
1485 | GNUNET_PEERSTORE_STOREOPTION_REPLACE, | ||
1486 | NULL, | ||
1487 | NULL); | ||
1488 | return GNUNET_OK; | ||
1489 | } | ||
1490 | |||
1491 | |||
1492 | /** | ||
1493 | * A peer disconnected from us. Tear down the connected peer | ||
1494 | * record. | ||
1495 | * | ||
1496 | * @param cls unused | ||
1497 | * @param peer identity of peer that disconnected | ||
1498 | * @param internal_cls the corresponding `struct GSF_ConnectedPeer` | ||
1499 | */ | ||
1500 | void | ||
1501 | GSF_peer_disconnect_handler (void *cls, | ||
1502 | const struct GNUNET_PeerIdentity *peer, | ||
1503 | void *internal_cls) | ||
1504 | { | ||
1505 | struct GSF_ConnectedPeer *cp = internal_cls; | ||
1506 | struct GSF_PeerTransmitHandle *pth; | ||
1507 | struct GSF_DelayedHandle *dh; | ||
1508 | |||
1509 | if (NULL == cp) | ||
1510 | return; /* must have been disconnect from core with | ||
1511 | * 'peer' == my_id, ignore */ | ||
1512 | flush_respect (NULL, | ||
1513 | peer, | ||
1514 | cp); | ||
1515 | GNUNET_assert (GNUNET_YES == | ||
1516 | GNUNET_CONTAINER_multipeermap_remove (cp_map, | ||
1517 | peer, | ||
1518 | cp)); | ||
1519 | GNUNET_STATISTICS_set (GSF_stats, | ||
1520 | gettext_noop ("# peers connected"), | ||
1521 | GNUNET_CONTAINER_multipeermap_size (cp_map), | ||
1522 | GNUNET_NO); | ||
1523 | if (NULL != cp->respect_iterate_req) | ||
1524 | { | ||
1525 | GNUNET_PEERSTORE_iterate_cancel (cp->respect_iterate_req); | ||
1526 | cp->respect_iterate_req = NULL; | ||
1527 | } | ||
1528 | if (NULL != cp->rc) | ||
1529 | { | ||
1530 | GNUNET_ATS_reserve_bandwidth_cancel (cp->rc); | ||
1531 | cp->rc = NULL; | ||
1532 | } | ||
1533 | if (NULL != cp->rc_delay_task) | ||
1534 | { | ||
1535 | GNUNET_SCHEDULER_cancel (cp->rc_delay_task); | ||
1536 | cp->rc_delay_task = NULL; | ||
1537 | } | ||
1538 | GNUNET_CONTAINER_multihashmap_iterate (cp->request_map, | ||
1539 | &cancel_pending_request, | ||
1540 | cp); | ||
1541 | GNUNET_CONTAINER_multihashmap_destroy (cp->request_map); | ||
1542 | cp->request_map = NULL; | ||
1543 | GSF_plan_notify_peer_disconnect_ (cp); | ||
1544 | GNUNET_LOAD_value_free (cp->ppd.transmission_delay); | ||
1545 | GNUNET_PEER_decrement_rcs (cp->ppd.last_p2p_replies, | ||
1546 | P2P_SUCCESS_LIST_SIZE); | ||
1547 | memset (cp->ppd.last_p2p_replies, | ||
1548 | 0, | ||
1549 | sizeof(cp->ppd.last_p2p_replies)); | ||
1550 | GSF_push_stop_ (cp); | ||
1551 | while (NULL != (pth = cp->pth_head)) | ||
1552 | { | ||
1553 | GNUNET_CONTAINER_DLL_remove (cp->pth_head, | ||
1554 | cp->pth_tail, | ||
1555 | pth); | ||
1556 | if (GNUNET_YES == pth->is_query) | ||
1557 | GNUNET_assert (0 < cp->ppd.pending_queries--); | ||
1558 | else if (GNUNET_NO == pth->is_query) | ||
1559 | GNUNET_assert (0 < cp->ppd.pending_replies--); | ||
1560 | GNUNET_free (pth); | ||
1561 | } | ||
1562 | while (NULL != (dh = cp->delayed_head)) | ||
1563 | { | ||
1564 | GNUNET_CONTAINER_DLL_remove (cp->delayed_head, | ||
1565 | cp->delayed_tail, | ||
1566 | dh); | ||
1567 | GNUNET_MQ_discard (dh->env); | ||
1568 | cp->delay_queue_size--; | ||
1569 | GNUNET_SCHEDULER_cancel (dh->delay_task); | ||
1570 | GNUNET_free (dh); | ||
1571 | } | ||
1572 | GNUNET_PEER_change_rc (cp->ppd.pid, -1); | ||
1573 | if (NULL != cp->mig_revive_task) | ||
1574 | { | ||
1575 | GNUNET_SCHEDULER_cancel (cp->mig_revive_task); | ||
1576 | cp->mig_revive_task = NULL; | ||
1577 | } | ||
1578 | GNUNET_break (0 == cp->ppd.pending_queries); | ||
1579 | GNUNET_break (0 == cp->ppd.pending_replies); | ||
1580 | GNUNET_free (cp); | ||
1581 | } | ||
1582 | |||
1583 | |||
1584 | /** | ||
1585 | * Closure for #call_iterator(). | ||
1586 | */ | ||
1587 | struct IterationContext | ||
1588 | { | ||
1589 | /** | ||
1590 | * Function to call on each entry. | ||
1591 | */ | ||
1592 | GSF_ConnectedPeerIterator it; | ||
1593 | |||
1594 | /** | ||
1595 | * Closure for @e it. | ||
1596 | */ | ||
1597 | void *it_cls; | ||
1598 | }; | ||
1599 | |||
1600 | |||
1601 | /** | ||
1602 | * Function that calls the callback for each peer. | ||
1603 | * | ||
1604 | * @param cls the `struct IterationContext *` | ||
1605 | * @param key identity of the peer | ||
1606 | * @param value the `struct GSF_ConnectedPeer *` | ||
1607 | * @return #GNUNET_YES to continue iteration | ||
1608 | */ | ||
1609 | static int | ||
1610 | call_iterator (void *cls, | ||
1611 | const struct GNUNET_PeerIdentity *key, | ||
1612 | void *value) | ||
1613 | { | ||
1614 | struct IterationContext *ic = cls; | ||
1615 | struct GSF_ConnectedPeer *cp = value; | ||
1616 | |||
1617 | ic->it (ic->it_cls, | ||
1618 | key, cp, | ||
1619 | &cp->ppd); | ||
1620 | return GNUNET_YES; | ||
1621 | } | ||
1622 | |||
1623 | |||
1624 | /** | ||
1625 | * Iterate over all connected peers. | ||
1626 | * | ||
1627 | * @param it function to call for each peer | ||
1628 | * @param it_cls closure for @a it | ||
1629 | */ | ||
1630 | void | ||
1631 | GSF_iterate_connected_peers_ (GSF_ConnectedPeerIterator it, | ||
1632 | void *it_cls) | ||
1633 | { | ||
1634 | struct IterationContext ic; | ||
1635 | |||
1636 | ic.it = it; | ||
1637 | ic.it_cls = it_cls; | ||
1638 | GNUNET_CONTAINER_multipeermap_iterate (cp_map, | ||
1639 | &call_iterator, | ||
1640 | &ic); | ||
1641 | } | ||
1642 | |||
1643 | |||
1644 | /** | ||
1645 | * Obtain the identity of a connected peer. | ||
1646 | * | ||
1647 | * @param cp peer to get identity of | ||
1648 | * @param id identity to set (written to) | ||
1649 | */ | ||
1650 | void | ||
1651 | GSF_connected_peer_get_identity_ (const struct GSF_ConnectedPeer *cp, | ||
1652 | struct GNUNET_PeerIdentity *id) | ||
1653 | { | ||
1654 | GNUNET_assert (0 != cp->ppd.pid); | ||
1655 | GNUNET_PEER_resolve (cp->ppd.pid, id); | ||
1656 | } | ||
1657 | |||
1658 | |||
1659 | /** | ||
1660 | * Obtain the identity of a connected peer. | ||
1661 | * | ||
1662 | * @param cp peer to get identity of | ||
1663 | * @return reference to peer identity, valid until peer disconnects (!) | ||
1664 | */ | ||
1665 | const struct GNUNET_PeerIdentity * | ||
1666 | GSF_connected_peer_get_identity2_ (const struct GSF_ConnectedPeer *cp) | ||
1667 | { | ||
1668 | GNUNET_assert (0 != cp->ppd.pid); | ||
1669 | return GNUNET_PEER_resolve2 (cp->ppd.pid); | ||
1670 | } | ||
1671 | |||
1672 | |||
1673 | /** | ||
1674 | * Ask a peer to stop migrating data to us until the given point | ||
1675 | * in time. | ||
1676 | * | ||
1677 | * @param cp peer to ask | ||
1678 | * @param block_time until when to block | ||
1679 | */ | ||
1680 | void | ||
1681 | GSF_block_peer_migration_ (struct GSF_ConnectedPeer *cp, | ||
1682 | struct GNUNET_TIME_Absolute block_time) | ||
1683 | { | ||
1684 | struct GNUNET_MQ_Envelope *env; | ||
1685 | struct MigrationStopMessage *msm; | ||
1686 | |||
1687 | if (cp->last_migration_block.abs_value_us > block_time.abs_value_us) | ||
1688 | { | ||
1689 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1690 | "Migration already blocked for another %s\n", | ||
1691 | GNUNET_STRINGS_relative_time_to_string ( | ||
1692 | GNUNET_TIME_absolute_get_remaining | ||
1693 | (cp-> | ||
1694 | last_migration_block), GNUNET_YES)); | ||
1695 | return; /* already blocked */ | ||
1696 | } | ||
1697 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to stop migration for %s\n", | ||
1698 | GNUNET_STRINGS_relative_time_to_string ( | ||
1699 | GNUNET_TIME_absolute_get_remaining (block_time), | ||
1700 | GNUNET_YES)); | ||
1701 | cp->last_migration_block = block_time; | ||
1702 | env = GNUNET_MQ_msg (msm, | ||
1703 | GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP); | ||
1704 | msm->reserved = htonl (0); | ||
1705 | msm->duration | ||
1706 | = GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining | ||
1707 | (cp->last_migration_block)); | ||
1708 | GNUNET_STATISTICS_update (GSF_stats, | ||
1709 | gettext_noop ("# migration stop messages sent"), | ||
1710 | 1, | ||
1711 | GNUNET_NO); | ||
1712 | GSF_peer_transmit_ (cp, | ||
1713 | GNUNET_SYSERR, | ||
1714 | UINT32_MAX, | ||
1715 | env); | ||
1716 | } | ||
1717 | |||
1718 | |||
1719 | /** | ||
1720 | * Notify core about a preference we have for the given peer | ||
1721 | * (to allocate more resources towards it). The change will | ||
1722 | * be communicated the next time we reserve bandwidth with | ||
1723 | * core (not instantly). | ||
1724 | * | ||
1725 | * @param cp peer to reserve bandwidth from | ||
1726 | * @param pref preference change | ||
1727 | */ | ||
1728 | void | ||
1729 | GSF_connected_peer_change_preference_ (struct GSF_ConnectedPeer *cp, | ||
1730 | uint64_t pref) | ||
1731 | { | ||
1732 | cp->inc_preference += pref; | ||
1733 | } | ||
1734 | |||
1735 | |||
1736 | /** | ||
1737 | * Call this method periodically to flush respect information to disk. | ||
1738 | * | ||
1739 | * @param cls closure, not used | ||
1740 | */ | ||
1741 | static void | ||
1742 | cron_flush_respect (void *cls) | ||
1743 | { | ||
1744 | fr_task = NULL; | ||
1745 | GNUNET_CONTAINER_multipeermap_iterate (cp_map, | ||
1746 | &flush_respect, | ||
1747 | NULL); | ||
1748 | fr_task = GNUNET_SCHEDULER_add_delayed_with_priority (RESPECT_FLUSH_FREQ, | ||
1749 | GNUNET_SCHEDULER_PRIORITY_HIGH, | ||
1750 | &cron_flush_respect, | ||
1751 | NULL); | ||
1752 | } | ||
1753 | |||
1754 | |||
1755 | /** | ||
1756 | * Initialize peer management subsystem. | ||
1757 | */ | ||
1758 | void | ||
1759 | GSF_connected_peer_init_ () | ||
1760 | { | ||
1761 | cp_map = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); | ||
1762 | peerstore = GNUNET_PEERSTORE_connect (GSF_cfg); | ||
1763 | fr_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_HIGH, | ||
1764 | &cron_flush_respect, NULL); | ||
1765 | } | ||
1766 | |||
1767 | |||
1768 | /** | ||
1769 | * Shutdown peer management subsystem. | ||
1770 | */ | ||
1771 | void | ||
1772 | GSF_connected_peer_done_ () | ||
1773 | { | ||
1774 | GNUNET_CONTAINER_multipeermap_iterate (cp_map, | ||
1775 | &flush_respect, | ||
1776 | NULL); | ||
1777 | GNUNET_SCHEDULER_cancel (fr_task); | ||
1778 | fr_task = NULL; | ||
1779 | GNUNET_CONTAINER_multipeermap_destroy (cp_map); | ||
1780 | cp_map = NULL; | ||
1781 | GNUNET_PEERSTORE_disconnect (peerstore, | ||
1782 | GNUNET_YES); | ||
1783 | } | ||
1784 | |||
1785 | |||
1786 | /** | ||
1787 | * Iterator to remove references to LC entry. | ||
1788 | * | ||
1789 | * @param cls the `struct GSF_LocalClient *` to look for | ||
1790 | * @param key current key code | ||
1791 | * @param value value in the hash map (peer entry) | ||
1792 | * @return #GNUNET_YES (we should continue to iterate) | ||
1793 | */ | ||
1794 | static int | ||
1795 | clean_local_client (void *cls, | ||
1796 | const struct GNUNET_PeerIdentity *key, | ||
1797 | void *value) | ||
1798 | { | ||
1799 | const struct GSF_LocalClient *lc = cls; | ||
1800 | struct GSF_ConnectedPeer *cp = value; | ||
1801 | unsigned int i; | ||
1802 | |||
1803 | for (i = 0; i < CS2P_SUCCESS_LIST_SIZE; i++) | ||
1804 | if (cp->ppd.last_client_replies[i] == lc) | ||
1805 | cp->ppd.last_client_replies[i] = NULL; | ||
1806 | return GNUNET_YES; | ||
1807 | } | ||
1808 | |||
1809 | |||
1810 | /** | ||
1811 | * Notification that a local client disconnected. Clean up all of our | ||
1812 | * references to the given handle. | ||
1813 | * | ||
1814 | * @param lc handle to the local client (henceforth invalid) | ||
1815 | */ | ||
1816 | void | ||
1817 | GSF_handle_local_client_disconnect_ (const struct GSF_LocalClient *lc) | ||
1818 | { | ||
1819 | if (NULL == cp_map) | ||
1820 | return; /* already cleaned up */ | ||
1821 | GNUNET_CONTAINER_multipeermap_iterate (cp_map, | ||
1822 | &clean_local_client, | ||
1823 | (void *) lc); | ||
1824 | } | ||
1825 | |||
1826 | |||
1827 | /* end of gnunet-service-fs_cp.c */ | ||
diff --git a/src/fs/gnunet-service-fs_cp.h b/src/fs/gnunet-service-fs_cp.h deleted file mode 100644 index 54f952778..000000000 --- a/src/fs/gnunet-service-fs_cp.h +++ /dev/null | |||
@@ -1,415 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_cp.h | ||
23 | * @brief API to handle 'connected peers' | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_FS_CP_H | ||
27 | #define GNUNET_SERVICE_FS_CP_H | ||
28 | |||
29 | #include "fs.h" | ||
30 | #include "gnunet-service-fs.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Maximum number of outgoing messages we queue per peer. | ||
35 | * | ||
36 | * Performance measurements for 2 peer setup for 50 MB file | ||
37 | * (using perf_gnunet_service_fs_p2p): | ||
38 | * | ||
39 | * 24: 2-3 MB/s # ~ 24 MB RAM | ||
40 | * 256: 8 MB/s # ~256 MB RAM | ||
41 | * | ||
42 | * Conclusion: 24 should suffice (reasonable | ||
43 | * performance, no excessive memory use). | ||
44 | */ | ||
45 | #define MAX_QUEUE_PER_PEER 24 | ||
46 | |||
47 | /** | ||
48 | * Length of the P2P success tracker. Note that having a very long | ||
49 | * list can also hurt performance. | ||
50 | */ | ||
51 | #define P2P_SUCCESS_LIST_SIZE 8 | ||
52 | |||
53 | /** | ||
54 | * Length of the CS-2-P success tracker. Note that | ||
55 | * having a very long list can also hurt performance. | ||
56 | */ | ||
57 | #define CS2P_SUCCESS_LIST_SIZE 8 | ||
58 | |||
59 | |||
60 | /** | ||
61 | * Performance data kept for a peer. | ||
62 | */ | ||
63 | struct GSF_PeerPerformanceData | ||
64 | { | ||
65 | /** | ||
66 | * List of the last clients for which this peer successfully | ||
67 | * answered a query. | ||
68 | */ | ||
69 | struct GSF_LocalClient *last_client_replies[CS2P_SUCCESS_LIST_SIZE]; | ||
70 | |||
71 | /** | ||
72 | * List of the last PIDs for which | ||
73 | * this peer successfully answered a query; | ||
74 | * We use 0 to indicate no successful reply. | ||
75 | */ | ||
76 | GNUNET_PEER_Id last_p2p_replies[P2P_SUCCESS_LIST_SIZE]; | ||
77 | |||
78 | /** | ||
79 | * Average delay between sending the peer a request and | ||
80 | * getting a reply (only calculated over the requests for | ||
81 | * which we actually got a reply). Calculated | ||
82 | * as a moving average: new_delay = ((n-1)*last_delay+curr_delay) / n | ||
83 | */ | ||
84 | struct GNUNET_TIME_Relative avg_reply_delay; | ||
85 | |||
86 | /** | ||
87 | * If we get content we already have from this peer, for how | ||
88 | * long do we block it? Adjusted based on the fraction of | ||
89 | * redundant data we receive, between 1s and 1h. | ||
90 | */ | ||
91 | struct GNUNET_TIME_Relative migration_delay; | ||
92 | |||
93 | /** | ||
94 | * Point in time until which this peer does not want us to migrate content | ||
95 | * to it. | ||
96 | */ | ||
97 | struct GNUNET_TIME_Absolute migration_blocked_until; | ||
98 | |||
99 | /** | ||
100 | * Transmission times for the last MAX_QUEUE_PER_PEER | ||
101 | * requests for this peer. Used as a ring buffer, current | ||
102 | * offset is stored in 'last_request_times_off'. If the | ||
103 | * oldest entry is more recent than the 'avg_delay', we should | ||
104 | * not send any more requests right now. | ||
105 | */ | ||
106 | struct GNUNET_TIME_Absolute last_request_times[MAX_QUEUE_PER_PEER]; | ||
107 | |||
108 | /** | ||
109 | * How long does it typically take for us to transmit a message | ||
110 | * to this peer? (delay between the request being issued and | ||
111 | * the callback being invoked). | ||
112 | */ | ||
113 | struct GNUNET_LOAD_Value *transmission_delay; | ||
114 | |||
115 | /** | ||
116 | * Average priority of successful replies. Calculated | ||
117 | * as a moving average: new_avg = ((n-1)*last_avg+curr_prio) / n | ||
118 | */ | ||
119 | double avg_priority; | ||
120 | |||
121 | /** | ||
122 | * The peer's identity (interned version). | ||
123 | */ | ||
124 | GNUNET_PEER_Id pid; | ||
125 | |||
126 | /** | ||
127 | * The peer's identity (pointer). | ||
128 | */ | ||
129 | const struct GNUNET_PeerIdentity *peer; | ||
130 | |||
131 | /** | ||
132 | * Respect rating for this peer | ||
133 | */ | ||
134 | uint32_t respect; | ||
135 | |||
136 | /** | ||
137 | * Number of pending queries (replies are not counted) | ||
138 | */ | ||
139 | unsigned int pending_queries; | ||
140 | |||
141 | /** | ||
142 | * Number of pending replies (queries are not counted) | ||
143 | */ | ||
144 | unsigned int pending_replies; | ||
145 | }; | ||
146 | |||
147 | |||
148 | /** | ||
149 | * Signature of function called on a connected peer. | ||
150 | * | ||
151 | * @param cls closure | ||
152 | * @param peer identity of the peer | ||
153 | * @param cp handle to the connected peer record | ||
154 | * @param perf peer performance data | ||
155 | */ | ||
156 | typedef void | ||
157 | (*GSF_ConnectedPeerIterator) (void *cls, | ||
158 | const struct GNUNET_PeerIdentity *peer, | ||
159 | struct GSF_ConnectedPeer *cp, | ||
160 | const struct GSF_PeerPerformanceData *ppd); | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Function called to get a message for transmission. | ||
165 | * | ||
166 | * @param cls closure | ||
167 | * @param buf_size number of bytes available in @a buf | ||
168 | * @param buf where to copy the message, NULL on error (peer disconnect) | ||
169 | * @return number of bytes copied to @a buf, can be 0 (without indicating an error) | ||
170 | */ | ||
171 | typedef size_t | ||
172 | (*GSF_GetMessageCallback) (void *cls, | ||
173 | size_t buf_size, | ||
174 | void *buf); | ||
175 | |||
176 | |||
177 | /** | ||
178 | * Signature of function called on a reservation success or failure. | ||
179 | * | ||
180 | * @param cls closure | ||
181 | * @param cp handle to the connected peer record | ||
182 | * @param success #GNUNET_YES on success, #GNUNET_NO on failure | ||
183 | */ | ||
184 | typedef void | ||
185 | (*GSF_PeerReserveCallback) (void *cls, | ||
186 | struct GSF_ConnectedPeer *cp, | ||
187 | int success); | ||
188 | |||
189 | |||
190 | /** | ||
191 | * Handle to cancel a transmission request. | ||
192 | */ | ||
193 | struct GSF_PeerTransmitHandle; | ||
194 | |||
195 | |||
196 | /** | ||
197 | * A peer connected to us. Setup the connected peer | ||
198 | * records. | ||
199 | * | ||
200 | * @param cls NULL | ||
201 | * @param peer identity of peer that connected | ||
202 | * @param mq queue for sending messages to @a peer | ||
203 | * @return internal handle for the peer | ||
204 | */ | ||
205 | void * | ||
206 | GSF_peer_connect_handler (void *cls, | ||
207 | const struct GNUNET_PeerIdentity *peer, | ||
208 | struct GNUNET_MQ_Handle *mq); | ||
209 | |||
210 | |||
211 | /** | ||
212 | * Get a handle for a connected peer. | ||
213 | * | ||
214 | * @param peer peer's identity | ||
215 | * @return NULL if this peer is not currently connected | ||
216 | */ | ||
217 | struct GSF_ConnectedPeer * | ||
218 | GSF_peer_get_ (const struct GNUNET_PeerIdentity *peer); | ||
219 | |||
220 | |||
221 | /** | ||
222 | * Update the latency information kept for the given peer. | ||
223 | * | ||
224 | * @param id peer record to update | ||
225 | * @param latency current latency value | ||
226 | */ | ||
227 | void | ||
228 | GSF_update_peer_latency_ (const struct GNUNET_PeerIdentity *id, | ||
229 | struct GNUNET_TIME_Relative latency); | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Transmit a message to the given peer as soon as possible. | ||
234 | * If the peer disconnects before the transmission can happen, | ||
235 | * the callback is invoked with a 'NULL' buffer. | ||
236 | * | ||
237 | * @param cp target peer | ||
238 | * @param is_query is this a query (#GNUNET_YES) or content (#GNUNET_NO) | ||
239 | * @param priority how important is this request? | ||
240 | * @param env envelope of message to send | ||
241 | */ | ||
242 | void | ||
243 | GSF_peer_transmit_ (struct GSF_ConnectedPeer *cp, | ||
244 | int is_query, | ||
245 | uint32_t priority, | ||
246 | struct GNUNET_MQ_Envelope *env); | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Report on receiving a reply; update the performance record of the given peer. | ||
251 | * | ||
252 | * @param cp responding peer (will be updated) | ||
253 | * @param request_time time at which the original query was transmitted | ||
254 | * @param request_priority priority of the original request | ||
255 | */ | ||
256 | void | ||
257 | GSF_peer_update_performance_ (struct GSF_ConnectedPeer *cp, | ||
258 | struct GNUNET_TIME_Absolute request_time, | ||
259 | uint32_t request_priority); | ||
260 | |||
261 | |||
262 | /** | ||
263 | * Report on receiving a reply in response to an initiating client. | ||
264 | * Remember that this peer is good for this client. | ||
265 | * | ||
266 | * @param cp responding peer (will be updated) | ||
267 | * @param initiator_client local client on responsible for query | ||
268 | */ | ||
269 | void | ||
270 | GSF_peer_update_responder_client_ (struct GSF_ConnectedPeer *cp, | ||
271 | struct GSF_LocalClient *initiator_client); | ||
272 | |||
273 | |||
274 | /** | ||
275 | * Report on receiving a reply in response to an initiating peer. | ||
276 | * Remember that this peer is good for this initiating peer. | ||
277 | * | ||
278 | * @param cp responding peer (will be updated) | ||
279 | * @param initiator_peer other peer responsible for query | ||
280 | */ | ||
281 | void | ||
282 | GSF_peer_update_responder_peer_ (struct GSF_ConnectedPeer *cp, | ||
283 | const struct GSF_ConnectedPeer | ||
284 | *initiator_peer); | ||
285 | |||
286 | |||
287 | /** | ||
288 | * Handle P2P #GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP message. | ||
289 | * | ||
290 | * @param cls closure, the `struct GSF_ConnectedPeer` | ||
291 | * @param msm the actual message | ||
292 | */ | ||
293 | void | ||
294 | handle_p2p_migration_stop (void *cls, | ||
295 | const struct MigrationStopMessage *message); | ||
296 | |||
297 | |||
298 | /** | ||
299 | * Handle P2P "QUERY" message. | ||
300 | * | ||
301 | * @param cls the `struct GSF_ConnectedPeer` of the other sender | ||
302 | * @param gm the actual message | ||
303 | */ | ||
304 | void | ||
305 | handle_p2p_get (void *cls, | ||
306 | const struct GetMessage *gm); | ||
307 | |||
308 | |||
309 | /** | ||
310 | * Return the performance data record for the given peer | ||
311 | * | ||
312 | * @param cp peer to query | ||
313 | * @return performance data record for the peer | ||
314 | */ | ||
315 | struct GSF_PeerPerformanceData * | ||
316 | GSF_get_peer_performance_data_ (struct GSF_ConnectedPeer *cp); | ||
317 | |||
318 | |||
319 | /** | ||
320 | * Ask a peer to stop migrating data to us until the given point | ||
321 | * in time. | ||
322 | * | ||
323 | * @param cp peer to ask | ||
324 | * @param block_time until when to block | ||
325 | */ | ||
326 | void | ||
327 | GSF_block_peer_migration_ (struct GSF_ConnectedPeer *cp, | ||
328 | struct GNUNET_TIME_Absolute block_time); | ||
329 | |||
330 | |||
331 | /** | ||
332 | * A peer disconnected from us. Tear down the connected peer | ||
333 | * record. | ||
334 | * | ||
335 | * @param cls unused | ||
336 | * @param peer identity of peer that connected | ||
337 | * @param internal_cls our `struct GSF_ConnectedPeer` for @a peer | ||
338 | */ | ||
339 | void | ||
340 | GSF_peer_disconnect_handler (void *cls, | ||
341 | const struct GNUNET_PeerIdentity *peer, | ||
342 | void *internal_cls); | ||
343 | |||
344 | |||
345 | /** | ||
346 | * Notification that a local client disconnected. Clean up all of our | ||
347 | * references to the given handle. | ||
348 | * | ||
349 | * @param lc handle to the local client (henceforth invalid) | ||
350 | */ | ||
351 | void | ||
352 | GSF_handle_local_client_disconnect_ (const struct GSF_LocalClient *lc); | ||
353 | |||
354 | |||
355 | /** | ||
356 | * Notify core about a preference we have for the given peer | ||
357 | * (to allocate more resources towards it). The change will | ||
358 | * be communicated the next time we reserve bandwidth with | ||
359 | * core (not instantly). | ||
360 | * | ||
361 | * @param cp peer to reserve bandwidth from | ||
362 | * @param pref preference change | ||
363 | */ | ||
364 | void | ||
365 | GSF_connected_peer_change_preference_ (struct GSF_ConnectedPeer *cp, | ||
366 | uint64_t pref); | ||
367 | |||
368 | |||
369 | /** | ||
370 | * Obtain the identity of a connected peer. | ||
371 | * | ||
372 | * @param cp peer to get identity of | ||
373 | * @param id identity to set (written to) | ||
374 | */ | ||
375 | void | ||
376 | GSF_connected_peer_get_identity_ (const struct GSF_ConnectedPeer *cp, | ||
377 | struct GNUNET_PeerIdentity *id); | ||
378 | |||
379 | |||
380 | /** | ||
381 | * Obtain the identity of a connected peer. | ||
382 | * | ||
383 | * @param cp peer to get identity of | ||
384 | * @return reference to peer identity, valid until peer disconnects (!) | ||
385 | */ | ||
386 | const struct GNUNET_PeerIdentity * | ||
387 | GSF_connected_peer_get_identity2_ (const struct GSF_ConnectedPeer *cp); | ||
388 | |||
389 | |||
390 | /** | ||
391 | * Iterate over all connected peers. | ||
392 | * | ||
393 | * @param it function to call for each peer | ||
394 | * @param it_cls closure for it | ||
395 | */ | ||
396 | void | ||
397 | GSF_iterate_connected_peers_ (GSF_ConnectedPeerIterator it, void *it_cls); | ||
398 | |||
399 | |||
400 | /** | ||
401 | * Initialize peer management subsystem. | ||
402 | */ | ||
403 | void | ||
404 | GSF_connected_peer_init_ (void); | ||
405 | |||
406 | |||
407 | /** | ||
408 | * Shutdown peer management subsystem. | ||
409 | */ | ||
410 | void | ||
411 | GSF_connected_peer_done_ (void); | ||
412 | |||
413 | |||
414 | #endif | ||
415 | /* end of gnunet-service-fs_cp.h */ | ||
diff --git a/src/fs/gnunet-service-fs_indexing.c b/src/fs/gnunet-service-fs_indexing.c deleted file mode 100644 index f4d560176..000000000 --- a/src/fs/gnunet-service-fs_indexing.c +++ /dev/null | |||
@@ -1,522 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_indexing.c | ||
23 | * @brief program that provides indexing functions of the file-sharing service | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include <float.h> | ||
28 | #include "gnunet_core_service.h" | ||
29 | #include "gnunet_datastore_service.h" | ||
30 | #include "gnunet_peer_lib.h" | ||
31 | #include "gnunet_protocols.h" | ||
32 | #include "gnunet_signatures.h" | ||
33 | #include "gnunet_util_lib.h" | ||
34 | #include "gnunet-service-fs.h" | ||
35 | #include "gnunet-service-fs_indexing.h" | ||
36 | #include "fs.h" | ||
37 | |||
38 | /** | ||
39 | * In-memory information about indexed files (also available | ||
40 | * on-disk). | ||
41 | */ | ||
42 | struct IndexInfo | ||
43 | { | ||
44 | /** | ||
45 | * This is a doubly linked list. | ||
46 | */ | ||
47 | struct IndexInfo *next; | ||
48 | |||
49 | /** | ||
50 | * This is a doubly linked list. | ||
51 | */ | ||
52 | struct IndexInfo *prev; | ||
53 | |||
54 | /** | ||
55 | * Name of the indexed file. Memory allocated | ||
56 | * at the end of this struct (do not free). | ||
57 | */ | ||
58 | const char *filename; | ||
59 | |||
60 | /** | ||
61 | * Context for transmitting confirmation to client, | ||
62 | * NULL if we've done this already. | ||
63 | */ | ||
64 | struct GNUNET_SERVER_TransmitContext *tc; | ||
65 | |||
66 | /** | ||
67 | * Context for hashing of the file. | ||
68 | */ | ||
69 | struct GNUNET_CRYPTO_FileHashContext *fhc; | ||
70 | |||
71 | /** | ||
72 | * Hash of the contents of the file. | ||
73 | */ | ||
74 | struct GNUNET_HashCode file_id; | ||
75 | }; | ||
76 | |||
77 | |||
78 | /** | ||
79 | * Head of linked list of indexed files. | ||
80 | * FIXME: we don't need both a DLL and a hashmap here! | ||
81 | */ | ||
82 | static struct IndexInfo *indexed_files_head; | ||
83 | |||
84 | /** | ||
85 | * Tail of linked list of indexed files. | ||
86 | */ | ||
87 | static struct IndexInfo *indexed_files_tail; | ||
88 | |||
89 | /** | ||
90 | * Maps hash over content of indexed files to the respective 'struct IndexInfo'. | ||
91 | * The filenames are pointers into the indexed_files linked list and | ||
92 | * do not need to be freed. | ||
93 | */ | ||
94 | static struct GNUNET_CONTAINER_MultiHashMap *ifm; | ||
95 | |||
96 | /** | ||
97 | * Our configuration. | ||
98 | */ | ||
99 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
100 | |||
101 | /** | ||
102 | * Datastore handle. Created and destroyed by code in | ||
103 | * gnunet-service-fs (this is an alias). | ||
104 | */ | ||
105 | static struct GNUNET_DATASTORE_Handle *dsh; | ||
106 | |||
107 | |||
108 | /** | ||
109 | * Write the current index information list to disk. | ||
110 | */ | ||
111 | static void | ||
112 | write_index_list () | ||
113 | { | ||
114 | struct GNUNET_BIO_WriteHandle *wh; | ||
115 | char *fn; | ||
116 | struct IndexInfo *pos; | ||
117 | |||
118 | if (GNUNET_OK != | ||
119 | GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) | ||
120 | { | ||
121 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
122 | "fs", | ||
123 | "INDEXDB"); | ||
124 | return; | ||
125 | } | ||
126 | wh = GNUNET_BIO_write_open_file (fn); | ||
127 | if (NULL == wh) | ||
128 | { | ||
129 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
130 | _ ("Could not open `%s'.\n"), | ||
131 | fn); | ||
132 | GNUNET_free (fn); | ||
133 | return; | ||
134 | } | ||
135 | for (pos = indexed_files_head; NULL != pos; pos = pos->next) | ||
136 | if ((GNUNET_OK != GNUNET_BIO_write (wh, | ||
137 | "fs-indexing-file-id", | ||
138 | &pos->file_id, | ||
139 | sizeof(struct GNUNET_HashCode))) || | ||
140 | (GNUNET_OK != GNUNET_BIO_write_string (wh, | ||
141 | "fs-indexing-filename", | ||
142 | pos->filename))) | ||
143 | break; | ||
144 | if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL)) | ||
145 | { | ||
146 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
147 | _ ("Error writing `%s'.\n"), | ||
148 | fn); | ||
149 | GNUNET_free (fn); | ||
150 | return; | ||
151 | } | ||
152 | GNUNET_free (fn); | ||
153 | } | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Read index information from disk. | ||
158 | */ | ||
159 | static void | ||
160 | read_index_list () | ||
161 | { | ||
162 | struct GNUNET_BIO_ReadHandle *rh; | ||
163 | char *fn; | ||
164 | struct IndexInfo *pos; | ||
165 | char *fname; | ||
166 | struct GNUNET_HashCode hc; | ||
167 | size_t slen; | ||
168 | char *emsg; | ||
169 | |||
170 | if (GNUNET_OK != | ||
171 | GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) | ||
172 | { | ||
173 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
174 | "fs", | ||
175 | "INDEXDB"); | ||
176 | return; | ||
177 | } | ||
178 | if (GNUNET_NO == GNUNET_DISK_file_test (fn)) | ||
179 | { | ||
180 | /* no index info yet */ | ||
181 | GNUNET_free (fn); | ||
182 | return; | ||
183 | } | ||
184 | rh = GNUNET_BIO_read_open_file (fn); | ||
185 | if (NULL == rh) | ||
186 | { | ||
187 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
188 | _ ("Could not open `%s'.\n"), | ||
189 | fn); | ||
190 | GNUNET_free (fn); | ||
191 | return; | ||
192 | } | ||
193 | while ( | ||
194 | (GNUNET_OK == GNUNET_BIO_read (rh, | ||
195 | "Hash of indexed file", | ||
196 | &hc, | ||
197 | sizeof(struct GNUNET_HashCode))) && | ||
198 | (GNUNET_OK == | ||
199 | GNUNET_BIO_read_string (rh, "Name of indexed file", &fname, 1024 * 16)) && | ||
200 | (fname != NULL)) | ||
201 | { | ||
202 | slen = strlen (fname) + 1; | ||
203 | pos = GNUNET_malloc (sizeof(struct IndexInfo) + slen); | ||
204 | pos->file_id = hc; | ||
205 | pos->filename = (const char *) &pos[1]; | ||
206 | GNUNET_memcpy (&pos[1], fname, slen); | ||
207 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put ( | ||
208 | ifm, | ||
209 | &pos->file_id, | ||
210 | pos, | ||
211 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
212 | { | ||
213 | GNUNET_free (pos); | ||
214 | } | ||
215 | else | ||
216 | { | ||
217 | GNUNET_CONTAINER_DLL_insert (indexed_files_head, indexed_files_tail, pos); | ||
218 | } | ||
219 | GNUNET_free (fname); | ||
220 | } | ||
221 | if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) | ||
222 | GNUNET_free (emsg); | ||
223 | GNUNET_free (fn); | ||
224 | } | ||
225 | |||
226 | |||
227 | /** | ||
228 | * Continuation called from datastore's remove | ||
229 | * function. | ||
230 | * | ||
231 | * @param cls unused | ||
232 | * @param success did the deletion work? | ||
233 | * @param min_expiration minimum expiration time required for content to be stored | ||
234 | * @param msg error message | ||
235 | */ | ||
236 | static void | ||
237 | remove_cont (void *cls, | ||
238 | int success, | ||
239 | struct GNUNET_TIME_Absolute min_expiration, | ||
240 | const char *msg) | ||
241 | { | ||
242 | if (GNUNET_OK != success) | ||
243 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
244 | _ ("Failed to delete bogus block: %s\n"), | ||
245 | msg); | ||
246 | } | ||
247 | |||
248 | |||
249 | /** | ||
250 | * We've received an on-demand encoded block from the datastore. | ||
251 | * Attempt to do on-demand encoding and (if successful), call the | ||
252 | * continuation with the resulting block. On error, clean up and ask | ||
253 | * the datastore for more results. | ||
254 | * | ||
255 | * @param key key for the content | ||
256 | * @param size number of bytes in data | ||
257 | * @param data content stored | ||
258 | * @param type type of the content | ||
259 | * @param priority priority of the content | ||
260 | * @param anonymity anonymity-level for the content | ||
261 | * @param replication replication-level for the content | ||
262 | * @param expiration expiration time for the content | ||
263 | * @param uid unique identifier for the datum; | ||
264 | * maybe 0 if no unique identifier is available | ||
265 | * @param cont function to call with the actual block (at most once, on success) | ||
266 | * @param cont_cls closure for cont | ||
267 | * @return GNUNET_OK on success | ||
268 | */ | ||
269 | int | ||
270 | GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode *key, | ||
271 | uint32_t size, | ||
272 | const void *data, | ||
273 | enum GNUNET_BLOCK_Type type, | ||
274 | uint32_t priority, | ||
275 | uint32_t anonymity, | ||
276 | uint32_t replication, | ||
277 | struct GNUNET_TIME_Absolute expiration, | ||
278 | uint64_t uid, | ||
279 | GNUNET_DATASTORE_DatumProcessor cont, | ||
280 | void *cont_cls) | ||
281 | { | ||
282 | const struct OnDemandBlock *odb; | ||
283 | struct GNUNET_HashCode nkey; | ||
284 | struct GNUNET_CRYPTO_SymmetricSessionKey skey; | ||
285 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
286 | struct GNUNET_HashCode query; | ||
287 | ssize_t nsize; | ||
288 | char ndata[DBLOCK_SIZE]; | ||
289 | char edata[DBLOCK_SIZE]; | ||
290 | const char *fn; | ||
291 | struct GNUNET_DISK_FileHandle *fh; | ||
292 | uint64_t off; | ||
293 | struct IndexInfo *ii; | ||
294 | |||
295 | if (size != sizeof(struct OnDemandBlock)) | ||
296 | { | ||
297 | GNUNET_break (0); | ||
298 | GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, &remove_cont, NULL); | ||
299 | return GNUNET_SYSERR; | ||
300 | } | ||
301 | odb = (const struct OnDemandBlock *) data; | ||
302 | off = GNUNET_ntohll (odb->offset); | ||
303 | ii = GNUNET_CONTAINER_multihashmap_get (ifm, &odb->file_id); | ||
304 | if (NULL == ii) | ||
305 | { | ||
306 | GNUNET_break (0); | ||
307 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
308 | "Failed to find index %s\n", | ||
309 | GNUNET_h2s (&odb->file_id)); | ||
310 | return GNUNET_SYSERR; | ||
311 | } | ||
312 | fn = ii->filename; | ||
313 | if ((NULL == fn) || (0 != access (fn, R_OK))) | ||
314 | { | ||
315 | GNUNET_STATISTICS_update ( | ||
316 | GSF_stats, | ||
317 | gettext_noop ("# index blocks removed: original file inaccessible"), | ||
318 | 1, | ||
319 | GNUNET_YES); | ||
320 | GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, &remove_cont, NULL); | ||
321 | return GNUNET_SYSERR; | ||
322 | } | ||
323 | if ((NULL == (fh = GNUNET_DISK_file_open (fn, | ||
324 | GNUNET_DISK_OPEN_READ, | ||
325 | GNUNET_DISK_PERM_NONE))) || | ||
326 | (off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)) || | ||
327 | (-1 == (nsize = GNUNET_DISK_file_read (fh, ndata, sizeof(ndata))))) | ||
328 | { | ||
329 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
330 | _ ( | ||
331 | "Could not access indexed file `%s' (%s) at offset %llu: %s\n"), | ||
332 | GNUNET_h2s (&odb->file_id), | ||
333 | fn, | ||
334 | (unsigned long long) off, | ||
335 | (fn == NULL) ? _ ("not indexed") : strerror (errno)); | ||
336 | if (fh != NULL) | ||
337 | GNUNET_DISK_file_close (fh); | ||
338 | GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, &remove_cont, NULL); | ||
339 | return GNUNET_SYSERR; | ||
340 | } | ||
341 | GNUNET_DISK_file_close (fh); | ||
342 | GNUNET_CRYPTO_hash (ndata, nsize, &nkey); | ||
343 | GNUNET_CRYPTO_hash_to_aes_key (&nkey, &skey, &iv); | ||
344 | GNUNET_CRYPTO_symmetric_encrypt (ndata, nsize, &skey, &iv, edata); | ||
345 | GNUNET_CRYPTO_hash (edata, nsize, &query); | ||
346 | if (0 != memcmp (&query, key, sizeof(struct GNUNET_HashCode))) | ||
347 | { | ||
348 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
349 | _ ("Indexed file `%s' changed at offset %llu\n"), | ||
350 | fn, | ||
351 | (unsigned long long) off); | ||
352 | GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, &remove_cont, NULL); | ||
353 | return GNUNET_SYSERR; | ||
354 | } | ||
355 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
356 | "On-demand encoded block for query `%s'\n", | ||
357 | GNUNET_h2s (key)); | ||
358 | cont (cont_cls, | ||
359 | key, | ||
360 | nsize, | ||
361 | edata, | ||
362 | GNUNET_BLOCK_TYPE_FS_DBLOCK, | ||
363 | priority, | ||
364 | anonymity, | ||
365 | replication, | ||
366 | expiration, | ||
367 | uid); | ||
368 | return GNUNET_OK; | ||
369 | } | ||
370 | |||
371 | |||
372 | /** | ||
373 | * Transmit information about indexed files to @a mq. | ||
374 | * | ||
375 | * @param mq message queue to send information to | ||
376 | */ | ||
377 | void | ||
378 | GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq) | ||
379 | { | ||
380 | struct GNUNET_MQ_Envelope *env; | ||
381 | struct IndexInfoMessage *iim; | ||
382 | struct GNUNET_MessageHeader *iem; | ||
383 | size_t slen; | ||
384 | const char *fn; | ||
385 | struct IndexInfo *pos; | ||
386 | |||
387 | for (pos = indexed_files_head; NULL != pos; pos = pos->next) | ||
388 | { | ||
389 | fn = pos->filename; | ||
390 | slen = strlen (fn) + 1; | ||
391 | if (slen + sizeof(struct IndexInfoMessage) >= GNUNET_MAX_MESSAGE_SIZE) | ||
392 | { | ||
393 | GNUNET_break (0); | ||
394 | break; | ||
395 | } | ||
396 | env = | ||
397 | GNUNET_MQ_msg_extra (iim, slen, GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY); | ||
398 | iim->reserved = 0; | ||
399 | iim->file_id = pos->file_id; | ||
400 | GNUNET_memcpy (&iim[1], fn, slen); | ||
401 | GNUNET_MQ_send (mq, env); | ||
402 | } | ||
403 | env = GNUNET_MQ_msg (iem, GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END); | ||
404 | GNUNET_MQ_send (mq, env); | ||
405 | } | ||
406 | |||
407 | |||
408 | /** | ||
409 | * Remove a file from the index. | ||
410 | * | ||
411 | * @param fid identifier of the file to remove | ||
412 | * @return #GNUNET_YES if the @a fid was found | ||
413 | */ | ||
414 | int | ||
415 | GNUNET_FS_indexing_do_unindex (const struct GNUNET_HashCode *fid) | ||
416 | { | ||
417 | struct IndexInfo *pos; | ||
418 | |||
419 | for (pos = indexed_files_head; NULL != pos; pos = pos->next) | ||
420 | { | ||
421 | if (0 == memcmp (&pos->file_id, fid, sizeof(struct GNUNET_HashCode))) | ||
422 | { | ||
423 | GNUNET_CONTAINER_DLL_remove (indexed_files_head, indexed_files_tail, pos); | ||
424 | GNUNET_break ( | ||
425 | GNUNET_OK == | ||
426 | GNUNET_CONTAINER_multihashmap_remove (ifm, &pos->file_id, pos)); | ||
427 | GNUNET_free (pos); | ||
428 | write_index_list (); | ||
429 | return GNUNET_YES; | ||
430 | } | ||
431 | } | ||
432 | return GNUNET_NO; | ||
433 | } | ||
434 | |||
435 | |||
436 | /** | ||
437 | * Add the given file to the list of indexed files. | ||
438 | * | ||
439 | * @param filename name of the file | ||
440 | * @param file_id hash identifier for @a filename | ||
441 | */ | ||
442 | void | ||
443 | GNUNET_FS_add_to_index (const char *filename, | ||
444 | const struct GNUNET_HashCode *file_id) | ||
445 | { | ||
446 | struct IndexInfo *ii; | ||
447 | size_t slen; | ||
448 | |||
449 | ii = GNUNET_CONTAINER_multihashmap_get (ifm, file_id); | ||
450 | if (NULL != ii) | ||
451 | { | ||
452 | GNUNET_log ( | ||
453 | GNUNET_ERROR_TYPE_INFO, | ||
454 | _ ( | ||
455 | "Index request received for file `%s' is already indexed as `%s'. Permitting anyway.\n"), | ||
456 | filename, | ||
457 | ii->filename); | ||
458 | return; | ||
459 | } | ||
460 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
461 | "Adding file %s to index as %s\n", | ||
462 | filename, | ||
463 | GNUNET_h2s (file_id)); | ||
464 | slen = strlen (filename) + 1; | ||
465 | ii = GNUNET_malloc (sizeof(struct IndexInfo) + slen); | ||
466 | ii->file_id = *file_id; | ||
467 | ii->filename = (const char *) &ii[1]; | ||
468 | GNUNET_memcpy (&ii[1], filename, slen); | ||
469 | GNUNET_CONTAINER_DLL_insert (indexed_files_head, indexed_files_tail, ii); | ||
470 | GNUNET_assert (GNUNET_OK == | ||
471 | GNUNET_CONTAINER_multihashmap_put ( | ||
472 | ifm, | ||
473 | &ii->file_id, | ||
474 | ii, | ||
475 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
476 | write_index_list (); | ||
477 | } | ||
478 | |||
479 | |||
480 | /** | ||
481 | * Shutdown the module. | ||
482 | */ | ||
483 | void | ||
484 | GNUNET_FS_indexing_done () | ||
485 | { | ||
486 | struct IndexInfo *pos; | ||
487 | |||
488 | while (NULL != (pos = indexed_files_head)) | ||
489 | { | ||
490 | GNUNET_CONTAINER_DLL_remove (indexed_files_head, indexed_files_tail, pos); | ||
491 | if (pos->fhc != NULL) | ||
492 | GNUNET_CRYPTO_hash_file_cancel (pos->fhc); | ||
493 | GNUNET_break ( | ||
494 | GNUNET_OK == | ||
495 | GNUNET_CONTAINER_multihashmap_remove (ifm, &pos->file_id, pos)); | ||
496 | GNUNET_free (pos); | ||
497 | } | ||
498 | GNUNET_CONTAINER_multihashmap_destroy (ifm); | ||
499 | ifm = NULL; | ||
500 | cfg = NULL; | ||
501 | } | ||
502 | |||
503 | |||
504 | /** | ||
505 | * Initialize the indexing submodule. | ||
506 | * | ||
507 | * @param c configuration to use | ||
508 | * @param d datastore to use | ||
509 | */ | ||
510 | int | ||
511 | GNUNET_FS_indexing_init (const struct GNUNET_CONFIGURATION_Handle *c, | ||
512 | struct GNUNET_DATASTORE_Handle *d) | ||
513 | { | ||
514 | cfg = c; | ||
515 | dsh = d; | ||
516 | ifm = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_YES); | ||
517 | read_index_list (); | ||
518 | return GNUNET_OK; | ||
519 | } | ||
520 | |||
521 | |||
522 | /* end of gnunet-service-fs_indexing.c */ | ||
diff --git a/src/fs/gnunet-service-fs_indexing.h b/src/fs/gnunet-service-fs_indexing.h deleted file mode 100644 index 546dbb172..000000000 --- a/src/fs/gnunet-service-fs_indexing.h +++ /dev/null | |||
@@ -1,121 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_indexing.h | ||
23 | * @brief indexing for the file-sharing service | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_FS_INDEXING_H | ||
27 | #define GNUNET_SERVICE_FS_INDEXING_H | ||
28 | |||
29 | #include "gnunet_block_lib.h" | ||
30 | #include "gnunet_core_service.h" | ||
31 | #include "gnunet_datastore_service.h" | ||
32 | #include "gnunet_peer_lib.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "gnunet_signatures.h" | ||
35 | #include "gnunet_util_lib.h" | ||
36 | |||
37 | |||
38 | /** | ||
39 | * We've received an on-demand encoded block from the datastore. | ||
40 | * Attempt to do on-demand encoding and (if successful), call the | ||
41 | * continuation with the resulting block. On error, clean up and ask | ||
42 | * the datastore for more results. | ||
43 | * | ||
44 | * @param key key for the content | ||
45 | * @param size number of bytes in data | ||
46 | * @param data content stored | ||
47 | * @param type type of the content | ||
48 | * @param priority priority of the content | ||
49 | * @param anonymity anonymity-level for the content | ||
50 | * @param replication replication-level for the content | ||
51 | * @param expiration expiration time for the content | ||
52 | * @param uid unique identifier for the datum; | ||
53 | * maybe 0 if no unique identifier is available | ||
54 | * @param cont function to call with the actual block (at most once, on success) | ||
55 | * @param cont_cls closure for @a cont | ||
56 | * @return #GNUNET_OK on success | ||
57 | */ | ||
58 | int | ||
59 | GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode *key, | ||
60 | uint32_t size, | ||
61 | const void *data, | ||
62 | enum GNUNET_BLOCK_Type type, | ||
63 | uint32_t priority, | ||
64 | uint32_t anonymity, | ||
65 | uint32_t replication, | ||
66 | struct GNUNET_TIME_Absolute expiration, | ||
67 | uint64_t uid, | ||
68 | GNUNET_DATASTORE_DatumProcessor cont, | ||
69 | void *cont_cls); | ||
70 | |||
71 | |||
72 | /** | ||
73 | * Transmit information about indexed files to @a mq. | ||
74 | * | ||
75 | * @param mq message queue to send information to | ||
76 | */ | ||
77 | void | ||
78 | GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq); | ||
79 | |||
80 | |||
81 | /** | ||
82 | * Remove a file from the index. | ||
83 | * | ||
84 | * @param fid identifier of the file to remove | ||
85 | * @return #GNUNET_YES if the @a fid was found | ||
86 | */ | ||
87 | int | ||
88 | GNUNET_FS_indexing_do_unindex (const struct GNUNET_HashCode *fid); | ||
89 | |||
90 | |||
91 | /** | ||
92 | * Add the given file to the list of indexed files. | ||
93 | * | ||
94 | * @param filename name of the file | ||
95 | * @param file_id hash identifier for @a filename | ||
96 | */ | ||
97 | void | ||
98 | GNUNET_FS_add_to_index (const char *filename, | ||
99 | const struct GNUNET_HashCode *file_id); | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Initialize the indexing submodule. | ||
104 | * | ||
105 | * @param c configuration to use | ||
106 | * @param d datastore to use | ||
107 | * @return GNUNET_OK on success | ||
108 | */ | ||
109 | int | ||
110 | GNUNET_FS_indexing_init (const struct GNUNET_CONFIGURATION_Handle *c, | ||
111 | struct GNUNET_DATASTORE_Handle *d); | ||
112 | |||
113 | |||
114 | /** | ||
115 | * Shutdown the module. | ||
116 | */ | ||
117 | void | ||
118 | GNUNET_FS_indexing_done (void); | ||
119 | |||
120 | |||
121 | #endif | ||
diff --git a/src/fs/gnunet-service-fs_pe.c b/src/fs/gnunet-service-fs_pe.c deleted file mode 100644 index 60dd0ab70..000000000 --- a/src/fs/gnunet-service-fs_pe.c +++ /dev/null | |||
@@ -1,814 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_pe.c | ||
23 | * @brief API to manage query plan | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet-service-fs.h" | ||
28 | #include "gnunet-service-fs_cp.h" | ||
29 | #include "gnunet-service-fs_pe.h" | ||
30 | #include "gnunet-service-fs_pr.h" | ||
31 | |||
32 | /** | ||
33 | * Collect an instance number of statistics? May cause excessive IPC. | ||
34 | */ | ||
35 | #define INSANE_STATISTICS GNUNET_NO | ||
36 | |||
37 | /** | ||
38 | * List of GSF_PendingRequests this request plan | ||
39 | * participates with. | ||
40 | */ | ||
41 | struct PendingRequestList; | ||
42 | |||
43 | /** | ||
44 | * Transmission plan for a peer. | ||
45 | */ | ||
46 | struct PeerPlan; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * M:N binding of plans to pending requests. | ||
51 | * Each pending request can be in a number of plans, | ||
52 | * and each plan can have a number of pending requests. | ||
53 | * Objects of this type indicate a mapping of a plan to | ||
54 | * a particular pending request. | ||
55 | * | ||
56 | * The corresponding head and tail of the "PE" MDLL | ||
57 | * are stored in a `struct GSF_RequestPlan`. (We need | ||
58 | * to be able to lookup all pending requests corresponding | ||
59 | * to a given plan entry.) | ||
60 | * | ||
61 | * Similarly head and tail of the "PR" MDLL are stored | ||
62 | * with the `struct GSF_PendingRequest`. (We need | ||
63 | * to be able to lookup all plan entries corresponding | ||
64 | * to a given pending request.) | ||
65 | */ | ||
66 | struct GSF_PendingRequestPlanBijection | ||
67 | { | ||
68 | /** | ||
69 | * This is a doubly-linked list. | ||
70 | */ | ||
71 | struct GSF_PendingRequestPlanBijection *next_PR; | ||
72 | |||
73 | /** | ||
74 | * This is a doubly-linked list. | ||
75 | */ | ||
76 | struct GSF_PendingRequestPlanBijection *prev_PR; | ||
77 | |||
78 | /** | ||
79 | * This is a doubly-linked list. | ||
80 | */ | ||
81 | struct GSF_PendingRequestPlanBijection *next_PE; | ||
82 | |||
83 | /** | ||
84 | * This is a doubly-linked list. | ||
85 | */ | ||
86 | struct GSF_PendingRequestPlanBijection *prev_PE; | ||
87 | |||
88 | /** | ||
89 | * Associated request plan (tells us one of the peers that | ||
90 | * we plan to forward the request to). | ||
91 | */ | ||
92 | struct GSF_RequestPlan *rp; | ||
93 | |||
94 | /** | ||
95 | * Associated pending request (identifies request details | ||
96 | * and one of the origins of the request). | ||
97 | */ | ||
98 | struct GSF_PendingRequest *pr; | ||
99 | }; | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Information we keep per request per peer. This is a doubly-linked | ||
104 | * list (with head and tail in the `struct GSF_PendingRequestData`) | ||
105 | * with one entry in each heap of each `struct PeerPlan`. Each | ||
106 | * entry tracks information relevant for this request and this peer. | ||
107 | */ | ||
108 | struct GSF_RequestPlan | ||
109 | { | ||
110 | /** | ||
111 | * This is a doubly-linked list. | ||
112 | */ | ||
113 | struct GSF_RequestPlan *next; | ||
114 | |||
115 | /** | ||
116 | * This is a doubly-linked list. | ||
117 | */ | ||
118 | struct GSF_RequestPlan *prev; | ||
119 | |||
120 | /** | ||
121 | * Heap node associated with this request and this peer. | ||
122 | */ | ||
123 | struct GNUNET_CONTAINER_HeapNode *hn; | ||
124 | |||
125 | /** | ||
126 | * The transmission plan for a peer that this request is associated with. | ||
127 | */ | ||
128 | struct PeerPlan *pp; | ||
129 | |||
130 | /** | ||
131 | * Head of list of associated pending requests. This tells us | ||
132 | * which incoming requests from other peers this plan entry | ||
133 | * corresponds to. | ||
134 | */ | ||
135 | struct GSF_PendingRequestPlanBijection *pe_head; | ||
136 | |||
137 | /** | ||
138 | * Tail of list of associated pending requests. | ||
139 | */ | ||
140 | struct GSF_PendingRequestPlanBijection *pe_tail; | ||
141 | |||
142 | /** | ||
143 | * Earliest time we'd be happy to (re)transmit this request. | ||
144 | */ | ||
145 | struct GNUNET_TIME_Absolute earliest_transmission; | ||
146 | |||
147 | /** | ||
148 | * When was the last time we transmitted this request to this peer? 0 for never. | ||
149 | */ | ||
150 | struct GNUNET_TIME_Absolute last_transmission; | ||
151 | |||
152 | /** | ||
153 | * Current priority for this request for this target. | ||
154 | */ | ||
155 | uint64_t priority; | ||
156 | |||
157 | /** | ||
158 | * How often did we transmit this request to this peer? | ||
159 | */ | ||
160 | unsigned int transmission_counter; | ||
161 | }; | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Transmission plan for a peer. | ||
166 | */ | ||
167 | struct PeerPlan | ||
168 | { | ||
169 | /** | ||
170 | * Heap with pending queries (`struct GSF_RequestPlan`), higher weights mean higher priority. | ||
171 | */ | ||
172 | struct GNUNET_CONTAINER_Heap *priority_heap; | ||
173 | |||
174 | /** | ||
175 | * Heap with pending queries (`struct GSF_RequestPlan`), by transmission time, lowest first. | ||
176 | */ | ||
177 | struct GNUNET_CONTAINER_Heap *delay_heap; | ||
178 | |||
179 | /** | ||
180 | * Map of queries to plan entries. All entries in the @e priority_heap | ||
181 | * or @e delay_heap should be in the @e plan_map. Note that it is | ||
182 | * possible for the @e plan_map to have multiple entries for the same | ||
183 | * query. | ||
184 | */ | ||
185 | struct GNUNET_CONTAINER_MultiHashMap *plan_map; | ||
186 | |||
187 | /** | ||
188 | * Peer for which this is the plan. | ||
189 | */ | ||
190 | struct GSF_ConnectedPeer *cp; | ||
191 | |||
192 | /** | ||
193 | * Current task for executing the plan. | ||
194 | */ | ||
195 | struct GNUNET_SCHEDULER_Task *task; | ||
196 | |||
197 | /** | ||
198 | * Current message under transmission for the plan. | ||
199 | */ | ||
200 | struct GNUNET_MQ_Envelope *env; | ||
201 | }; | ||
202 | |||
203 | |||
204 | /** | ||
205 | * Hash map from peer identities to PeerPlans. | ||
206 | */ | ||
207 | static struct GNUNET_CONTAINER_MultiPeerMap *plans; | ||
208 | |||
209 | /** | ||
210 | * Sum of all transmission counters (equals total delay for all plan entries). | ||
211 | */ | ||
212 | static unsigned long long total_delay; | ||
213 | |||
214 | /** | ||
215 | * Number of plan entries. | ||
216 | */ | ||
217 | static unsigned long long plan_count; | ||
218 | |||
219 | |||
220 | /** | ||
221 | * Return the query (key in the plan_map) for the given request plan. | ||
222 | * Note that this key may change as there can be multiple pending | ||
223 | * requests for the same key and we just return _one_ of them; this | ||
224 | * particular one might complete while another one might still be | ||
225 | * active, hence the lifetime of the returned hash code is NOT | ||
226 | * necessarily identical to that of the `struct GSF_RequestPlan` | ||
227 | * given. | ||
228 | * | ||
229 | * @param rp a request plan | ||
230 | * @return the associated query | ||
231 | */ | ||
232 | static const struct GNUNET_HashCode * | ||
233 | get_rp_key (struct GSF_RequestPlan *rp) | ||
234 | { | ||
235 | return &GSF_pending_request_get_data_ (rp->pe_head->pr)->query; | ||
236 | } | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Insert the given request plan into the heap with the appropriate weight. | ||
241 | * | ||
242 | * @param pp associated peer's plan | ||
243 | * @param rp request to plan | ||
244 | */ | ||
245 | static void | ||
246 | plan (struct PeerPlan *pp, | ||
247 | struct GSF_RequestPlan *rp) | ||
248 | { | ||
249 | #define N ((double) 128.0) | ||
250 | /** | ||
251 | * Running average delay we currently impose. | ||
252 | */ | ||
253 | static double avg_delay; | ||
254 | |||
255 | struct GSF_PendingRequestData *prd; | ||
256 | struct GNUNET_TIME_Relative delay; | ||
257 | |||
258 | GNUNET_assert (rp->pp == pp); | ||
259 | GNUNET_STATISTICS_set (GSF_stats, | ||
260 | gettext_noop ("# average retransmission delay (ms)"), | ||
261 | total_delay * 1000LL / plan_count, GNUNET_NO); | ||
262 | prd = GSF_pending_request_get_data_ (rp->pe_head->pr); | ||
263 | |||
264 | if (rp->transmission_counter < 8) | ||
265 | delay = | ||
266 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
267 | rp->transmission_counter); | ||
268 | else if (rp->transmission_counter < 32) | ||
269 | delay = | ||
270 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
271 | 8 | ||
272 | + (1LL << (rp->transmission_counter - 8))); | ||
273 | else | ||
274 | delay = | ||
275 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
276 | 8 + (1LL << 24)); | ||
277 | delay.rel_value_us = | ||
278 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
279 | delay.rel_value_us + 1); | ||
280 | /* Add 0.01 to avg_delay to avoid division-by-zero later */ | ||
281 | avg_delay = (((avg_delay * (N - 1.0)) + delay.rel_value_us) / N) + 0.01; | ||
282 | |||
283 | /* | ||
284 | * For the priority, we need to consider a few basic rules: | ||
285 | * 1) if we just started requesting (delay is small), we should | ||
286 | * virtually always have a priority of zero. | ||
287 | * 2) for requests with average latency, our priority should match | ||
288 | * the average priority observed on the network | ||
289 | * 3) even the longest-running requests should not be WAY out of | ||
290 | * the observed average (thus we bound by a factor of 2) | ||
291 | * 4) we add +1 to the observed average priority to avoid everyone | ||
292 | * staying put at zero (2 * 0 = 0...). | ||
293 | * | ||
294 | * Using the specific calculation below, we get: | ||
295 | * | ||
296 | * delay = 0 => priority = 0; | ||
297 | * delay = avg delay => priority = running-average-observed-priority; | ||
298 | * delay >> avg_delay => priority = 2 * running-average-observed-priority; | ||
299 | * | ||
300 | * which satisfies all of the rules above. | ||
301 | * | ||
302 | * Note: M_PI_4 = PI/4 = arctan(1) | ||
303 | */rp->priority = | ||
304 | round ((GSF_current_priorities | ||
305 | + 1.0) * atan (delay.rel_value_us / avg_delay)) / M_PI_4; | ||
306 | /* Note: usage of 'round' and 'atan' requires -lm */ | ||
307 | |||
308 | if (rp->transmission_counter != 0) | ||
309 | delay.rel_value_us += TTL_DECREMENT * 1000; | ||
310 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
311 | "Considering (re)transmission number %u in %s\n", | ||
312 | (unsigned int) rp->transmission_counter, | ||
313 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
314 | GNUNET_YES)); | ||
315 | rp->earliest_transmission = GNUNET_TIME_relative_to_absolute (delay); | ||
316 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
317 | "Earliest (re)transmission for `%s' in %us\n", | ||
318 | GNUNET_h2s (&prd->query), | ||
319 | rp->transmission_counter); | ||
320 | GNUNET_assert (rp->hn == NULL); | ||
321 | if (0 == GNUNET_TIME_absolute_get_remaining ( | ||
322 | rp->earliest_transmission).rel_value_us) | ||
323 | rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, | ||
324 | rp, | ||
325 | rp->priority); | ||
326 | else | ||
327 | rp->hn = | ||
328 | GNUNET_CONTAINER_heap_insert (pp->delay_heap, | ||
329 | rp, | ||
330 | rp->earliest_transmission.abs_value_us); | ||
331 | GNUNET_assert (GNUNET_YES == | ||
332 | GNUNET_CONTAINER_multihashmap_contains_value (pp->plan_map, | ||
333 | get_rp_key (rp), | ||
334 | rp)); | ||
335 | #undef N | ||
336 | } | ||
337 | |||
338 | |||
339 | /** | ||
340 | * Get the pending request with the highest TTL from the given plan. | ||
341 | * | ||
342 | * @param rp plan to investigate | ||
343 | * @return pending request with highest TTL | ||
344 | */ | ||
345 | struct GSF_PendingRequest * | ||
346 | get_latest (const struct GSF_RequestPlan *rp) | ||
347 | { | ||
348 | struct GSF_PendingRequest *ret; | ||
349 | struct GSF_PendingRequestPlanBijection *bi; | ||
350 | const struct GSF_PendingRequestData *rprd; | ||
351 | const struct GSF_PendingRequestData *prd; | ||
352 | |||
353 | bi = rp->pe_head; | ||
354 | if (NULL == bi) | ||
355 | return NULL; /* should never happen */ | ||
356 | ret = bi->pr; | ||
357 | rprd = GSF_pending_request_get_data_ (ret); | ||
358 | for (bi = bi->next_PE; NULL != bi; bi = bi->next_PE) | ||
359 | { | ||
360 | GNUNET_break (GNUNET_YES == | ||
361 | GSF_pending_request_test_active_ (bi->pr)); | ||
362 | prd = GSF_pending_request_get_data_ (bi->pr); | ||
363 | if (prd->ttl.abs_value_us > rprd->ttl.abs_value_us) | ||
364 | { | ||
365 | ret = bi->pr; | ||
366 | rprd = prd; | ||
367 | } | ||
368 | } | ||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | |||
373 | /** | ||
374 | * Figure out when and how to transmit to the given peer. | ||
375 | * | ||
376 | * @param cls the `struct PeerPlan` | ||
377 | */ | ||
378 | static void | ||
379 | schedule_peer_transmission (void *cls) | ||
380 | { | ||
381 | struct PeerPlan *pp = cls; | ||
382 | struct GSF_RequestPlan *rp; | ||
383 | struct GNUNET_TIME_Relative delay; | ||
384 | |||
385 | if (NULL != pp->task) | ||
386 | { | ||
387 | pp->task = NULL; | ||
388 | } | ||
389 | else | ||
390 | { | ||
391 | GNUNET_assert (NULL != pp->env); | ||
392 | pp->env = NULL; | ||
393 | } | ||
394 | /* move ready requests to priority queue */ | ||
395 | while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) && | ||
396 | (0 == GNUNET_TIME_absolute_get_remaining | ||
397 | (rp->earliest_transmission).rel_value_us)) | ||
398 | { | ||
399 | GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)); | ||
400 | rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, | ||
401 | rp, | ||
402 | rp->priority); | ||
403 | } | ||
404 | if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap)) | ||
405 | { | ||
406 | /* priority heap (still) empty, check for delay... */ | ||
407 | rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap); | ||
408 | if (NULL == rp) | ||
409 | { | ||
410 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
411 | "No active requests for plan %p.\n", | ||
412 | pp); | ||
413 | return; /* both queues empty */ | ||
414 | } | ||
415 | delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission); | ||
416 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
417 | "Sleeping for %s before retrying requests on plan %p.\n", | ||
418 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
419 | GNUNET_YES), | ||
420 | pp); | ||
421 | GNUNET_STATISTICS_set (GSF_stats, | ||
422 | gettext_noop ("# delay heap timeout (ms)"), | ||
423 | delay.rel_value_us / 1000LL, GNUNET_NO); | ||
424 | |||
425 | pp->task | ||
426 | = GNUNET_SCHEDULER_add_at (rp->earliest_transmission, | ||
427 | &schedule_peer_transmission, | ||
428 | pp); | ||
429 | return; | ||
430 | } | ||
431 | #if INSANE_STATISTICS | ||
432 | GNUNET_STATISTICS_update (GSF_stats, | ||
433 | gettext_noop ("# query plans executed"), | ||
434 | 1, | ||
435 | GNUNET_NO); | ||
436 | #endif | ||
437 | /* process from priority heap */ | ||
438 | rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap); | ||
439 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
440 | "Executing query plan %p\n", | ||
441 | rp); | ||
442 | GNUNET_assert (NULL != rp); | ||
443 | rp->hn = NULL; | ||
444 | rp->last_transmission = GNUNET_TIME_absolute_get (); | ||
445 | rp->transmission_counter++; | ||
446 | total_delay++; | ||
447 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
448 | "Executing plan %p executed %u times, planning retransmission\n", | ||
449 | rp, | ||
450 | rp->transmission_counter); | ||
451 | GNUNET_assert (NULL == pp->env); | ||
452 | pp->env = GSF_pending_request_get_message_ (get_latest (rp)); | ||
453 | GNUNET_MQ_notify_sent (pp->env, | ||
454 | &schedule_peer_transmission, | ||
455 | pp); | ||
456 | GSF_peer_transmit_ (pp->cp, | ||
457 | GNUNET_YES, | ||
458 | rp->priority, | ||
459 | pp->env); | ||
460 | GNUNET_STATISTICS_update (GSF_stats, | ||
461 | gettext_noop ( | ||
462 | "# query messages sent to other peers"), | ||
463 | 1, | ||
464 | GNUNET_NO); | ||
465 | plan (pp, | ||
466 | rp); | ||
467 | } | ||
468 | |||
469 | |||
470 | /** | ||
471 | * Closure for merge_pr(). | ||
472 | */ | ||
473 | struct MergeContext | ||
474 | { | ||
475 | /** | ||
476 | * Request we are trying to merge. | ||
477 | */ | ||
478 | struct GSF_PendingRequest *pr; | ||
479 | |||
480 | /** | ||
481 | * Set to #GNUNET_YES if we succeeded to merge. | ||
482 | */ | ||
483 | int merged; | ||
484 | }; | ||
485 | |||
486 | |||
487 | /** | ||
488 | * Iterator that checks if an equivalent request is already | ||
489 | * present for this peer. | ||
490 | * | ||
491 | * @param cls closure | ||
492 | * @param query the query | ||
493 | * @param element request plan stored at the node | ||
494 | * @return #GNUNET_YES if we should continue to iterate, | ||
495 | * #GNUNET_NO if not (merge success) | ||
496 | */ | ||
497 | static int | ||
498 | merge_pr (void *cls, | ||
499 | const struct GNUNET_HashCode *query, | ||
500 | void *element) | ||
501 | { | ||
502 | struct MergeContext *mpr = cls; | ||
503 | struct GSF_RequestPlan *rp = element; | ||
504 | struct GSF_PendingRequestData *prd; | ||
505 | struct GSF_PendingRequestPlanBijection *bi; | ||
506 | struct GSF_PendingRequest *latest; | ||
507 | |||
508 | GNUNET_break (GNUNET_YES == | ||
509 | GSF_pending_request_test_active_ (mpr->pr)); | ||
510 | if (GNUNET_OK != | ||
511 | GSF_pending_request_is_compatible_ (mpr->pr, | ||
512 | rp->pe_head->pr)) | ||
513 | return GNUNET_YES; | ||
514 | /* merge new request with existing request plan */ | ||
515 | bi = GNUNET_new (struct GSF_PendingRequestPlanBijection); | ||
516 | bi->rp = rp; | ||
517 | bi->pr = mpr->pr; | ||
518 | prd = GSF_pending_request_get_data_ (mpr->pr); | ||
519 | GNUNET_CONTAINER_MDLL_insert (PR, | ||
520 | prd->pr_head, | ||
521 | prd->pr_tail, | ||
522 | bi); | ||
523 | GNUNET_CONTAINER_MDLL_insert (PE, | ||
524 | rp->pe_head, | ||
525 | rp->pe_tail, | ||
526 | bi); | ||
527 | mpr->merged = GNUNET_YES; | ||
528 | #if INSANE_STATISTICS | ||
529 | GNUNET_STATISTICS_update (GSF_stats, | ||
530 | gettext_noop ("# requests merged"), | ||
531 | 1, | ||
532 | GNUNET_NO); | ||
533 | #endif | ||
534 | latest = get_latest (rp); | ||
535 | if (GSF_pending_request_get_data_ (latest)->ttl.abs_value_us < | ||
536 | prd->ttl.abs_value_us) | ||
537 | { | ||
538 | #if INSANE_STATISTICS | ||
539 | GNUNET_STATISTICS_update (GSF_stats, | ||
540 | gettext_noop ("# requests refreshed"), | ||
541 | 1, | ||
542 | GNUNET_NO); | ||
543 | #endif | ||
544 | rp->transmission_counter = 0; /* reset */ | ||
545 | } | ||
546 | return GNUNET_NO; | ||
547 | } | ||
548 | |||
549 | |||
550 | /** | ||
551 | * Create a new query plan entry. | ||
552 | * | ||
553 | * @param cp peer with the entry | ||
554 | * @param pr request with the entry | ||
555 | */ | ||
556 | void | ||
557 | GSF_plan_add_ (struct GSF_ConnectedPeer *cp, | ||
558 | struct GSF_PendingRequest *pr) | ||
559 | { | ||
560 | const struct GNUNET_PeerIdentity *id; | ||
561 | struct PeerPlan *pp; | ||
562 | struct GSF_PendingRequestData *prd; | ||
563 | struct GSF_RequestPlan *rp; | ||
564 | struct GSF_PendingRequestPlanBijection *bi; | ||
565 | struct MergeContext mpc; | ||
566 | |||
567 | GNUNET_assert (GNUNET_YES == | ||
568 | GSF_pending_request_test_active_ (pr)); | ||
569 | GNUNET_assert (NULL != cp); | ||
570 | id = GSF_connected_peer_get_identity2_ (cp); | ||
571 | pp = GNUNET_CONTAINER_multipeermap_get (plans, id); | ||
572 | if (NULL == pp) | ||
573 | { | ||
574 | pp = GNUNET_new (struct PeerPlan); | ||
575 | pp->plan_map = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO); | ||
576 | pp->priority_heap = | ||
577 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); | ||
578 | pp->delay_heap = | ||
579 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
580 | pp->cp = cp; | ||
581 | GNUNET_assert (GNUNET_OK == | ||
582 | GNUNET_CONTAINER_multipeermap_put (plans, | ||
583 | id, | ||
584 | pp, | ||
585 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
586 | pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, | ||
587 | pp); | ||
588 | } | ||
589 | mpc.merged = GNUNET_NO; | ||
590 | mpc.pr = pr; | ||
591 | prd = GSF_pending_request_get_data_ (pr); | ||
592 | GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map, | ||
593 | &prd->query, | ||
594 | &merge_pr, | ||
595 | &mpc); | ||
596 | if (GNUNET_NO != mpc.merged) | ||
597 | return; | ||
598 | plan_count++; | ||
599 | GNUNET_STATISTICS_update (GSF_stats, | ||
600 | gettext_noop ("# query plan entries"), | ||
601 | 1, | ||
602 | GNUNET_NO); | ||
603 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
604 | "Planning transmission of query `%s' to peer `%s'\n", | ||
605 | GNUNET_h2s (&prd->query), | ||
606 | GNUNET_i2s (id)); | ||
607 | rp = GNUNET_new (struct GSF_RequestPlan); | ||
608 | bi = GNUNET_new (struct GSF_PendingRequestPlanBijection); | ||
609 | bi->rp = rp; | ||
610 | bi->pr = pr; | ||
611 | GNUNET_CONTAINER_MDLL_insert (PR, | ||
612 | prd->pr_head, | ||
613 | prd->pr_tail, | ||
614 | bi); | ||
615 | GNUNET_CONTAINER_MDLL_insert (PE, | ||
616 | rp->pe_head, | ||
617 | rp->pe_tail, | ||
618 | bi); | ||
619 | rp->pp = pp; | ||
620 | GNUNET_assert (GNUNET_YES == | ||
621 | GNUNET_CONTAINER_multihashmap_put (pp->plan_map, | ||
622 | get_rp_key (rp), | ||
623 | rp, | ||
624 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
625 | plan (pp, | ||
626 | rp); | ||
627 | } | ||
628 | |||
629 | |||
630 | /** | ||
631 | * Notify the plan about a peer being no longer available; | ||
632 | * destroy all entries associated with this peer. | ||
633 | * | ||
634 | * @param cp connected peer | ||
635 | */ | ||
636 | void | ||
637 | GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp) | ||
638 | { | ||
639 | const struct GNUNET_PeerIdentity *id; | ||
640 | struct PeerPlan *pp; | ||
641 | struct GSF_RequestPlan *rp; | ||
642 | struct GSF_PendingRequestData *prd; | ||
643 | struct GSF_PendingRequestPlanBijection *bi; | ||
644 | |||
645 | id = GSF_connected_peer_get_identity2_ (cp); | ||
646 | pp = GNUNET_CONTAINER_multipeermap_get (plans, id); | ||
647 | if (NULL == pp) | ||
648 | return; /* nothing was ever planned for this peer */ | ||
649 | GNUNET_assert (GNUNET_YES == | ||
650 | GNUNET_CONTAINER_multipeermap_remove (plans, id, | ||
651 | pp)); | ||
652 | if (NULL != pp->task) | ||
653 | { | ||
654 | GNUNET_SCHEDULER_cancel (pp->task); | ||
655 | pp->task = NULL; | ||
656 | } | ||
657 | while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap))) | ||
658 | { | ||
659 | GNUNET_break (GNUNET_YES == | ||
660 | GNUNET_CONTAINER_multihashmap_remove (pp->plan_map, | ||
661 | get_rp_key (rp), | ||
662 | rp)); | ||
663 | while (NULL != (bi = rp->pe_head)) | ||
664 | { | ||
665 | GNUNET_CONTAINER_MDLL_remove (PE, | ||
666 | rp->pe_head, | ||
667 | rp->pe_tail, | ||
668 | bi); | ||
669 | prd = GSF_pending_request_get_data_ (bi->pr); | ||
670 | GNUNET_CONTAINER_MDLL_remove (PR, | ||
671 | prd->pr_head, | ||
672 | prd->pr_tail, | ||
673 | bi); | ||
674 | GNUNET_free (bi); | ||
675 | } | ||
676 | plan_count--; | ||
677 | GNUNET_free (rp); | ||
678 | } | ||
679 | GNUNET_CONTAINER_heap_destroy (pp->priority_heap); | ||
680 | while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->delay_heap))) | ||
681 | { | ||
682 | GNUNET_break (GNUNET_YES == | ||
683 | GNUNET_CONTAINER_multihashmap_remove (pp->plan_map, | ||
684 | get_rp_key (rp), | ||
685 | rp)); | ||
686 | while (NULL != (bi = rp->pe_head)) | ||
687 | { | ||
688 | prd = GSF_pending_request_get_data_ (bi->pr); | ||
689 | GNUNET_CONTAINER_MDLL_remove (PE, | ||
690 | rp->pe_head, | ||
691 | rp->pe_tail, | ||
692 | bi); | ||
693 | GNUNET_CONTAINER_MDLL_remove (PR, | ||
694 | prd->pr_head, | ||
695 | prd->pr_tail, | ||
696 | bi); | ||
697 | GNUNET_free (bi); | ||
698 | } | ||
699 | plan_count--; | ||
700 | GNUNET_free (rp); | ||
701 | } | ||
702 | GNUNET_STATISTICS_set (GSF_stats, | ||
703 | gettext_noop ("# query plan entries"), | ||
704 | plan_count, | ||
705 | GNUNET_NO); | ||
706 | GNUNET_CONTAINER_heap_destroy (pp->delay_heap); | ||
707 | GNUNET_CONTAINER_multihashmap_destroy (pp->plan_map); | ||
708 | GNUNET_free (pp); | ||
709 | } | ||
710 | |||
711 | |||
712 | /** | ||
713 | * Get the last transmission attempt time for the request plan list | ||
714 | * referenced by @a pr_head, that was sent to @a sender | ||
715 | * | ||
716 | * @param pr_head request plan reference list to check. | ||
717 | * @param sender the peer that we've sent the request to. | ||
718 | * @param result the timestamp to fill, set to #GNUNET_TIME_UNIT_FOREVER_ABS if never transmitted | ||
719 | * @return #GNUNET_YES if @a result was changed, #GNUNET_NO otherwise. | ||
720 | */ | ||
721 | int | ||
722 | GSF_request_plan_reference_get_last_transmission_ (struct | ||
723 | GSF_PendingRequestPlanBijection | ||
724 | *pr_head, | ||
725 | struct GSF_ConnectedPeer * | ||
726 | sender, | ||
727 | struct GNUNET_TIME_Absolute * | ||
728 | result) | ||
729 | { | ||
730 | struct GSF_PendingRequestPlanBijection *bi; | ||
731 | |||
732 | for (bi = pr_head; NULL != bi; bi = bi->next_PR) | ||
733 | { | ||
734 | if (bi->rp->pp->cp == sender) | ||
735 | { | ||
736 | if (0 == bi->rp->last_transmission.abs_value_us) | ||
737 | *result = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
738 | else | ||
739 | *result = bi->rp->last_transmission; | ||
740 | return GNUNET_YES; | ||
741 | } | ||
742 | } | ||
743 | return GNUNET_NO; | ||
744 | } | ||
745 | |||
746 | |||
747 | /** | ||
748 | * Notify the plan about a request being done; destroy all entries | ||
749 | * associated with this request. | ||
750 | * | ||
751 | * @param pr request that is done | ||
752 | */ | ||
753 | void | ||
754 | GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr) | ||
755 | { | ||
756 | struct GSF_RequestPlan *rp; | ||
757 | struct GSF_PendingRequestData *prd; | ||
758 | struct GSF_PendingRequestPlanBijection *bi; | ||
759 | |||
760 | prd = GSF_pending_request_get_data_ (pr); | ||
761 | while (NULL != (bi = prd->pr_head)) | ||
762 | { | ||
763 | rp = bi->rp; | ||
764 | GNUNET_CONTAINER_MDLL_remove (PR, | ||
765 | prd->pr_head, | ||
766 | prd->pr_tail, | ||
767 | bi); | ||
768 | GNUNET_CONTAINER_MDLL_remove (PE, | ||
769 | rp->pe_head, | ||
770 | rp->pe_tail, | ||
771 | bi); | ||
772 | GNUNET_assert (bi->pr == pr); | ||
773 | if (NULL == rp->pe_head) | ||
774 | { | ||
775 | GNUNET_CONTAINER_heap_remove_node (rp->hn); | ||
776 | plan_count--; | ||
777 | GNUNET_break (GNUNET_YES == | ||
778 | GNUNET_CONTAINER_multihashmap_remove (rp->pp->plan_map, | ||
779 | &prd->query, | ||
780 | rp)); | ||
781 | GNUNET_free (rp); | ||
782 | } | ||
783 | GNUNET_free (bi); | ||
784 | } | ||
785 | GNUNET_STATISTICS_set (GSF_stats, | ||
786 | gettext_noop ("# query plan entries"), | ||
787 | plan_count, | ||
788 | GNUNET_NO); | ||
789 | } | ||
790 | |||
791 | |||
792 | /** | ||
793 | * Initialize plan subsystem. | ||
794 | */ | ||
795 | void | ||
796 | GSF_plan_init () | ||
797 | { | ||
798 | plans = GNUNET_CONTAINER_multipeermap_create (256, | ||
799 | GNUNET_YES); | ||
800 | } | ||
801 | |||
802 | |||
803 | /** | ||
804 | * Shutdown plan subsystem. | ||
805 | */ | ||
806 | void | ||
807 | GSF_plan_done () | ||
808 | { | ||
809 | GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (plans)); | ||
810 | GNUNET_CONTAINER_multipeermap_destroy (plans); | ||
811 | } | ||
812 | |||
813 | |||
814 | /* end of gnunet-service-fs_pe.h */ | ||
diff --git a/src/fs/gnunet-service-fs_pe.h b/src/fs/gnunet-service-fs_pe.h deleted file mode 100644 index d532b6b71..000000000 --- a/src/fs/gnunet-service-fs_pe.h +++ /dev/null | |||
@@ -1,95 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_pe.h | ||
23 | * @brief API to manage query plan | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_FS_PE_H | ||
27 | #define GNUNET_SERVICE_FS_PE_H | ||
28 | |||
29 | #include "gnunet-service-fs.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Create a new query plan entry. | ||
34 | * | ||
35 | * @param cp peer with the entry | ||
36 | * @param pr request with the entry | ||
37 | */ | ||
38 | void | ||
39 | GSF_plan_add_ (struct GSF_ConnectedPeer *cp, | ||
40 | struct GSF_PendingRequest *pr); | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Notify the plan about a peer being no longer available; | ||
45 | * destroy all entries associated with this peer. | ||
46 | * | ||
47 | * @param cp connected peer | ||
48 | */ | ||
49 | void | ||
50 | GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp); | ||
51 | |||
52 | |||
53 | /** | ||
54 | * Notify the plan about a request being done; | ||
55 | * destroy all entries associated with this request. | ||
56 | * | ||
57 | * @param pr request that is done | ||
58 | */ | ||
59 | void | ||
60 | GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr); | ||
61 | |||
62 | /** | ||
63 | * Get the last transmission attempt time for the request plan list | ||
64 | * referenced by 'rpr_head', that was sent to 'sender' | ||
65 | * | ||
66 | * @param pr_head request plan reference list to check. | ||
67 | * @param sender the peer that we've sent the request to. | ||
68 | * @param result the timestamp to fill. | ||
69 | * @return GNUNET_YES if 'result' was changed, GNUNET_NO otherwise. | ||
70 | */ | ||
71 | int | ||
72 | GSF_request_plan_reference_get_last_transmission_ (struct | ||
73 | GSF_PendingRequestPlanBijection | ||
74 | *pr_head, | ||
75 | struct GSF_ConnectedPeer * | ||
76 | sender, | ||
77 | struct GNUNET_TIME_Absolute * | ||
78 | result); | ||
79 | |||
80 | /** | ||
81 | * Initialize plan subsystem. | ||
82 | */ | ||
83 | void | ||
84 | GSF_plan_init (void); | ||
85 | |||
86 | |||
87 | /** | ||
88 | * Shutdown plan subsystem. | ||
89 | */ | ||
90 | void | ||
91 | GSF_plan_done (void); | ||
92 | |||
93 | |||
94 | #endif | ||
95 | /* end of gnunet-service-fs_pe.h */ | ||
diff --git a/src/fs/gnunet-service-fs_pr.c b/src/fs/gnunet-service-fs_pr.c deleted file mode 100644 index beb29a506..000000000 --- a/src/fs/gnunet-service-fs_pr.c +++ /dev/null | |||
@@ -1,1899 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_pr.c | ||
23 | * @brief API to handle pending requests | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_load_lib.h" | ||
29 | #include "gnunet-service-fs.h" | ||
30 | #include "gnunet-service-fs_cp.h" | ||
31 | #include "gnunet-service-fs_indexing.h" | ||
32 | #include "gnunet-service-fs_pe.h" | ||
33 | #include "gnunet-service-fs_pr.h" | ||
34 | #include "gnunet-service-fs_cadet.h" | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Desired replication level for GETs. | ||
39 | */ | ||
40 | #define DHT_GET_REPLICATION 5 | ||
41 | |||
42 | /** | ||
43 | * Maximum size of the datastore queue for P2P operations. Needs to | ||
44 | * be large enough to queue #MAX_QUEUE_PER_PEER operations for roughly | ||
45 | * the number of active (connected) peers. | ||
46 | */ | ||
47 | #define MAX_DATASTORE_QUEUE (16 * MAX_QUEUE_PER_PEER) | ||
48 | |||
49 | /** | ||
50 | * Bandwidth value of a 0-priority content (must be fairly high | ||
51 | * compared to query since content is typically significantly larger | ||
52 | * -- and more valuable since it can take many queries to get one | ||
53 | * piece of content). | ||
54 | */ | ||
55 | #define CONTENT_BANDWIDTH_VALUE 800 | ||
56 | |||
57 | /** | ||
58 | * Hard limit on the number of results we may get from the datastore per query. | ||
59 | */ | ||
60 | #define MAX_RESULTS (100 * 1024) | ||
61 | |||
62 | /** | ||
63 | * Collect an instance number of statistics? May cause excessive IPC. | ||
64 | */ | ||
65 | #define INSANE_STATISTICS GNUNET_NO | ||
66 | |||
67 | /** | ||
68 | * If obtaining a block via cadet fails, how often do we retry it before | ||
69 | * giving up for good (and sticking to non-anonymous transfer)? | ||
70 | */ | ||
71 | #define CADET_RETRY_MAX 3 | ||
72 | |||
73 | |||
74 | /** | ||
75 | * An active request. | ||
76 | */ | ||
77 | struct GSF_PendingRequest | ||
78 | { | ||
79 | /** | ||
80 | * Public data for the request. | ||
81 | */ | ||
82 | struct GSF_PendingRequestData public_data; | ||
83 | |||
84 | /** | ||
85 | * Function to call if we encounter a reply. | ||
86 | */ | ||
87 | GSF_PendingRequestReplyHandler rh; | ||
88 | |||
89 | /** | ||
90 | * Closure for @e rh | ||
91 | */ | ||
92 | void *rh_cls; | ||
93 | |||
94 | /** | ||
95 | * Array of hash codes of replies we've already seen. | ||
96 | */ | ||
97 | struct GNUNET_HashCode *replies_seen; | ||
98 | |||
99 | /** | ||
100 | * Block group for filtering replies we've already seen. | ||
101 | */ | ||
102 | struct GNUNET_BLOCK_Group *bg; | ||
103 | |||
104 | /** | ||
105 | * Entry for this pending request in the expiration heap, or NULL. | ||
106 | */ | ||
107 | struct GNUNET_CONTAINER_HeapNode *hnode; | ||
108 | |||
109 | /** | ||
110 | * Datastore queue entry for this request (or NULL for none). | ||
111 | */ | ||
112 | struct GNUNET_DATASTORE_QueueEntry *qe; | ||
113 | |||
114 | /** | ||
115 | * DHT request handle for this request (or NULL for none). | ||
116 | */ | ||
117 | struct GNUNET_DHT_GetHandle *gh; | ||
118 | |||
119 | /** | ||
120 | * Cadet request handle for this request (or NULL for none). | ||
121 | */ | ||
122 | struct GSF_CadetRequest *cadet_request; | ||
123 | |||
124 | /** | ||
125 | * Function to call upon completion of the local get | ||
126 | * request, or NULL for none. | ||
127 | */ | ||
128 | GSF_LocalLookupContinuation llc_cont; | ||
129 | |||
130 | /** | ||
131 | * Closure for @e llc_cont. | ||
132 | */ | ||
133 | void *llc_cont_cls; | ||
134 | |||
135 | /** | ||
136 | * Last result from the local datastore lookup evaluation. | ||
137 | */ | ||
138 | enum GNUNET_BLOCK_ReplyEvaluationResult local_result; | ||
139 | |||
140 | /** | ||
141 | * Identity of the peer that we should use for the 'sender' | ||
142 | * (recipient of the response) when forwarding (0 for none). | ||
143 | */ | ||
144 | GNUNET_PEER_Id sender_pid; | ||
145 | |||
146 | /** | ||
147 | * Identity of the peer that we should never forward this query | ||
148 | * to since it originated this query (0 for none). | ||
149 | */ | ||
150 | GNUNET_PEER_Id origin_pid; | ||
151 | |||
152 | /** | ||
153 | * Time we started the last datastore lookup. | ||
154 | */ | ||
155 | struct GNUNET_TIME_Absolute qe_start; | ||
156 | |||
157 | /** | ||
158 | * Task that warns us if the local datastore lookup takes too long. | ||
159 | */ | ||
160 | struct GNUNET_SCHEDULER_Task *warn_task; | ||
161 | |||
162 | /** | ||
163 | * Do we have a first UID yet? | ||
164 | */ | ||
165 | bool have_first_uid; | ||
166 | |||
167 | /** | ||
168 | * Have we seen a NULL result yet? | ||
169 | */ | ||
170 | bool seen_null; | ||
171 | |||
172 | /** | ||
173 | * Unique ID of the first result from the local datastore; | ||
174 | * used to terminate the loop. | ||
175 | */ | ||
176 | uint64_t first_uid; | ||
177 | |||
178 | /** | ||
179 | * Result count. | ||
180 | */ | ||
181 | size_t result_count; | ||
182 | |||
183 | /** | ||
184 | * How often have we retried this request via 'cadet'? | ||
185 | * (used to bound overall retries). | ||
186 | */ | ||
187 | unsigned int cadet_retry_count; | ||
188 | |||
189 | /** | ||
190 | * Number of valid entries in the 'replies_seen' array. | ||
191 | */ | ||
192 | unsigned int replies_seen_count; | ||
193 | |||
194 | /** | ||
195 | * Length of the 'replies_seen' array. | ||
196 | */ | ||
197 | unsigned int replies_seen_size; | ||
198 | }; | ||
199 | |||
200 | |||
201 | /** | ||
202 | * All pending requests, ordered by the query. Entries | ||
203 | * are of type 'struct GSF_PendingRequest*'. | ||
204 | */ | ||
205 | static struct GNUNET_CONTAINER_MultiHashMap *pr_map; | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Datastore 'PUT' load tracking. | ||
210 | */ | ||
211 | static struct GNUNET_LOAD_Value *datastore_put_load; | ||
212 | |||
213 | |||
214 | /** | ||
215 | * Are we allowed to migrate content to this peer. | ||
216 | */ | ||
217 | static int active_to_migration; | ||
218 | |||
219 | |||
220 | /** | ||
221 | * Heap with the request that will expire next at the top. Contains | ||
222 | * pointers of type "struct PendingRequest*"; these will *also* be | ||
223 | * aliased from the "requests_by_peer" data structures and the | ||
224 | * "requests_by_query" table. Note that requests from our clients | ||
225 | * don't expire and are thus NOT in the "requests_by_expiration" | ||
226 | * (or the "requests_by_peer" tables). | ||
227 | */ | ||
228 | static struct GNUNET_CONTAINER_Heap *requests_by_expiration_heap; | ||
229 | |||
230 | |||
231 | /** | ||
232 | * Maximum number of requests (from other peers, overall) that we're | ||
233 | * willing to have pending at any given point in time. Can be changed | ||
234 | * via the configuration file (32k is just the default). | ||
235 | */ | ||
236 | static unsigned long long max_pending_requests = (32 * 1024); | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Recalculate our bloom filter for filtering replies. This function | ||
241 | * will create a new bloom filter from scratch, so it should only be | ||
242 | * called if we have no bloomfilter at all (and hence can create a | ||
243 | * fresh one of minimal size without problems) OR if our peer is the | ||
244 | * initiator (in which case we may resize to larger than minimum size). | ||
245 | * | ||
246 | * @param type type of the request | ||
247 | * @param pr request for which the BF is to be recomputed | ||
248 | */ | ||
249 | static void | ||
250 | refresh_bloomfilter (enum GNUNET_BLOCK_Type type, struct GSF_PendingRequest *pr) | ||
251 | { | ||
252 | if (NULL != pr->bg) | ||
253 | { | ||
254 | GNUNET_BLOCK_group_destroy (pr->bg); | ||
255 | pr->bg = NULL; | ||
256 | } | ||
257 | if (GNUNET_BLOCK_TYPE_FS_UBLOCK != type) | ||
258 | return; /* no need */ | ||
259 | pr->bg = | ||
260 | GNUNET_BLOCK_group_create (GSF_block_ctx, | ||
261 | type, | ||
262 | GNUNET_CRYPTO_random_u32 ( | ||
263 | GNUNET_CRYPTO_QUALITY_WEAK, | ||
264 | UINT32_MAX), | ||
265 | NULL, | ||
266 | 0, | ||
267 | "seen-set-size", | ||
268 | pr->replies_seen_count, | ||
269 | NULL); | ||
270 | if (NULL == pr->bg) | ||
271 | return; | ||
272 | GNUNET_break (GNUNET_OK == | ||
273 | GNUNET_BLOCK_group_set_seen (pr->bg, | ||
274 | pr->replies_seen, | ||
275 | pr->replies_seen_count)); | ||
276 | } | ||
277 | |||
278 | |||
279 | /** | ||
280 | * Create a new pending request. | ||
281 | * | ||
282 | * @param options request options | ||
283 | * @param type type of the block that is being requested | ||
284 | * @param query key for the lookup | ||
285 | * @param target preferred target for the request, NULL for none | ||
286 | * @param bf_data raw data for bloom filter for known replies, can be NULL | ||
287 | * @param bf_size number of bytes in @a bf_data | ||
288 | * @param mingle mingle value for bf | ||
289 | * @param anonymity_level desired anonymity level | ||
290 | * @param priority maximum outgoing cumulative request priority to use | ||
291 | * @param ttl current time-to-live for the request | ||
292 | * @param sender_pid peer ID to use for the sender when forwarding, 0 for none | ||
293 | * @param origin_pid peer ID of origin of query (do not loop back) | ||
294 | * @param replies_seen hash codes of known local replies | ||
295 | * @param replies_seen_count size of the @a replies_seen array | ||
296 | * @param rh handle to call when we get a reply | ||
297 | * @param rh_cls closure for @a rh | ||
298 | * @return handle for the new pending request | ||
299 | */ | ||
300 | struct GSF_PendingRequest * | ||
301 | GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, | ||
302 | enum GNUNET_BLOCK_Type type, | ||
303 | const struct GNUNET_HashCode *query, | ||
304 | const struct GNUNET_PeerIdentity *target, | ||
305 | const char *bf_data, | ||
306 | size_t bf_size, | ||
307 | uint32_t mingle, | ||
308 | uint32_t anonymity_level, | ||
309 | uint32_t priority, | ||
310 | int32_t ttl, | ||
311 | GNUNET_PEER_Id sender_pid, | ||
312 | GNUNET_PEER_Id origin_pid, | ||
313 | const struct GNUNET_HashCode *replies_seen, | ||
314 | unsigned int replies_seen_count, | ||
315 | GSF_PendingRequestReplyHandler rh, | ||
316 | void *rh_cls) | ||
317 | { | ||
318 | struct GSF_PendingRequest *pr; | ||
319 | struct GSF_PendingRequest *dpr; | ||
320 | size_t extra; | ||
321 | struct GNUNET_HashCode *eptr; | ||
322 | |||
323 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
324 | "Creating request handle for `%s' of type %d\n", | ||
325 | GNUNET_h2s (query), | ||
326 | type); | ||
327 | #if INSANE_STATISTICS | ||
328 | GNUNET_STATISTICS_update (GSF_stats, | ||
329 | gettext_noop ("# Pending requests created"), | ||
330 | 1, | ||
331 | GNUNET_NO); | ||
332 | #endif | ||
333 | extra = 0; | ||
334 | if (NULL != target) | ||
335 | extra += sizeof(struct GNUNET_PeerIdentity); | ||
336 | pr = GNUNET_malloc (sizeof(struct GSF_PendingRequest) + extra); | ||
337 | pr->public_data.query = *query; | ||
338 | eptr = (struct GNUNET_HashCode *) &pr[1]; | ||
339 | if (NULL != target) | ||
340 | { | ||
341 | pr->public_data.target = (struct GNUNET_PeerIdentity *) eptr; | ||
342 | GNUNET_memcpy (eptr, target, sizeof(struct GNUNET_PeerIdentity)); | ||
343 | } | ||
344 | pr->public_data.anonymity_level = anonymity_level; | ||
345 | pr->public_data.priority = priority; | ||
346 | pr->public_data.original_priority = priority; | ||
347 | pr->public_data.options = options; | ||
348 | pr->public_data.type = type; | ||
349 | pr->public_data.start_time = GNUNET_TIME_absolute_get (); | ||
350 | pr->sender_pid = sender_pid; | ||
351 | pr->origin_pid = origin_pid; | ||
352 | pr->rh = rh; | ||
353 | pr->rh_cls = rh_cls; | ||
354 | GNUNET_assert ((sender_pid != 0) || (0 == (options & GSF_PRO_FORWARD_ONLY))); | ||
355 | if (ttl >= 0) | ||
356 | pr->public_data.ttl = GNUNET_TIME_relative_to_absolute ( | ||
357 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, (uint32_t) ttl)); | ||
358 | else | ||
359 | pr->public_data.ttl = GNUNET_TIME_absolute_subtract ( | ||
360 | pr->public_data.start_time, | ||
361 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
362 | (uint32_t) (-ttl))); | ||
363 | if (replies_seen_count > 0) | ||
364 | { | ||
365 | pr->replies_seen_size = replies_seen_count; | ||
366 | pr->replies_seen = | ||
367 | GNUNET_new_array (pr->replies_seen_size, struct GNUNET_HashCode); | ||
368 | GNUNET_memcpy (pr->replies_seen, | ||
369 | replies_seen, | ||
370 | replies_seen_count * sizeof(struct GNUNET_HashCode)); | ||
371 | pr->replies_seen_count = replies_seen_count; | ||
372 | } | ||
373 | if ((NULL != bf_data) && | ||
374 | (GNUNET_BLOCK_TYPE_FS_UBLOCK == pr->public_data.type)) | ||
375 | { | ||
376 | pr->bg = GNUNET_BLOCK_group_create (GSF_block_ctx, | ||
377 | pr->public_data.type, | ||
378 | mingle, | ||
379 | bf_data, | ||
380 | bf_size, | ||
381 | "seen-set-size", | ||
382 | 0, | ||
383 | NULL); | ||
384 | } | ||
385 | else if ((replies_seen_count > 0) && | ||
386 | (0 != (options & GSF_PRO_BLOOMFILTER_FULL_REFRESH))) | ||
387 | { | ||
388 | refresh_bloomfilter (pr->public_data.type, pr); | ||
389 | } | ||
390 | GNUNET_CONTAINER_multihashmap_put (pr_map, | ||
391 | &pr->public_data.query, | ||
392 | pr, | ||
393 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
394 | if (0 == (options & GSF_PRO_REQUEST_NEVER_EXPIRES)) | ||
395 | { | ||
396 | pr->hnode = GNUNET_CONTAINER_heap_insert (requests_by_expiration_heap, | ||
397 | pr, | ||
398 | pr->public_data.ttl.abs_value_us); | ||
399 | /* make sure we don't track too many requests */ | ||
400 | while (GNUNET_CONTAINER_heap_get_size (requests_by_expiration_heap) > | ||
401 | max_pending_requests) | ||
402 | { | ||
403 | dpr = GNUNET_CONTAINER_heap_peek (requests_by_expiration_heap); | ||
404 | GNUNET_assert (NULL != dpr); | ||
405 | if (pr == dpr) | ||
406 | break; /* let the request live briefly... */ | ||
407 | if (NULL != dpr->rh) | ||
408 | dpr->rh (dpr->rh_cls, | ||
409 | GNUNET_BLOCK_EVALUATION_REQUEST_VALID, | ||
410 | dpr, | ||
411 | UINT32_MAX, | ||
412 | GNUNET_TIME_UNIT_FOREVER_ABS, | ||
413 | GNUNET_TIME_UNIT_FOREVER_ABS, | ||
414 | GNUNET_BLOCK_TYPE_ANY, | ||
415 | NULL, | ||
416 | 0); | ||
417 | GSF_pending_request_cancel_ (dpr, GNUNET_YES); | ||
418 | } | ||
419 | } | ||
420 | GNUNET_STATISTICS_update (GSF_stats, | ||
421 | gettext_noop ("# Pending requests active"), | ||
422 | 1, | ||
423 | GNUNET_NO); | ||
424 | return pr; | ||
425 | } | ||
426 | |||
427 | |||
428 | /** | ||
429 | * Obtain the public data associated with a pending request | ||
430 | * | ||
431 | * @param pr pending request | ||
432 | * @return associated public data | ||
433 | */ | ||
434 | struct GSF_PendingRequestData * | ||
435 | GSF_pending_request_get_data_ (struct GSF_PendingRequest *pr) | ||
436 | { | ||
437 | return &pr->public_data; | ||
438 | } | ||
439 | |||
440 | |||
441 | /** | ||
442 | * Test if two pending requests are compatible (would generate | ||
443 | * the same query modulo filters and should thus be processed | ||
444 | * jointly). | ||
445 | * | ||
446 | * @param pra a pending request | ||
447 | * @param prb another pending request | ||
448 | * @return #GNUNET_OK if the requests are compatible | ||
449 | */ | ||
450 | int | ||
451 | GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, | ||
452 | struct GSF_PendingRequest *prb) | ||
453 | { | ||
454 | if ((pra->public_data.type != prb->public_data.type) || | ||
455 | (0 != memcmp (&pra->public_data.query, | ||
456 | &prb->public_data.query, | ||
457 | sizeof(struct GNUNET_HashCode)))) | ||
458 | return GNUNET_NO; | ||
459 | return GNUNET_OK; | ||
460 | } | ||
461 | |||
462 | |||
463 | /** | ||
464 | * Update a given pending request with additional replies | ||
465 | * that have been seen. | ||
466 | * | ||
467 | * @param pr request to update | ||
468 | * @param replies_seen hash codes of replies that we've seen | ||
469 | * @param replies_seen_count size of the replies_seen array | ||
470 | */ | ||
471 | void | ||
472 | GSF_pending_request_update_ (struct GSF_PendingRequest *pr, | ||
473 | const struct GNUNET_HashCode *replies_seen, | ||
474 | unsigned int replies_seen_count) | ||
475 | { | ||
476 | if (replies_seen_count + pr->replies_seen_count < pr->replies_seen_count) | ||
477 | return; /* integer overflow */ | ||
478 | if (0 != (pr->public_data.options & GSF_PRO_BLOOMFILTER_FULL_REFRESH)) | ||
479 | { | ||
480 | /* we're responsible for the BF, full refresh */ | ||
481 | if (replies_seen_count + pr->replies_seen_count > pr->replies_seen_size) | ||
482 | GNUNET_array_grow (pr->replies_seen, | ||
483 | pr->replies_seen_size, | ||
484 | replies_seen_count + pr->replies_seen_count); | ||
485 | GNUNET_memcpy (&pr->replies_seen[pr->replies_seen_count], | ||
486 | replies_seen, | ||
487 | sizeof(struct GNUNET_HashCode) * replies_seen_count); | ||
488 | pr->replies_seen_count += replies_seen_count; | ||
489 | refresh_bloomfilter (pr->public_data.type, pr); | ||
490 | } | ||
491 | else | ||
492 | { | ||
493 | if (NULL == pr->bg) | ||
494 | { | ||
495 | /* we're not the initiator, but the initiator did not give us | ||
496 | * any bloom-filter, so we need to create one on-the-fly */ | ||
497 | refresh_bloomfilter (pr->public_data.type, pr); | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | GNUNET_break (GNUNET_OK == | ||
502 | GNUNET_BLOCK_group_set_seen (pr->bg, | ||
503 | replies_seen, | ||
504 | pr->replies_seen_count)); | ||
505 | } | ||
506 | } | ||
507 | if (NULL != pr->gh) | ||
508 | GNUNET_DHT_get_filter_known_results (pr->gh, | ||
509 | replies_seen_count, | ||
510 | replies_seen); | ||
511 | } | ||
512 | |||
513 | |||
514 | /** | ||
515 | * Generate the message corresponding to the given pending request for | ||
516 | * transmission to other peers. | ||
517 | * | ||
518 | * @param pr request to generate the message for | ||
519 | * @return envelope with the request message | ||
520 | */ | ||
521 | struct GNUNET_MQ_Envelope * | ||
522 | GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr) | ||
523 | { | ||
524 | struct GNUNET_MQ_Envelope *env; | ||
525 | struct GetMessage *gm; | ||
526 | struct GNUNET_PeerIdentity *ext; | ||
527 | unsigned int k; | ||
528 | uint32_t bm; | ||
529 | uint32_t prio; | ||
530 | size_t bf_size; | ||
531 | struct GNUNET_TIME_Absolute now; | ||
532 | int64_t ttl; | ||
533 | int do_route; | ||
534 | void *bf_data; | ||
535 | uint32_t bf_nonce; | ||
536 | |||
537 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
538 | "Building request message for `%s' of type %d\n", | ||
539 | GNUNET_h2s (&pr->public_data.query), | ||
540 | pr->public_data.type); | ||
541 | k = 0; | ||
542 | bm = 0; | ||
543 | do_route = (0 == (pr->public_data.options & GSF_PRO_FORWARD_ONLY)); | ||
544 | if ((! do_route) && (pr->sender_pid == 0)) | ||
545 | { | ||
546 | GNUNET_break (0); | ||
547 | do_route = GNUNET_YES; | ||
548 | } | ||
549 | if (! do_route) | ||
550 | { | ||
551 | bm |= GET_MESSAGE_BIT_RETURN_TO; | ||
552 | k++; | ||
553 | } | ||
554 | if (NULL != pr->public_data.target) | ||
555 | { | ||
556 | bm |= GET_MESSAGE_BIT_TRANSMIT_TO; | ||
557 | k++; | ||
558 | } | ||
559 | if (GNUNET_OK != | ||
560 | GNUNET_BLOCK_group_serialize (pr->bg, &bf_nonce, &bf_data, &bf_size)) | ||
561 | { | ||
562 | bf_size = 0; | ||
563 | bf_data = NULL; | ||
564 | } | ||
565 | env = GNUNET_MQ_msg_extra (gm, | ||
566 | bf_size + k * sizeof(struct GNUNET_PeerIdentity), | ||
567 | GNUNET_MESSAGE_TYPE_FS_GET); | ||
568 | gm->type = htonl (pr->public_data.type); | ||
569 | if (do_route) | ||
570 | prio = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
571 | pr->public_data.priority + 1); | ||
572 | else | ||
573 | prio = 0; | ||
574 | pr->public_data.priority -= prio; | ||
575 | pr->public_data.num_transmissions++; | ||
576 | pr->public_data.respect_offered += prio; | ||
577 | gm->priority = htonl (prio); | ||
578 | now = GNUNET_TIME_absolute_get (); | ||
579 | ttl = (int64_t) (pr->public_data.ttl.abs_value_us - now.abs_value_us); | ||
580 | gm->ttl = htonl (ttl / 1000LL / 1000LL); | ||
581 | gm->filter_mutator = htonl (bf_nonce); | ||
582 | gm->hash_bitmap = htonl (bm); | ||
583 | gm->query = pr->public_data.query; | ||
584 | ext = (struct GNUNET_PeerIdentity *) &gm[1]; | ||
585 | k = 0; | ||
586 | if (! do_route) | ||
587 | GNUNET_PEER_resolve (pr->sender_pid, &ext[k++]); | ||
588 | if (NULL != pr->public_data.target) | ||
589 | ext[k++] = *pr->public_data.target; | ||
590 | GNUNET_memcpy (&ext[k], bf_data, bf_size); | ||
591 | GNUNET_free (bf_data); | ||
592 | return env; | ||
593 | } | ||
594 | |||
595 | |||
596 | /** | ||
597 | * Iterator to free pending requests. | ||
598 | * | ||
599 | * @param cls closure, unused | ||
600 | * @param key current key code | ||
601 | * @param value value in the hash map (pending request) | ||
602 | * @return #GNUNET_YES (we should continue to iterate) | ||
603 | */ | ||
604 | static int | ||
605 | clean_request (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
606 | { | ||
607 | struct GSF_PendingRequest *pr = value; | ||
608 | GSF_LocalLookupContinuation cont; | ||
609 | |||
610 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
611 | "Cleaning up pending request for `%s'.\n", | ||
612 | GNUNET_h2s (key)); | ||
613 | if (NULL != pr->cadet_request) | ||
614 | { | ||
615 | pr->cadet_retry_count = CADET_RETRY_MAX; | ||
616 | GSF_cadet_query_cancel (pr->cadet_request); | ||
617 | pr->cadet_request = NULL; | ||
618 | } | ||
619 | if (NULL != (cont = pr->llc_cont)) | ||
620 | { | ||
621 | pr->llc_cont = NULL; | ||
622 | cont (pr->llc_cont_cls, | ||
623 | pr, | ||
624 | pr->local_result); | ||
625 | } | ||
626 | GSF_plan_notify_request_done_ (pr); | ||
627 | GNUNET_free (pr->replies_seen); | ||
628 | GNUNET_BLOCK_group_destroy (pr->bg); | ||
629 | pr->bg = NULL; | ||
630 | GNUNET_PEER_change_rc (pr->sender_pid, -1); | ||
631 | pr->sender_pid = 0; | ||
632 | GNUNET_PEER_change_rc (pr->origin_pid, -1); | ||
633 | pr->origin_pid = 0; | ||
634 | if (NULL != pr->hnode) | ||
635 | { | ||
636 | GNUNET_CONTAINER_heap_remove_node (pr->hnode); | ||
637 | pr->hnode = NULL; | ||
638 | } | ||
639 | if (NULL != pr->qe) | ||
640 | { | ||
641 | GNUNET_DATASTORE_cancel (pr->qe); | ||
642 | pr->qe = NULL; | ||
643 | } | ||
644 | if (NULL != pr->gh) | ||
645 | { | ||
646 | GNUNET_DHT_get_stop (pr->gh); | ||
647 | pr->gh = NULL; | ||
648 | } | ||
649 | if (NULL != pr->warn_task) | ||
650 | { | ||
651 | GNUNET_SCHEDULER_cancel (pr->warn_task); | ||
652 | pr->warn_task = NULL; | ||
653 | } | ||
654 | GNUNET_assert ( | ||
655 | GNUNET_OK == | ||
656 | GNUNET_CONTAINER_multihashmap_remove (pr_map, &pr->public_data.query, pr)); | ||
657 | GNUNET_STATISTICS_update (GSF_stats, | ||
658 | gettext_noop ("# Pending requests active"), | ||
659 | -1, | ||
660 | GNUNET_NO); | ||
661 | GNUNET_free (pr); | ||
662 | return GNUNET_YES; | ||
663 | } | ||
664 | |||
665 | |||
666 | /** | ||
667 | * Explicitly cancel a pending request. | ||
668 | * | ||
669 | * @param pr request to cancel | ||
670 | * @param full_cleanup fully purge the request | ||
671 | */ | ||
672 | void | ||
673 | GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup) | ||
674 | { | ||
675 | GSF_LocalLookupContinuation cont; | ||
676 | |||
677 | if (NULL == pr_map) | ||
678 | return; /* already cleaned up! */ | ||
679 | if (GNUNET_NO == full_cleanup) | ||
680 | { | ||
681 | /* make request inactive (we're no longer interested in more results), | ||
682 | * but do NOT remove from our data-structures, we still need it there | ||
683 | * to prevent the request from looping */ | ||
684 | pr->rh = NULL; | ||
685 | if (NULL != pr->cadet_request) | ||
686 | { | ||
687 | pr->cadet_retry_count = CADET_RETRY_MAX; | ||
688 | GSF_cadet_query_cancel (pr->cadet_request); | ||
689 | pr->cadet_request = NULL; | ||
690 | } | ||
691 | if (NULL != (cont = pr->llc_cont)) | ||
692 | { | ||
693 | pr->llc_cont = NULL; | ||
694 | cont (pr->llc_cont_cls, | ||
695 | pr, | ||
696 | pr->local_result); | ||
697 | } | ||
698 | GSF_plan_notify_request_done_ (pr); | ||
699 | if (NULL != pr->qe) | ||
700 | { | ||
701 | GNUNET_DATASTORE_cancel (pr->qe); | ||
702 | pr->qe = NULL; | ||
703 | } | ||
704 | if (NULL != pr->gh) | ||
705 | { | ||
706 | GNUNET_DHT_get_stop (pr->gh); | ||
707 | pr->gh = NULL; | ||
708 | } | ||
709 | if (NULL != pr->warn_task) | ||
710 | { | ||
711 | GNUNET_SCHEDULER_cancel (pr->warn_task); | ||
712 | pr->warn_task = NULL; | ||
713 | } | ||
714 | return; | ||
715 | } | ||
716 | GNUNET_assert (GNUNET_YES == | ||
717 | clean_request (NULL, &pr->public_data.query, pr)); | ||
718 | } | ||
719 | |||
720 | |||
721 | /** | ||
722 | * Iterate over all pending requests. | ||
723 | * | ||
724 | * @param it function to call for each request | ||
725 | * @param cls closure for @a it | ||
726 | */ | ||
727 | void | ||
728 | GSF_iterate_pending_requests_ (GSF_PendingRequestIterator it, void *cls) | ||
729 | { | ||
730 | GNUNET_CONTAINER_multihashmap_iterate ( | ||
731 | pr_map, | ||
732 | (GNUNET_CONTAINER_MulitHashMapIteratorCallback) it, | ||
733 | cls); | ||
734 | } | ||
735 | |||
736 | |||
737 | /** | ||
738 | * Closure for process_reply() function. | ||
739 | */ | ||
740 | struct ProcessReplyClosure | ||
741 | { | ||
742 | /** | ||
743 | * The data for the reply. | ||
744 | */ | ||
745 | const void *data; | ||
746 | |||
747 | /** | ||
748 | * Who gave us this reply? NULL for local host (or DHT) | ||
749 | */ | ||
750 | struct GSF_ConnectedPeer *sender; | ||
751 | |||
752 | /** | ||
753 | * When the reply expires. | ||
754 | */ | ||
755 | struct GNUNET_TIME_Absolute expiration; | ||
756 | |||
757 | /** | ||
758 | * Size of data. | ||
759 | */ | ||
760 | size_t size; | ||
761 | |||
762 | /** | ||
763 | * Type of the block. | ||
764 | */ | ||
765 | enum GNUNET_BLOCK_Type type; | ||
766 | |||
767 | /** | ||
768 | * Control flags for evaluation. | ||
769 | */ | ||
770 | enum GNUNET_BLOCK_EvaluationOptions eo; | ||
771 | |||
772 | /** | ||
773 | * How much was this reply worth to us? | ||
774 | */ | ||
775 | uint32_t priority; | ||
776 | |||
777 | /** | ||
778 | * Anonymity requirements for this reply. | ||
779 | */ | ||
780 | uint32_t anonymity_level; | ||
781 | |||
782 | /** | ||
783 | * Evaluation result (returned). | ||
784 | */ | ||
785 | enum GNUNET_BLOCK_ReplyEvaluationResult eval; | ||
786 | |||
787 | /** | ||
788 | * Did we find a matching request? | ||
789 | */ | ||
790 | int request_found; | ||
791 | }; | ||
792 | |||
793 | |||
794 | /** | ||
795 | * Update the performance data for the sender (if any) since | ||
796 | * the sender successfully answered one of our queries. | ||
797 | * | ||
798 | * @param prq information about the sender | ||
799 | * @param pr request that was satisfied | ||
800 | */ | ||
801 | static void | ||
802 | update_request_performance_data (struct ProcessReplyClosure *prq, | ||
803 | struct GSF_PendingRequest *pr) | ||
804 | { | ||
805 | if (prq->sender == NULL) | ||
806 | return; | ||
807 | GSF_peer_update_performance_ (prq->sender, | ||
808 | pr->public_data.start_time, | ||
809 | prq->priority); | ||
810 | } | ||
811 | |||
812 | |||
813 | /** | ||
814 | * We have received a reply; handle it! | ||
815 | * | ||
816 | * @param cls response (a `struct ProcessReplyClosure`) | ||
817 | * @param key our query | ||
818 | * @param value value in the hash map (info about the query) | ||
819 | * @return #GNUNET_YES (we should continue to iterate) | ||
820 | */ | ||
821 | static enum GNUNET_GenericReturnValue | ||
822 | process_reply (void *cls, | ||
823 | const struct GNUNET_HashCode *key, | ||
824 | void *value) | ||
825 | { | ||
826 | struct ProcessReplyClosure *prq = cls; | ||
827 | struct GSF_PendingRequest *pr = value; | ||
828 | struct GNUNET_HashCode chash; | ||
829 | struct GNUNET_TIME_Absolute last_transmission; | ||
830 | |||
831 | if (NULL == pr->rh) | ||
832 | return GNUNET_YES; | ||
833 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
834 | "Matched result (type %u) for query `%s' with pending request\n", | ||
835 | (unsigned int) prq->type, | ||
836 | GNUNET_h2s (key)); | ||
837 | GNUNET_STATISTICS_update (GSF_stats, | ||
838 | gettext_noop ("# replies received and matched"), | ||
839 | 1, | ||
840 | GNUNET_NO); | ||
841 | prq->eval = GNUNET_BLOCK_check_reply (GSF_block_ctx, | ||
842 | prq->type, | ||
843 | pr->bg, | ||
844 | key, | ||
845 | NULL, 0, | ||
846 | prq->data, | ||
847 | prq->size); | ||
848 | switch (prq->eval) | ||
849 | { | ||
850 | case GNUNET_BLOCK_REPLY_OK_MORE: | ||
851 | update_request_performance_data (prq, pr); | ||
852 | break; | ||
853 | |||
854 | case GNUNET_BLOCK_REPLY_OK_LAST: | ||
855 | /* short cut: stop processing early, no BF-update, etc. */ | ||
856 | update_request_performance_data (prq, pr); | ||
857 | GNUNET_LOAD_update (GSF_rt_entry_lifetime, | ||
858 | GNUNET_TIME_absolute_get_duration ( | ||
859 | pr->public_data.start_time) | ||
860 | .rel_value_us); | ||
861 | if (GNUNET_YES != | ||
862 | GSF_request_plan_reference_get_last_transmission_ (pr->public_data | ||
863 | .pr_head, | ||
864 | prq->sender, | ||
865 | &last_transmission)) | ||
866 | last_transmission = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
867 | /* pass on to other peers / local clients */ | ||
868 | pr->rh (pr->rh_cls, | ||
869 | prq->eval, | ||
870 | pr, | ||
871 | prq->anonymity_level, | ||
872 | prq->expiration, | ||
873 | last_transmission, | ||
874 | prq->type, | ||
875 | prq->data, | ||
876 | prq->size); | ||
877 | return GNUNET_YES; | ||
878 | case GNUNET_BLOCK_REPLY_OK_DUPLICATE: | ||
879 | #if INSANE_STATISTICS | ||
880 | GNUNET_STATISTICS_update (GSF_stats, | ||
881 | "# duplicate replies discarded (bloomfilter)", | ||
882 | 1, | ||
883 | GNUNET_NO); | ||
884 | #endif | ||
885 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
886 | "Duplicate response, discarding.\n"); | ||
887 | return GNUNET_YES; /* duplicate */ | ||
888 | |||
889 | case GNUNET_BLOCK_REPLY_IRRELEVANT: | ||
890 | GNUNET_STATISTICS_update (GSF_stats, | ||
891 | "# irrelevant replies discarded", | ||
892 | 1, | ||
893 | GNUNET_NO); | ||
894 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
895 | "Irrelevant response, ignoring.\n"); | ||
896 | return GNUNET_YES; | ||
897 | case GNUNET_BLOCK_REPLY_INVALID: | ||
898 | return GNUNET_YES; | ||
899 | case GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED: | ||
900 | GNUNET_break (0); /* bad installation? */ | ||
901 | return GNUNET_NO; | ||
902 | } | ||
903 | /* update bloomfilter */ | ||
904 | GNUNET_CRYPTO_hash (prq->data, | ||
905 | prq->size, | ||
906 | &chash); | ||
907 | GSF_pending_request_update_ (pr, | ||
908 | &chash, | ||
909 | 1); | ||
910 | if (NULL == prq->sender) | ||
911 | { | ||
912 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
913 | "Found result for query `%s' in local datastore\n", | ||
914 | GNUNET_h2s (key)); | ||
915 | GNUNET_STATISTICS_update (GSF_stats, | ||
916 | gettext_noop ("# results found locally"), | ||
917 | 1, | ||
918 | GNUNET_NO); | ||
919 | } | ||
920 | else | ||
921 | { | ||
922 | GSF_dht_lookup_ (pr); | ||
923 | } | ||
924 | prq->priority += pr->public_data.original_priority; | ||
925 | pr->public_data.priority = 0; | ||
926 | pr->public_data.original_priority = 0; | ||
927 | pr->public_data.results_found++; | ||
928 | prq->request_found = GNUNET_YES; | ||
929 | /* finally, pass on to other peer / local client */ | ||
930 | if (! GSF_request_plan_reference_get_last_transmission_ (pr->public_data | ||
931 | .pr_head, | ||
932 | prq->sender, | ||
933 | &last_transmission)) | ||
934 | last_transmission = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
935 | pr->rh (pr->rh_cls, | ||
936 | prq->eval, | ||
937 | pr, | ||
938 | prq->anonymity_level, | ||
939 | prq->expiration, | ||
940 | last_transmission, | ||
941 | prq->type, | ||
942 | prq->data, | ||
943 | prq->size); | ||
944 | return GNUNET_YES; | ||
945 | } | ||
946 | |||
947 | |||
948 | /** | ||
949 | * Context for put_migration_continuation(). | ||
950 | */ | ||
951 | struct PutMigrationContext | ||
952 | { | ||
953 | /** | ||
954 | * Start time for the operation. | ||
955 | */ | ||
956 | struct GNUNET_TIME_Absolute start; | ||
957 | |||
958 | /** | ||
959 | * Request origin. | ||
960 | */ | ||
961 | struct GNUNET_PeerIdentity origin; | ||
962 | |||
963 | /** | ||
964 | * #GNUNET_YES if we had a matching request for this block, | ||
965 | * #GNUNET_NO if not. | ||
966 | */ | ||
967 | int requested; | ||
968 | }; | ||
969 | |||
970 | |||
971 | /** | ||
972 | * Continuation called to notify client about result of the | ||
973 | * operation. | ||
974 | * | ||
975 | * @param cls closure | ||
976 | * @param success #GNUNET_SYSERR on failure | ||
977 | * @param min_expiration minimum expiration time required for content to be stored | ||
978 | * @param msg NULL on success, otherwise an error message | ||
979 | */ | ||
980 | static void | ||
981 | put_migration_continuation (void *cls, | ||
982 | int success, | ||
983 | struct GNUNET_TIME_Absolute min_expiration, | ||
984 | const char *msg) | ||
985 | { | ||
986 | struct PutMigrationContext *pmc = cls; | ||
987 | struct GSF_ConnectedPeer *cp; | ||
988 | struct GNUNET_TIME_Relative mig_pause; | ||
989 | struct GSF_PeerPerformanceData *ppd; | ||
990 | |||
991 | if (NULL != datastore_put_load) | ||
992 | { | ||
993 | if (GNUNET_SYSERR != success) | ||
994 | { | ||
995 | GNUNET_LOAD_update (datastore_put_load, | ||
996 | GNUNET_TIME_absolute_get_duration (pmc->start) | ||
997 | .rel_value_us); | ||
998 | } | ||
999 | else | ||
1000 | { | ||
1001 | /* on queue failure / timeout, increase the put load dramatically */ | ||
1002 | GNUNET_LOAD_update (datastore_put_load, | ||
1003 | GNUNET_TIME_UNIT_MINUTES.rel_value_us); | ||
1004 | } | ||
1005 | } | ||
1006 | cp = GSF_peer_get_ (&pmc->origin); | ||
1007 | if (GNUNET_OK == success) | ||
1008 | { | ||
1009 | if (NULL != cp) | ||
1010 | { | ||
1011 | ppd = GSF_get_peer_performance_data_ (cp); | ||
1012 | ppd->migration_delay.rel_value_us /= 2; | ||
1013 | } | ||
1014 | GNUNET_free (pmc); | ||
1015 | return; | ||
1016 | } | ||
1017 | if ((GNUNET_NO == success) && (GNUNET_NO == pmc->requested) && (NULL != cp)) | ||
1018 | { | ||
1019 | ppd = GSF_get_peer_performance_data_ (cp); | ||
1020 | if (min_expiration.abs_value_us > 0) | ||
1021 | { | ||
1022 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1023 | "Asking to stop migration for %s because datastore is full\n", | ||
1024 | GNUNET_STRINGS_relative_time_to_string ( | ||
1025 | GNUNET_TIME_absolute_get_remaining (min_expiration), | ||
1026 | GNUNET_YES)); | ||
1027 | GSF_block_peer_migration_ (cp, min_expiration); | ||
1028 | } | ||
1029 | else | ||
1030 | { | ||
1031 | ppd->migration_delay = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_SECONDS, | ||
1032 | ppd->migration_delay); | ||
1033 | ppd->migration_delay = | ||
1034 | GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_HOURS, ppd->migration_delay); | ||
1035 | mig_pause.rel_value_us = | ||
1036 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1037 | ppd->migration_delay.rel_value_us); | ||
1038 | ppd->migration_delay = | ||
1039 | GNUNET_TIME_relative_saturating_multiply (ppd->migration_delay, 2); | ||
1040 | GNUNET_log ( | ||
1041 | GNUNET_ERROR_TYPE_DEBUG, | ||
1042 | "Replicated content already exists locally, asking to stop migration for %s\n", | ||
1043 | GNUNET_STRINGS_relative_time_to_string (mig_pause, GNUNET_YES)); | ||
1044 | GSF_block_peer_migration_ (cp, | ||
1045 | GNUNET_TIME_relative_to_absolute (mig_pause)); | ||
1046 | } | ||
1047 | } | ||
1048 | GNUNET_free (pmc); | ||
1049 | GNUNET_STATISTICS_update (GSF_stats, | ||
1050 | gettext_noop ("# Datastore `PUT' failures"), | ||
1051 | 1, | ||
1052 | GNUNET_NO); | ||
1053 | } | ||
1054 | |||
1055 | |||
1056 | /** | ||
1057 | * Test if the DATABASE (PUT) load on this peer is too high | ||
1058 | * to even consider processing the query at | ||
1059 | * all. | ||
1060 | * | ||
1061 | * @param priority the priority of the item | ||
1062 | * @return #GNUNET_YES if the load is too high to do anything (load high) | ||
1063 | * #GNUNET_NO to process normally (load normal or low) | ||
1064 | */ | ||
1065 | static int | ||
1066 | test_put_load_too_high (uint32_t priority) | ||
1067 | { | ||
1068 | double ld; | ||
1069 | |||
1070 | if (NULL == datastore_put_load) | ||
1071 | return GNUNET_NO; | ||
1072 | if (GNUNET_LOAD_get_average (datastore_put_load) < 50) | ||
1073 | return GNUNET_NO; /* very fast */ | ||
1074 | ld = GNUNET_LOAD_get_load (datastore_put_load); | ||
1075 | if (ld < 2.0 * (1 + priority)) | ||
1076 | return GNUNET_NO; | ||
1077 | GNUNET_STATISTICS_update (GSF_stats, | ||
1078 | gettext_noop ( | ||
1079 | "# storage requests dropped due to high load"), | ||
1080 | 1, | ||
1081 | GNUNET_NO); | ||
1082 | return GNUNET_YES; | ||
1083 | } | ||
1084 | |||
1085 | |||
1086 | /** | ||
1087 | * Iterator called on each result obtained for a DHT | ||
1088 | * operation that expects a reply | ||
1089 | * | ||
1090 | * @param cls closure | ||
1091 | * @param exp when will this value expire | ||
1092 | * @param key key of the result | ||
1093 | * @param get_path peers on reply path (or NULL if not recorded) | ||
1094 | * @param get_path_length number of entries in @a get_path | ||
1095 | * @param put_path peers on the PUT path (or NULL if not recorded) | ||
1096 | * @param put_path_length number of entries in @a get_path | ||
1097 | * @param type type of the result | ||
1098 | * @param size number of bytes in @a data | ||
1099 | * @param data pointer to the result data | ||
1100 | */ | ||
1101 | static void | ||
1102 | handle_dht_reply (void *cls, | ||
1103 | struct GNUNET_TIME_Absolute exp, | ||
1104 | const struct GNUNET_HashCode *key, | ||
1105 | const struct GNUNET_DHT_PathElement *get_path, | ||
1106 | unsigned int get_path_length, | ||
1107 | const struct GNUNET_DHT_PathElement *put_path, | ||
1108 | unsigned int put_path_length, | ||
1109 | enum GNUNET_BLOCK_Type type, | ||
1110 | size_t size, | ||
1111 | const void *data) | ||
1112 | { | ||
1113 | struct GSF_PendingRequest *pr = cls; | ||
1114 | struct ProcessReplyClosure prq; | ||
1115 | struct PutMigrationContext *pmc; | ||
1116 | |||
1117 | GNUNET_STATISTICS_update (GSF_stats, | ||
1118 | gettext_noop ("# Replies received from DHT"), | ||
1119 | 1, | ||
1120 | GNUNET_NO); | ||
1121 | memset (&prq, 0, sizeof(prq)); | ||
1122 | prq.data = data; | ||
1123 | prq.expiration = exp; | ||
1124 | /* do not allow migrated content to live longer than 1 year */ | ||
1125 | prq.expiration = GNUNET_TIME_absolute_min (GNUNET_TIME_relative_to_absolute ( | ||
1126 | GNUNET_TIME_UNIT_YEARS), | ||
1127 | prq.expiration); | ||
1128 | prq.size = size; | ||
1129 | prq.type = type; | ||
1130 | prq.eo = GNUNET_BLOCK_EO_NONE; | ||
1131 | process_reply (&prq, key, pr); | ||
1132 | if ((GNUNET_YES == active_to_migration) && | ||
1133 | (GNUNET_NO == test_put_load_too_high (prq.priority))) | ||
1134 | { | ||
1135 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1136 | "Replicating result for query `%s' with priority %u\n", | ||
1137 | GNUNET_h2s (key), | ||
1138 | prq.priority); | ||
1139 | pmc = GNUNET_new (struct PutMigrationContext); | ||
1140 | pmc->start = GNUNET_TIME_absolute_get (); | ||
1141 | pmc->requested = GNUNET_YES; | ||
1142 | if (NULL == GNUNET_DATASTORE_put (GSF_dsh, | ||
1143 | 0, | ||
1144 | key, | ||
1145 | size, | ||
1146 | data, | ||
1147 | type, | ||
1148 | prq.priority, | ||
1149 | 1 /* anonymity */, | ||
1150 | 0 /* replication */, | ||
1151 | exp, | ||
1152 | 1 + prq.priority, | ||
1153 | MAX_DATASTORE_QUEUE, | ||
1154 | &put_migration_continuation, | ||
1155 | pmc)) | ||
1156 | { | ||
1157 | put_migration_continuation (pmc, | ||
1158 | GNUNET_SYSERR, | ||
1159 | GNUNET_TIME_UNIT_ZERO_ABS, | ||
1160 | NULL); | ||
1161 | } | ||
1162 | } | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | /** | ||
1167 | * Consider looking up the data in the DHT (anonymity-level permitting). | ||
1168 | * | ||
1169 | * @param pr the pending request to process | ||
1170 | */ | ||
1171 | void | ||
1172 | GSF_dht_lookup_ (struct GSF_PendingRequest *pr) | ||
1173 | { | ||
1174 | const void *xquery; | ||
1175 | size_t xquery_size; | ||
1176 | struct GNUNET_PeerIdentity pi; | ||
1177 | char buf[sizeof(struct GNUNET_HashCode) * 2] GNUNET_ALIGN; | ||
1178 | |||
1179 | if (0 != pr->public_data.anonymity_level) | ||
1180 | return; | ||
1181 | if (NULL != pr->gh) | ||
1182 | { | ||
1183 | GNUNET_DHT_get_stop (pr->gh); | ||
1184 | pr->gh = NULL; | ||
1185 | } | ||
1186 | xquery = NULL; | ||
1187 | xquery_size = 0; | ||
1188 | if (0 != (pr->public_data.options & GSF_PRO_FORWARD_ONLY)) | ||
1189 | { | ||
1190 | GNUNET_assert (0 != pr->sender_pid); | ||
1191 | GNUNET_PEER_resolve (pr->sender_pid, &pi); | ||
1192 | GNUNET_memcpy (&buf[xquery_size], &pi, sizeof(struct GNUNET_PeerIdentity)); | ||
1193 | xquery_size += sizeof(struct GNUNET_PeerIdentity); | ||
1194 | } | ||
1195 | pr->gh = GNUNET_DHT_get_start (GSF_dht, | ||
1196 | pr->public_data.type, | ||
1197 | &pr->public_data.query, | ||
1198 | DHT_GET_REPLICATION, | ||
1199 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, | ||
1200 | xquery, | ||
1201 | xquery_size, | ||
1202 | &handle_dht_reply, | ||
1203 | pr); | ||
1204 | if ((NULL != pr->gh) && (0 != pr->replies_seen_count)) | ||
1205 | GNUNET_DHT_get_filter_known_results (pr->gh, | ||
1206 | pr->replies_seen_count, | ||
1207 | pr->replies_seen); | ||
1208 | } | ||
1209 | |||
1210 | |||
1211 | /** | ||
1212 | * Function called with a reply from the cadet. | ||
1213 | * | ||
1214 | * @param cls the pending request struct | ||
1215 | * @param type type of the block, ANY on error | ||
1216 | * @param expiration expiration time for the block | ||
1217 | * @param data_size number of bytes in @a data, 0 on error | ||
1218 | * @param data reply block data, NULL on error | ||
1219 | */ | ||
1220 | static void | ||
1221 | cadet_reply_proc (void *cls, | ||
1222 | enum GNUNET_BLOCK_Type type, | ||
1223 | struct GNUNET_TIME_Absolute expiration, | ||
1224 | size_t data_size, | ||
1225 | const void *data) | ||
1226 | { | ||
1227 | struct GSF_PendingRequest *pr = cls; | ||
1228 | struct ProcessReplyClosure prq; | ||
1229 | struct GNUNET_HashCode query; | ||
1230 | |||
1231 | pr->cadet_request = NULL; | ||
1232 | if (GNUNET_BLOCK_TYPE_ANY == type) | ||
1233 | { | ||
1234 | GNUNET_break (NULL == data); | ||
1235 | GNUNET_break (0 == data_size); | ||
1236 | pr->cadet_retry_count++; | ||
1237 | if (pr->cadet_retry_count >= CADET_RETRY_MAX) | ||
1238 | return; /* give up on cadet */ | ||
1239 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error retrieiving block via cadet\n"); | ||
1240 | /* retry -- without delay, as this is non-anonymous | ||
1241 | and cadet/cadet connect will take some time anyway */ | ||
1242 | pr->cadet_request = GSF_cadet_query (pr->public_data.target, | ||
1243 | &pr->public_data.query, | ||
1244 | pr->public_data.type, | ||
1245 | &cadet_reply_proc, | ||
1246 | pr); | ||
1247 | return; | ||
1248 | } | ||
1249 | if (GNUNET_YES != | ||
1250 | GNUNET_BLOCK_get_key (GSF_block_ctx, type, data, data_size, &query)) | ||
1251 | { | ||
1252 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1253 | "Failed to derive key for block of type %d\n", | ||
1254 | (int) type); | ||
1255 | GNUNET_break_op (0); | ||
1256 | return; | ||
1257 | } | ||
1258 | GNUNET_STATISTICS_update (GSF_stats, | ||
1259 | gettext_noop ("# Replies received from CADET"), | ||
1260 | 1, | ||
1261 | GNUNET_NO); | ||
1262 | memset (&prq, 0, sizeof(prq)); | ||
1263 | prq.data = data; | ||
1264 | prq.expiration = expiration; | ||
1265 | /* do not allow migrated content to live longer than 1 year */ | ||
1266 | prq.expiration = GNUNET_TIME_absolute_min (GNUNET_TIME_relative_to_absolute ( | ||
1267 | GNUNET_TIME_UNIT_YEARS), | ||
1268 | prq.expiration); | ||
1269 | prq.size = data_size; | ||
1270 | prq.type = type; | ||
1271 | prq.eo = GNUNET_BLOCK_EO_NONE; | ||
1272 | process_reply (&prq, &query, pr); | ||
1273 | } | ||
1274 | |||
1275 | |||
1276 | /** | ||
1277 | * Consider downloading via cadet (if possible) | ||
1278 | * | ||
1279 | * @param pr the pending request to process | ||
1280 | */ | ||
1281 | void | ||
1282 | GSF_cadet_lookup_ (struct GSF_PendingRequest *pr) | ||
1283 | { | ||
1284 | if (0 != pr->public_data.anonymity_level) | ||
1285 | return; | ||
1286 | if (0 == pr->public_data.target) | ||
1287 | { | ||
1288 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1289 | "Cannot do cadet-based download, target peer not known\n"); | ||
1290 | return; | ||
1291 | } | ||
1292 | if (NULL != pr->cadet_request) | ||
1293 | return; | ||
1294 | pr->cadet_request = GSF_cadet_query (pr->public_data.target, | ||
1295 | &pr->public_data.query, | ||
1296 | pr->public_data.type, | ||
1297 | &cadet_reply_proc, | ||
1298 | pr); | ||
1299 | } | ||
1300 | |||
1301 | |||
1302 | /** | ||
1303 | * Task that issues a warning if the datastore lookup takes too long. | ||
1304 | * | ||
1305 | * @param cls the `struct GSF_PendingRequest` | ||
1306 | */ | ||
1307 | static void | ||
1308 | warn_delay_task (void *cls) | ||
1309 | { | ||
1310 | struct GSF_PendingRequest *pr = cls; | ||
1311 | |||
1312 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, | ||
1313 | _ ("Datastore lookup already took %s!\n"), | ||
1314 | GNUNET_STRINGS_relative_time_to_string ( | ||
1315 | GNUNET_TIME_absolute_get_duration (pr->qe_start), | ||
1316 | GNUNET_YES)); | ||
1317 | pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
1318 | &warn_delay_task, | ||
1319 | pr); | ||
1320 | } | ||
1321 | |||
1322 | |||
1323 | /** | ||
1324 | * Task that issues a warning if the datastore lookup takes too long. | ||
1325 | * | ||
1326 | * @param cls the `struct GSF_PendingRequest` | ||
1327 | */ | ||
1328 | static void | ||
1329 | odc_warn_delay_task (void *cls) | ||
1330 | { | ||
1331 | struct GSF_PendingRequest *pr = cls; | ||
1332 | |||
1333 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1334 | _ ("On-demand lookup already took %s!\n"), | ||
1335 | GNUNET_STRINGS_relative_time_to_string ( | ||
1336 | GNUNET_TIME_absolute_get_duration (pr->qe_start), | ||
1337 | GNUNET_YES)); | ||
1338 | pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
1339 | &odc_warn_delay_task, | ||
1340 | pr); | ||
1341 | } | ||
1342 | |||
1343 | |||
1344 | /* Call our continuation (if we have any) */ | ||
1345 | static void | ||
1346 | call_continuation (struct GSF_PendingRequest *pr) | ||
1347 | { | ||
1348 | GSF_LocalLookupContinuation cont = pr->llc_cont; | ||
1349 | |||
1350 | GNUNET_assert (NULL == pr->qe); | ||
1351 | if (NULL != pr->warn_task) | ||
1352 | { | ||
1353 | GNUNET_SCHEDULER_cancel (pr->warn_task); | ||
1354 | pr->warn_task = NULL; | ||
1355 | } | ||
1356 | if (NULL == cont) | ||
1357 | return; /* no continuation */ | ||
1358 | pr->llc_cont = NULL; | ||
1359 | if (0 != (GSF_PRO_LOCAL_ONLY & pr->public_data.options)) | ||
1360 | { | ||
1361 | if (GNUNET_BLOCK_REPLY_OK_LAST != pr->local_result) | ||
1362 | { | ||
1363 | /* Signal that we are done and that there won't be any | ||
1364 | additional results to allow client to clean up state. */ | ||
1365 | pr->rh (pr->rh_cls, | ||
1366 | GNUNET_BLOCK_REPLY_OK_LAST, | ||
1367 | pr, | ||
1368 | UINT32_MAX, | ||
1369 | GNUNET_TIME_UNIT_ZERO_ABS, | ||
1370 | GNUNET_TIME_UNIT_FOREVER_ABS, | ||
1371 | GNUNET_BLOCK_TYPE_ANY, | ||
1372 | NULL, | ||
1373 | 0); | ||
1374 | } | ||
1375 | /* Finally, call our continuation to signal that we are | ||
1376 | done with local processing of this request; i.e. to | ||
1377 | start reading again from the client. */ | ||
1378 | cont (pr->llc_cont_cls, | ||
1379 | NULL, | ||
1380 | GNUNET_BLOCK_REPLY_OK_LAST); | ||
1381 | return; | ||
1382 | } | ||
1383 | |||
1384 | cont (pr->llc_cont_cls, | ||
1385 | pr, | ||
1386 | pr->local_result); | ||
1387 | } | ||
1388 | |||
1389 | |||
1390 | /* Update stats and call continuation */ | ||
1391 | static void | ||
1392 | no_more_local_results (struct GSF_PendingRequest *pr) | ||
1393 | { | ||
1394 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
1395 | "No further local responses available.\n"); | ||
1396 | #if INSANE_STATISTICS | ||
1397 | if ((GNUNET_BLOCK_TYPE_FS_DBLOCK == pr->public_data.type) || | ||
1398 | (GNUNET_BLOCK_TYPE_FS_IBLOCK == pr->public_data.type)) | ||
1399 | GNUNET_STATISTICS_update (GSF_stats, | ||
1400 | gettext_noop ( | ||
1401 | "# requested DBLOCK or IBLOCK not found"), | ||
1402 | 1, | ||
1403 | GNUNET_NO); | ||
1404 | #endif | ||
1405 | call_continuation (pr); | ||
1406 | } | ||
1407 | |||
1408 | |||
1409 | /* forward declaration */ | ||
1410 | static void | ||
1411 | process_local_reply (void *cls, | ||
1412 | const struct GNUNET_HashCode *key, | ||
1413 | size_t size, | ||
1414 | const void *data, | ||
1415 | enum GNUNET_BLOCK_Type type, | ||
1416 | uint32_t priority, | ||
1417 | uint32_t anonymity, | ||
1418 | uint32_t replication, | ||
1419 | struct GNUNET_TIME_Absolute expiration, | ||
1420 | uint64_t uid); | ||
1421 | |||
1422 | |||
1423 | /* Start a local query */ | ||
1424 | static void | ||
1425 | start_local_query (struct GSF_PendingRequest *pr, | ||
1426 | uint64_t next_uid, | ||
1427 | bool random) | ||
1428 | { | ||
1429 | pr->qe_start = GNUNET_TIME_absolute_get (); | ||
1430 | pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
1431 | &warn_delay_task, | ||
1432 | pr); | ||
1433 | pr->qe = GNUNET_DATASTORE_get_key (GSF_dsh, | ||
1434 | next_uid, | ||
1435 | random, | ||
1436 | &pr->public_data.query, | ||
1437 | pr->public_data.type == | ||
1438 | GNUNET_BLOCK_TYPE_FS_DBLOCK | ||
1439 | ? GNUNET_BLOCK_TYPE_ANY | ||
1440 | : pr->public_data.type, | ||
1441 | (0 != (GSF_PRO_PRIORITY_UNLIMITED | ||
1442 | & pr->public_data.options)) | ||
1443 | ? UINT_MAX | ||
1444 | : 1 | ||
1445 | /* queue priority */, | ||
1446 | (0 != (GSF_PRO_PRIORITY_UNLIMITED | ||
1447 | & pr->public_data.options)) | ||
1448 | ? UINT_MAX | ||
1449 | : GSF_datastore_queue_size | ||
1450 | /* max queue size */, | ||
1451 | &process_local_reply, | ||
1452 | pr); | ||
1453 | if (NULL != pr->qe) | ||
1454 | return; | ||
1455 | GNUNET_log ( | ||
1456 | GNUNET_ERROR_TYPE_DEBUG, | ||
1457 | "ERROR Requesting `%s' of type %d with next_uid %llu from datastore.\n", | ||
1458 | GNUNET_h2s (&pr->public_data.query), | ||
1459 | pr->public_data.type, | ||
1460 | (unsigned long long) next_uid); | ||
1461 | GNUNET_STATISTICS_update (GSF_stats, | ||
1462 | gettext_noop ( | ||
1463 | "# Datastore lookups concluded (error queueing)"), | ||
1464 | 1, | ||
1465 | GNUNET_NO); | ||
1466 | call_continuation (pr); | ||
1467 | } | ||
1468 | |||
1469 | |||
1470 | /** | ||
1471 | * We're processing (local) results for a search request | ||
1472 | * from another peer. Pass applicable results to the | ||
1473 | * peer and if we are done either clean up (operation | ||
1474 | * complete) or forward to other peers (more results possible). | ||
1475 | * | ||
1476 | * @param cls our closure (`struct GSF_PendingRequest *`) | ||
1477 | * @param key key for the content | ||
1478 | * @param size number of bytes in @a data | ||
1479 | * @param data content stored | ||
1480 | * @param type type of the content | ||
1481 | * @param priority priority of the content | ||
1482 | * @param anonymity anonymity-level for the content | ||
1483 | * @param replication replication-level for the content | ||
1484 | * @param expiration expiration time for the content | ||
1485 | * @param uid unique identifier for the datum; | ||
1486 | * maybe 0 if no unique identifier is available | ||
1487 | */ | ||
1488 | static void | ||
1489 | process_local_reply (void *cls, | ||
1490 | const struct GNUNET_HashCode *key, | ||
1491 | size_t size, | ||
1492 | const void *data, | ||
1493 | enum GNUNET_BLOCK_Type type, | ||
1494 | uint32_t priority, | ||
1495 | uint32_t anonymity, | ||
1496 | uint32_t replication, | ||
1497 | struct GNUNET_TIME_Absolute expiration, | ||
1498 | uint64_t uid) | ||
1499 | { | ||
1500 | struct GSF_PendingRequest *pr = cls; | ||
1501 | struct ProcessReplyClosure prq; | ||
1502 | struct GNUNET_HashCode query; | ||
1503 | unsigned int old_rf; | ||
1504 | |||
1505 | GNUNET_SCHEDULER_cancel (pr->warn_task); | ||
1506 | pr->warn_task = NULL; | ||
1507 | if (NULL == pr->qe) | ||
1508 | goto called_from_on_demand; | ||
1509 | pr->qe = NULL; | ||
1510 | if ( | ||
1511 | (NULL == key) && pr->seen_null && | ||
1512 | ! pr->have_first_uid) /* We have hit the end for the 2nd time with no results */ | ||
1513 | { | ||
1514 | /* No results */ | ||
1515 | #if INSANE_STATISTICS | ||
1516 | GNUNET_STATISTICS_update (GSF_stats, | ||
1517 | gettext_noop ( | ||
1518 | "# Datastore lookups concluded (no results)"), | ||
1519 | 1, | ||
1520 | GNUNET_NO); | ||
1521 | #endif | ||
1522 | no_more_local_results (pr); | ||
1523 | return; | ||
1524 | } | ||
1525 | if (((NULL == key) && | ||
1526 | pr->seen_null) || /* We have hit the end for the 2nd time OR */ | ||
1527 | (pr->seen_null && pr->have_first_uid && | ||
1528 | (uid >= pr->first_uid))) /* We have hit the end and past first UID */ | ||
1529 | { | ||
1530 | /* Seen all results */ | ||
1531 | GNUNET_STATISTICS_update (GSF_stats, | ||
1532 | gettext_noop ( | ||
1533 | "# Datastore lookups concluded (seen all)"), | ||
1534 | 1, | ||
1535 | GNUNET_NO); | ||
1536 | no_more_local_results (pr); | ||
1537 | return; | ||
1538 | } | ||
1539 | if (NULL == key) | ||
1540 | { | ||
1541 | GNUNET_assert (! pr->seen_null); | ||
1542 | pr->seen_null = true; | ||
1543 | start_local_query (pr, 0 /* next_uid */, false /* random */); | ||
1544 | return; | ||
1545 | } | ||
1546 | if (! pr->have_first_uid) | ||
1547 | { | ||
1548 | pr->first_uid = uid; | ||
1549 | pr->have_first_uid = true; | ||
1550 | } | ||
1551 | pr->result_count++; | ||
1552 | if (pr->result_count > MAX_RESULTS) | ||
1553 | { | ||
1554 | GNUNET_STATISTICS_update ( | ||
1555 | GSF_stats, | ||
1556 | gettext_noop ("# Datastore lookups aborted (more than MAX_RESULTS)"), | ||
1557 | 1, | ||
1558 | GNUNET_NO); | ||
1559 | no_more_local_results (pr); | ||
1560 | return; | ||
1561 | } | ||
1562 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1563 | "Received reply for `%s' of type %d with UID %llu from datastore.\n", | ||
1564 | GNUNET_h2s (key), | ||
1565 | type, | ||
1566 | (unsigned long long) uid); | ||
1567 | if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type) | ||
1568 | { | ||
1569 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1570 | "Found ONDEMAND block, performing on-demand encoding\n"); | ||
1571 | GNUNET_STATISTICS_update (GSF_stats, | ||
1572 | gettext_noop ( | ||
1573 | "# on-demand blocks matched requests"), | ||
1574 | 1, | ||
1575 | GNUNET_NO); | ||
1576 | pr->qe_start = GNUNET_TIME_absolute_get (); | ||
1577 | pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
1578 | &odc_warn_delay_task, | ||
1579 | pr); | ||
1580 | if (GNUNET_OK == GNUNET_FS_handle_on_demand_block (key, | ||
1581 | size, | ||
1582 | data, | ||
1583 | type, | ||
1584 | priority, | ||
1585 | anonymity, | ||
1586 | replication, | ||
1587 | expiration, | ||
1588 | uid, | ||
1589 | &process_local_reply, | ||
1590 | pr)) | ||
1591 | { | ||
1592 | GNUNET_STATISTICS_update (GSF_stats, | ||
1593 | gettext_noop ( | ||
1594 | "# on-demand lookups performed successfully"), | ||
1595 | 1, | ||
1596 | GNUNET_NO); | ||
1597 | return; /* we're done */ | ||
1598 | } | ||
1599 | GNUNET_STATISTICS_update (GSF_stats, | ||
1600 | gettext_noop ("# on-demand lookups failed"), | ||
1601 | 1, | ||
1602 | GNUNET_NO); | ||
1603 | GNUNET_SCHEDULER_cancel (pr->warn_task); | ||
1604 | start_local_query (pr, uid + 1 /* next_uid */, false /* random */); | ||
1605 | return; | ||
1606 | } | ||
1607 | called_from_on_demand: | ||
1608 | old_rf = pr->public_data.results_found; | ||
1609 | memset (&prq, 0, sizeof(prq)); | ||
1610 | prq.data = data; | ||
1611 | prq.expiration = expiration; | ||
1612 | prq.size = size; | ||
1613 | if (GNUNET_OK != | ||
1614 | GNUNET_BLOCK_get_key (GSF_block_ctx, type, data, size, &query)) | ||
1615 | { | ||
1616 | GNUNET_break (0); | ||
1617 | GNUNET_DATASTORE_remove (GSF_dsh, | ||
1618 | key, | ||
1619 | size, | ||
1620 | data, | ||
1621 | UINT_MAX, | ||
1622 | UINT_MAX, | ||
1623 | NULL, | ||
1624 | NULL); | ||
1625 | start_local_query (pr, uid + 1 /* next_uid */, false /* random */); | ||
1626 | return; | ||
1627 | } | ||
1628 | prq.type = type; | ||
1629 | prq.priority = priority; | ||
1630 | prq.request_found = GNUNET_NO; | ||
1631 | prq.anonymity_level = anonymity; | ||
1632 | if ((0 == old_rf) && (0 == pr->public_data.results_found)) | ||
1633 | GSF_update_datastore_delay_ (pr->public_data.start_time); | ||
1634 | prq.eo = GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO; | ||
1635 | process_reply (&prq, key, pr); | ||
1636 | pr->local_result = prq.eval; | ||
1637 | if (GNUNET_BLOCK_REPLY_OK_LAST == prq.eval) | ||
1638 | { | ||
1639 | GNUNET_STATISTICS_update ( | ||
1640 | GSF_stats, | ||
1641 | gettext_noop ("# Datastore lookups concluded (found last result)"), | ||
1642 | 1, | ||
1643 | GNUNET_NO); | ||
1644 | call_continuation (pr); | ||
1645 | return; | ||
1646 | } | ||
1647 | if ((0 == (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) && | ||
1648 | ((GNUNET_YES == GSF_test_get_load_too_high_ (0)) || | ||
1649 | (pr->public_data.results_found > 5 + 2 * pr->public_data.priority))) | ||
1650 | { | ||
1651 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load too high, done with request\n"); | ||
1652 | GNUNET_STATISTICS_update (GSF_stats, | ||
1653 | gettext_noop ( | ||
1654 | "# Datastore lookups concluded (load too high)"), | ||
1655 | 1, | ||
1656 | GNUNET_NO); | ||
1657 | call_continuation (pr); | ||
1658 | return; | ||
1659 | } | ||
1660 | start_local_query (pr, uid + 1 /* next_uid */, false /* random */); | ||
1661 | } | ||
1662 | |||
1663 | |||
1664 | /** | ||
1665 | * Is the given target a legitimate peer for forwarding the given request? | ||
1666 | * | ||
1667 | * @param pr request | ||
1668 | * @param target | ||
1669 | * @return #GNUNET_YES if this request could be forwarded to the given peer | ||
1670 | */ | ||
1671 | int | ||
1672 | GSF_pending_request_test_target_ (struct GSF_PendingRequest *pr, | ||
1673 | const struct GNUNET_PeerIdentity *target) | ||
1674 | { | ||
1675 | struct GNUNET_PeerIdentity pi; | ||
1676 | |||
1677 | if (0 == pr->origin_pid) | ||
1678 | return GNUNET_YES; | ||
1679 | GNUNET_PEER_resolve (pr->origin_pid, &pi); | ||
1680 | return (0 == memcmp (&pi, target, sizeof(struct GNUNET_PeerIdentity))) | ||
1681 | ? GNUNET_NO | ||
1682 | : GNUNET_YES; | ||
1683 | } | ||
1684 | |||
1685 | |||
1686 | /** | ||
1687 | * Look up the request in the local datastore. | ||
1688 | * | ||
1689 | * @param pr the pending request to process | ||
1690 | * @param cont function to call at the end | ||
1691 | * @param cont_cls closure for @a cont | ||
1692 | */ | ||
1693 | void | ||
1694 | GSF_local_lookup_ (struct GSF_PendingRequest *pr, | ||
1695 | GSF_LocalLookupContinuation cont, | ||
1696 | void *cont_cls) | ||
1697 | { | ||
1698 | GNUNET_assert (NULL == pr->gh); | ||
1699 | GNUNET_assert (NULL == pr->cadet_request); | ||
1700 | GNUNET_assert (NULL == pr->llc_cont); | ||
1701 | pr->llc_cont = cont; | ||
1702 | pr->llc_cont_cls = cont_cls; | ||
1703 | #if INSANE_STATISTICS | ||
1704 | GNUNET_STATISTICS_update (GSF_stats, | ||
1705 | gettext_noop ("# Datastore lookups initiated"), | ||
1706 | 1, | ||
1707 | GNUNET_NO); | ||
1708 | #endif | ||
1709 | start_local_query (pr, 0 /* next_uid */, true /* random */); | ||
1710 | } | ||
1711 | |||
1712 | |||
1713 | /** | ||
1714 | * Handle P2P "CONTENT" message. Checks that the message is | ||
1715 | * well-formed and then checks if there are any pending requests for | ||
1716 | * this content and possibly passes it on (to local clients or other | ||
1717 | * peers). Does NOT perform migration (content caching at this peer). | ||
1718 | * | ||
1719 | * @param cls the other peer involved | ||
1720 | * @param put the actual message | ||
1721 | */ | ||
1722 | void | ||
1723 | handle_p2p_put (void *cls, const struct PutMessage *put) | ||
1724 | { | ||
1725 | struct GSF_ConnectedPeer *cp = cls; | ||
1726 | uint16_t msize; | ||
1727 | size_t dsize; | ||
1728 | enum GNUNET_BLOCK_Type type; | ||
1729 | struct GNUNET_TIME_Absolute expiration; | ||
1730 | struct GNUNET_HashCode query; | ||
1731 | struct ProcessReplyClosure prq; | ||
1732 | struct GNUNET_TIME_Relative block_time; | ||
1733 | double putl; | ||
1734 | struct PutMigrationContext *pmc; | ||
1735 | |||
1736 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1737 | "Received P2P PUT from %s\n", | ||
1738 | GNUNET_i2s (GSF_get_peer_performance_data_ (cp)->peer)); | ||
1739 | GSF_cover_content_count++; | ||
1740 | msize = ntohs (put->header.size); | ||
1741 | dsize = msize - sizeof(struct PutMessage); | ||
1742 | type = ntohl (put->type); | ||
1743 | expiration = GNUNET_TIME_absolute_ntoh (put->expiration); | ||
1744 | /* do not allow migrated content to live longer than 1 year */ | ||
1745 | expiration = GNUNET_TIME_absolute_min (GNUNET_TIME_relative_to_absolute ( | ||
1746 | GNUNET_TIME_UNIT_YEARS), | ||
1747 | expiration); | ||
1748 | if (GNUNET_OK != | ||
1749 | GNUNET_BLOCK_get_key (GSF_block_ctx, type, &put[1], dsize, &query)) | ||
1750 | { | ||
1751 | GNUNET_break_op (0); | ||
1752 | return; | ||
1753 | } | ||
1754 | GNUNET_STATISTICS_update (GSF_stats, | ||
1755 | gettext_noop ("# GAP PUT messages received"), | ||
1756 | 1, | ||
1757 | GNUNET_NO); | ||
1758 | /* now, lookup 'query' */ | ||
1759 | prq.data = (const void *) &put[1]; | ||
1760 | prq.sender = cp; | ||
1761 | prq.size = dsize; | ||
1762 | prq.type = type; | ||
1763 | prq.expiration = expiration; | ||
1764 | prq.priority = 0; | ||
1765 | prq.anonymity_level = UINT32_MAX; | ||
1766 | prq.request_found = GNUNET_NO; | ||
1767 | prq.eo = GNUNET_BLOCK_EO_NONE; | ||
1768 | GNUNET_CONTAINER_multihashmap_get_multiple (pr_map, | ||
1769 | &query, | ||
1770 | &process_reply, | ||
1771 | &prq); | ||
1772 | if (NULL != cp) | ||
1773 | { | ||
1774 | GSF_connected_peer_change_preference_ (cp, | ||
1775 | CONTENT_BANDWIDTH_VALUE | ||
1776 | + 1000 * prq.priority); | ||
1777 | GSF_get_peer_performance_data_ (cp)->respect += prq.priority; | ||
1778 | } | ||
1779 | if ((GNUNET_YES == active_to_migration) && (NULL != cp) && | ||
1780 | (GNUNET_NO == test_put_load_too_high (prq.priority))) | ||
1781 | { | ||
1782 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1783 | "Replicating result for query `%s' with priority %u\n", | ||
1784 | GNUNET_h2s (&query), | ||
1785 | prq.priority); | ||
1786 | pmc = GNUNET_new (struct PutMigrationContext); | ||
1787 | pmc->start = GNUNET_TIME_absolute_get (); | ||
1788 | pmc->requested = prq.request_found; | ||
1789 | GNUNET_assert (0 != GSF_get_peer_performance_data_ (cp)->pid); | ||
1790 | GNUNET_PEER_resolve (GSF_get_peer_performance_data_ (cp)->pid, | ||
1791 | &pmc->origin); | ||
1792 | if (NULL == GNUNET_DATASTORE_put (GSF_dsh, | ||
1793 | 0, | ||
1794 | &query, | ||
1795 | dsize, | ||
1796 | &put[1], | ||
1797 | type, | ||
1798 | prq.priority, | ||
1799 | 1 /* anonymity */, | ||
1800 | 0 /* replication */, | ||
1801 | expiration, | ||
1802 | 1 + prq.priority, | ||
1803 | MAX_DATASTORE_QUEUE, | ||
1804 | &put_migration_continuation, | ||
1805 | pmc)) | ||
1806 | { | ||
1807 | put_migration_continuation (pmc, | ||
1808 | GNUNET_SYSERR, | ||
1809 | GNUNET_TIME_UNIT_ZERO_ABS, | ||
1810 | NULL); | ||
1811 | } | ||
1812 | } | ||
1813 | else if (NULL != cp) | ||
1814 | { | ||
1815 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1816 | "Choosing not to keep content `%s' (%d/%d)\n", | ||
1817 | GNUNET_h2s (&query), | ||
1818 | active_to_migration, | ||
1819 | test_put_load_too_high (prq.priority)); | ||
1820 | } | ||
1821 | putl = GNUNET_LOAD_get_load (datastore_put_load); | ||
1822 | if ((NULL != cp) && (GNUNET_NO == prq.request_found) && | ||
1823 | ((GNUNET_YES != active_to_migration) || | ||
1824 | (putl > 2.5 * (1 + prq.priority)))) | ||
1825 | { | ||
1826 | if (GNUNET_YES != active_to_migration) | ||
1827 | putl = 1.0 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 5); | ||
1828 | block_time = GNUNET_TIME_relative_multiply ( | ||
1829 | GNUNET_TIME_UNIT_MILLISECONDS, | ||
1830 | 5000 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1831 | (unsigned int) (60000 * putl * putl))); | ||
1832 | GNUNET_log ( | ||
1833 | GNUNET_ERROR_TYPE_DEBUG, | ||
1834 | "Asking to stop migration for %s because of load %f and events %d/%d\n", | ||
1835 | GNUNET_STRINGS_relative_time_to_string (block_time, GNUNET_YES), | ||
1836 | putl, | ||
1837 | active_to_migration, | ||
1838 | (GNUNET_NO == prq.request_found)); | ||
1839 | GSF_block_peer_migration_ (cp, | ||
1840 | GNUNET_TIME_relative_to_absolute (block_time)); | ||
1841 | } | ||
1842 | } | ||
1843 | |||
1844 | |||
1845 | /** | ||
1846 | * Check if the given request is still active. | ||
1847 | * | ||
1848 | * @param pr pending request | ||
1849 | * @return #GNUNET_YES if the request is still active | ||
1850 | */ | ||
1851 | int | ||
1852 | GSF_pending_request_test_active_ (struct GSF_PendingRequest *pr) | ||
1853 | { | ||
1854 | return (NULL != pr->rh) ? GNUNET_YES : GNUNET_NO; | ||
1855 | } | ||
1856 | |||
1857 | |||
1858 | /** | ||
1859 | * Setup the subsystem. | ||
1860 | */ | ||
1861 | void | ||
1862 | GSF_pending_request_init_ () | ||
1863 | { | ||
1864 | if (GNUNET_OK != | ||
1865 | GNUNET_CONFIGURATION_get_value_number (GSF_cfg, | ||
1866 | "fs", | ||
1867 | "MAX_PENDING_REQUESTS", | ||
1868 | &max_pending_requests)) | ||
1869 | { | ||
1870 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO, | ||
1871 | "fs", | ||
1872 | "MAX_PENDING_REQUESTS"); | ||
1873 | } | ||
1874 | active_to_migration = | ||
1875 | GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg, "FS", "CONTENT_CACHING"); | ||
1876 | datastore_put_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE); | ||
1877 | pr_map = GNUNET_CONTAINER_multihashmap_create (32 * 1024, GNUNET_YES); | ||
1878 | requests_by_expiration_heap = | ||
1879 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1880 | } | ||
1881 | |||
1882 | |||
1883 | /** | ||
1884 | * Shutdown the subsystem. | ||
1885 | */ | ||
1886 | void | ||
1887 | GSF_pending_request_done_ () | ||
1888 | { | ||
1889 | GNUNET_CONTAINER_multihashmap_iterate (pr_map, &clean_request, NULL); | ||
1890 | GNUNET_CONTAINER_multihashmap_destroy (pr_map); | ||
1891 | pr_map = NULL; | ||
1892 | GNUNET_CONTAINER_heap_destroy (requests_by_expiration_heap); | ||
1893 | requests_by_expiration_heap = NULL; | ||
1894 | GNUNET_LOAD_value_free (datastore_put_load); | ||
1895 | datastore_put_load = NULL; | ||
1896 | } | ||
1897 | |||
1898 | |||
1899 | /* end of gnunet-service-fs_pr.c */ | ||
diff --git a/src/fs/gnunet-service-fs_pr.h b/src/fs/gnunet-service-fs_pr.h deleted file mode 100644 index a10fb9b4c..000000000 --- a/src/fs/gnunet-service-fs_pr.h +++ /dev/null | |||
@@ -1,424 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_pr.h | ||
23 | * @brief API to handle pending requests | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_FS_PR_H | ||
27 | #define GNUNET_SERVICE_FS_PR_H | ||
28 | |||
29 | #include "gnunet-service-fs.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Options for pending requests (bits to be ORed). | ||
34 | */ | ||
35 | enum GSF_PendingRequestOptions | ||
36 | { | ||
37 | /** | ||
38 | * No special options (P2P-default). | ||
39 | */ | ||
40 | GSF_PRO_DEFAULTS = 0, | ||
41 | |||
42 | /** | ||
43 | * Request must only be processed locally. | ||
44 | */ | ||
45 | GSF_PRO_LOCAL_ONLY = 1, | ||
46 | |||
47 | /** | ||
48 | * Request must only be forwarded (no routing) | ||
49 | */ | ||
50 | GSF_PRO_FORWARD_ONLY = 2, | ||
51 | |||
52 | /** | ||
53 | * Request persists indefinitely (no expiration). | ||
54 | */ | ||
55 | GSF_PRO_REQUEST_NEVER_EXPIRES = 4, | ||
56 | |||
57 | /** | ||
58 | * Request is allowed to refresh bloomfilter and change mingle value. | ||
59 | */ | ||
60 | GSF_PRO_BLOOMFILTER_FULL_REFRESH = 8, | ||
61 | |||
62 | /** | ||
63 | * Request priority is allowed to be exceeded. | ||
64 | */ | ||
65 | GSF_PRO_PRIORITY_UNLIMITED = 16, | ||
66 | |||
67 | /** | ||
68 | * Option mask for typical local requests. | ||
69 | */ | ||
70 | GSF_PRO_LOCAL_REQUEST = | ||
71 | (GSF_PRO_BLOOMFILTER_FULL_REFRESH | GSF_PRO_PRIORITY_UNLIMITED | ||
72 | | GSF_PRO_REQUEST_NEVER_EXPIRES) | ||
73 | }; | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Public data (in the sense of not encapsulated within | ||
78 | * 'gnunet-service-fs_pr', not in the sense of network-wide | ||
79 | * known) associated with each pending request. | ||
80 | */ | ||
81 | struct GSF_PendingRequestData | ||
82 | { | ||
83 | /** | ||
84 | * Primary query hash for this request. | ||
85 | */ | ||
86 | struct GNUNET_HashCode query; | ||
87 | |||
88 | /** | ||
89 | * Identity of a peer hosting the content, otherwise NULl. | ||
90 | * Allocated after struct only if needed. Do not free! | ||
91 | */ | ||
92 | const struct GNUNET_PeerIdentity *target; | ||
93 | |||
94 | /** | ||
95 | * Fields for the plan module to track a DLL with the request. | ||
96 | */ | ||
97 | struct GSF_PendingRequestPlanBijection *pr_head; | ||
98 | |||
99 | /** | ||
100 | * Fields for the plan module to track a DLL with the request. | ||
101 | */ | ||
102 | struct GSF_PendingRequestPlanBijection *pr_tail; | ||
103 | |||
104 | /** | ||
105 | * Current TTL for the request. | ||
106 | */ | ||
107 | struct GNUNET_TIME_Absolute ttl; | ||
108 | |||
109 | /** | ||
110 | * When did we start with the request. | ||
111 | */ | ||
112 | struct GNUNET_TIME_Absolute start_time; | ||
113 | |||
114 | /** | ||
115 | * Desired anonymity level. | ||
116 | */ | ||
117 | uint32_t anonymity_level; | ||
118 | |||
119 | /** | ||
120 | * Priority that this request (still) has for us. | ||
121 | */ | ||
122 | uint32_t priority; | ||
123 | |||
124 | /** | ||
125 | * Priority that this request (originally) had for us. | ||
126 | */ | ||
127 | uint32_t original_priority; | ||
128 | |||
129 | /** | ||
130 | * Counter for how often this request has been transmitted (estimate, | ||
131 | * because we might have the same request pending for multiple clients, | ||
132 | * and of course because a transmission may have failed at a lower | ||
133 | * layer). | ||
134 | */ | ||
135 | uint32_t num_transmissions; | ||
136 | |||
137 | /** | ||
138 | * How much respect did we (in total) offer for this request so far (estimate, | ||
139 | * because we might have the same request pending for multiple clients, | ||
140 | * and of course because a transmission may have failed at a lower | ||
141 | * layer). | ||
142 | */ | ||
143 | uint32_t respect_offered; | ||
144 | |||
145 | /** | ||
146 | * Options for the request. | ||
147 | */ | ||
148 | enum GSF_PendingRequestOptions options; | ||
149 | |||
150 | /** | ||
151 | * Type of the requested block. | ||
152 | */ | ||
153 | enum GNUNET_BLOCK_Type type; | ||
154 | |||
155 | /** | ||
156 | * Number of results we have found for this request so far. | ||
157 | */ | ||
158 | unsigned int results_found; | ||
159 | |||
160 | /** | ||
161 | * Has this request been started yet (local/p2p operations)? Or are | ||
162 | * we still constructing it? | ||
163 | */ | ||
164 | int has_started; | ||
165 | }; | ||
166 | |||
167 | |||
168 | /** | ||
169 | * Handle a reply to a pending request. Also called if a request | ||
170 | * expires (then with data == NULL). The handler may be called | ||
171 | * many times (depending on the request type), but will not be | ||
172 | * called during or after a call to GSF_pending_request_cancel | ||
173 | * and will also not be called anymore after a call signalling | ||
174 | * expiration. | ||
175 | * | ||
176 | * @param cls user-specified closure | ||
177 | * @param eval evaluation of the result | ||
178 | * @param pr handle to the original pending request | ||
179 | * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" | ||
180 | * @param expiration when does @a data expire? | ||
181 | * @param last_transmission the last time we've tried to get this block (FOREVER if unknown) | ||
182 | * @param type type of the block | ||
183 | * @param data response data, NULL on request expiration | ||
184 | * @param data_len number of bytes in @a data | ||
185 | */ | ||
186 | typedef void | ||
187 | (*GSF_PendingRequestReplyHandler) ( | ||
188 | void *cls, | ||
189 | enum GNUNET_BLOCK_ReplyEvaluationResult eval, | ||
190 | struct GSF_PendingRequest *pr, | ||
191 | uint32_t reply_anonymity_level, | ||
192 | struct GNUNET_TIME_Absolute expiration, | ||
193 | struct GNUNET_TIME_Absolute | ||
194 | last_transmission, | ||
195 | enum GNUNET_BLOCK_Type type, | ||
196 | const void *data, | ||
197 | size_t data_len); | ||
198 | |||
199 | |||
200 | /** | ||
201 | * Create a new pending request. | ||
202 | * | ||
203 | * @param options request options | ||
204 | * @param type type of the block that is being requested | ||
205 | * @param query key for the lookup | ||
206 | * @param target preferred target for the request, NULL for none | ||
207 | * @param bf_data raw data for bloom filter for known replies, can be NULL | ||
208 | * @param bf_size number of bytes in bf_data | ||
209 | * @param mingle mingle value for bf | ||
210 | * @param anonymity_level desired anonymity level | ||
211 | * @param priority maximum outgoing cumulative request priority to use | ||
212 | * @param ttl current time-to-live for the request | ||
213 | * @param sender_pid peer ID to use for the sender when forwarding, 0 for none; | ||
214 | * reference counter is taken over by this function | ||
215 | * @param origin_pid peer ID of origin of query (do not loop back) | ||
216 | * @param replies_seen hash codes of known local replies | ||
217 | * @param replies_seen_count size of the 'replies_seen' array | ||
218 | * @param rh handle to call when we get a reply | ||
219 | * @param rh_cls closure for rh | ||
220 | * @return handle for the new pending request | ||
221 | */ | ||
222 | struct GSF_PendingRequest * | ||
223 | GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, | ||
224 | enum GNUNET_BLOCK_Type type, | ||
225 | const struct GNUNET_HashCode *query, | ||
226 | const struct GNUNET_PeerIdentity *target, | ||
227 | const char *bf_data, | ||
228 | size_t bf_size, | ||
229 | uint32_t mingle, | ||
230 | uint32_t anonymity_level, | ||
231 | uint32_t priority, | ||
232 | int32_t ttl, | ||
233 | GNUNET_PEER_Id sender_pid, | ||
234 | GNUNET_PEER_Id origin_pid, | ||
235 | const struct GNUNET_HashCode *replies_seen, | ||
236 | unsigned int replies_seen_count, | ||
237 | GSF_PendingRequestReplyHandler rh, | ||
238 | void *rh_cls); | ||
239 | |||
240 | |||
241 | /** | ||
242 | * Update a given pending request with additional replies | ||
243 | * that have been seen. | ||
244 | * | ||
245 | * @param pr request to update | ||
246 | * @param replies_seen hash codes of replies that we've seen | ||
247 | * @param replies_seen_count size of the @a replies_seen array | ||
248 | */ | ||
249 | void | ||
250 | GSF_pending_request_update_ (struct GSF_PendingRequest *pr, | ||
251 | const struct GNUNET_HashCode *replies_seen, | ||
252 | unsigned int replies_seen_count); | ||
253 | |||
254 | |||
255 | /** | ||
256 | * Obtain the public data associated with a pending request | ||
257 | * | ||
258 | * @param pr pending request | ||
259 | * @return associated public data | ||
260 | */ | ||
261 | struct GSF_PendingRequestData * | ||
262 | GSF_pending_request_get_data_ (struct GSF_PendingRequest *pr); | ||
263 | |||
264 | |||
265 | /** | ||
266 | * Check if the given request is still active. | ||
267 | * | ||
268 | * @param pr pending request | ||
269 | * @return #GNUNET_YES if the request is still active | ||
270 | */ | ||
271 | int | ||
272 | GSF_pending_request_test_active_ (struct GSF_PendingRequest *pr); | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Test if two pending requests are compatible (would generate | ||
277 | * the same query modulo filters and should thus be processed | ||
278 | * jointly). | ||
279 | * | ||
280 | * @param pra a pending request | ||
281 | * @param prb another pending request | ||
282 | * @return #GNUNET_OK if the requests are compatible | ||
283 | */ | ||
284 | int | ||
285 | GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, | ||
286 | struct GSF_PendingRequest *prb); | ||
287 | |||
288 | |||
289 | /** | ||
290 | * Generate the message corresponding to the given pending request for | ||
291 | * transmission to other peers. | ||
292 | * | ||
293 | * @param pr request to generate the message for | ||
294 | * @return envelope with the request message | ||
295 | */ | ||
296 | struct GNUNET_MQ_Envelope * | ||
297 | GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr); | ||
298 | |||
299 | |||
300 | /** | ||
301 | * Explicitly cancel a pending request. | ||
302 | * | ||
303 | * @param pr request to cancel | ||
304 | * @param full_cleanup fully purge the request | ||
305 | */ | ||
306 | void | ||
307 | GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, | ||
308 | int full_cleanup); | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Signature of function called on each request. | ||
313 | * (Note: 'subtype' of GNUNET_CONTAINER_HashMapIterator). | ||
314 | * | ||
315 | * @param cls closure | ||
316 | * @param key query for the request | ||
317 | * @param pr handle to the pending request | ||
318 | * @return #GNUNET_YES to continue to iterate | ||
319 | */ | ||
320 | typedef int | ||
321 | (*GSF_PendingRequestIterator) (void *cls, | ||
322 | const struct GNUNET_HashCode *key, | ||
323 | struct GSF_PendingRequest *pr); | ||
324 | |||
325 | |||
326 | /** | ||
327 | * Iterate over all pending requests. | ||
328 | * | ||
329 | * @param it function to call for each request | ||
330 | * @param cls closure for it | ||
331 | */ | ||
332 | void | ||
333 | GSF_iterate_pending_requests_ (GSF_PendingRequestIterator it, | ||
334 | void *cls); | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Handle P2P "CONTENT" message. Checks that the message is | ||
339 | * well-formed and then checks if there are any pending requests for | ||
340 | * this content and possibly passes it on (to local clients or other | ||
341 | * peers). Does NOT perform migration (content caching at this peer). | ||
342 | * | ||
343 | * @param cls the other peer involved (sender) | ||
344 | * @param put the actual message | ||
345 | */ | ||
346 | void | ||
347 | handle_p2p_put (void *cls, | ||
348 | const struct PutMessage *put); | ||
349 | |||
350 | |||
351 | /** | ||
352 | * Consider looking up the data in the DHT (anonymity-level permitting). | ||
353 | * | ||
354 | * @param pr the pending request to process | ||
355 | */ | ||
356 | void | ||
357 | GSF_dht_lookup_ (struct GSF_PendingRequest *pr); | ||
358 | |||
359 | |||
360 | /** | ||
361 | * Consider downloading via cadet (if possible) | ||
362 | * | ||
363 | * @param pr the pending request to process | ||
364 | */ | ||
365 | void | ||
366 | GSF_cadet_lookup_ (struct GSF_PendingRequest *pr); | ||
367 | |||
368 | |||
369 | /** | ||
370 | * Function to be called after we're done processing | ||
371 | * replies from the local lookup. | ||
372 | * | ||
373 | * @param cls closure | ||
374 | * @param pr the pending request we were processing | ||
375 | * @param result final datastore lookup result | ||
376 | */ | ||
377 | typedef void | ||
378 | (*GSF_LocalLookupContinuation) ( | ||
379 | void *cls, | ||
380 | struct GSF_PendingRequest *pr, | ||
381 | enum GNUNET_BLOCK_ReplyEvaluationResult result); | ||
382 | |||
383 | |||
384 | /** | ||
385 | * Look up the request in the local datastore. | ||
386 | * | ||
387 | * @param pr the pending request to process | ||
388 | * @param cont function to call at the end | ||
389 | * @param cont_cls closure for @a cont | ||
390 | */ | ||
391 | void | ||
392 | GSF_local_lookup_ (struct GSF_PendingRequest *pr, | ||
393 | GSF_LocalLookupContinuation cont, | ||
394 | void *cont_cls); | ||
395 | |||
396 | |||
397 | /** | ||
398 | * Is the given target a legitimate peer for forwarding the given request? | ||
399 | * | ||
400 | * @param pr request | ||
401 | * @param target | ||
402 | * @return #GNUNET_YES if this request could be forwarded to the given peer | ||
403 | */ | ||
404 | int | ||
405 | GSF_pending_request_test_target_ (struct GSF_PendingRequest *pr, | ||
406 | const struct GNUNET_PeerIdentity *target); | ||
407 | |||
408 | |||
409 | /** | ||
410 | * Setup the subsystem. | ||
411 | */ | ||
412 | void | ||
413 | GSF_pending_request_init_ (void); | ||
414 | |||
415 | |||
416 | /** | ||
417 | * Shutdown the subsystem. | ||
418 | */ | ||
419 | void | ||
420 | GSF_pending_request_done_ (void); | ||
421 | |||
422 | |||
423 | #endif | ||
424 | /* end of gnunet-service-fs_pr.h */ | ||
diff --git a/src/fs/gnunet-service-fs_push.c b/src/fs/gnunet-service-fs_push.c deleted file mode 100644 index 1825e8eb3..000000000 --- a/src/fs/gnunet-service-fs_push.c +++ /dev/null | |||
@@ -1,677 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_push.c | ||
23 | * @brief API to push content from our datastore to other peers | ||
24 | * ('anonymous'-content P2P migration) | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet-service-fs.h" | ||
29 | #include "gnunet-service-fs_cp.h" | ||
30 | #include "gnunet-service-fs_indexing.h" | ||
31 | #include "gnunet-service-fs_push.h" | ||
32 | |||
33 | |||
34 | /** | ||
35 | * Maximum number of blocks we keep in memory for migration. | ||
36 | */ | ||
37 | #define MAX_MIGRATION_QUEUE 8 | ||
38 | |||
39 | /** | ||
40 | * Blocks are at most migrated to this number of peers | ||
41 | * plus one, each time they are fetched from the database. | ||
42 | */ | ||
43 | #define MIGRATION_LIST_SIZE 2 | ||
44 | |||
45 | /** | ||
46 | * How long must content remain valid for us to consider it for migration? | ||
47 | * If content will expire too soon, there is clearly no point in pushing | ||
48 | * it to other peers. This value gives the threshold for migration. Note | ||
49 | * that if this value is increased, the migration testcase may need to be | ||
50 | * adjusted as well (especially the CONTENT_LIFETIME in fs_test_lib.c). | ||
51 | */ | ||
52 | #define MIN_MIGRATION_CONTENT_LIFETIME GNUNET_TIME_relative_multiply ( \ | ||
53 | GNUNET_TIME_UNIT_MINUTES, 30) | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Block that is ready for migration to other peers. Actual data is at the end of the block. | ||
58 | */ | ||
59 | struct MigrationReadyBlock | ||
60 | { | ||
61 | /** | ||
62 | * This is a doubly-linked list. | ||
63 | */ | ||
64 | struct MigrationReadyBlock *next; | ||
65 | |||
66 | /** | ||
67 | * This is a doubly-linked list. | ||
68 | */ | ||
69 | struct MigrationReadyBlock *prev; | ||
70 | |||
71 | /** | ||
72 | * Query for the block. | ||
73 | */ | ||
74 | struct GNUNET_HashCode query; | ||
75 | |||
76 | /** | ||
77 | * When does this block expire? | ||
78 | */ | ||
79 | struct GNUNET_TIME_Absolute expiration; | ||
80 | |||
81 | /** | ||
82 | * Peers we already forwarded this | ||
83 | * block to. Zero for empty entries. | ||
84 | */ | ||
85 | GNUNET_PEER_Id target_list[MIGRATION_LIST_SIZE]; | ||
86 | |||
87 | /** | ||
88 | * Size of the block. | ||
89 | */ | ||
90 | size_t size; | ||
91 | |||
92 | /** | ||
93 | * Number of targets already used. | ||
94 | */ | ||
95 | unsigned int used_targets; | ||
96 | |||
97 | /** | ||
98 | * Type of the block. | ||
99 | */ | ||
100 | enum GNUNET_BLOCK_Type type; | ||
101 | }; | ||
102 | |||
103 | |||
104 | /** | ||
105 | * Information about a peer waiting for migratable data. | ||
106 | */ | ||
107 | struct MigrationReadyPeer | ||
108 | { | ||
109 | /** | ||
110 | * This is a doubly-linked list. | ||
111 | */ | ||
112 | struct MigrationReadyPeer *next; | ||
113 | |||
114 | /** | ||
115 | * This is a doubly-linked list. | ||
116 | */ | ||
117 | struct MigrationReadyPeer *prev; | ||
118 | |||
119 | /** | ||
120 | * Handle to peer. | ||
121 | */ | ||
122 | struct GSF_ConnectedPeer *peer; | ||
123 | |||
124 | /** | ||
125 | * Envelope of the currently pushed message. | ||
126 | */ | ||
127 | struct GNUNET_MQ_Envelope *env; | ||
128 | }; | ||
129 | |||
130 | |||
131 | /** | ||
132 | * Head of linked list of blocks that can be migrated. | ||
133 | */ | ||
134 | static struct MigrationReadyBlock *mig_head; | ||
135 | |||
136 | /** | ||
137 | * Tail of linked list of blocks that can be migrated. | ||
138 | */ | ||
139 | static struct MigrationReadyBlock *mig_tail; | ||
140 | |||
141 | /** | ||
142 | * Head of linked list of peers. | ||
143 | */ | ||
144 | static struct MigrationReadyPeer *peer_head; | ||
145 | |||
146 | /** | ||
147 | * Tail of linked list of peers. | ||
148 | */ | ||
149 | static struct MigrationReadyPeer *peer_tail; | ||
150 | |||
151 | /** | ||
152 | * Request to datastore for migration (or NULL). | ||
153 | */ | ||
154 | static struct GNUNET_DATASTORE_QueueEntry *mig_qe; | ||
155 | |||
156 | /** | ||
157 | * ID of task that collects blocks for migration. | ||
158 | */ | ||
159 | static struct GNUNET_SCHEDULER_Task *mig_task; | ||
160 | |||
161 | /** | ||
162 | * What is the maximum frequency at which we are allowed to | ||
163 | * poll the datastore for migration content? | ||
164 | */ | ||
165 | static struct GNUNET_TIME_Relative min_migration_delay; | ||
166 | |||
167 | /** | ||
168 | * Size of the doubly-linked list of migration blocks. | ||
169 | */ | ||
170 | static unsigned int mig_size; | ||
171 | |||
172 | /** | ||
173 | * Is this module enabled? | ||
174 | */ | ||
175 | static int enabled; | ||
176 | |||
177 | /** | ||
178 | * Did we find anything in the datastore? | ||
179 | */ | ||
180 | static int value_found; | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Delete the given migration block. | ||
185 | * | ||
186 | * @param mb block to delete | ||
187 | */ | ||
188 | static void | ||
189 | delete_migration_block (struct MigrationReadyBlock *mb) | ||
190 | { | ||
191 | GNUNET_CONTAINER_DLL_remove (mig_head, | ||
192 | mig_tail, | ||
193 | mb); | ||
194 | GNUNET_PEER_decrement_rcs (mb->target_list, | ||
195 | MIGRATION_LIST_SIZE); | ||
196 | mig_size--; | ||
197 | GNUNET_free (mb); | ||
198 | } | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Find content for migration to this peer. | ||
203 | * | ||
204 | * @param cls a `struct MigrationReadyPeer *` | ||
205 | */ | ||
206 | static void | ||
207 | find_content (void *cls); | ||
208 | |||
209 | |||
210 | /** | ||
211 | * Send the given block to the given peer. | ||
212 | * | ||
213 | * @param peer target peer | ||
214 | * @param block the block | ||
215 | * @return #GNUNET_YES if the block was deleted (!) | ||
216 | */ | ||
217 | static int | ||
218 | transmit_content (struct MigrationReadyPeer *mrp, | ||
219 | struct MigrationReadyBlock *block) | ||
220 | { | ||
221 | struct PutMessage *msg; | ||
222 | unsigned int i; | ||
223 | struct GSF_PeerPerformanceData *ppd; | ||
224 | int ret; | ||
225 | |||
226 | ppd = GSF_get_peer_performance_data_ (mrp->peer); | ||
227 | GNUNET_assert (NULL == mrp->env); | ||
228 | mrp->env = GNUNET_MQ_msg_extra (msg, | ||
229 | block->size, | ||
230 | GNUNET_MESSAGE_TYPE_FS_PUT); | ||
231 | msg->type = htonl (block->type); | ||
232 | msg->expiration = GNUNET_TIME_absolute_hton (block->expiration); | ||
233 | GNUNET_memcpy (&msg[1], | ||
234 | &block[1], | ||
235 | block->size); | ||
236 | for (i = 0; i < MIGRATION_LIST_SIZE; i++) | ||
237 | { | ||
238 | if (block->target_list[i] == 0) | ||
239 | { | ||
240 | block->target_list[i] = ppd->pid; | ||
241 | GNUNET_PEER_change_rc (block->target_list[i], | ||
242 | 1); | ||
243 | break; | ||
244 | } | ||
245 | } | ||
246 | if (MIGRATION_LIST_SIZE == i) | ||
247 | { | ||
248 | delete_migration_block (block); | ||
249 | ret = GNUNET_YES; | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | ret = GNUNET_NO; | ||
254 | } | ||
255 | GNUNET_MQ_notify_sent (mrp->env, | ||
256 | &find_content, | ||
257 | mrp); | ||
258 | GSF_peer_transmit_ (mrp->peer, | ||
259 | GNUNET_NO, | ||
260 | 0 /* priority */, | ||
261 | mrp->env); | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | |||
266 | /** | ||
267 | * Count the number of peers this block has | ||
268 | * already been forwarded to. | ||
269 | * | ||
270 | * @param block the block | ||
271 | * @return number of times block was forwarded | ||
272 | */ | ||
273 | static unsigned int | ||
274 | count_targets (struct MigrationReadyBlock *block) | ||
275 | { | ||
276 | unsigned int i; | ||
277 | |||
278 | for (i = 0; i < MIGRATION_LIST_SIZE; i++) | ||
279 | if (block->target_list[i] == 0) | ||
280 | return i; | ||
281 | return i; | ||
282 | } | ||
283 | |||
284 | |||
285 | /** | ||
286 | * Check if sending this block to this peer would | ||
287 | * be a good idea. | ||
288 | * | ||
289 | * @param mrp target peer | ||
290 | * @param block the block | ||
291 | * @return score (>= 0: feasible, negative: infeasible) | ||
292 | */ | ||
293 | static long | ||
294 | score_content (struct MigrationReadyPeer *mrp, | ||
295 | struct MigrationReadyBlock *block) | ||
296 | { | ||
297 | unsigned int i; | ||
298 | struct GSF_PeerPerformanceData *ppd; | ||
299 | struct GNUNET_PeerIdentity id; | ||
300 | struct GNUNET_HashCode hc; | ||
301 | uint32_t dist; | ||
302 | |||
303 | ppd = GSF_get_peer_performance_data_ (mrp->peer); | ||
304 | for (i = 0; i < MIGRATION_LIST_SIZE; i++) | ||
305 | if (block->target_list[i] == ppd->pid) | ||
306 | return -1; | ||
307 | GNUNET_assert (0 != ppd->pid); | ||
308 | GNUNET_PEER_resolve (ppd->pid, | ||
309 | &id); | ||
310 | GNUNET_CRYPTO_hash (&id, | ||
311 | sizeof(struct GNUNET_PeerIdentity), | ||
312 | &hc); | ||
313 | dist = GNUNET_CRYPTO_hash_distance_u32 (&block->query, | ||
314 | &hc); | ||
315 | /* closer distance, higher score: */ | ||
316 | return UINT32_MAX - dist; | ||
317 | } | ||
318 | |||
319 | |||
320 | /** | ||
321 | * If the migration task is not currently running, consider | ||
322 | * (re)scheduling it with the appropriate delay. | ||
323 | */ | ||
324 | static void | ||
325 | consider_gathering (void); | ||
326 | |||
327 | |||
328 | /** | ||
329 | * Find content for migration to this peer. | ||
330 | * | ||
331 | * @param cls peer to find content for | ||
332 | */ | ||
333 | static void | ||
334 | find_content (void *cls) | ||
335 | { | ||
336 | struct MigrationReadyPeer *mrp = cls; | ||
337 | struct MigrationReadyBlock *pos; | ||
338 | long score; | ||
339 | long best_score; | ||
340 | struct MigrationReadyBlock *best; | ||
341 | |||
342 | mrp->env = NULL; | ||
343 | best = NULL; | ||
344 | best_score = -1; | ||
345 | pos = mig_head; | ||
346 | while (NULL != pos) | ||
347 | { | ||
348 | score = score_content (mrp, pos); | ||
349 | if (score > best_score) | ||
350 | { | ||
351 | best_score = score; | ||
352 | best = pos; | ||
353 | } | ||
354 | pos = pos->next; | ||
355 | } | ||
356 | if (NULL == best) | ||
357 | { | ||
358 | if (mig_size < MAX_MIGRATION_QUEUE) | ||
359 | { | ||
360 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
361 | "No content found for pushing, waiting for queue to fill\n"); | ||
362 | return; /* will fill up eventually... */ | ||
363 | } | ||
364 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
365 | "No suitable content found, purging content from full queue\n"); | ||
366 | /* failed to find migration target AND | ||
367 | * queue is full, purge most-forwarded | ||
368 | * block from queue to make room for more */ | ||
369 | pos = mig_head; | ||
370 | while (NULL != pos) | ||
371 | { | ||
372 | score = count_targets (pos); | ||
373 | if (score >= best_score) | ||
374 | { | ||
375 | best_score = score; | ||
376 | best = pos; | ||
377 | } | ||
378 | pos = pos->next; | ||
379 | } | ||
380 | GNUNET_assert (NULL != best); | ||
381 | delete_migration_block (best); | ||
382 | consider_gathering (); | ||
383 | return; | ||
384 | } | ||
385 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
386 | "Preparing to push best content to peer\n"); | ||
387 | transmit_content (mrp, | ||
388 | best); | ||
389 | } | ||
390 | |||
391 | |||
392 | /** | ||
393 | * Task that is run periodically to obtain blocks for content | ||
394 | * migration | ||
395 | * | ||
396 | * @param cls unused | ||
397 | */ | ||
398 | static void | ||
399 | gather_migration_blocks (void *cls); | ||
400 | |||
401 | |||
402 | /** | ||
403 | * If the migration task is not currently running, consider | ||
404 | * (re)scheduling it with the appropriate delay. | ||
405 | */ | ||
406 | static void | ||
407 | consider_gathering () | ||
408 | { | ||
409 | struct GNUNET_TIME_Relative delay; | ||
410 | |||
411 | if (NULL == GSF_dsh) | ||
412 | return; | ||
413 | if (NULL != mig_qe) | ||
414 | return; | ||
415 | if (NULL != mig_task) | ||
416 | return; | ||
417 | if (mig_size >= MAX_MIGRATION_QUEUE) | ||
418 | return; | ||
419 | delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
420 | mig_size); | ||
421 | delay = GNUNET_TIME_relative_divide (delay, | ||
422 | MAX_MIGRATION_QUEUE); | ||
423 | delay = GNUNET_TIME_relative_max (delay, | ||
424 | min_migration_delay); | ||
425 | if (GNUNET_NO == value_found) | ||
426 | { | ||
427 | /* wait at least 5s if the datastore is empty */ | ||
428 | delay = GNUNET_TIME_relative_max (delay, | ||
429 | GNUNET_TIME_relative_multiply ( | ||
430 | GNUNET_TIME_UNIT_SECONDS, | ||
431 | 5)); | ||
432 | } | ||
433 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
434 | "Scheduling gathering task (queue size: %u)\n", | ||
435 | mig_size); | ||
436 | mig_task = GNUNET_SCHEDULER_add_delayed (delay, | ||
437 | &gather_migration_blocks, | ||
438 | NULL); | ||
439 | } | ||
440 | |||
441 | |||
442 | /** | ||
443 | * Process content offered for migration. | ||
444 | * | ||
445 | * @param cls closure | ||
446 | * @param key key for the content | ||
447 | * @param size number of bytes in data | ||
448 | * @param data content stored | ||
449 | * @param type type of the content | ||
450 | * @param priority priority of the content | ||
451 | * @param anonymity anonymity-level for the content | ||
452 | * @param replication replication-level for the content | ||
453 | * @param expiration expiration time for the content | ||
454 | * @param uid unique identifier for the datum; | ||
455 | * maybe 0 if no unique identifier is available | ||
456 | */ | ||
457 | static void | ||
458 | process_migration_content (void *cls, | ||
459 | const struct GNUNET_HashCode *key, | ||
460 | size_t size, | ||
461 | const void *data, | ||
462 | enum GNUNET_BLOCK_Type type, | ||
463 | uint32_t priority, | ||
464 | uint32_t anonymity, | ||
465 | uint32_t replication, | ||
466 | struct GNUNET_TIME_Absolute expiration, | ||
467 | uint64_t uid) | ||
468 | { | ||
469 | struct MigrationReadyBlock *mb; | ||
470 | struct MigrationReadyPeer *pos; | ||
471 | |||
472 | mig_qe = NULL; | ||
473 | if (NULL == key) | ||
474 | { | ||
475 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
476 | "No content found for migration...\n"); | ||
477 | consider_gathering (); | ||
478 | return; | ||
479 | } | ||
480 | value_found = GNUNET_YES; | ||
481 | if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us < | ||
482 | MIN_MIGRATION_CONTENT_LIFETIME.rel_value_us) | ||
483 | { | ||
484 | /* content will expire soon, don't bother */ | ||
485 | consider_gathering (); | ||
486 | return; | ||
487 | } | ||
488 | if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) | ||
489 | { | ||
490 | if (GNUNET_OK != | ||
491 | GNUNET_FS_handle_on_demand_block (key, | ||
492 | size, | ||
493 | data, | ||
494 | type, | ||
495 | priority, | ||
496 | anonymity, | ||
497 | replication, | ||
498 | expiration, | ||
499 | uid, | ||
500 | &process_migration_content, | ||
501 | NULL)) | ||
502 | consider_gathering (); | ||
503 | return; | ||
504 | } | ||
505 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
506 | "Retrieved block `%s' of type %u for migration (queue size: %u/%u)\n", | ||
507 | GNUNET_h2s (key), | ||
508 | type, mig_size + 1, | ||
509 | MAX_MIGRATION_QUEUE); | ||
510 | mb = GNUNET_malloc (sizeof(struct MigrationReadyBlock) + size); | ||
511 | mb->query = *key; | ||
512 | mb->expiration = expiration; | ||
513 | mb->size = size; | ||
514 | mb->type = type; | ||
515 | GNUNET_memcpy (&mb[1], data, size); | ||
516 | GNUNET_CONTAINER_DLL_insert_after (mig_head, | ||
517 | mig_tail, | ||
518 | mig_tail, | ||
519 | mb); | ||
520 | mig_size++; | ||
521 | for (pos = peer_head; NULL != pos; pos = pos->next) | ||
522 | { | ||
523 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
524 | "Preparing to push best content to peer %s\n", | ||
525 | GNUNET_i2s (GSF_connected_peer_get_identity2_ (pos->peer))); | ||
526 | if ((NULL == pos->env) && | ||
527 | (GNUNET_YES == transmit_content (pos, | ||
528 | mb))) | ||
529 | { | ||
530 | break; /* 'mb' was freed! */ | ||
531 | } | ||
532 | } | ||
533 | consider_gathering (); | ||
534 | } | ||
535 | |||
536 | |||
537 | /** | ||
538 | * Task that is run periodically to obtain blocks for content | ||
539 | * migration | ||
540 | * | ||
541 | * @param cls unused | ||
542 | */ | ||
543 | static void | ||
544 | gather_migration_blocks (void *cls) | ||
545 | { | ||
546 | mig_task = NULL; | ||
547 | if (mig_size >= MAX_MIGRATION_QUEUE) | ||
548 | return; | ||
549 | if (NULL == GSF_dsh) | ||
550 | return; | ||
551 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
552 | "Asking datastore for content for replication (queue size: %u)\n", | ||
553 | mig_size); | ||
554 | value_found = GNUNET_NO; | ||
555 | mig_qe = GNUNET_DATASTORE_get_for_replication (GSF_dsh, | ||
556 | 0, | ||
557 | UINT_MAX, | ||
558 | &process_migration_content, | ||
559 | NULL); | ||
560 | if (NULL == mig_qe) | ||
561 | consider_gathering (); | ||
562 | } | ||
563 | |||
564 | |||
565 | /** | ||
566 | * A peer connected to us. Start pushing content | ||
567 | * to this peer. | ||
568 | * | ||
569 | * @param peer handle for the peer that connected | ||
570 | */ | ||
571 | void | ||
572 | GSF_push_start_ (struct GSF_ConnectedPeer *peer) | ||
573 | { | ||
574 | struct MigrationReadyPeer *mrp; | ||
575 | |||
576 | if (GNUNET_YES != enabled) | ||
577 | return; | ||
578 | for (mrp = peer_head; NULL != mrp; mrp = mrp->next) | ||
579 | if (mrp->peer == peer) | ||
580 | break; | ||
581 | if (NULL != mrp) | ||
582 | { | ||
583 | /* same peer added twice, must not happen */ | ||
584 | GNUNET_break (0); | ||
585 | return; | ||
586 | } | ||
587 | |||
588 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
589 | "Adding peer %s to list for pushing\n", | ||
590 | GNUNET_i2s (GSF_connected_peer_get_identity2_ (peer))); | ||
591 | |||
592 | mrp = GNUNET_new (struct MigrationReadyPeer); | ||
593 | mrp->peer = peer; | ||
594 | find_content (mrp); | ||
595 | GNUNET_CONTAINER_DLL_insert (peer_head, | ||
596 | peer_tail, | ||
597 | mrp); | ||
598 | } | ||
599 | |||
600 | |||
601 | /** | ||
602 | * A peer disconnected from us. Stop pushing content | ||
603 | * to this peer. | ||
604 | * | ||
605 | * @param peer handle for the peer that disconnected | ||
606 | */ | ||
607 | void | ||
608 | GSF_push_stop_ (struct GSF_ConnectedPeer *peer) | ||
609 | { | ||
610 | struct MigrationReadyPeer *pos; | ||
611 | |||
612 | for (pos = peer_head; NULL != pos; pos = pos->next) | ||
613 | if (pos->peer == peer) | ||
614 | break; | ||
615 | if (NULL == pos) | ||
616 | return; | ||
617 | if (NULL != pos->env) | ||
618 | GNUNET_MQ_send_cancel (pos->env); | ||
619 | GNUNET_CONTAINER_DLL_remove (peer_head, | ||
620 | peer_tail, | ||
621 | pos); | ||
622 | GNUNET_free (pos); | ||
623 | } | ||
624 | |||
625 | |||
626 | /** | ||
627 | * Setup the module. | ||
628 | */ | ||
629 | void | ||
630 | GSF_push_init_ () | ||
631 | { | ||
632 | enabled = | ||
633 | GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg, | ||
634 | "FS", | ||
635 | "CONTENT_PUSHING"); | ||
636 | if (GNUNET_YES != enabled) | ||
637 | return; | ||
638 | |||
639 | if (GNUNET_OK != | ||
640 | GNUNET_CONFIGURATION_get_value_time (GSF_cfg, | ||
641 | "fs", | ||
642 | "MIN_MIGRATION_DELAY", | ||
643 | &min_migration_delay)) | ||
644 | { | ||
645 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
646 | "fs", | ||
647 | "MIN_MIGRATION_DELAY", | ||
648 | _ ("time required, content pushing disabled")); | ||
649 | return; | ||
650 | } | ||
651 | consider_gathering (); | ||
652 | } | ||
653 | |||
654 | |||
655 | /** | ||
656 | * Shutdown the module. | ||
657 | */ | ||
658 | void | ||
659 | GSF_push_done_ () | ||
660 | { | ||
661 | if (NULL != mig_task) | ||
662 | { | ||
663 | GNUNET_SCHEDULER_cancel (mig_task); | ||
664 | mig_task = NULL; | ||
665 | } | ||
666 | if (NULL != mig_qe) | ||
667 | { | ||
668 | GNUNET_DATASTORE_cancel (mig_qe); | ||
669 | mig_qe = NULL; | ||
670 | } | ||
671 | while (NULL != mig_head) | ||
672 | delete_migration_block (mig_head); | ||
673 | GNUNET_assert (0 == mig_size); | ||
674 | } | ||
675 | |||
676 | |||
677 | /* end of gnunet-service-fs_push.c */ | ||
diff --git a/src/fs/gnunet-service-fs_push.h b/src/fs/gnunet-service-fs_push.h deleted file mode 100644 index 2cd621bbb..000000000 --- a/src/fs/gnunet-service-fs_push.h +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_push.h | ||
23 | * @brief support for pushing out content | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_FS_PUSH_H | ||
27 | #define GNUNET_SERVICE_FS_PUSH_H | ||
28 | |||
29 | #include "gnunet-service-fs.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Setup the module. | ||
34 | */ | ||
35 | void | ||
36 | GSF_push_init_ (void); | ||
37 | |||
38 | |||
39 | /** | ||
40 | * Shutdown the module. | ||
41 | */ | ||
42 | void | ||
43 | GSF_push_done_ (void); | ||
44 | |||
45 | |||
46 | /** | ||
47 | * A peer connected to us or we are now again allowed to push content. | ||
48 | * Start pushing content to this peer. | ||
49 | * | ||
50 | * @param peer handle for the peer that connected | ||
51 | */ | ||
52 | void | ||
53 | GSF_push_start_ (struct GSF_ConnectedPeer *peer); | ||
54 | |||
55 | |||
56 | /** | ||
57 | * A peer disconnected from us or asked us to stop pushing content for | ||
58 | * a while. Stop pushing content to this peer. | ||
59 | * | ||
60 | * @param peer handle for the peer that disconnected | ||
61 | */ | ||
62 | void | ||
63 | GSF_push_stop_ (struct GSF_ConnectedPeer *peer); | ||
64 | |||
65 | |||
66 | #endif | ||
diff --git a/src/fs/gnunet-service-fs_put.c b/src/fs/gnunet-service-fs_put.c deleted file mode 100644 index 93333b7a2..000000000 --- a/src/fs/gnunet-service-fs_put.c +++ /dev/null | |||
@@ -1,296 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_put.c | ||
23 | * @brief API to PUT zero-anonymity index data from our datastore into the DHT | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet-service-fs.h" | ||
28 | #include "gnunet-service-fs_put.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * How often do we at most PUT content into the DHT? | ||
33 | */ | ||
34 | #define MAX_DHT_PUT_FREQ GNUNET_TIME_relative_multiply ( \ | ||
35 | GNUNET_TIME_UNIT_SECONDS, 5) | ||
36 | |||
37 | /** | ||
38 | * How many replicas do we try to create per PUT? | ||
39 | */ | ||
40 | #define DEFAULT_PUT_REPLICATION 5 | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Context for each zero-anonymity iterator. | ||
45 | */ | ||
46 | struct PutOperator | ||
47 | { | ||
48 | /** | ||
49 | * Request to datastore for DHT PUTs (or NULL). | ||
50 | */ | ||
51 | struct GNUNET_DATASTORE_QueueEntry *dht_qe; | ||
52 | |||
53 | /** | ||
54 | * Type we request from the datastore. | ||
55 | */ | ||
56 | enum GNUNET_BLOCK_Type dht_put_type; | ||
57 | |||
58 | /** | ||
59 | * Handle to PUT operation. | ||
60 | */ | ||
61 | struct GNUNET_DHT_PutHandle *dht_put; | ||
62 | |||
63 | /** | ||
64 | * ID of task that collects blocks for DHT PUTs. | ||
65 | */ | ||
66 | struct GNUNET_SCHEDULER_Task *dht_task; | ||
67 | |||
68 | /** | ||
69 | * How many entries with zero anonymity of our type do we currently | ||
70 | * estimate to have in the database? | ||
71 | */ | ||
72 | uint64_t zero_anonymity_count_estimate; | ||
73 | |||
74 | /** | ||
75 | * Count of results received from the database. | ||
76 | */ | ||
77 | uint64_t result_count; | ||
78 | |||
79 | /** | ||
80 | * Next UID to request when iterating the database. | ||
81 | */ | ||
82 | uint64_t next_uid; | ||
83 | }; | ||
84 | |||
85 | |||
86 | /** | ||
87 | * ANY-terminated list of our operators (one per type | ||
88 | * of block that we're putting into the DHT). | ||
89 | */ | ||
90 | static struct PutOperator operators[] = { | ||
91 | { NULL, GNUNET_BLOCK_TYPE_FS_UBLOCK, 0, 0, 0 }, | ||
92 | { NULL, GNUNET_BLOCK_TYPE_ANY, 0, 0, 0 } | ||
93 | }; | ||
94 | |||
95 | |||
96 | /** | ||
97 | * Task that is run periodically to obtain blocks for DHT PUTs. | ||
98 | * | ||
99 | * @param cls type of blocks to gather | ||
100 | * @param tc scheduler context (unused) | ||
101 | */ | ||
102 | static void | ||
103 | gather_dht_put_blocks (void *cls); | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Calculate when to run the next PUT operation and schedule it. | ||
108 | * | ||
109 | * @param po put operator to schedule | ||
110 | */ | ||
111 | static void | ||
112 | schedule_next_put (struct PutOperator *po) | ||
113 | { | ||
114 | struct GNUNET_TIME_Relative delay; | ||
115 | |||
116 | if (po->zero_anonymity_count_estimate > 0) | ||
117 | { | ||
118 | delay = | ||
119 | GNUNET_TIME_relative_divide (GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY, | ||
120 | po->zero_anonymity_count_estimate); | ||
121 | delay = GNUNET_TIME_relative_min (delay, MAX_DHT_PUT_FREQ); | ||
122 | } | ||
123 | else | ||
124 | { | ||
125 | /* if we have NO zero-anonymity content yet, wait 5 minutes for some to | ||
126 | * (hopefully) appear */ | ||
127 | delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5); | ||
128 | } | ||
129 | po->dht_task = | ||
130 | GNUNET_SCHEDULER_add_delayed (delay, &gather_dht_put_blocks, po); | ||
131 | } | ||
132 | |||
133 | |||
134 | /** | ||
135 | * Continuation called after DHT PUT operation has finished. | ||
136 | * | ||
137 | * @param cls type of blocks to gather | ||
138 | */ | ||
139 | static void | ||
140 | delay_dht_put_blocks (void *cls) | ||
141 | { | ||
142 | struct PutOperator *po = cls; | ||
143 | |||
144 | po->dht_put = NULL; | ||
145 | schedule_next_put (po); | ||
146 | } | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Task that is run periodically to obtain blocks for DHT PUTs. | ||
151 | * | ||
152 | * @param cls type of blocks to gather | ||
153 | */ | ||
154 | static void | ||
155 | delay_dht_put_task (void *cls) | ||
156 | { | ||
157 | struct PutOperator *po = cls; | ||
158 | |||
159 | po->dht_task = NULL; | ||
160 | schedule_next_put (po); | ||
161 | } | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Store content in DHT. | ||
166 | * | ||
167 | * @param cls closure | ||
168 | * @param key key for the content | ||
169 | * @param size number of bytes in data | ||
170 | * @param data content stored | ||
171 | * @param type type of the content | ||
172 | * @param priority priority of the content | ||
173 | * @param anonymity anonymity-level for the content | ||
174 | * @param replication replication-level for the content | ||
175 | * @param expiration expiration time for the content | ||
176 | * @param uid unique identifier for the datum; | ||
177 | * maybe 0 if no unique identifier is available | ||
178 | */ | ||
179 | static void | ||
180 | process_dht_put_content (void *cls, | ||
181 | const struct GNUNET_HashCode *key, | ||
182 | size_t size, | ||
183 | const void *data, | ||
184 | enum GNUNET_BLOCK_Type type, | ||
185 | uint32_t priority, | ||
186 | uint32_t anonymity, | ||
187 | uint32_t replication, | ||
188 | struct GNUNET_TIME_Absolute expiration, | ||
189 | uint64_t uid) | ||
190 | { | ||
191 | struct PutOperator *po = cls; | ||
192 | |||
193 | po->dht_qe = NULL; | ||
194 | if (key == NULL) | ||
195 | { | ||
196 | po->zero_anonymity_count_estimate = po->result_count; | ||
197 | po->result_count = 0; | ||
198 | po->next_uid = 0; | ||
199 | po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po); | ||
200 | return; | ||
201 | } | ||
202 | po->result_count++; | ||
203 | po->next_uid = uid + 1; | ||
204 | po->zero_anonymity_count_estimate = | ||
205 | GNUNET_MAX (po->result_count, po->zero_anonymity_count_estimate); | ||
206 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
207 | "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key), | ||
208 | type); | ||
209 | po->dht_put = GNUNET_DHT_put (GSF_dht, | ||
210 | key, | ||
211 | DEFAULT_PUT_REPLICATION, | ||
212 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, | ||
213 | type, | ||
214 | size, | ||
215 | data, | ||
216 | expiration, | ||
217 | &delay_dht_put_blocks, | ||
218 | po); | ||
219 | } | ||
220 | |||
221 | |||
222 | /** | ||
223 | * Task that is run periodically to obtain blocks for DHT PUTs. | ||
224 | * | ||
225 | * @param cls type of blocks to gather | ||
226 | */ | ||
227 | static void | ||
228 | gather_dht_put_blocks (void *cls) | ||
229 | { | ||
230 | struct PutOperator *po = cls; | ||
231 | |||
232 | po->dht_task = NULL; | ||
233 | po->dht_qe = | ||
234 | GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh, | ||
235 | po->next_uid, | ||
236 | 0, | ||
237 | UINT_MAX, | ||
238 | po->dht_put_type, | ||
239 | &process_dht_put_content, | ||
240 | po); | ||
241 | if (NULL == po->dht_qe) | ||
242 | po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po); | ||
243 | } | ||
244 | |||
245 | |||
246 | /** | ||
247 | * Setup the module. | ||
248 | */ | ||
249 | void | ||
250 | GSF_put_init_ () | ||
251 | { | ||
252 | unsigned int i; | ||
253 | |||
254 | i = 0; | ||
255 | while (operators[i].dht_put_type != GNUNET_BLOCK_TYPE_ANY) | ||
256 | { | ||
257 | operators[i].dht_task = | ||
258 | GNUNET_SCHEDULER_add_now (&gather_dht_put_blocks, &operators[i]); | ||
259 | i++; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | |||
264 | /** | ||
265 | * Shutdown the module. | ||
266 | */ | ||
267 | void | ||
268 | GSF_put_done_ () | ||
269 | { | ||
270 | struct PutOperator *po; | ||
271 | unsigned int i; | ||
272 | |||
273 | i = 0; | ||
274 | while ((po = &operators[i])->dht_put_type != GNUNET_BLOCK_TYPE_ANY) | ||
275 | { | ||
276 | if (NULL != po->dht_task) | ||
277 | { | ||
278 | GNUNET_SCHEDULER_cancel (po->dht_task); | ||
279 | po->dht_task = NULL; | ||
280 | } | ||
281 | if (NULL != po->dht_put) | ||
282 | { | ||
283 | GNUNET_DHT_put_cancel (po->dht_put); | ||
284 | po->dht_put = NULL; | ||
285 | } | ||
286 | if (NULL != po->dht_qe) | ||
287 | { | ||
288 | GNUNET_DATASTORE_cancel (po->dht_qe); | ||
289 | po->dht_qe = NULL; | ||
290 | } | ||
291 | i++; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | |||
296 | /* end of gnunet-service-fs_put.c */ | ||
diff --git a/src/fs/gnunet-service-fs_put.h b/src/fs/gnunet-service-fs_put.h deleted file mode 100644 index b6c9ba86f..000000000 --- a/src/fs/gnunet-service-fs_put.h +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/gnunet-service-fs_put.h | ||
23 | * @brief support for putting content into the DHT | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_FS_PUT_H | ||
27 | #define GNUNET_SERVICE_FS_PUT_H | ||
28 | |||
29 | #include "gnunet-service-fs.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Setup the module. | ||
34 | */ | ||
35 | void | ||
36 | GSF_put_init_ (void); | ||
37 | |||
38 | |||
39 | /** | ||
40 | * Shutdown the module. | ||
41 | */ | ||
42 | void | ||
43 | GSF_put_done_ (void); | ||
44 | |||
45 | |||
46 | #endif | ||
diff --git a/src/fs/gnunet-unindex.c b/src/fs/gnunet-unindex.c deleted file mode 100644 index afc547127..000000000 --- a/src/fs/gnunet-unindex.c +++ /dev/null | |||
@@ -1,205 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/gnunet-unindex.c | ||
22 | * @brief unindex files published on GNUnet | ||
23 | * @author Christian Grothoff | ||
24 | * @author Krista Bennett | ||
25 | * @author James Blackwell | ||
26 | * @author Igor Wronsky | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | static int ret; | ||
32 | |||
33 | static unsigned int verbose; | ||
34 | |||
35 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
36 | |||
37 | static struct GNUNET_FS_Handle *ctx; | ||
38 | |||
39 | static struct GNUNET_FS_UnindexContext *uc; | ||
40 | |||
41 | |||
42 | static void | ||
43 | cleanup_task (void *cls) | ||
44 | { | ||
45 | GNUNET_FS_stop (ctx); | ||
46 | ctx = NULL; | ||
47 | } | ||
48 | |||
49 | |||
50 | static void | ||
51 | shutdown_task (void *cls) | ||
52 | { | ||
53 | struct GNUNET_FS_UnindexContext *u; | ||
54 | |||
55 | if (uc != NULL) | ||
56 | { | ||
57 | u = uc; | ||
58 | uc = NULL; | ||
59 | GNUNET_FS_unindex_stop (u); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | |||
64 | /** | ||
65 | * Called by FS client to give information about the progress of an | ||
66 | * operation. | ||
67 | * | ||
68 | * @param cls closure | ||
69 | * @param info details about the event, specifying the event type | ||
70 | * and various bits about the event | ||
71 | * @return client-context (for the next progress call | ||
72 | * for this operation; should be set to NULL for | ||
73 | * SUSPEND and STOPPED events). The value returned | ||
74 | * will be passed to future callbacks in the respective | ||
75 | * field in the GNUNET_FS_ProgressInfo struct. | ||
76 | */ | ||
77 | static void * | ||
78 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) | ||
79 | { | ||
80 | const char *s; | ||
81 | |||
82 | switch (info->status) | ||
83 | { | ||
84 | case GNUNET_FS_STATUS_UNINDEX_START: | ||
85 | break; | ||
86 | |||
87 | case GNUNET_FS_STATUS_UNINDEX_PROGRESS: | ||
88 | if (verbose) | ||
89 | { | ||
90 | s = GNUNET_STRINGS_relative_time_to_string (info->value.unindex.eta, | ||
91 | GNUNET_YES); | ||
92 | fprintf (stdout, | ||
93 | _ ("Unindexing at %llu/%llu (%s remaining)\n"), | ||
94 | (unsigned long long) info->value.unindex.completed, | ||
95 | (unsigned long long) info->value.unindex.size, | ||
96 | s); | ||
97 | } | ||
98 | break; | ||
99 | |||
100 | case GNUNET_FS_STATUS_UNINDEX_ERROR: | ||
101 | fprintf (stderr, | ||
102 | _ ("Error unindexing: %s.\n"), | ||
103 | info->value.unindex.specifics.error.message); | ||
104 | GNUNET_SCHEDULER_shutdown (); | ||
105 | break; | ||
106 | |||
107 | case GNUNET_FS_STATUS_UNINDEX_COMPLETED: | ||
108 | fprintf (stdout, "%s", _ ("Unindexing done.\n")); | ||
109 | GNUNET_SCHEDULER_shutdown (); | ||
110 | break; | ||
111 | |||
112 | case GNUNET_FS_STATUS_UNINDEX_STOPPED: | ||
113 | GNUNET_SCHEDULER_add_now (&cleanup_task, NULL); | ||
114 | break; | ||
115 | |||
116 | default: | ||
117 | fprintf (stderr, _ ("Unexpected status: %d\n"), info->status); | ||
118 | break; | ||
119 | } | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Main function that will be run by the scheduler. | ||
126 | * | ||
127 | * @param cls closure | ||
128 | * @param args remaining command-line arguments | ||
129 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
130 | * @param c configuration | ||
131 | */ | ||
132 | static void | ||
133 | run (void *cls, | ||
134 | char *const *args, | ||
135 | const char *cfgfile, | ||
136 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
137 | { | ||
138 | /* check arguments */ | ||
139 | if ((args[0] == NULL) || (args[1] != NULL)) | ||
140 | { | ||
141 | printf (_ ("You must specify one and only one filename for unindexing.\n")); | ||
142 | ret = -1; | ||
143 | return; | ||
144 | } | ||
145 | cfg = c; | ||
146 | ctx = GNUNET_FS_start (cfg, | ||
147 | "gnunet-unindex", | ||
148 | &progress_cb, | ||
149 | NULL, | ||
150 | GNUNET_FS_FLAGS_NONE, | ||
151 | GNUNET_FS_OPTIONS_END); | ||
152 | if (NULL == ctx) | ||
153 | { | ||
154 | fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS"); | ||
155 | ret = 1; | ||
156 | return; | ||
157 | } | ||
158 | uc = GNUNET_FS_unindex_start (ctx, args[0], NULL); | ||
159 | if (NULL == uc) | ||
160 | { | ||
161 | fprintf (stderr, "%s", _ ("Could not start unindex operation.\n")); | ||
162 | GNUNET_FS_stop (ctx); | ||
163 | return; | ||
164 | } | ||
165 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
166 | } | ||
167 | |||
168 | |||
169 | /** | ||
170 | * The main function to unindex content. | ||
171 | * | ||
172 | * @param argc number of arguments from the command line | ||
173 | * @param argv command line arguments | ||
174 | * @return 0 ok, 1 on error | ||
175 | */ | ||
176 | int | ||
177 | main (int argc, char *const *argv) | ||
178 | { | ||
179 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
180 | GNUNET_GETOPT_option_verbose (&verbose), | ||
181 | |||
182 | GNUNET_GETOPT_OPTION_END | ||
183 | }; | ||
184 | |||
185 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
186 | return 2; | ||
187 | |||
188 | ret = (GNUNET_OK == | ||
189 | GNUNET_PROGRAM_run ( | ||
190 | argc, | ||
191 | argv, | ||
192 | "gnunet-unindex [OPTIONS] FILENAME", | ||
193 | gettext_noop ( | ||
194 | "Unindex a file that was previously indexed with gnunet-publish."), | ||
195 | options, | ||
196 | &run, | ||
197 | NULL)) | ||
198 | ? ret | ||
199 | : 1; | ||
200 | GNUNET_free_nz ((void *) argv); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | |||
205 | /* end of gnunet-unindex.c */ | ||
diff --git a/src/fs/perf_gnunet_service_fs_p2p.c b/src/fs/perf_gnunet_service_fs_p2p.c deleted file mode 100644 index 062f062b5..000000000 --- a/src/fs/perf_gnunet_service_fs_p2p.c +++ /dev/null | |||
@@ -1,368 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/perf_gnunet_service_fs_p2p.c | ||
23 | * @brief profile P2P routing using simple publish + download operation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "fs_test_lib.h" | ||
28 | #include "gnunet_testbed_service.h" | ||
29 | |||
30 | #define VERBOSE GNUNET_NO | ||
31 | |||
32 | /** | ||
33 | * File-size we use for testing. | ||
34 | */ | ||
35 | #define FILESIZE (1024 * 1024 * 10) | ||
36 | |||
37 | /** | ||
38 | * How long until we give up on transmitting the message? | ||
39 | */ | ||
40 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) | ||
41 | |||
42 | #define NUM_DAEMONS 2 | ||
43 | |||
44 | #define SEED 42 | ||
45 | |||
46 | static struct GNUNET_TESTBED_Peer *daemons[NUM_DAEMONS]; | ||
47 | |||
48 | static int ok; | ||
49 | |||
50 | static struct GNUNET_TIME_Absolute start_time; | ||
51 | |||
52 | static const char *progname; | ||
53 | |||
54 | static struct GNUNET_TIME_Absolute start_time; | ||
55 | |||
56 | |||
57 | /** | ||
58 | * Master context for 'stat_run'. | ||
59 | */ | ||
60 | struct StatMaster | ||
61 | { | ||
62 | struct GNUNET_STATISTICS_Handle *stat; | ||
63 | struct GNUNET_TESTBED_Operation *op; | ||
64 | unsigned int daemon; | ||
65 | unsigned int value; | ||
66 | }; | ||
67 | |||
68 | struct StatValues | ||
69 | { | ||
70 | const char *subsystem; | ||
71 | const char *name; | ||
72 | }; | ||
73 | |||
74 | /** | ||
75 | * Statistics we print out. | ||
76 | */ | ||
77 | static struct StatValues stats[] = { | ||
78 | { "fs", "# queries forwarded" }, | ||
79 | { "fs", "# replies received and matched" }, | ||
80 | { "fs", "# results found locally" }, | ||
81 | { "fs", "# requests forwarded due to high load" }, | ||
82 | { "fs", "# requests done for free (low load)" }, | ||
83 | { "fs", "# requests dropped, priority insufficient" }, | ||
84 | { "fs", "# requests done for a price (normal load)" }, | ||
85 | { "fs", "# requests dropped by datastore (queue length limit)" }, | ||
86 | { "fs", "# P2P searches received" }, | ||
87 | { "fs", "# P2P searches discarded (queue length bound)" }, | ||
88 | { "fs", "# replies received for local clients" }, | ||
89 | { "fs", "# queries retransmitted to same target" }, | ||
90 | { "core", "# bytes decrypted" }, | ||
91 | { "core", "# bytes encrypted" }, | ||
92 | { "core", "# discarded CORE_SEND requests" }, | ||
93 | { "core", "# discarded CORE_SEND request bytes" }, | ||
94 | { "core", "# discarded lower priority CORE_SEND requests" }, | ||
95 | { "core", "# discarded lower priority CORE_SEND request bytes" }, | ||
96 | { "transport", "# bytes received via TCP" }, | ||
97 | { "transport", "# bytes transmitted via TCP" }, | ||
98 | { "datacache", "# bytes stored" }, | ||
99 | { NULL, NULL } | ||
100 | }; | ||
101 | |||
102 | |||
103 | /** | ||
104 | * Callback function to process statistic values. | ||
105 | * | ||
106 | * @param cls closure | ||
107 | * @param subsystem name of subsystem that created the statistic | ||
108 | * @param name the name of the datum | ||
109 | * @param value the current value | ||
110 | * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not | ||
111 | * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration | ||
112 | */ | ||
113 | static int | ||
114 | print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, | ||
115 | int is_persistent) | ||
116 | { | ||
117 | struct StatMaster *sm = cls; | ||
118 | |||
119 | fprintf (stderr, | ||
120 | "Peer %2u: %12s/%50s = %12llu\n", | ||
121 | sm->daemon, | ||
122 | subsystem, | ||
123 | name, | ||
124 | (unsigned long long) value); | ||
125 | return GNUNET_OK; | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * Function that gathers stats from all daemons. | ||
131 | */ | ||
132 | static void | ||
133 | stat_run (void *cls, | ||
134 | struct GNUNET_TESTBED_Operation *op, | ||
135 | void *ca_result, | ||
136 | const char *emsg); | ||
137 | |||
138 | |||
139 | /** | ||
140 | * Function called when GET operation on stats is done. | ||
141 | */ | ||
142 | static void | ||
143 | get_done (void *cls, int success) | ||
144 | { | ||
145 | struct StatMaster *sm = cls; | ||
146 | |||
147 | GNUNET_break (GNUNET_OK == success); | ||
148 | sm->value++; | ||
149 | stat_run (sm, sm->op, sm->stat, NULL); | ||
150 | } | ||
151 | |||
152 | |||
153 | /** | ||
154 | * Adapter function called to establish a connection to | ||
155 | * statistics service. | ||
156 | * | ||
157 | * @param cls closure | ||
158 | * @param cfg configuration of the peer to connect to; will be available until | ||
159 | * GNUNET_TESTBED_operation_done() is called on the operation returned | ||
160 | * from GNUNET_TESTBED_service_connect() | ||
161 | * @return service handle to return in 'op_result', NULL on error | ||
162 | */ | ||
163 | static void * | ||
164 | statistics_connect_adapter (void *cls, | ||
165 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
166 | { | ||
167 | return GNUNET_STATISTICS_create ("<driver>", | ||
168 | cfg); | ||
169 | } | ||
170 | |||
171 | |||
172 | /** | ||
173 | * Adapter function called to destroy a connection to | ||
174 | * statistics service. | ||
175 | * | ||
176 | * @param cls closure | ||
177 | * @param op_result service handle returned from the connect adapter | ||
178 | */ | ||
179 | static void | ||
180 | statistics_disconnect_adapter (void *cls, | ||
181 | void *op_result) | ||
182 | { | ||
183 | GNUNET_STATISTICS_destroy (op_result, GNUNET_NO); | ||
184 | } | ||
185 | |||
186 | |||
187 | /** | ||
188 | * Function that gathers stats from all daemons. | ||
189 | */ | ||
190 | static void | ||
191 | stat_run (void *cls, | ||
192 | struct GNUNET_TESTBED_Operation *op, | ||
193 | void *ca_result, | ||
194 | const char *emsg) | ||
195 | { | ||
196 | struct StatMaster *sm = cls; | ||
197 | |||
198 | if (NULL != emsg) | ||
199 | { | ||
200 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
201 | "Failed to statistics service: %s\n", | ||
202 | emsg); | ||
203 | GNUNET_SCHEDULER_shutdown (); | ||
204 | return; | ||
205 | } | ||
206 | sm->stat = ca_result; | ||
207 | |||
208 | if (stats[sm->value].name != NULL) | ||
209 | { | ||
210 | GNUNET_STATISTICS_get (sm->stat, | ||
211 | #if 0 | ||
212 | NULL, NULL, | ||
213 | #else | ||
214 | stats[sm->value].subsystem, stats[sm->value].name, | ||
215 | #endif | ||
216 | &get_done, &print_stat, | ||
217 | sm); | ||
218 | return; | ||
219 | } | ||
220 | GNUNET_TESTBED_operation_done (sm->op); | ||
221 | sm->value = 0; | ||
222 | sm->daemon++; | ||
223 | if (NUM_DAEMONS == sm->daemon) | ||
224 | { | ||
225 | GNUNET_free (sm); | ||
226 | GNUNET_SCHEDULER_shutdown (); | ||
227 | return; | ||
228 | } | ||
229 | sm->op = | ||
230 | GNUNET_TESTBED_service_connect (NULL, | ||
231 | daemons[sm->daemon], | ||
232 | "statistics", | ||
233 | &stat_run, sm, | ||
234 | &statistics_connect_adapter, | ||
235 | &statistics_disconnect_adapter, | ||
236 | NULL); | ||
237 | } | ||
238 | |||
239 | |||
240 | static void | ||
241 | do_report (void *cls) | ||
242 | { | ||
243 | char *fn = cls; | ||
244 | struct GNUNET_TIME_Relative del; | ||
245 | char *fancy; | ||
246 | struct StatMaster *sm; | ||
247 | |||
248 | if (NULL != fn) | ||
249 | { | ||
250 | GNUNET_DISK_directory_remove (fn); | ||
251 | GNUNET_free (fn); | ||
252 | } | ||
253 | if (0 == | ||
254 | GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (start_time, | ||
255 | TIMEOUT)). | ||
256 | rel_value_us) | ||
257 | { | ||
258 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
259 | "Timeout during download, shutting down with error\n"); | ||
260 | ok = 1; | ||
261 | GNUNET_SCHEDULER_shutdown (); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | del = GNUNET_TIME_absolute_get_duration (start_time); | ||
266 | if (del.rel_value_us == 0) | ||
267 | del.rel_value_us = 1; | ||
268 | fancy = | ||
269 | GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) | ||
270 | * 1000000LL / del.rel_value_us); | ||
271 | fprintf (stdout, | ||
272 | "Download speed was %s/s\n", | ||
273 | fancy); | ||
274 | GNUNET_free (fancy); | ||
275 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
276 | "Finished download, shutting down\n"); | ||
277 | sm = GNUNET_new (struct StatMaster); | ||
278 | sm->op = | ||
279 | GNUNET_TESTBED_service_connect (NULL, | ||
280 | daemons[sm->daemon], | ||
281 | "statistics", | ||
282 | &stat_run, sm, | ||
283 | &statistics_connect_adapter, | ||
284 | &statistics_disconnect_adapter, | ||
285 | NULL); | ||
286 | } | ||
287 | |||
288 | |||
289 | static void | ||
290 | do_download (void *cls, | ||
291 | const struct GNUNET_FS_Uri *uri, | ||
292 | const char *fn) | ||
293 | { | ||
294 | int anonymity; | ||
295 | |||
296 | if (NULL == uri) | ||
297 | { | ||
298 | GNUNET_SCHEDULER_shutdown (); | ||
299 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
300 | "Timeout during upload attempt, shutting down with error\n"); | ||
301 | ok = 1; | ||
302 | return; | ||
303 | } | ||
304 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", | ||
305 | (unsigned long long) FILESIZE); | ||
306 | start_time = GNUNET_TIME_absolute_get (); | ||
307 | if (NULL != strstr (progname, "dht")) | ||
308 | anonymity = 0; | ||
309 | else | ||
310 | anonymity = 1; | ||
311 | start_time = GNUNET_TIME_absolute_get (); | ||
312 | GNUNET_FS_TEST_download (daemons[0], | ||
313 | TIMEOUT, | ||
314 | anonymity, | ||
315 | SEED, | ||
316 | uri, | ||
317 | VERBOSE, | ||
318 | &do_report, | ||
319 | (NULL == fn) ? NULL : GNUNET_strdup (fn)); | ||
320 | } | ||
321 | |||
322 | |||
323 | static void | ||
324 | do_publish (void *cls, | ||
325 | struct GNUNET_TESTBED_RunHandle *h, | ||
326 | unsigned int num_peers, | ||
327 | struct GNUNET_TESTBED_Peer **peers, | ||
328 | unsigned int links_succeeded, | ||
329 | unsigned int links_failed) | ||
330 | { | ||
331 | unsigned int i; | ||
332 | int do_index; | ||
333 | int anonymity; | ||
334 | |||
335 | GNUNET_assert (NUM_DAEMONS == num_peers); | ||
336 | for (i = 0; i < num_peers; i++) | ||
337 | daemons[i] = peers[i]; | ||
338 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", | ||
339 | (unsigned long long) FILESIZE); | ||
340 | if (NULL != strstr (progname, "index")) | ||
341 | do_index = GNUNET_YES; | ||
342 | else | ||
343 | do_index = GNUNET_NO; | ||
344 | if (NULL != strstr (progname, "dht")) | ||
345 | anonymity = 0; | ||
346 | else | ||
347 | anonymity = 1; | ||
348 | GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, | ||
349 | do_index, FILESIZE, SEED, VERBOSE, &do_download, | ||
350 | NULL); | ||
351 | } | ||
352 | |||
353 | |||
354 | int | ||
355 | main (int argc, char *argv[]) | ||
356 | { | ||
357 | progname = argv[0]; | ||
358 | (void) GNUNET_TESTBED_test_run ("perf-gnunet-service-fs-p2p", | ||
359 | "perf_gnunet_service_fs_p2p.conf", | ||
360 | NUM_DAEMONS, | ||
361 | 0, NULL, NULL, | ||
362 | &do_publish, NULL); | ||
363 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); | ||
364 | return ok; | ||
365 | } | ||
366 | |||
367 | |||
368 | /* end of perf_gnunet_service_fs_p2p.c */ | ||
diff --git a/src/fs/perf_gnunet_service_fs_p2p.conf b/src/fs/perf_gnunet_service_fs_p2p.conf deleted file mode 100644 index 00f0f512e..000000000 --- a/src/fs/perf_gnunet_service_fs_p2p.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ fs_test_lib_data.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-fs-test-lib/ | ||
4 | |||
5 | [fs] | ||
6 | GAUGER_HEAP = "2-peer 10 MB P2P download" | ||
7 | # PREFIX = valgrind | ||
diff --git a/src/fs/perf_gnunet_service_fs_p2p_respect.c b/src/fs/perf_gnunet_service_fs_p2p_respect.c deleted file mode 100644 index c48db2383..000000000 --- a/src/fs/perf_gnunet_service_fs_p2p_respect.c +++ /dev/null | |||
@@ -1,479 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2011, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/perf_gnunet_service_fs_p2p_respect.c | ||
23 | * @brief profile P2P routing respect mechanism. Creates | ||
24 | * a clique of NUM_DAEMONS (at least 3) where two | ||
25 | * peers share (seed) different files and download | ||
26 | * them from each other while all the other peers | ||
27 | * just "leach" those files. Ideally, the seeders | ||
28 | * "learn" that they contribute (to each other), | ||
29 | * and give the other seeder higher priority; | ||
30 | * naturally, this only happens nicely for larger | ||
31 | * files; finally, once the seeders are done, the | ||
32 | * leachers should see fast download rates as well. | ||
33 | * @author Christian Grothoff | ||
34 | * | ||
35 | * Sample output: | ||
36 | * - 10 MB, 3 peers, with delays: | ||
37 | * Download speed of type `seeder 1' was 757 KiB/s | ||
38 | * Download speed of type `seeder 2' was 613 KiB/s | ||
39 | * Download speed of type `leach` was 539 KiB/s | ||
40 | * | ||
41 | * - 10 MB, 3 peers, without delays: | ||
42 | * Download speed of type `seeder 1' was 1784 KiB/s | ||
43 | * Download speed of type `seeder 2' was 1604 KiB/s | ||
44 | * Download speed of type `leach` was 1384 KiB/s | ||
45 | */ | ||
46 | #include "platform.h" | ||
47 | #include "fs_test_lib.h" | ||
48 | #include "gnunet_testbed_service.h" | ||
49 | |||
50 | #define VERBOSE GNUNET_NO | ||
51 | |||
52 | /** | ||
53 | * File-size we use for testing. | ||
54 | */ | ||
55 | #define FILESIZE (1024 * 1024 * 1) | ||
56 | |||
57 | /** | ||
58 | * How long until we give up on transmitting the message? | ||
59 | */ | ||
60 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) | ||
61 | |||
62 | /** | ||
63 | * Number of daemons in clique, must be at least 3 (!). | ||
64 | */ | ||
65 | #define NUM_DAEMONS 3 | ||
66 | |||
67 | /** | ||
68 | * Seed for first file on offer. | ||
69 | */ | ||
70 | #define SEED1 42 | ||
71 | |||
72 | /** | ||
73 | * Seed for second file on offer. | ||
74 | */ | ||
75 | #define SEED2 43 | ||
76 | |||
77 | static struct GNUNET_TESTBED_Peer *daemons[NUM_DAEMONS]; | ||
78 | |||
79 | static int ok; | ||
80 | |||
81 | static struct GNUNET_TIME_Absolute start_time; | ||
82 | |||
83 | static const char *progname; | ||
84 | |||
85 | static struct GNUNET_FS_Uri *uri1; | ||
86 | |||
87 | static struct GNUNET_FS_Uri *uri2; | ||
88 | |||
89 | static char *fn1; | ||
90 | |||
91 | static char *fn2; | ||
92 | |||
93 | /** | ||
94 | * Master context for 'stat_run'. | ||
95 | */ | ||
96 | struct StatMaster | ||
97 | { | ||
98 | struct GNUNET_STATISTICS_Handle *stat; | ||
99 | struct GNUNET_TESTBED_Operation *op; | ||
100 | unsigned int daemon; | ||
101 | unsigned int value; | ||
102 | }; | ||
103 | |||
104 | struct StatValues | ||
105 | { | ||
106 | const char *subsystem; | ||
107 | const char *name; | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * Statistics we print out. | ||
112 | */ | ||
113 | static struct StatValues stats[] = { | ||
114 | { "fs", "# artificial delays introduced (ms)" }, | ||
115 | { "fs", "# queries forwarded" }, | ||
116 | { "fs", "# replies received and matched" }, | ||
117 | { "fs", "# results found locally" }, | ||
118 | { "fs", "# requests forwarded due to high load" }, | ||
119 | { "fs", "# requests done for free (low load)" }, | ||
120 | { "fs", "# requests dropped, priority insufficient" }, | ||
121 | { "fs", "# requests done for a price (normal load)" }, | ||
122 | { "fs", "# requests dropped by datastore (queue length limit)" }, | ||
123 | { "fs", "# P2P searches received" }, | ||
124 | { "fs", "# P2P searches discarded (queue length bound)" }, | ||
125 | { "fs", "# replies received for local clients" }, | ||
126 | { "fs", "# queries retransmitted to same target" }, | ||
127 | { "core", "# bytes decrypted" }, | ||
128 | { "core", "# bytes encrypted" }, | ||
129 | { "core", "# discarded CORE_SEND requests" }, | ||
130 | { "core", "# discarded lower priority CORE_SEND requests" }, | ||
131 | { "transport", "# bytes received via TCP" }, | ||
132 | { "transport", "# bytes transmitted via TCP" }, | ||
133 | { "datacache", "# bytes stored" }, | ||
134 | { NULL, NULL } | ||
135 | }; | ||
136 | |||
137 | |||
138 | static void | ||
139 | cleanup () | ||
140 | { | ||
141 | GNUNET_SCHEDULER_shutdown (); | ||
142 | if (NULL != fn1) | ||
143 | { | ||
144 | GNUNET_DISK_directory_remove (fn1); | ||
145 | GNUNET_free (fn1); | ||
146 | } | ||
147 | if (NULL != fn2) | ||
148 | { | ||
149 | GNUNET_DISK_directory_remove (fn2); | ||
150 | GNUNET_free (fn2); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | |||
155 | /** | ||
156 | * Callback function to process statistic values. | ||
157 | * | ||
158 | * @param cls closure | ||
159 | * @param subsystem name of subsystem that created the statistic | ||
160 | * @param name the name of the datum | ||
161 | * @param value the current value | ||
162 | * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not | ||
163 | * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration | ||
164 | */ | ||
165 | static int | ||
166 | print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, | ||
167 | int is_persistent) | ||
168 | { | ||
169 | struct StatMaster *sm = cls; | ||
170 | |||
171 | fprintf (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem, | ||
172 | name, (unsigned long long) value); | ||
173 | return GNUNET_OK; | ||
174 | } | ||
175 | |||
176 | |||
177 | /** | ||
178 | * Function that gathers stats from all daemons. | ||
179 | */ | ||
180 | static void | ||
181 | stat_run (void *cls, | ||
182 | struct GNUNET_TESTBED_Operation *op, | ||
183 | void *ca_result, | ||
184 | const char *emsg); | ||
185 | |||
186 | |||
187 | /** | ||
188 | * Function called when GET operation on stats is done. | ||
189 | */ | ||
190 | static void | ||
191 | get_done (void *cls, int success) | ||
192 | { | ||
193 | struct StatMaster *sm = cls; | ||
194 | |||
195 | GNUNET_break (GNUNET_OK == success); | ||
196 | sm->value++; | ||
197 | stat_run (sm, sm->op, sm->stat, NULL); | ||
198 | } | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Adapter function called to establish a connection to | ||
203 | * statistics service. | ||
204 | * | ||
205 | * @param cls closure | ||
206 | * @param cfg configuration of the peer to connect to; will be available until | ||
207 | * GNUNET_TESTBED_operation_done() is called on the operation returned | ||
208 | * from GNUNET_TESTBED_service_connect() | ||
209 | * @return service handle to return in 'op_result', NULL on error | ||
210 | */ | ||
211 | static void * | ||
212 | statistics_connect_adapter (void *cls, | ||
213 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
214 | { | ||
215 | return GNUNET_STATISTICS_create ("<driver>", | ||
216 | cfg); | ||
217 | } | ||
218 | |||
219 | |||
220 | /** | ||
221 | * Adapter function called to destroy a connection to | ||
222 | * statistics service. | ||
223 | * | ||
224 | * @param cls closure | ||
225 | * @param op_result service handle returned from the connect adapter | ||
226 | */ | ||
227 | static void | ||
228 | statistics_disconnect_adapter (void *cls, | ||
229 | void *op_result) | ||
230 | { | ||
231 | GNUNET_STATISTICS_destroy (op_result, GNUNET_NO); | ||
232 | } | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Function that gathers stats from all daemons. | ||
237 | */ | ||
238 | static void | ||
239 | stat_run (void *cls, | ||
240 | struct GNUNET_TESTBED_Operation *op, | ||
241 | void *ca_result, | ||
242 | const char *emsg) | ||
243 | { | ||
244 | struct StatMaster *sm = cls; | ||
245 | |||
246 | sm->stat = ca_result; | ||
247 | GNUNET_assert (NULL != sm->stat); | ||
248 | if (NULL != stats[sm->value].name) | ||
249 | { | ||
250 | GNUNET_STATISTICS_get (sm->stat, | ||
251 | #if 0 | ||
252 | NULL, NULL, | ||
253 | #else | ||
254 | stats[sm->value].subsystem, stats[sm->value].name, | ||
255 | #endif | ||
256 | &get_done, &print_stat, | ||
257 | sm); | ||
258 | return; | ||
259 | } | ||
260 | GNUNET_TESTBED_operation_done (sm->op); | ||
261 | sm->value = 0; | ||
262 | sm->daemon++; | ||
263 | if (NUM_DAEMONS == sm->daemon) | ||
264 | { | ||
265 | GNUNET_free (sm); | ||
266 | cleanup (); | ||
267 | return; | ||
268 | } | ||
269 | sm->op = | ||
270 | GNUNET_TESTBED_service_connect (NULL, | ||
271 | daemons[sm->daemon], | ||
272 | "statistics", | ||
273 | &stat_run, sm, | ||
274 | &statistics_connect_adapter, | ||
275 | &statistics_disconnect_adapter, | ||
276 | NULL); | ||
277 | } | ||
278 | |||
279 | |||
280 | static void | ||
281 | do_report (void *cls) | ||
282 | { | ||
283 | static int download_counter; | ||
284 | const char *type = cls; | ||
285 | struct GNUNET_TIME_Relative del; | ||
286 | char *fancy; | ||
287 | struct StatMaster *sm; | ||
288 | |||
289 | if (0 == | ||
290 | GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (start_time, | ||
291 | TIMEOUT)). | ||
292 | rel_value_us) | ||
293 | { | ||
294 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
295 | "Timeout during download for type `%s', shutting down with error\n", | ||
296 | type); | ||
297 | ok = 1; | ||
298 | cleanup (); | ||
299 | return; | ||
300 | } | ||
301 | del = GNUNET_TIME_absolute_get_duration (start_time); | ||
302 | if (del.rel_value_us == 0) | ||
303 | del.rel_value_us = 1; | ||
304 | fancy = | ||
305 | GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) | ||
306 | * 1000000LL / del.rel_value_us); | ||
307 | fprintf (stderr, "Download speed of type `%s' was %s/s\n", type, fancy); | ||
308 | GNUNET_free (fancy); | ||
309 | if (NUM_DAEMONS != ++download_counter) | ||
310 | return; /* more downloads to come */ | ||
311 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
312 | "Finished all downloads, getting statistics\n"); | ||
313 | sm = GNUNET_new (struct StatMaster); | ||
314 | sm->op = | ||
315 | GNUNET_TESTBED_service_connect (NULL, | ||
316 | daemons[sm->daemon], | ||
317 | "statistics", | ||
318 | &stat_run, sm, | ||
319 | &statistics_connect_adapter, | ||
320 | &statistics_disconnect_adapter, | ||
321 | NULL); | ||
322 | } | ||
323 | |||
324 | |||
325 | static void | ||
326 | do_downloads (void *cls, const struct GNUNET_FS_Uri *u2, | ||
327 | const char *fn) | ||
328 | { | ||
329 | int anonymity; | ||
330 | unsigned int i; | ||
331 | |||
332 | if (NULL == u2) | ||
333 | { | ||
334 | cleanup (); | ||
335 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
336 | "Timeout during upload attempt, shutting down with error\n"); | ||
337 | ok = 1; | ||
338 | return; | ||
339 | } | ||
340 | if (NULL != fn) | ||
341 | fn2 = GNUNET_strdup (fn); | ||
342 | uri2 = GNUNET_FS_uri_dup (u2); | ||
343 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", | ||
344 | (unsigned long long) FILESIZE); | ||
345 | start_time = GNUNET_TIME_absolute_get (); | ||
346 | if (NULL != strstr (progname, "dht")) | ||
347 | anonymity = 0; | ||
348 | else | ||
349 | anonymity = 1; | ||
350 | /* (semi) leach-download(s); not true leaches since | ||
351 | * these peers do participate in sharing, they just | ||
352 | * don't have to offer anything *initially*. */ | ||
353 | for (i = 0; i < NUM_DAEMONS - 2; i++) | ||
354 | GNUNET_FS_TEST_download (daemons[i], TIMEOUT, anonymity, | ||
355 | 0 == (i % 2) ? SEED1 : SEED2, | ||
356 | 0 == (i % 2) ? uri1 : uri2, VERBOSE, &do_report, | ||
357 | "leach"); | ||
358 | /* mutual downloads of (primary) sharing peers */ | ||
359 | GNUNET_FS_TEST_download (daemons[NUM_DAEMONS - 2], TIMEOUT, anonymity, SEED1, | ||
360 | uri1, VERBOSE, &do_report, "seeder 2"); | ||
361 | GNUNET_FS_TEST_download (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, SEED2, | ||
362 | uri2, VERBOSE, &do_report, "seeder 1"); | ||
363 | } | ||
364 | |||
365 | |||
366 | static void | ||
367 | do_publish2 (void *cls, | ||
368 | const struct GNUNET_FS_Uri *u1, | ||
369 | const char *fn) | ||
370 | { | ||
371 | int do_index; | ||
372 | int anonymity; | ||
373 | |||
374 | if (NULL == u1) | ||
375 | { | ||
376 | cleanup (); | ||
377 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
378 | "Timeout during upload attempt, shutting down with error\n"); | ||
379 | ok = 1; | ||
380 | return; | ||
381 | } | ||
382 | if (NULL != fn) | ||
383 | fn1 = GNUNET_strdup (fn); | ||
384 | uri1 = GNUNET_FS_uri_dup (u1); | ||
385 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", | ||
386 | (unsigned long long) FILESIZE); | ||
387 | if (NULL != strstr (progname, "index")) | ||
388 | do_index = GNUNET_YES; | ||
389 | else | ||
390 | do_index = GNUNET_NO; | ||
391 | if (NULL != strstr (progname, "dht")) | ||
392 | anonymity = 0; | ||
393 | else | ||
394 | anonymity = 1; | ||
395 | |||
396 | GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 2], TIMEOUT, anonymity, | ||
397 | do_index, FILESIZE, SEED2, VERBOSE, &do_downloads, | ||
398 | NULL); | ||
399 | } | ||
400 | |||
401 | |||
402 | static void | ||
403 | do_publish1 (void *cls, | ||
404 | struct GNUNET_TESTBED_Operation *op, | ||
405 | const char *emsg) | ||
406 | { | ||
407 | unsigned int *coco = cls; | ||
408 | int do_index; | ||
409 | int anonymity; | ||
410 | |||
411 | GNUNET_TESTBED_operation_done (op); | ||
412 | if (NULL != emsg) | ||
413 | { | ||
414 | cleanup (); | ||
415 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error trying to connect: %s\n", emsg); | ||
416 | ok = 1; | ||
417 | return; | ||
418 | } | ||
419 | if (0 != (--(*coco))) | ||
420 | return; /* more connections to be created */ | ||
421 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", | ||
422 | (unsigned long long) FILESIZE); | ||
423 | if (NULL != strstr (progname, "index")) | ||
424 | do_index = GNUNET_YES; | ||
425 | else | ||
426 | do_index = GNUNET_NO; | ||
427 | if (NULL != strstr (progname, "dht")) | ||
428 | anonymity = 0; | ||
429 | else | ||
430 | anonymity = 1; | ||
431 | GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, | ||
432 | do_index, FILESIZE, SEED1, VERBOSE, &do_publish2, | ||
433 | NULL); | ||
434 | } | ||
435 | |||
436 | |||
437 | static void | ||
438 | do_connect (void *cls, | ||
439 | struct GNUNET_TESTBED_RunHandle *h, | ||
440 | unsigned int num_peers, | ||
441 | struct GNUNET_TESTBED_Peer **peers, | ||
442 | unsigned int links_succeeded, | ||
443 | unsigned int links_failed) | ||
444 | { | ||
445 | static unsigned int coco; | ||
446 | unsigned int i; | ||
447 | unsigned int j; | ||
448 | |||
449 | GNUNET_assert (NUM_DAEMONS == num_peers); | ||
450 | for (i = 0; i < num_peers; i++) | ||
451 | daemons[i] = peers[i]; | ||
452 | for (i = 0; i < NUM_DAEMONS; i++) | ||
453 | for (j = i + 1; j < NUM_DAEMONS; j++) | ||
454 | { | ||
455 | coco++; | ||
456 | GNUNET_TESTBED_overlay_connect (NULL, | ||
457 | &do_publish1, | ||
458 | &coco, | ||
459 | peers[i], | ||
460 | peers[j]); | ||
461 | } | ||
462 | } | ||
463 | |||
464 | |||
465 | int | ||
466 | main (int argc, char *argv[]) | ||
467 | { | ||
468 | progname = argv[0]; | ||
469 | (void) GNUNET_TESTBED_test_run ("perf-gnunet-service-fs-p2p-respect", | ||
470 | "perf_gnunet_service_fs_p2p.conf", | ||
471 | NUM_DAEMONS, | ||
472 | 0, NULL, NULL, | ||
473 | &do_connect, NULL); | ||
474 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); | ||
475 | return ok; | ||
476 | } | ||
477 | |||
478 | |||
479 | /* end of perf_gnunet_service_fs_p2p_respect.c */ | ||
diff --git a/src/fs/plugin_block_fs.c b/src/fs/plugin_block_fs.c deleted file mode 100644 index 43380b3b6..000000000 --- a/src/fs/plugin_block_fs.c +++ /dev/null | |||
@@ -1,443 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2010, 2013, 2021 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/plugin_block_fs.c | ||
23 | * @brief blocks used for file-sharing | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_block_plugin.h" | ||
28 | #include "gnunet_fs_service.h" | ||
29 | #include "block_fs.h" | ||
30 | #include "gnunet_signatures.h" | ||
31 | #include "gnunet_block_group_lib.h" | ||
32 | |||
33 | |||
34 | /** | ||
35 | * Number of bits we set per entry in the bloomfilter. | ||
36 | * Do not change! | ||
37 | */ | ||
38 | #define BLOOMFILTER_K 16 | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Create a new block group. | ||
43 | * | ||
44 | * @param ctx block context in which the block group is created | ||
45 | * @param type type of the block for which we are creating the group | ||
46 | * @param nonce random value used to seed the group creation | ||
47 | * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh | ||
48 | * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh | ||
49 | * @param va variable arguments specific to @a type | ||
50 | * @return block group handle, NULL if block groups are not supported | ||
51 | * by this @a type of block (this is not an error) | ||
52 | */ | ||
53 | static struct GNUNET_BLOCK_Group * | ||
54 | block_plugin_fs_create_group (void *cls, | ||
55 | enum GNUNET_BLOCK_Type type, | ||
56 | uint32_t nonce, | ||
57 | const void *raw_data, | ||
58 | size_t raw_data_size, | ||
59 | va_list va) | ||
60 | { | ||
61 | unsigned int size; | ||
62 | const char *guard; | ||
63 | |||
64 | switch (type) | ||
65 | { | ||
66 | case GNUNET_BLOCK_TYPE_FS_DBLOCK: | ||
67 | GNUNET_break (NULL == va_arg (va, const char *)); | ||
68 | return NULL; | ||
69 | |||
70 | case GNUNET_BLOCK_TYPE_FS_IBLOCK: | ||
71 | GNUNET_break (NULL == va_arg (va, const char *)); | ||
72 | return NULL; | ||
73 | |||
74 | case GNUNET_BLOCK_TYPE_FS_UBLOCK: | ||
75 | guard = va_arg (va, const char *); | ||
76 | if (0 == strcmp (guard, | ||
77 | "seen-set-size")) | ||
78 | { | ||
79 | size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned | ||
80 | int), | ||
81 | BLOOMFILTER_K); | ||
82 | } | ||
83 | else if (0 == strcmp (guard, | ||
84 | "filter-size")) | ||
85 | { | ||
86 | size = va_arg (va, unsigned int); | ||
87 | } | ||
88 | else | ||
89 | { | ||
90 | /* va-args invalid! bad bug, complain! */ | ||
91 | GNUNET_break (0); | ||
92 | size = 8; | ||
93 | } | ||
94 | if (0 == size) | ||
95 | size = raw_data_size; /* not for us to determine, use what we got! */ | ||
96 | GNUNET_break (NULL == va_arg (va, const char *)); | ||
97 | return GNUNET_BLOCK_GROUP_bf_create (cls, | ||
98 | size, | ||
99 | BLOOMFILTER_K, | ||
100 | type, | ||
101 | nonce, | ||
102 | raw_data, | ||
103 | raw_data_size); | ||
104 | |||
105 | default: | ||
106 | GNUNET_break (NULL == va_arg (va, const char *)); | ||
107 | GNUNET_break (0); | ||
108 | return NULL; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | |||
113 | /** | ||
114 | * Function called to validate a reply or a request. For | ||
115 | * request evaluation, simply pass "NULL" for the reply_block. | ||
116 | * Note that it is assumed that the reply has already been | ||
117 | * matched to the key (and signatures checked) as it would | ||
118 | * be done with the #GNUNET_BLOCK_get_key() function. | ||
119 | * | ||
120 | * @param cls closure | ||
121 | * @param ctx block context | ||
122 | * @param type block type | ||
123 | * @param bg group to use for evaluation | ||
124 | * @param eo control flags | ||
125 | * @param query original query (hash) | ||
126 | * @param xquery extrended query data (can be NULL, depending on type) | ||
127 | * @param xquery_size number of bytes in @a xquery | ||
128 | * @param reply_block response to validate | ||
129 | * @param reply_block_size number of bytes in @a reply_block | ||
130 | * @return characterization of result | ||
131 | */ | ||
132 | static enum GNUNET_BLOCK_EvaluationResult | ||
133 | block_plugin_fs_evaluate (void *cls, | ||
134 | struct GNUNET_BLOCK_Context *ctx, | ||
135 | enum GNUNET_BLOCK_Type type, | ||
136 | struct GNUNET_BLOCK_Group *bg, | ||
137 | enum GNUNET_BLOCK_EvaluationOptions eo, | ||
138 | const struct GNUNET_HashCode *query, | ||
139 | const void *xquery, | ||
140 | size_t xquery_size, | ||
141 | const void *reply_block, | ||
142 | size_t reply_block_size) | ||
143 | { | ||
144 | const struct UBlock *ub; | ||
145 | struct GNUNET_HashCode hc; | ||
146 | struct GNUNET_HashCode chash; | ||
147 | |||
148 | switch (type) | ||
149 | { | ||
150 | case GNUNET_BLOCK_TYPE_FS_DBLOCK: | ||
151 | case GNUNET_BLOCK_TYPE_FS_IBLOCK: | ||
152 | if (0 != xquery_size) | ||
153 | { | ||
154 | GNUNET_break_op (0); | ||
155 | return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; | ||
156 | } | ||
157 | if (NULL == reply_block) | ||
158 | return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; | ||
159 | return GNUNET_BLOCK_EVALUATION_OK_LAST; | ||
160 | |||
161 | case GNUNET_BLOCK_TYPE_FS_UBLOCK: | ||
162 | if (0 != xquery_size) | ||
163 | { | ||
164 | GNUNET_break_op (0); | ||
165 | return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; | ||
166 | } | ||
167 | if (NULL == reply_block) | ||
168 | return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; | ||
169 | |||
170 | if (reply_block_size < sizeof(struct UBlock)) | ||
171 | { | ||
172 | GNUNET_break_op (0); | ||
173 | return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; | ||
174 | } | ||
175 | ub = reply_block; | ||
176 | GNUNET_CRYPTO_hash (&ub->verification_key, | ||
177 | sizeof(ub->verification_key), | ||
178 | &hc); | ||
179 | if (0 != memcmp (&hc, | ||
180 | query, | ||
181 | sizeof(struct GNUNET_HashCode))) | ||
182 | { | ||
183 | GNUNET_break_op (0); | ||
184 | return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; | ||
185 | } | ||
186 | if (reply_block_size != ntohl (ub->purpose.size) + sizeof(struct | ||
187 | GNUNET_CRYPTO_EcdsaSignature)) | ||
188 | { | ||
189 | GNUNET_break_op (0); | ||
190 | return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; | ||
191 | } | ||
192 | if ((0 == (eo & GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO)) && | ||
193 | (GNUNET_OK != | ||
194 | GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK, | ||
195 | &ub->purpose, | ||
196 | &ub->signature, | ||
197 | &ub->verification_key))) | ||
198 | { | ||
199 | GNUNET_break_op (0); | ||
200 | return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; | ||
201 | } | ||
202 | GNUNET_CRYPTO_hash (reply_block, | ||
203 | reply_block_size, | ||
204 | &chash); | ||
205 | if (GNUNET_YES == | ||
206 | GNUNET_BLOCK_GROUP_bf_test_and_set (bg, | ||
207 | &chash)) | ||
208 | return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; | ||
209 | return GNUNET_BLOCK_EVALUATION_OK_MORE; | ||
210 | |||
211 | default: | ||
212 | return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | |||
217 | /** | ||
218 | * Function called to obtain the key for a block. | ||
219 | * | ||
220 | * @param cls closure | ||
221 | * @param type block type | ||
222 | * @param block block to get the key for | ||
223 | * @param block_size number of bytes in @a block | ||
224 | * @param key set to the key (query) for the given block | ||
225 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported | ||
226 | * (or if extracting a key from a block of this type does not work) | ||
227 | */ | ||
228 | static enum GNUNET_GenericReturnValue | ||
229 | block_plugin_fs_get_key (void *cls, | ||
230 | enum GNUNET_BLOCK_Type type, | ||
231 | const void *block, | ||
232 | size_t block_size, | ||
233 | struct GNUNET_HashCode *key) | ||
234 | { | ||
235 | const struct UBlock *ub; | ||
236 | |||
237 | switch (type) | ||
238 | { | ||
239 | case GNUNET_BLOCK_TYPE_FS_DBLOCK: | ||
240 | case GNUNET_BLOCK_TYPE_FS_IBLOCK: | ||
241 | GNUNET_CRYPTO_hash (block, | ||
242 | block_size, | ||
243 | key); | ||
244 | return GNUNET_OK; | ||
245 | case GNUNET_BLOCK_TYPE_FS_UBLOCK: | ||
246 | if (block_size < sizeof(struct UBlock)) | ||
247 | { | ||
248 | GNUNET_break (0); | ||
249 | return GNUNET_SYSERR; | ||
250 | } | ||
251 | ub = block; | ||
252 | GNUNET_CRYPTO_hash (&ub->verification_key, | ||
253 | sizeof(ub->verification_key), | ||
254 | key); | ||
255 | return GNUNET_OK; | ||
256 | default: | ||
257 | GNUNET_break (0); | ||
258 | return GNUNET_SYSERR; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | |||
263 | /** | ||
264 | * Function called to validate a query. | ||
265 | * | ||
266 | * @param cls closure | ||
267 | * @param ctx block context | ||
268 | * @param type block type | ||
269 | * @param query original query (hash) | ||
270 | * @param xquery extrended query data (can be NULL, depending on type) | ||
271 | * @param xquery_size number of bytes in @a xquery | ||
272 | * @return #GNUNET_OK if the query is fine, #GNUNET_NO if not | ||
273 | */ | ||
274 | static enum GNUNET_GenericReturnValue | ||
275 | block_plugin_fs_check_query (void *cls, | ||
276 | enum GNUNET_BLOCK_Type type, | ||
277 | const struct GNUNET_HashCode *query, | ||
278 | const void *xquery, | ||
279 | size_t xquery_size) | ||
280 | { | ||
281 | switch (type) | ||
282 | { | ||
283 | case GNUNET_BLOCK_TYPE_FS_DBLOCK: | ||
284 | case GNUNET_BLOCK_TYPE_FS_IBLOCK: | ||
285 | case GNUNET_BLOCK_TYPE_FS_UBLOCK: | ||
286 | if (0 != xquery_size) | ||
287 | { | ||
288 | GNUNET_break_op (0); | ||
289 | return GNUNET_NO; | ||
290 | } | ||
291 | return GNUNET_OK; | ||
292 | default: | ||
293 | return GNUNET_SYSERR; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | |||
298 | /** | ||
299 | * Function called to validate a block for storage. | ||
300 | * | ||
301 | * @param cls closure | ||
302 | * @param type block type | ||
303 | * @param query key for the block (hash), must match exactly | ||
304 | * @param block block data to validate | ||
305 | * @param block_size number of bytes in @a block | ||
306 | * @return #GNUNET_OK if the block is fine, #GNUNET_NO if not | ||
307 | */ | ||
308 | static enum GNUNET_GenericReturnValue | ||
309 | block_plugin_fs_check_block (void *cls, | ||
310 | enum GNUNET_BLOCK_Type type, | ||
311 | const struct GNUNET_HashCode *query, | ||
312 | const void *block, | ||
313 | size_t block_size) | ||
314 | { | ||
315 | switch (type) | ||
316 | { | ||
317 | case GNUNET_BLOCK_TYPE_FS_DBLOCK: | ||
318 | case GNUNET_BLOCK_TYPE_FS_IBLOCK: | ||
319 | return GNUNET_OK; | ||
320 | case GNUNET_BLOCK_TYPE_FS_UBLOCK: | ||
321 | { | ||
322 | const struct UBlock *ub; | ||
323 | |||
324 | if (block_size < sizeof(struct UBlock)) | ||
325 | { | ||
326 | GNUNET_break_op (0); | ||
327 | return GNUNET_NO; | ||
328 | } | ||
329 | ub = block; | ||
330 | if (block_size != | ||
331 | ntohl (ub->purpose.size) + | ||
332 | sizeof (struct GNUNET_CRYPTO_EcdsaSignature)) | ||
333 | { | ||
334 | GNUNET_break_op (0); | ||
335 | return GNUNET_NO; | ||
336 | } | ||
337 | if (GNUNET_OK != | ||
338 | GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK, | ||
339 | &ub->purpose, | ||
340 | &ub->signature, | ||
341 | &ub->verification_key)) | ||
342 | { | ||
343 | GNUNET_break_op (0); | ||
344 | return GNUNET_NO; | ||
345 | } | ||
346 | return GNUNET_OK; | ||
347 | } | ||
348 | default: | ||
349 | return GNUNET_SYSERR; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | |||
354 | /** | ||
355 | * Function called to validate a reply to a request. Note that it is assumed | ||
356 | * that the reply has already been matched to the key (and signatures checked) | ||
357 | * as it would be done with the GetKeyFunction and the | ||
358 | * BlockEvaluationFunction. | ||
359 | * | ||
360 | * @param cls closure | ||
361 | * @param type block type | ||
362 | * @param group which block group to use for evaluation | ||
363 | * @param query original query (hash) | ||
364 | * @param xquery extrended query data (can be NULL, depending on type) | ||
365 | * @param xquery_size number of bytes in @a xquery | ||
366 | * @param reply_block response to validate | ||
367 | * @param reply_block_size number of bytes in @a reply_block | ||
368 | * @return characterization of result | ||
369 | */ | ||
370 | static enum GNUNET_BLOCK_ReplyEvaluationResult | ||
371 | block_plugin_fs_check_reply (void *cls, | ||
372 | enum GNUNET_BLOCK_Type type, | ||
373 | struct GNUNET_BLOCK_Group *group, | ||
374 | const struct GNUNET_HashCode *query, | ||
375 | const void *xquery, | ||
376 | size_t xquery_size, | ||
377 | const void *reply_block, | ||
378 | size_t reply_block_size) | ||
379 | { | ||
380 | switch (type) | ||
381 | { | ||
382 | case GNUNET_BLOCK_TYPE_FS_DBLOCK: | ||
383 | case GNUNET_BLOCK_TYPE_FS_IBLOCK: | ||
384 | return GNUNET_BLOCK_REPLY_OK_LAST; | ||
385 | case GNUNET_BLOCK_TYPE_FS_UBLOCK: | ||
386 | { | ||
387 | struct GNUNET_HashCode chash; | ||
388 | |||
389 | GNUNET_CRYPTO_hash (reply_block, | ||
390 | reply_block_size, | ||
391 | &chash); | ||
392 | if (GNUNET_YES == | ||
393 | GNUNET_BLOCK_GROUP_bf_test_and_set (group, | ||
394 | &chash)) | ||
395 | return GNUNET_BLOCK_REPLY_OK_DUPLICATE; | ||
396 | return GNUNET_BLOCK_REPLY_OK_MORE; | ||
397 | } | ||
398 | default: | ||
399 | return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | |||
404 | /** | ||
405 | * Entry point for the plugin. | ||
406 | */ | ||
407 | void * | ||
408 | libgnunet_plugin_block_fs_init (void *cls) | ||
409 | { | ||
410 | static const enum GNUNET_BLOCK_Type types[] = { | ||
411 | GNUNET_BLOCK_TYPE_FS_DBLOCK, | ||
412 | GNUNET_BLOCK_TYPE_FS_IBLOCK, | ||
413 | GNUNET_BLOCK_TYPE_FS_UBLOCK, | ||
414 | GNUNET_BLOCK_TYPE_ANY /* end of list */ | ||
415 | }; | ||
416 | struct GNUNET_BLOCK_PluginFunctions *api; | ||
417 | |||
418 | api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); | ||
419 | api->evaluate = &block_plugin_fs_evaluate; | ||
420 | api->get_key = &block_plugin_fs_get_key; | ||
421 | api->create_group = &block_plugin_fs_create_group; | ||
422 | api->check_query = &block_plugin_fs_check_query; | ||
423 | api->check_block = &block_plugin_fs_check_block; | ||
424 | api->check_reply = &block_plugin_fs_check_reply; | ||
425 | api->types = types; | ||
426 | return api; | ||
427 | } | ||
428 | |||
429 | |||
430 | /** | ||
431 | * Exit point from the plugin. | ||
432 | */ | ||
433 | void * | ||
434 | libgnunet_plugin_block_fs_done (void *cls) | ||
435 | { | ||
436 | struct GNUNET_BLOCK_PluginFunctions *api = cls; | ||
437 | |||
438 | GNUNET_free (api); | ||
439 | return NULL; | ||
440 | } | ||
441 | |||
442 | |||
443 | /* end of plugin_block_fs.c */ | ||
diff --git a/src/fs/test_fs.c b/src/fs/test_fs.c deleted file mode 100644 index 7a57e98b0..000000000 --- a/src/fs/test_fs.c +++ /dev/null | |||
@@ -1,262 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs.c | ||
23 | * @brief testcase for FS (upload-search-download-unindex) | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util.h" | ||
29 | #include "gnunet_fsui_lib.h" | ||
30 | |||
31 | #define DEBUG_VERBOSE GNUNET_NO | ||
32 | |||
33 | #define CHECK(a) if (! (a)) { ok = GNUNET_NO; GNUNET_GE_BREAK (NULL, 0); \ | ||
34 | goto FAILURE; } | ||
35 | |||
36 | static char * | ||
37 | makeName (unsigned int i) | ||
38 | { | ||
39 | char *fn; | ||
40 | |||
41 | fn = GNUNET_malloc (strlen ("/tmp/gnunet-basic_fsui_test/BASIC_FSUI_TEST") | ||
42 | + 14); | ||
43 | GNUNET_snprintf (fn, | ||
44 | strlen ("/tmp/gnunet-basic_fsui_test/BASIC_FSUI_TEST") + 14, | ||
45 | "/tmp/gnunet-basic_fsui_test/BASIC_FSUI_TEST%u", i); | ||
46 | GNUNET_disk_directory_create_for_file (NULL, fn); | ||
47 | return fn; | ||
48 | } | ||
49 | |||
50 | |||
51 | static enum GNUNET_FSUI_EventType lastEvent; | ||
52 | |||
53 | static struct GNUNET_MetaData *search_meta; | ||
54 | |||
55 | static struct GNUNET_ECRS_URI *search_uri; | ||
56 | |||
57 | static struct GNUNET_FSUI_Context *ctx; | ||
58 | |||
59 | static void * | ||
60 | eventCallback (void *cls, const GNUNET_FSUI_Event *event) | ||
61 | { | ||
62 | static char unused; | ||
63 | |||
64 | switch (event->type) | ||
65 | { | ||
66 | case GNUNET_FSUI_search_resumed: | ||
67 | case GNUNET_FSUI_download_resumed: | ||
68 | case GNUNET_FSUI_upload_resumed: | ||
69 | case GNUNET_FSUI_unindex_resumed: | ||
70 | return &unused; | ||
71 | |||
72 | case GNUNET_FSUI_search_result: | ||
73 | #if DEBUG_VERBOSE | ||
74 | printf ("Received search result\n"); | ||
75 | #endif | ||
76 | search_uri = GNUNET_ECRS_uri_duplicate (event->data.SearchResult.fi.uri); | ||
77 | search_meta = GNUNET_meta_data_duplicate (event->data.SearchResult.fi.meta); | ||
78 | break; | ||
79 | |||
80 | case GNUNET_FSUI_upload_completed: | ||
81 | #if DEBUG_VERBOSE | ||
82 | printf ("Upload complete.\n"); | ||
83 | #endif | ||
84 | break; | ||
85 | |||
86 | case GNUNET_FSUI_download_completed: | ||
87 | #if DEBUG_VERBOSE | ||
88 | printf ("Download complete.\n"); | ||
89 | #endif | ||
90 | break; | ||
91 | |||
92 | case GNUNET_FSUI_unindex_completed: | ||
93 | #if DEBUG_VERBOSE | ||
94 | printf ("Unindex complete.\n"); | ||
95 | #endif | ||
96 | break; | ||
97 | |||
98 | default: | ||
99 | break; | ||
100 | } | ||
101 | lastEvent = event->type; | ||
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | |||
106 | #define START_DAEMON 1 | ||
107 | |||
108 | int | ||
109 | main (int argc, char *argv[]) | ||
110 | { | ||
111 | #if START_DAEMON | ||
112 | struct GNUNET_OS_Process *daemon; | ||
113 | #endif | ||
114 | int ok; | ||
115 | struct GNUNET_ECRS_URI *uri; | ||
116 | char *filename = NULL; | ||
117 | |||
118 | char *keywords[] = { | ||
119 | "fsui_foo", | ||
120 | "fsui_bar", | ||
121 | }; | ||
122 | char keyword[40]; | ||
123 | char *fn; | ||
124 | int prog; | ||
125 | struct GNUNET_MetaData *meta; | ||
126 | struct GNUNET_ECRS_URI *kuri; | ||
127 | struct GNUNET_GC_Configuration *cfg; | ||
128 | struct GNUNET_FSUI_UploadList *upload = NULL; | ||
129 | struct GNUNET_FSUI_SearchList *search = NULL; | ||
130 | struct GNUNET_FSUI_UnindexList *unindex = NULL; | ||
131 | struct GNUNET_FSUI_DownloadList *download = NULL; | ||
132 | |||
133 | cfg = GNUNET_GC_create (); | ||
134 | if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf")) | ||
135 | { | ||
136 | GNUNET_GC_free (cfg); | ||
137 | return -1; | ||
138 | } | ||
139 | #if START_DAEMON | ||
140 | daemon = GNUNET_daemon_start (NULL, cfg, "peer.conf", GNUNET_NO); | ||
141 | GNUNET_GE_ASSERT (NULL, daemon != NULL); | ||
142 | CHECK (GNUNET_OK == | ||
143 | GNUNET_wait_for_daemon_running (NULL, cfg, 60 * GNUNET_CRON_SECONDS)); | ||
144 | #endif | ||
145 | GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS); /* give apps time to start */ | ||
146 | ok = GNUNET_YES; | ||
147 | |||
148 | /* ACTUAL TEST CODE */ | ||
149 | ctx = GNUNET_FSUI_start (NULL, cfg, "basic_fsui_test", 32, /* thread pool size */ | ||
150 | GNUNET_NO, /* no resume */ | ||
151 | &eventCallback, NULL); | ||
152 | CHECK (ctx != NULL); | ||
153 | filename = makeName (42); | ||
154 | GNUNET_disk_file_write (NULL, filename, "foo bar test!", | ||
155 | strlen ("foo bar test!"), "600"); | ||
156 | meta = GNUNET_meta_data_create (); | ||
157 | kuri = | ||
158 | GNUNET_ECRS_keyword_command_line_to_uri (NULL, 2, | ||
159 | (const char **) keywords); | ||
160 | /* upload */ | ||
161 | upload = GNUNET_FSUI_upload_start (ctx, filename, | ||
162 | (GNUNET_FSUI_DirectoryScanCallback) | ||
163 | & GNUNET_disk_directory_scan, NULL, 0, /* anonymity */ | ||
164 | 0, /* priority */ | ||
165 | GNUNET_YES, GNUNET_NO, GNUNET_NO, | ||
166 | GNUNET_get_time () + 5 * GNUNET_CRON_HOURS, | ||
167 | meta, kuri, kuri); | ||
168 | CHECK (upload != NULL); | ||
169 | GNUNET_ECRS_uri_destroy (kuri); | ||
170 | GNUNET_meta_data_destroy (meta); | ||
171 | prog = 0; | ||
172 | while (lastEvent != GNUNET_FSUI_upload_completed) | ||
173 | { | ||
174 | prog++; | ||
175 | CHECK (prog < 10000) GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS); | ||
176 | if (GNUNET_shutdown_test () == GNUNET_YES) | ||
177 | break; | ||
178 | } | ||
179 | |||
180 | /* search */ | ||
181 | GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0], keywords[1]); | ||
182 | uri = GNUNET_ECRS_keyword_string_to_uri (NULL, keyword); | ||
183 | search = GNUNET_FSUI_search_start (ctx, 0, uri); | ||
184 | GNUNET_ECRS_uri_destroy (uri); | ||
185 | CHECK (search != NULL); | ||
186 | prog = 0; | ||
187 | while (lastEvent != GNUNET_FSUI_search_result) | ||
188 | { | ||
189 | prog++; | ||
190 | CHECK (prog < 10000); | ||
191 | GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS); | ||
192 | if (GNUNET_shutdown_test () == GNUNET_YES) | ||
193 | break; | ||
194 | } | ||
195 | GNUNET_FSUI_search_abort (search); | ||
196 | GNUNET_FSUI_search_stop (search); | ||
197 | |||
198 | /* download */ | ||
199 | fn = makeName (43); | ||
200 | download = | ||
201 | GNUNET_FSUI_download_start (ctx, 0, GNUNET_NO, search_uri, search_meta, | ||
202 | fn, NULL, NULL); | ||
203 | GNUNET_free (fn); | ||
204 | prog = 0; | ||
205 | while (lastEvent != GNUNET_FSUI_download_completed) | ||
206 | { | ||
207 | prog++; | ||
208 | CHECK (prog < 10000); | ||
209 | GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS); | ||
210 | if (GNUNET_shutdown_test () == GNUNET_YES) | ||
211 | break; | ||
212 | } | ||
213 | GNUNET_FSUI_download_stop (download); | ||
214 | download = NULL; | ||
215 | GNUNET_ECRS_uri_destroy (search_uri); | ||
216 | GNUNET_meta_data_destroy (search_meta); | ||
217 | /* unindex */ | ||
218 | unindex = GNUNET_FSUI_unindex_start (ctx, filename); | ||
219 | prog = 0; | ||
220 | while (lastEvent != GNUNET_FSUI_unindex_completed) | ||
221 | { | ||
222 | prog++; | ||
223 | CHECK (prog < 10000); | ||
224 | GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS); | ||
225 | if (GNUNET_shutdown_test () == GNUNET_YES) | ||
226 | break; | ||
227 | } | ||
228 | if (lastEvent != GNUNET_FSUI_unindex_completed) | ||
229 | GNUNET_FSUI_unindex_abort (unindex); | ||
230 | GNUNET_FSUI_unindex_stop (unindex); | ||
231 | |||
232 | |||
233 | /* END OF TEST CODE */ | ||
234 | FAILURE: | ||
235 | if (ctx != NULL) | ||
236 | GNUNET_FSUI_stop (ctx); | ||
237 | if (filename != NULL) | ||
238 | { | ||
239 | unlink (filename); | ||
240 | GNUNET_free (filename); | ||
241 | } | ||
242 | if (download != NULL) | ||
243 | { | ||
244 | GNUNET_FSUI_download_abort (download); | ||
245 | GNUNET_FSUI_download_stop (download); | ||
246 | } | ||
247 | filename = makeName (43); | ||
248 | /* TODO: verify file 'filename(42)' == file 'filename(43)' */ | ||
249 | unlink (filename); | ||
250 | GNUNET_free (filename); | ||
251 | |||
252 | #if START_DAEMON | ||
253 | GNUNET_GE_ASSERT (NULL, GNUNET_OK == GNUNET_daemon_stop (NULL, daemon)); | ||
254 | GNUNET_OS_process_destroy (daemon); | ||
255 | #endif | ||
256 | GNUNET_GC_free (cfg); | ||
257 | |||
258 | return (ok == GNUNET_YES) ? 0 : 1; | ||
259 | } | ||
260 | |||
261 | |||
262 | /* end of test_fs.c */ | ||
diff --git a/src/fs/test_fs_data.conf b/src/fs/test_fs_data.conf deleted file mode 100644 index 993141064..000000000 --- a/src/fs/test_fs_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-data/ | ||
4 | |||
5 | [fs] | ||
6 | ACTIVEMIGRATION = NO | ||
7 | |||
diff --git a/src/fs/test_fs_defaults.conf b/src/fs/test_fs_defaults.conf deleted file mode 100644 index 6ead78257..000000000 --- a/src/fs/test_fs_defaults.conf +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | |||
3 | [PATHS] | ||
4 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-lib/ | ||
5 | |||
6 | [transport] | ||
7 | PLUGINS = tcp | ||
8 | |||
9 | [nat] | ||
10 | DISABLEV6 = YES | ||
11 | ENABLE_UPNP = NO | ||
12 | BEHIND_NAT = NO | ||
13 | ALLOW_NAT = NO | ||
14 | INTERNAL_ADDRESS = 127.0.0.1 | ||
15 | EXTERNAL_ADDRESS = 127.0.0.1 | ||
16 | USE_LOCALADDR = YES | ||
17 | RETURN_LOCAL_ADDRESSES = YES | ||
18 | |||
19 | [datastore] | ||
20 | QUOTA = 100 MB | ||
21 | |||
22 | [transport-tcp] | ||
23 | BINDTO = 127.0.0.1 | ||
24 | PORT = 54368 | ||
25 | |||
26 | [peerinfo] | ||
27 | NO_IO = YES | ||
28 | |||
29 | [ats] | ||
30 | WAN_QUOTA_IN = 65536 | ||
31 | WAN_QUOTA_OUT = 65536 | ||
32 | |||
33 | [fs] | ||
34 | CONTENT_CACHING = YES | ||
35 | CONTENT_PUSHING = YES | ||
36 | DELAY = YES | ||
37 | # PREFIX = valgrind --leak-check=full | ||
38 | |||
39 | [dhtcache] | ||
40 | QUOTA=65536 | ||
41 | DATABASE=heap | ||
42 | |||
43 | [cadet] | ||
44 | REFRESH_PATH_TIME = 30 min | ||
45 | |||
46 | [nse] | ||
47 | WORKBITS = 0 | ||
diff --git a/src/fs/test_fs_directory.c b/src/fs/test_fs_directory.c deleted file mode 100644 index 908e7c555..000000000 --- a/src/fs/test_fs_directory.c +++ /dev/null | |||
@@ -1,186 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2005, 2006, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_directory.c | ||
22 | * @brief Test for fs_directory.c | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #if HAVE_EXTRACTOR_H | ||
27 | #include <extractor.h> | ||
28 | #endif | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_fs_service.h" | ||
31 | #include "fs_api.h" | ||
32 | |||
33 | #define ABORT() { fprintf (stderr, "Error at %s:%d\n", __FILE__, __LINE__); \ | ||
34 | return 1; } | ||
35 | |||
36 | struct PCLS | ||
37 | { | ||
38 | struct GNUNET_FS_Uri **uri; | ||
39 | struct GNUNET_CONTAINER_MetaData **md; | ||
40 | unsigned int pos; | ||
41 | unsigned int max; | ||
42 | }; | ||
43 | |||
44 | static void | ||
45 | processor (void *cls, const char *filename, const struct GNUNET_FS_Uri *uri, | ||
46 | const struct GNUNET_CONTAINER_MetaData *md, size_t length, | ||
47 | const void *data) | ||
48 | { | ||
49 | struct PCLS *p = cls; | ||
50 | int i; | ||
51 | |||
52 | if (NULL == uri) | ||
53 | return; /* ignore directory's meta data */ | ||
54 | for (i = 0; i < p->max; i++) | ||
55 | { | ||
56 | if (GNUNET_CONTAINER_meta_data_test_equal (p->md[i], md) && | ||
57 | GNUNET_FS_uri_test_equal (p->uri[i], uri)) | ||
58 | { | ||
59 | p->pos++; | ||
60 | return; | ||
61 | } | ||
62 | } | ||
63 | fprintf (stderr, "Error at %s:%d\n", __FILE__, __LINE__); | ||
64 | } | ||
65 | |||
66 | |||
67 | static int | ||
68 | testDirectory (unsigned int i) | ||
69 | { | ||
70 | struct GNUNET_FS_DirectoryBuilder *db; | ||
71 | char *data; | ||
72 | size_t dlen; | ||
73 | struct GNUNET_FS_Uri **uris; | ||
74 | struct GNUNET_CONTAINER_MetaData **mds; | ||
75 | struct GNUNET_CONTAINER_MetaData *meta; | ||
76 | struct PCLS cls; | ||
77 | char *emsg; | ||
78 | int p; | ||
79 | int q; | ||
80 | char uri[512]; | ||
81 | char txt[128]; | ||
82 | int ret = 0; | ||
83 | struct GNUNET_TIME_Absolute start; | ||
84 | const char *s; | ||
85 | |||
86 | cls.max = i; | ||
87 | uris = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri *) * i); | ||
88 | mds = GNUNET_malloc (sizeof(struct GNUNET_CONTAINER_MetaData *) * i); | ||
89 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
90 | GNUNET_CONTAINER_meta_data_insert (meta, "<test>", EXTRACTOR_METATYPE_TITLE, | ||
91 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
92 | "A title", strlen ("A title") + 1); | ||
93 | GNUNET_CONTAINER_meta_data_insert (meta, "<test>", | ||
94 | EXTRACTOR_METATYPE_AUTHOR_NAME, | ||
95 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
96 | "An author", strlen ("An author") + 1); | ||
97 | for (p = 0; p < i; p++) | ||
98 | { | ||
99 | mds[p] = GNUNET_CONTAINER_meta_data_create (); | ||
100 | for (q = 0; q <= p; q++) | ||
101 | { | ||
102 | GNUNET_snprintf (txt, sizeof(txt), "%u -- %u\n", p, q); | ||
103 | GNUNET_CONTAINER_meta_data_insert (mds[p], "<test>", | ||
104 | #if HAVE_EXTRACTOR_H && HAVE_LIBEXTRACTOR | ||
105 | q % EXTRACTOR_metatype_get_max (), | ||
106 | #else | ||
107 | q % 128, | ||
108 | #endif | ||
109 | EXTRACTOR_METAFORMAT_UTF8, | ||
110 | "text/plain", txt, strlen (txt) + 1); | ||
111 | } | ||
112 | GNUNET_snprintf (uri, sizeof(uri), | ||
113 | "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.%u", | ||
114 | p); | ||
115 | emsg = NULL; | ||
116 | uris[p] = GNUNET_FS_uri_parse (uri, &emsg); | ||
117 | if (uris[p] == NULL) | ||
118 | { | ||
119 | GNUNET_CONTAINER_meta_data_destroy (mds[p]); | ||
120 | while (--p > 0) | ||
121 | { | ||
122 | GNUNET_CONTAINER_meta_data_destroy (mds[p]); | ||
123 | GNUNET_FS_uri_destroy (uris[p]); | ||
124 | } | ||
125 | GNUNET_free (mds); | ||
126 | GNUNET_free (uris); | ||
127 | GNUNET_free (emsg); | ||
128 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
129 | ABORT (); /* error in testcase */ | ||
130 | } | ||
131 | GNUNET_assert (emsg == NULL); | ||
132 | } | ||
133 | start = GNUNET_TIME_absolute_get (); | ||
134 | db = GNUNET_FS_directory_builder_create (meta); | ||
135 | for (p = 0; p < i; p++) | ||
136 | GNUNET_FS_directory_builder_add (db, uris[p], mds[p], NULL); | ||
137 | GNUNET_FS_directory_builder_finish (db, &dlen, (void **) &data); | ||
138 | s = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration | ||
139 | (start), | ||
140 | GNUNET_YES); | ||
141 | fprintf (stdout, | ||
142 | "Creating directory with %u entries and total size %llu took %s\n", | ||
143 | i, (unsigned long long) dlen, s); | ||
144 | if (i < 100) | ||
145 | { | ||
146 | cls.pos = 0; | ||
147 | cls.uri = uris; | ||
148 | cls.md = mds; | ||
149 | GNUNET_FS_directory_list_contents (dlen, data, 0, &processor, &cls); | ||
150 | GNUNET_assert (cls.pos == i); | ||
151 | } | ||
152 | GNUNET_free (data); | ||
153 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
154 | for (p = 0; p < i; p++) | ||
155 | { | ||
156 | GNUNET_CONTAINER_meta_data_destroy (mds[p]); | ||
157 | GNUNET_FS_uri_destroy (uris[p]); | ||
158 | } | ||
159 | GNUNET_free (uris); | ||
160 | GNUNET_free (mds); | ||
161 | return ret; | ||
162 | } | ||
163 | |||
164 | |||
165 | int | ||
166 | main (int argc, char *argv[]) | ||
167 | { | ||
168 | int failureCount = 0; | ||
169 | int i; | ||
170 | |||
171 | GNUNET_log_setup ("test_fs_directory", | ||
172 | #if VERBOSE | ||
173 | "DEBUG", | ||
174 | #else | ||
175 | "WARNING", | ||
176 | #endif | ||
177 | NULL); | ||
178 | for (i = 17; i < 1000; i *= 2) | ||
179 | failureCount += testDirectory (i); | ||
180 | if (failureCount != 0) | ||
181 | return 1; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | |||
186 | /* end of test_fs_directory.c */ | ||
diff --git a/src/fs/test_fs_download.c b/src/fs/test_fs_download.c deleted file mode 100644 index 2fe0da77c..000000000 --- a/src/fs/test_fs_download.c +++ /dev/null | |||
@@ -1,368 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009, 2011, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_download.c | ||
23 | * @brief simple testcase for simple publish + download operation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | #include "gnunet_testing_lib.h" | ||
31 | #include <gauger.h> | ||
32 | |||
33 | /** | ||
34 | * File-size we use for testing. | ||
35 | */ | ||
36 | #define FILESIZE (1024 * 1024 * 2) | ||
37 | |||
38 | /** | ||
39 | * How long until we give up on transmitting the message? | ||
40 | */ | ||
41 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) | ||
42 | |||
43 | /** | ||
44 | * How long should our test-content live? | ||
45 | */ | ||
46 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
47 | |||
48 | static unsigned int anonymity_level; | ||
49 | |||
50 | static int indexed; | ||
51 | |||
52 | static struct GNUNET_TIME_Absolute start; | ||
53 | |||
54 | static struct GNUNET_FS_Handle *fs; | ||
55 | |||
56 | static struct GNUNET_FS_DownloadContext *download; | ||
57 | |||
58 | static struct GNUNET_FS_PublishContext *publish; | ||
59 | |||
60 | static struct GNUNET_SCHEDULER_Task *timeout_kill; | ||
61 | |||
62 | static char *fn; | ||
63 | |||
64 | static char *fn1; | ||
65 | |||
66 | static int err; | ||
67 | |||
68 | |||
69 | static void | ||
70 | timeout_kill_task (void *cls) | ||
71 | { | ||
72 | if (NULL != download) | ||
73 | { | ||
74 | GNUNET_FS_download_stop (download, GNUNET_YES); | ||
75 | download = NULL; | ||
76 | } | ||
77 | else if (NULL != publish) | ||
78 | { | ||
79 | GNUNET_FS_publish_stop (publish); | ||
80 | publish = NULL; | ||
81 | } | ||
82 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout downloading file\n"); | ||
83 | timeout_kill = NULL; | ||
84 | err = 1; | ||
85 | } | ||
86 | |||
87 | |||
88 | static void | ||
89 | abort_publish_task (void *cls) | ||
90 | { | ||
91 | if (NULL != publish) | ||
92 | { | ||
93 | GNUNET_FS_publish_stop (publish); | ||
94 | publish = NULL; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | |||
99 | static void | ||
100 | stop_fs_task (void *cls) | ||
101 | { | ||
102 | GNUNET_FS_stop (fs); | ||
103 | fs = NULL; | ||
104 | } | ||
105 | |||
106 | |||
107 | static void | ||
108 | abort_download_task (void *cls) | ||
109 | { | ||
110 | uint64_t size; | ||
111 | |||
112 | if (NULL != download) | ||
113 | { | ||
114 | GNUNET_FS_download_stop (download, GNUNET_YES); | ||
115 | download = NULL; | ||
116 | } | ||
117 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES, | ||
118 | GNUNET_NO)); | ||
119 | GNUNET_assert (size == FILESIZE); | ||
120 | GNUNET_DISK_directory_remove (fn); | ||
121 | GNUNET_free (fn); | ||
122 | fn = NULL; | ||
123 | GNUNET_SCHEDULER_cancel (timeout_kill); | ||
124 | timeout_kill = NULL; | ||
125 | } | ||
126 | |||
127 | |||
128 | static void * | ||
129 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
130 | { | ||
131 | switch (event->status) | ||
132 | { | ||
133 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
134 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
135 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
136 | (unsigned long long) event->value.publish.completed, | ||
137 | (unsigned long long) event->value.publish.size, | ||
138 | event->value.publish.specifics.progress.depth, | ||
139 | (unsigned long long) event->value.publish.specifics. | ||
140 | progress.offset); | ||
141 | break; | ||
142 | |||
143 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
144 | break; | ||
145 | |||
146 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
147 | fprintf (stdout, | ||
148 | "Publishing complete, %llu kb/s.\n", | ||
149 | (unsigned long long) (FILESIZE * 1000000LL | ||
150 | / (1 | ||
151 | + GNUNET_TIME_absolute_get_duration | ||
152 | (start).rel_value_us) / 1024LL)); | ||
153 | GAUGER ("FS", | ||
154 | (GNUNET_YES == indexed) | ||
155 | ? "Publishing speed (indexing)" | ||
156 | : "Publishing speed (insertion)", | ||
157 | (unsigned long long) (FILESIZE * 1000000LL | ||
158 | / (1 | ||
159 | + GNUNET_TIME_absolute_get_duration | ||
160 | (start).rel_value_us) / 1024LL), "kb/s"); | ||
161 | fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst"); | ||
162 | start = GNUNET_TIME_absolute_get (); | ||
163 | download = | ||
164 | GNUNET_FS_download_start (fs, | ||
165 | event->value.publish.specifics. | ||
166 | completed.chk_uri, NULL, fn, NULL, 0, | ||
167 | FILESIZE, anonymity_level, | ||
168 | GNUNET_FS_DOWNLOAD_OPTION_NONE, | ||
169 | "download", NULL); | ||
170 | GNUNET_assert (download != NULL); | ||
171 | break; | ||
172 | |||
173 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: | ||
174 | fprintf (stdout, | ||
175 | "Download complete, %llu kb/s.\n", | ||
176 | (unsigned long long) (FILESIZE * 1000000LL | ||
177 | / (1 | ||
178 | + GNUNET_TIME_absolute_get_duration | ||
179 | (start).rel_value_us) / 1024LL)); | ||
180 | GAUGER ("FS", | ||
181 | (GNUNET_YES == indexed) | ||
182 | ? "Local download speed (indexed)" | ||
183 | : "Local download speed (inserted)", | ||
184 | (unsigned long long) (FILESIZE * 1000000LL | ||
185 | / (1 | ||
186 | + GNUNET_TIME_absolute_get_duration | ||
187 | (start).rel_value_us) / 1024LL), "kb/s"); | ||
188 | GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); | ||
189 | break; | ||
190 | |||
191 | case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: | ||
192 | GNUNET_assert (download == event->value.download.dc); | ||
193 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
194 | "Download is progressing (%llu/%llu at level %u off %llu)...\n", | ||
195 | (unsigned long long) event->value.download.completed, | ||
196 | (unsigned long long) event->value.download.size, | ||
197 | event->value.download.specifics.progress.depth, | ||
198 | (unsigned long long) event->value.download.specifics. | ||
199 | progress.offset); | ||
200 | break; | ||
201 | |||
202 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
203 | fprintf (stderr, "Error publishing file: %s\n", | ||
204 | event->value.publish.specifics.error.message); | ||
205 | GNUNET_break (0); | ||
206 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
207 | GNUNET_SCHEDULER_shutdown (); | ||
208 | break; | ||
209 | |||
210 | case GNUNET_FS_STATUS_DOWNLOAD_ERROR: | ||
211 | fprintf (stderr, "Error downloading file: %s\n", | ||
212 | event->value.download.specifics.error.message); | ||
213 | GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); | ||
214 | GNUNET_SCHEDULER_shutdown (); | ||
215 | break; | ||
216 | |||
217 | case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: | ||
218 | case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: | ||
219 | break; | ||
220 | |||
221 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
222 | GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); | ||
223 | GNUNET_assert (NULL == event->value.publish.pctx); | ||
224 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
225 | GNUNET_assert (0 == event->value.publish.completed); | ||
226 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
227 | break; | ||
228 | |||
229 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
230 | GNUNET_assert (publish == event->value.publish.pc); | ||
231 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
232 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
233 | GNUNET_SCHEDULER_add_now (&stop_fs_task, NULL); | ||
234 | break; | ||
235 | |||
236 | case GNUNET_FS_STATUS_DOWNLOAD_START: | ||
237 | GNUNET_assert (0 == strcmp ("download", event->value.download.cctx)); | ||
238 | GNUNET_assert (NULL == event->value.download.pctx); | ||
239 | GNUNET_assert (NULL != event->value.download.uri); | ||
240 | GNUNET_assert (0 == strcmp (fn, event->value.download.filename)); | ||
241 | GNUNET_assert (FILESIZE == event->value.download.size); | ||
242 | GNUNET_assert (0 == event->value.download.completed); | ||
243 | GNUNET_assert (1 == event->value.download.anonymity); | ||
244 | break; | ||
245 | |||
246 | case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: | ||
247 | GNUNET_assert (download == event->value.download.dc); | ||
248 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
249 | break; | ||
250 | |||
251 | default: | ||
252 | printf ("Unexpected event: %d\n", event->status); | ||
253 | break; | ||
254 | } | ||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | |||
259 | static void | ||
260 | run (void *cls, | ||
261 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
262 | struct GNUNET_TESTING_Peer *peer) | ||
263 | { | ||
264 | const char *binary_name = cls; | ||
265 | const char *keywords[] = { | ||
266 | "down_foo", | ||
267 | "down_bar", | ||
268 | }; | ||
269 | char *buf; | ||
270 | struct GNUNET_CONTAINER_MetaData *meta; | ||
271 | struct GNUNET_FS_Uri *kuri; | ||
272 | struct GNUNET_FS_FileInformation *fi; | ||
273 | size_t i; | ||
274 | struct GNUNET_FS_BlockOptions bo; | ||
275 | |||
276 | if (GNUNET_YES == | ||
277 | GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
278 | "download-test", | ||
279 | "USE_STREAM")) | ||
280 | anonymity_level = 0; | ||
281 | else | ||
282 | anonymity_level = 1; | ||
283 | fs = GNUNET_FS_start (cfg, binary_name, &progress_cb, NULL, | ||
284 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
285 | GNUNET_assert (NULL != fs); | ||
286 | buf = GNUNET_malloc (FILESIZE); | ||
287 | for (i = 0; i < FILESIZE; i++) | ||
288 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
289 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
290 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
291 | bo.content_priority = 42; | ||
292 | bo.anonymity_level = anonymity_level; | ||
293 | bo.replication_level = 0; | ||
294 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
295 | |||
296 | if (GNUNET_YES == | ||
297 | GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
298 | "download-test", | ||
299 | "USE_INDEX")) | ||
300 | { | ||
301 | fn1 = GNUNET_DISK_mktemp ("gnunet-download-indexed-test"); | ||
302 | (void) GNUNET_DISK_directory_remove (fn1); | ||
303 | GNUNET_assert (GNUNET_OK == | ||
304 | GNUNET_DISK_fn_write (fn1, | ||
305 | buf, | ||
306 | FILESIZE, | ||
307 | GNUNET_DISK_PERM_USER_READ | ||
308 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
309 | GNUNET_free (buf); | ||
310 | fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", | ||
311 | fn1, | ||
312 | kuri, meta, GNUNET_YES, | ||
313 | &bo); | ||
314 | indexed = GNUNET_YES; | ||
315 | } | ||
316 | else | ||
317 | { | ||
318 | fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", | ||
319 | FILESIZE, buf, kuri, meta, | ||
320 | GNUNET_NO, &bo); | ||
321 | /* note: buf will be free'd as part of 'fi' now */ | ||
322 | indexed = GNUNET_NO; | ||
323 | } | ||
324 | GNUNET_FS_uri_destroy (kuri); | ||
325 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
326 | GNUNET_assert (NULL != fi); | ||
327 | timeout_kill = | ||
328 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL); | ||
329 | start = GNUNET_TIME_absolute_get (); | ||
330 | publish = | ||
331 | GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, | ||
332 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
333 | GNUNET_assert (publish != NULL); | ||
334 | } | ||
335 | |||
336 | |||
337 | int | ||
338 | main (int argc, char *argv[]) | ||
339 | { | ||
340 | const char *binary_name; | ||
341 | const char *config_name; | ||
342 | |||
343 | binary_name = "test-fs-download"; | ||
344 | config_name = "test_fs_download_data.conf"; | ||
345 | if (NULL != strstr (argv[0], "indexed")) | ||
346 | { | ||
347 | binary_name = "test-fs-download-indexed"; | ||
348 | config_name = "test_fs_download_indexed.conf"; | ||
349 | } | ||
350 | if (NULL != strstr (argv[0], "cadet")) | ||
351 | { | ||
352 | binary_name = "test-fs-download-cadet"; | ||
353 | config_name = "test_fs_download_cadet.conf"; | ||
354 | } | ||
355 | if (0 != GNUNET_TESTING_peer_run (binary_name, | ||
356 | config_name, | ||
357 | &run, (void *) binary_name)) | ||
358 | return 1; | ||
359 | if (NULL != fn1) | ||
360 | { | ||
361 | unlink (fn1); | ||
362 | GNUNET_free (fn1); | ||
363 | } | ||
364 | return err; | ||
365 | } | ||
366 | |||
367 | |||
368 | /* end of test_fs_download.c */ | ||
diff --git a/src/fs/test_fs_download_data.conf b/src/fs/test_fs_download_data.conf deleted file mode 100644 index 160dec3ae..000000000 --- a/src/fs/test_fs_download_data.conf +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-download/ | ||
4 | |||
5 | [download-test] | ||
6 | # set to 'YES' to test non-anonymous download | ||
7 | USE_STREAM = NO | ||
8 | |||
9 | # set to 'YES' to use indexing | ||
10 | USE_INDEX = NO \ No newline at end of file | ||
diff --git a/src/fs/test_fs_download_indexed.conf b/src/fs/test_fs_download_indexed.conf deleted file mode 100644 index 7f1e36935..000000000 --- a/src/fs/test_fs_download_indexed.conf +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-download/ | ||
4 | |||
5 | [download-test] | ||
6 | # set to 'YES' to test non-anonymous download | ||
7 | USE_STREAM = NO | ||
8 | |||
9 | # set to 'YES' to use indexing | ||
10 | USE_INDEX = YES | ||
diff --git a/src/fs/test_fs_download_persistence.c b/src/fs/test_fs_download_persistence.c deleted file mode 100644 index 35d4ed441..000000000 --- a/src/fs/test_fs_download_persistence.c +++ /dev/null | |||
@@ -1,351 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_download_persistence.c | ||
23 | * @brief simple testcase for persistence of simple download operation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE (1024 * 1024 * 2) | ||
35 | |||
36 | /** | ||
37 | * How long until we give up on transmitting the message? | ||
38 | */ | ||
39 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
40 | |||
41 | /** | ||
42 | * How long should our test-content live? | ||
43 | */ | ||
44 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
45 | |||
46 | |||
47 | static struct GNUNET_TIME_Absolute start; | ||
48 | |||
49 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
50 | |||
51 | static struct GNUNET_FS_Handle *fs; | ||
52 | |||
53 | static struct GNUNET_FS_DownloadContext *download; | ||
54 | |||
55 | static struct GNUNET_FS_PublishContext *publish; | ||
56 | |||
57 | static struct GNUNET_SCHEDULER_Task *timeout_kill; | ||
58 | |||
59 | static char *fn; | ||
60 | |||
61 | static int err; | ||
62 | |||
63 | |||
64 | static void | ||
65 | timeout_kill_task (void *cls) | ||
66 | { | ||
67 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout downloading file\n"); | ||
68 | if (download != NULL) | ||
69 | { | ||
70 | GNUNET_FS_download_stop (download, GNUNET_YES); | ||
71 | download = NULL; | ||
72 | } | ||
73 | else if (publish != NULL) | ||
74 | { | ||
75 | GNUNET_FS_publish_stop (publish); | ||
76 | publish = NULL; | ||
77 | } | ||
78 | timeout_kill = NULL; | ||
79 | err = 1; | ||
80 | } | ||
81 | |||
82 | |||
83 | static void | ||
84 | abort_publish_task (void *cls) | ||
85 | { | ||
86 | if (publish != NULL) | ||
87 | { | ||
88 | GNUNET_FS_publish_stop (publish); | ||
89 | publish = NULL; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | |||
94 | static void | ||
95 | abort_download_task (void *cls) | ||
96 | { | ||
97 | uint64_t size; | ||
98 | |||
99 | if (download != NULL) | ||
100 | { | ||
101 | GNUNET_FS_download_stop (download, GNUNET_YES); | ||
102 | download = NULL; | ||
103 | } | ||
104 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES, | ||
105 | GNUNET_NO)); | ||
106 | GNUNET_assert (size == FILESIZE); | ||
107 | GNUNET_DISK_directory_remove (fn); | ||
108 | GNUNET_free (fn); | ||
109 | fn = NULL; | ||
110 | GNUNET_SCHEDULER_cancel (timeout_kill); | ||
111 | timeout_kill = NULL; | ||
112 | } | ||
113 | |||
114 | |||
115 | static void * | ||
116 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); | ||
117 | |||
118 | |||
119 | static void | ||
120 | restart_fs_task (void *cls) | ||
121 | { | ||
122 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting FS.\n"); | ||
123 | GNUNET_FS_stop (fs); | ||
124 | fs = GNUNET_FS_start (cfg, "test-fs-download-persistence", &progress_cb, NULL, | ||
125 | GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * Consider scheduling the restart-task. | ||
131 | * Only runs the restart task once per event | ||
132 | * category. | ||
133 | * | ||
134 | * @param ev type of the event to consider | ||
135 | */ | ||
136 | static void | ||
137 | consider_restart (int ev) | ||
138 | { | ||
139 | static int prev[32]; | ||
140 | static int off; | ||
141 | int i; | ||
142 | |||
143 | for (i = 0; i < off; i++) | ||
144 | if (prev[i] == ev) | ||
145 | return; | ||
146 | prev[off++] = ev; | ||
147 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, | ||
148 | &restart_fs_task, NULL); | ||
149 | } | ||
150 | |||
151 | |||
152 | static void * | ||
153 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
154 | { | ||
155 | switch (event->status) | ||
156 | { | ||
157 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
158 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
159 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
160 | (unsigned long long) event->value.publish.completed, | ||
161 | (unsigned long long) event->value.publish.size, | ||
162 | event->value.publish.specifics.progress.depth, | ||
163 | (unsigned long long) event->value.publish.specifics. | ||
164 | progress.offset); | ||
165 | break; | ||
166 | |||
167 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
168 | break; | ||
169 | |||
170 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
171 | printf ("Publishing complete, %llu kbps.\n", | ||
172 | (unsigned long long) (FILESIZE * 1000000LL | ||
173 | / (1 | ||
174 | + GNUNET_TIME_absolute_get_duration | ||
175 | (start).rel_value_us) / 1024LL)); | ||
176 | fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst"); | ||
177 | start = GNUNET_TIME_absolute_get (); | ||
178 | GNUNET_assert (download == NULL); | ||
179 | GNUNET_FS_download_start (fs, | ||
180 | event->value.publish.specifics.completed.chk_uri, | ||
181 | NULL, fn, NULL, 0, FILESIZE, 1, | ||
182 | GNUNET_FS_DOWNLOAD_OPTION_NONE, "download", NULL); | ||
183 | break; | ||
184 | |||
185 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: | ||
186 | printf ("Download complete, %llu kbps.\n", | ||
187 | (unsigned long long) (FILESIZE * 1000000LL | ||
188 | / (1 | ||
189 | + GNUNET_TIME_absolute_get_duration | ||
190 | (start).rel_value_us) / 1024LL)); | ||
191 | GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); | ||
192 | break; | ||
193 | |||
194 | case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: | ||
195 | consider_restart (event->status); | ||
196 | GNUNET_assert (download == event->value.download.dc); | ||
197 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
198 | "Download is progressing (%llu/%llu at level %u off %llu)...\n", | ||
199 | (unsigned long long) event->value.download.completed, | ||
200 | (unsigned long long) event->value.download.size, | ||
201 | event->value.download.specifics.progress.depth, | ||
202 | (unsigned long long) event->value.download.specifics. | ||
203 | progress.offset); | ||
204 | break; | ||
205 | |||
206 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
207 | fprintf (stderr, "Error publishing file: %s\n", | ||
208 | event->value.publish.specifics.error.message); | ||
209 | GNUNET_break (0); | ||
210 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
211 | break; | ||
212 | |||
213 | case GNUNET_FS_STATUS_DOWNLOAD_ERROR: | ||
214 | fprintf (stderr, "Error downloading file: %s\n", | ||
215 | event->value.download.specifics.error.message); | ||
216 | GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); | ||
217 | break; | ||
218 | |||
219 | case GNUNET_FS_STATUS_PUBLISH_SUSPEND: | ||
220 | GNUNET_assert (event->value.publish.pc == publish); | ||
221 | publish = NULL; | ||
222 | break; | ||
223 | |||
224 | case GNUNET_FS_STATUS_PUBLISH_RESUME: | ||
225 | GNUNET_assert (NULL == publish); | ||
226 | publish = event->value.publish.pc; | ||
227 | break; | ||
228 | |||
229 | case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND: | ||
230 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download suspended.\n"); | ||
231 | GNUNET_assert (event->value.download.dc == download); | ||
232 | download = NULL; | ||
233 | break; | ||
234 | |||
235 | case GNUNET_FS_STATUS_DOWNLOAD_RESUME: | ||
236 | GNUNET_assert (NULL == download); | ||
237 | download = event->value.download.dc; | ||
238 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download resumed.\n"); | ||
239 | break; | ||
240 | |||
241 | case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: | ||
242 | consider_restart (event->status); | ||
243 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download active.\n"); | ||
244 | break; | ||
245 | |||
246 | case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: | ||
247 | consider_restart (event->status); | ||
248 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download inactive.\n"); | ||
249 | break; | ||
250 | |||
251 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
252 | GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); | ||
253 | GNUNET_assert (NULL == event->value.publish.pctx); | ||
254 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
255 | GNUNET_assert (0 == event->value.publish.completed); | ||
256 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
257 | break; | ||
258 | |||
259 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
260 | GNUNET_assert (publish == event->value.publish.pc); | ||
261 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
262 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
263 | GNUNET_FS_stop (fs); | ||
264 | fs = NULL; | ||
265 | break; | ||
266 | |||
267 | case GNUNET_FS_STATUS_DOWNLOAD_START: | ||
268 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download started.\n"); | ||
269 | consider_restart (event->status); | ||
270 | GNUNET_assert (download == NULL); | ||
271 | download = event->value.download.dc; | ||
272 | GNUNET_assert (0 == strcmp ("download", event->value.download.cctx)); | ||
273 | GNUNET_assert (NULL == event->value.download.pctx); | ||
274 | GNUNET_assert (NULL != event->value.download.uri); | ||
275 | GNUNET_assert (0 == strcmp (fn, event->value.download.filename)); | ||
276 | GNUNET_assert (FILESIZE == event->value.download.size); | ||
277 | GNUNET_assert (0 == event->value.download.completed); | ||
278 | GNUNET_assert (1 == event->value.download.anonymity); | ||
279 | break; | ||
280 | |||
281 | case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: | ||
282 | GNUNET_assert (download == event->value.download.dc); | ||
283 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
284 | download = NULL; | ||
285 | break; | ||
286 | |||
287 | default: | ||
288 | printf ("Unexpected event: %d\n", event->status); | ||
289 | break; | ||
290 | } | ||
291 | return NULL; | ||
292 | } | ||
293 | |||
294 | |||
295 | static void | ||
296 | run (void *cls, | ||
297 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
298 | struct GNUNET_TESTING_Peer *peer) | ||
299 | { | ||
300 | const char *keywords[] = { | ||
301 | "down_foo", | ||
302 | "down_bar", | ||
303 | }; | ||
304 | char *buf; | ||
305 | struct GNUNET_CONTAINER_MetaData *meta; | ||
306 | struct GNUNET_FS_Uri *kuri; | ||
307 | struct GNUNET_FS_FileInformation *fi; | ||
308 | size_t i; | ||
309 | struct GNUNET_FS_BlockOptions bo; | ||
310 | |||
311 | cfg = c; | ||
312 | fs = GNUNET_FS_start (cfg, "test-fs-download-persistence", &progress_cb, NULL, | ||
313 | GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); | ||
314 | GNUNET_assert (NULL != fs); | ||
315 | buf = GNUNET_malloc (FILESIZE); | ||
316 | for (i = 0; i < FILESIZE; i++) | ||
317 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
318 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
319 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
320 | bo.content_priority = 42; | ||
321 | bo.anonymity_level = 1; | ||
322 | bo.replication_level = 0; | ||
323 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
324 | fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", | ||
325 | FILESIZE, buf, kuri, meta, | ||
326 | GNUNET_NO, &bo); | ||
327 | GNUNET_FS_uri_destroy (kuri); | ||
328 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
329 | GNUNET_assert (NULL != fi); | ||
330 | timeout_kill = | ||
331 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL); | ||
332 | start = GNUNET_TIME_absolute_get (); | ||
333 | publish = | ||
334 | GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, | ||
335 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
336 | GNUNET_assert (publish != NULL); | ||
337 | } | ||
338 | |||
339 | |||
340 | int | ||
341 | main (int argc, char *argv[]) | ||
342 | { | ||
343 | if (0 != GNUNET_TESTING_peer_run ("test-fs-download-persistence", | ||
344 | "test_fs_download_data.conf", | ||
345 | &run, NULL)) | ||
346 | return 1; | ||
347 | return err; | ||
348 | } | ||
349 | |||
350 | |||
351 | /* end of test_fs_download_persistence.c */ | ||
diff --git a/src/fs/test_fs_file_information.c b/src/fs/test_fs_file_information.c deleted file mode 100644 index 22013db27..000000000 --- a/src/fs/test_fs_file_information.c +++ /dev/null | |||
@@ -1,163 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_file_information.c | ||
23 | * @brief simple testcase for file_information operations | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - test that metadata, etc. are all correct (for example, | ||
28 | * there is a known bug with dirname never being set that is | ||
29 | * not detected!) | ||
30 | * - need to iterate over file-information structure | ||
31 | * - other API functions may not yet be tested (such as | ||
32 | * filedata-from-callback) | ||
33 | */ | ||
34 | #include "platform.h" | ||
35 | #include "gnunet_util_lib.h" | ||
36 | #include "gnunet_fs_service.h" | ||
37 | |||
38 | |||
39 | /** | ||
40 | * File-size we use for testing. | ||
41 | */ | ||
42 | #define FILESIZE (1024 * 1024 * 2) | ||
43 | |||
44 | /** | ||
45 | * How long should our test-content live? | ||
46 | */ | ||
47 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
48 | |||
49 | |||
50 | static int | ||
51 | mycleaner (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, | ||
52 | struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, | ||
53 | struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) | ||
54 | { | ||
55 | return GNUNET_OK; | ||
56 | } | ||
57 | |||
58 | |||
59 | static void | ||
60 | run (void *cls, char *const *args, const char *cfgfile, | ||
61 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
62 | { | ||
63 | const char *keywords[] = { | ||
64 | "down_foo", | ||
65 | "down_bar", | ||
66 | }; | ||
67 | char *fn1; | ||
68 | char *fn2; | ||
69 | char *buf; | ||
70 | struct GNUNET_CONTAINER_MetaData *meta; | ||
71 | struct GNUNET_FS_Uri *kuri; | ||
72 | struct GNUNET_FS_FileInformation *fi1; | ||
73 | struct GNUNET_FS_FileInformation *fi2; | ||
74 | struct GNUNET_FS_FileInformation *fidir; | ||
75 | struct GNUNET_FS_Handle *fs; | ||
76 | size_t i; | ||
77 | struct GNUNET_FS_BlockOptions bo; | ||
78 | |||
79 | fs = GNUNET_FS_start (cfg, "test-fs-file-information", NULL, NULL, | ||
80 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
81 | fn1 = GNUNET_DISK_mktemp ("gnunet-file_information-test-dst"); | ||
82 | buf = GNUNET_malloc (FILESIZE); | ||
83 | for (i = 0; i < FILESIZE; i++) | ||
84 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
85 | (void) GNUNET_DISK_directory_remove (fn1); | ||
86 | GNUNET_assert (GNUNET_OK == | ||
87 | GNUNET_DISK_fn_write (fn1, buf, FILESIZE, | ||
88 | GNUNET_DISK_PERM_USER_READ | ||
89 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
90 | GNUNET_free (buf); | ||
91 | |||
92 | fn2 = GNUNET_DISK_mktemp ("gnunet-file_information-test-dst"); | ||
93 | buf = GNUNET_malloc (FILESIZE); | ||
94 | for (i = 0; i < FILESIZE; i++) | ||
95 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
96 | (void) GNUNET_DISK_directory_remove (fn2); | ||
97 | GNUNET_assert (GNUNET_OK == | ||
98 | GNUNET_DISK_fn_write (fn2, buf, FILESIZE, | ||
99 | GNUNET_DISK_PERM_USER_READ | ||
100 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
101 | GNUNET_free (buf); | ||
102 | |||
103 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
104 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
105 | bo.content_priority = 42; | ||
106 | bo.anonymity_level = 1; | ||
107 | bo.replication_level = 0; | ||
108 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
109 | fi1 = | ||
110 | GNUNET_FS_file_information_create_from_file (fs, | ||
111 | "file_information-context1", | ||
112 | fn1, kuri, meta, GNUNET_YES, | ||
113 | &bo); | ||
114 | GNUNET_assert (fi1 != NULL); | ||
115 | fi2 = | ||
116 | GNUNET_FS_file_information_create_from_file (fs, | ||
117 | "file_information-context2", | ||
118 | fn2, kuri, meta, GNUNET_YES, | ||
119 | &bo); | ||
120 | GNUNET_assert (fi2 != NULL); | ||
121 | fidir = | ||
122 | GNUNET_FS_file_information_create_empty_directory (fs, | ||
123 | "file_information-context-dir", | ||
124 | kuri, meta, &bo, NULL); | ||
125 | GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); | ||
126 | GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); | ||
127 | GNUNET_FS_uri_destroy (kuri); | ||
128 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
129 | GNUNET_assert (NULL != fidir); | ||
130 | /* FIXME: test more of API! */ | ||
131 | GNUNET_FS_file_information_destroy (fidir, &mycleaner, NULL); | ||
132 | GNUNET_DISK_directory_remove (fn1); | ||
133 | GNUNET_DISK_directory_remove (fn2); | ||
134 | GNUNET_free (fn1); | ||
135 | GNUNET_free (fn2); | ||
136 | GNUNET_FS_stop (fs); | ||
137 | } | ||
138 | |||
139 | |||
140 | int | ||
141 | main (int argc, char *argv[]) | ||
142 | { | ||
143 | char *const argvx[] = { | ||
144 | "test-fs-file_information", | ||
145 | "-c", | ||
146 | "test_fs_file_information_data.conf", | ||
147 | NULL | ||
148 | }; | ||
149 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
150 | GNUNET_GETOPT_OPTION_END | ||
151 | }; | ||
152 | |||
153 | GNUNET_log_setup ("test_fs_file_information", | ||
154 | "WARNING", | ||
155 | NULL); | ||
156 | GNUNET_PROGRAM_run ((sizeof(argvx) / sizeof(char *)) - 1, argvx, | ||
157 | "test-fs-file_information", "nohelp", options, &run, | ||
158 | NULL); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | |||
163 | /* end of test_fs_file_information.c */ | ||
diff --git a/src/fs/test_fs_file_information_data.conf b/src/fs/test_fs_file_information_data.conf deleted file mode 100644 index c8fc0938c..000000000 --- a/src/fs/test_fs_file_information_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-file-information/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
diff --git a/src/fs/test_fs_getopt.c b/src/fs/test_fs_getopt.c deleted file mode 100644 index 3d0da752b..000000000 --- a/src/fs/test_fs_getopt.c +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_getopt.c | ||
22 | * @brief test for fs_getopt.c | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_fs_service.h" | ||
27 | |||
28 | |||
29 | int | ||
30 | main (int argc, char *argv[]) | ||
31 | { | ||
32 | GNUNET_log_setup ("test_fs_getopt", | ||
33 | "WARNING", | ||
34 | NULL); | ||
35 | fprintf (stderr, "%s", "WARNING: testcase not yet written.\n"); | ||
36 | return 0; /* testcase passed */ | ||
37 | } | ||
diff --git a/src/fs/test_fs_list_indexed.c b/src/fs/test_fs_list_indexed.c deleted file mode 100644 index 2f04a017a..000000000 --- a/src/fs/test_fs_list_indexed.c +++ /dev/null | |||
@@ -1,265 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_list_indexed.c | ||
23 | * @brief simple testcase for list_indexed operation (indexing, listing | ||
24 | * indexed) | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * TODO: | ||
28 | * - actually call list_indexed API! | ||
29 | */ | ||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_testing_lib.h" | ||
33 | #include "gnunet_fs_service.h" | ||
34 | |||
35 | /** | ||
36 | * File-size we use for testing. | ||
37 | */ | ||
38 | #define FILESIZE (1024 * 1024 * 2) | ||
39 | |||
40 | /** | ||
41 | * How long until we give up on transmitting the message? | ||
42 | */ | ||
43 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
44 | |||
45 | /** | ||
46 | * How long should our test-content live? | ||
47 | */ | ||
48 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
49 | |||
50 | |||
51 | static struct GNUNET_TIME_Absolute start; | ||
52 | |||
53 | static struct GNUNET_FS_Handle *fs; | ||
54 | |||
55 | static struct GNUNET_FS_PublishContext *publish; | ||
56 | |||
57 | static char *fn1; | ||
58 | |||
59 | static char *fn2; | ||
60 | |||
61 | static int err; | ||
62 | |||
63 | |||
64 | static void | ||
65 | abort_publish_task (void *cls) | ||
66 | { | ||
67 | GNUNET_FS_publish_stop (publish); | ||
68 | publish = NULL; | ||
69 | GNUNET_DISK_directory_remove (fn1); | ||
70 | GNUNET_free (fn1); | ||
71 | fn1 = NULL; | ||
72 | GNUNET_DISK_directory_remove (fn2); | ||
73 | GNUNET_free (fn2); | ||
74 | fn2 = NULL; | ||
75 | } | ||
76 | |||
77 | |||
78 | static void | ||
79 | list_indexed_task (void *cls) | ||
80 | { | ||
81 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
82 | } | ||
83 | |||
84 | |||
85 | static void * | ||
86 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
87 | { | ||
88 | void *ret; | ||
89 | |||
90 | ret = NULL; | ||
91 | switch (event->status) | ||
92 | { | ||
93 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
94 | ret = event->value.publish.cctx; | ||
95 | printf ("Publish complete, %llu kbps.\n", | ||
96 | (unsigned long long) (FILESIZE * 1000000LL | ||
97 | / (1 | ||
98 | + GNUNET_TIME_absolute_get_duration | ||
99 | (start).rel_value_us) / 1024)); | ||
100 | if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) | ||
101 | GNUNET_SCHEDULER_add_now (&list_indexed_task, NULL); | ||
102 | |||
103 | break; | ||
104 | |||
105 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
106 | ret = event->value.publish.cctx; | ||
107 | GNUNET_assert (publish == event->value.publish.pc); | ||
108 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
109 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
110 | (unsigned long long) event->value.publish.completed, | ||
111 | (unsigned long long) event->value.publish.size, | ||
112 | event->value.publish.specifics.progress.depth, | ||
113 | (unsigned long long) event->value.publish.specifics. | ||
114 | progress.offset); | ||
115 | break; | ||
116 | |||
117 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
118 | ret = event->value.publish.cctx; | ||
119 | break; | ||
120 | |||
121 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
122 | ret = event->value.publish.cctx; | ||
123 | fprintf (stderr, "Error publishing file: %s\n", | ||
124 | event->value.publish.specifics.error.message); | ||
125 | err = 1; | ||
126 | if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) | ||
127 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
128 | break; | ||
129 | |||
130 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
131 | ret = event->value.publish.cctx; | ||
132 | if (0 == strcmp ("list_indexed-context1", event->value.publish.cctx)) | ||
133 | { | ||
134 | GNUNET_assert (0 == | ||
135 | strcmp ("list_indexed-context-dir", | ||
136 | event->value.publish.pctx)); | ||
137 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
138 | GNUNET_assert (0 == event->value.publish.completed); | ||
139 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
140 | } | ||
141 | else if (0 == strcmp ("list_indexed-context2", event->value.publish.cctx)) | ||
142 | { | ||
143 | GNUNET_assert (0 == | ||
144 | strcmp ("list_indexed-context-dir", | ||
145 | event->value.publish.pctx)); | ||
146 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
147 | GNUNET_assert (0 == event->value.publish.completed); | ||
148 | GNUNET_assert (2 == event->value.publish.anonymity); | ||
149 | } | ||
150 | else if (0 == | ||
151 | strcmp ("list_indexed-context-dir", event->value.publish.cctx)) | ||
152 | { | ||
153 | GNUNET_assert (0 == event->value.publish.completed); | ||
154 | GNUNET_assert (3 == event->value.publish.anonymity); | ||
155 | } | ||
156 | else | ||
157 | GNUNET_assert (0); | ||
158 | break; | ||
159 | |||
160 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
161 | if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) | ||
162 | { | ||
163 | GNUNET_assert (publish == event->value.publish.pc); | ||
164 | publish = NULL; | ||
165 | } | ||
166 | break; | ||
167 | |||
168 | default: | ||
169 | printf ("Unexpected event: %d\n", event->status); | ||
170 | break; | ||
171 | } | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | |||
176 | static void | ||
177 | run (void *cls, | ||
178 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
179 | struct GNUNET_TESTING_Peer *peer) | ||
180 | { | ||
181 | const char *keywords[] = { | ||
182 | "down_foo", | ||
183 | "down_bar", | ||
184 | }; | ||
185 | char *buf; | ||
186 | struct GNUNET_CONTAINER_MetaData *meta; | ||
187 | struct GNUNET_FS_Uri *kuri; | ||
188 | struct GNUNET_FS_FileInformation *fi1; | ||
189 | struct GNUNET_FS_FileInformation *fi2; | ||
190 | struct GNUNET_FS_FileInformation *fidir; | ||
191 | size_t i; | ||
192 | struct GNUNET_FS_BlockOptions bo; | ||
193 | |||
194 | fs = GNUNET_FS_start (cfg, "test-fs-list_indexed", &progress_cb, NULL, | ||
195 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
196 | GNUNET_assert (NULL != fs); | ||
197 | fn1 = GNUNET_DISK_mktemp ("gnunet-list_indexed-test-dst"); | ||
198 | buf = GNUNET_malloc (FILESIZE); | ||
199 | for (i = 0; i < FILESIZE; i++) | ||
200 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
201 | (void) GNUNET_DISK_directory_remove (fn1); | ||
202 | GNUNET_assert (GNUNET_OK == | ||
203 | GNUNET_DISK_fn_write (fn1, buf, FILESIZE, | ||
204 | GNUNET_DISK_PERM_USER_READ | ||
205 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
206 | GNUNET_free (buf); | ||
207 | |||
208 | fn2 = GNUNET_DISK_mktemp ("gnunet-list_indexed-test-dst"); | ||
209 | buf = GNUNET_malloc (FILESIZE); | ||
210 | for (i = 0; i < FILESIZE; i++) | ||
211 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
212 | (void) GNUNET_DISK_directory_remove (fn2); | ||
213 | GNUNET_assert (GNUNET_OK == | ||
214 | GNUNET_DISK_fn_write (fn2, buf, FILESIZE, | ||
215 | GNUNET_DISK_PERM_USER_READ | ||
216 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
217 | GNUNET_free (buf); | ||
218 | |||
219 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
220 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
221 | bo.content_priority = 42; | ||
222 | bo.anonymity_level = 1; | ||
223 | bo.replication_level = 0; | ||
224 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
225 | fi1 = | ||
226 | GNUNET_FS_file_information_create_from_file (fs, "list_indexed-context1", | ||
227 | fn1, kuri, meta, GNUNET_YES, | ||
228 | &bo); | ||
229 | GNUNET_assert (NULL != fi1); | ||
230 | bo.anonymity_level = 2; | ||
231 | fi2 = | ||
232 | GNUNET_FS_file_information_create_from_file (fs, "list_indexed-context2", | ||
233 | fn2, kuri, meta, GNUNET_YES, | ||
234 | &bo); | ||
235 | GNUNET_assert (NULL != fi2); | ||
236 | bo.anonymity_level = 3; | ||
237 | fidir = | ||
238 | GNUNET_FS_file_information_create_empty_directory (fs, | ||
239 | "list_indexed-context-dir", | ||
240 | kuri, meta, &bo, NULL); | ||
241 | GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); | ||
242 | GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); | ||
243 | GNUNET_FS_uri_destroy (kuri); | ||
244 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
245 | GNUNET_assert (NULL != fidir); | ||
246 | start = GNUNET_TIME_absolute_get (); | ||
247 | publish = | ||
248 | GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, | ||
249 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
250 | GNUNET_assert (publish != NULL); | ||
251 | } | ||
252 | |||
253 | |||
254 | int | ||
255 | main (int argc, char *argv[]) | ||
256 | { | ||
257 | if (0 != GNUNET_TESTING_peer_run ("test-fs-list-indexed", | ||
258 | "test_fs_list_indexed_data.conf", | ||
259 | &run, NULL)) | ||
260 | return 1; | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | |||
265 | /* end of test_fs_list_indexed.c */ | ||
diff --git a/src/fs/test_fs_list_indexed_data.conf b/src/fs/test_fs_list_indexed_data.conf deleted file mode 100644 index 941809322..000000000 --- a/src/fs/test_fs_list_indexed_data.conf +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-list-indexed/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
8 | [fs] | ||
9 | ACTIVEMIGRATION = NO | ||
10 | |||
diff --git a/src/fs/test_fs_namespace.c b/src/fs/test_fs_namespace.c deleted file mode 100644 index c1e10d575..000000000 --- a/src/fs/test_fs_namespace.c +++ /dev/null | |||
@@ -1,320 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2005-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_namespace.c | ||
23 | * @brief Test for fs_namespace.c | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | |||
32 | static struct GNUNET_CRYPTO_EcdsaPublicKey nsid; | ||
33 | |||
34 | static struct GNUNET_FS_Uri *sks_expect_uri; | ||
35 | |||
36 | static struct GNUNET_FS_Uri *ksk_expect_uri; | ||
37 | |||
38 | static struct GNUNET_FS_Handle *fs; | ||
39 | |||
40 | static struct GNUNET_FS_SearchContext *sks_search; | ||
41 | |||
42 | static struct GNUNET_FS_SearchContext *ksk_search; | ||
43 | |||
44 | static struct GNUNET_SCHEDULER_Task *kill_task; | ||
45 | |||
46 | static int update_started; | ||
47 | |||
48 | static int err; | ||
49 | |||
50 | |||
51 | static void | ||
52 | abort_ksk_search_task (void *cls) | ||
53 | { | ||
54 | if (ksk_search != NULL) | ||
55 | { | ||
56 | GNUNET_FS_search_stop (ksk_search); | ||
57 | ksk_search = NULL; | ||
58 | if (sks_search == NULL) | ||
59 | { | ||
60 | GNUNET_FS_stop (fs); | ||
61 | if (NULL != kill_task) | ||
62 | GNUNET_SCHEDULER_cancel (kill_task); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
67 | |||
68 | static void | ||
69 | abort_sks_search_task (void *cls) | ||
70 | { | ||
71 | if (sks_search == NULL) | ||
72 | return; | ||
73 | GNUNET_FS_search_stop (sks_search); | ||
74 | sks_search = NULL; | ||
75 | if (ksk_search == NULL) | ||
76 | { | ||
77 | GNUNET_FS_stop (fs); | ||
78 | if (NULL != kill_task) | ||
79 | GNUNET_SCHEDULER_cancel (kill_task); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | |||
84 | static void | ||
85 | do_timeout (void *cls) | ||
86 | { | ||
87 | err = 1; | ||
88 | fprintf (stderr, "%s", "Operation timed out\n"); | ||
89 | kill_task = NULL; | ||
90 | abort_sks_search_task (NULL); | ||
91 | abort_ksk_search_task (NULL); | ||
92 | } | ||
93 | |||
94 | |||
95 | static void * | ||
96 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
97 | { | ||
98 | switch (event->status) | ||
99 | { | ||
100 | case GNUNET_FS_STATUS_SEARCH_RESULT: | ||
101 | if (sks_search == event->value.search.sc) | ||
102 | { | ||
103 | if (! GNUNET_FS_uri_test_equal | ||
104 | (sks_expect_uri, event->value.search.specifics.result.uri)) | ||
105 | { | ||
106 | fprintf (stderr, "%s", "Wrong result for sks search!\n"); | ||
107 | err = 1; | ||
108 | } | ||
109 | /* give system 1ms to initiate update search! */ | ||
110 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | ||
111 | &abort_sks_search_task, NULL); | ||
112 | } | ||
113 | else if (ksk_search == event->value.search.sc) | ||
114 | { | ||
115 | if (! GNUNET_FS_uri_test_equal | ||
116 | (ksk_expect_uri, event->value.search.specifics.result.uri)) | ||
117 | { | ||
118 | fprintf (stderr, "%s", "Wrong result for ksk search!\n"); | ||
119 | err = 1; | ||
120 | } | ||
121 | GNUNET_SCHEDULER_add_now (&abort_ksk_search_task, NULL); | ||
122 | } | ||
123 | else | ||
124 | { | ||
125 | fprintf (stderr, "%s", "Unexpected search result received!\n"); | ||
126 | GNUNET_break (0); | ||
127 | } | ||
128 | break; | ||
129 | |||
130 | case GNUNET_FS_STATUS_SEARCH_ERROR: | ||
131 | fprintf (stderr, "Error searching file: %s\n", | ||
132 | event->value.search.specifics.error.message); | ||
133 | if (sks_search == event->value.search.sc) | ||
134 | GNUNET_SCHEDULER_add_now (&abort_sks_search_task, NULL); | ||
135 | else if (ksk_search == event->value.search.sc) | ||
136 | GNUNET_SCHEDULER_add_now (&abort_ksk_search_task, NULL); | ||
137 | else | ||
138 | GNUNET_break (0); | ||
139 | break; | ||
140 | |||
141 | case GNUNET_FS_STATUS_SEARCH_START: | ||
142 | GNUNET_assert ((NULL == event->value.search.cctx) || | ||
143 | (0 == strcmp ("sks_search", event->value.search.cctx)) || | ||
144 | (0 == strcmp ("ksk_search", event->value.search.cctx))); | ||
145 | if (NULL == event->value.search.cctx) | ||
146 | { | ||
147 | GNUNET_assert (0 == strcmp ("sks_search", event->value.search.pctx)); | ||
148 | update_started = GNUNET_YES; | ||
149 | } | ||
150 | GNUNET_assert (1 == event->value.search.anonymity); | ||
151 | break; | ||
152 | |||
153 | case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: | ||
154 | return NULL; | ||
155 | |||
156 | case GNUNET_FS_STATUS_SEARCH_STOPPED: | ||
157 | return NULL; | ||
158 | |||
159 | default: | ||
160 | fprintf (stderr, "Unexpected event: %d\n", event->status); | ||
161 | break; | ||
162 | } | ||
163 | return event->value.search.cctx; | ||
164 | } | ||
165 | |||
166 | |||
167 | static void | ||
168 | publish_cont (void *cls, const struct GNUNET_FS_Uri *ksk_uri, const char *emsg) | ||
169 | { | ||
170 | char *msg; | ||
171 | struct GNUNET_FS_Uri *sks_uri; | ||
172 | char sbuf[1024]; | ||
173 | char buf[1024]; | ||
174 | char *ret; | ||
175 | |||
176 | if (NULL != emsg) | ||
177 | { | ||
178 | fprintf (stderr, "Error publishing: %s\n", emsg); | ||
179 | err = 1; | ||
180 | GNUNET_FS_stop (fs); | ||
181 | return; | ||
182 | } | ||
183 | ret = GNUNET_STRINGS_data_to_string (&nsid, sizeof(nsid), buf, sizeof(buf)); | ||
184 | GNUNET_assert (NULL != ret); | ||
185 | ret[0] = '\0'; | ||
186 | GNUNET_snprintf (sbuf, sizeof(sbuf), "gnunet://fs/sks/%s/this", buf); | ||
187 | sks_uri = GNUNET_FS_uri_parse (sbuf, &msg); | ||
188 | if (NULL == sks_uri) | ||
189 | { | ||
190 | fprintf (stderr, "failed to parse URI `%s': %s\n", sbuf, msg); | ||
191 | err = 1; | ||
192 | GNUNET_FS_stop (fs); | ||
193 | GNUNET_free (msg); | ||
194 | return; | ||
195 | } | ||
196 | ksk_search = | ||
197 | GNUNET_FS_search_start (fs, ksk_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, | ||
198 | "ksk_search"); | ||
199 | sks_search = | ||
200 | GNUNET_FS_search_start (fs, sks_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, | ||
201 | "sks_search"); | ||
202 | GNUNET_FS_uri_destroy (sks_uri); | ||
203 | } | ||
204 | |||
205 | |||
206 | static void | ||
207 | sks_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) | ||
208 | { | ||
209 | struct GNUNET_CONTAINER_MetaData *meta; | ||
210 | struct GNUNET_FS_Uri *ksk_uri; | ||
211 | char *msg; | ||
212 | struct GNUNET_FS_BlockOptions bo; | ||
213 | |||
214 | if (NULL == uri) | ||
215 | { | ||
216 | fprintf (stderr, "Error publishing: %s\n", emsg); | ||
217 | err = 1; | ||
218 | GNUNET_FS_stop (fs); | ||
219 | return; | ||
220 | } | ||
221 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
222 | msg = NULL; | ||
223 | ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/ns-search", &msg); | ||
224 | GNUNET_assert (NULL == msg); | ||
225 | ksk_expect_uri = GNUNET_FS_uri_dup (uri); | ||
226 | bo.content_priority = 1; | ||
227 | bo.anonymity_level = 1; | ||
228 | bo.replication_level = 0; | ||
229 | bo.expiration_time = | ||
230 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); | ||
231 | GNUNET_FS_publish_ksk (fs, ksk_uri, meta, uri, &bo, | ||
232 | GNUNET_FS_PUBLISH_OPTION_NONE, &publish_cont, NULL); | ||
233 | GNUNET_FS_uri_destroy (ksk_uri); | ||
234 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
235 | } | ||
236 | |||
237 | |||
238 | static void | ||
239 | adv_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) | ||
240 | { | ||
241 | struct GNUNET_CONTAINER_MetaData *meta; | ||
242 | struct GNUNET_CRYPTO_EcdsaPrivateKey ns; | ||
243 | struct GNUNET_FS_BlockOptions bo; | ||
244 | |||
245 | if (NULL != emsg) | ||
246 | { | ||
247 | fprintf (stderr, "Error publishing: %s\n", emsg); | ||
248 | err = 1; | ||
249 | GNUNET_FS_stop (fs); | ||
250 | return; | ||
251 | } | ||
252 | GNUNET_CRYPTO_ecdsa_key_create (&ns); | ||
253 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
254 | sks_expect_uri = GNUNET_FS_uri_dup (uri); | ||
255 | bo.content_priority = 1; | ||
256 | bo.anonymity_level = 1; | ||
257 | bo.replication_level = 0; | ||
258 | bo.expiration_time = | ||
259 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); | ||
260 | GNUNET_CRYPTO_ecdsa_key_get_public (&ns, | ||
261 | &nsid); | ||
262 | GNUNET_FS_publish_sks (fs, | ||
263 | &ns, "this", "next", meta, uri, | ||
264 | &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont, NULL); | ||
265 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
266 | } | ||
267 | |||
268 | |||
269 | static void | ||
270 | testNamespace (void) | ||
271 | { | ||
272 | struct GNUNET_FS_BlockOptions bo; | ||
273 | struct GNUNET_CONTAINER_MetaData *meta; | ||
274 | struct GNUNET_FS_Uri *ksk_uri; | ||
275 | struct GNUNET_FS_Uri *sks_uri; | ||
276 | |||
277 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
278 | ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/testnsa", NULL); | ||
279 | bo.content_priority = 1; | ||
280 | bo.anonymity_level = 1; | ||
281 | bo.replication_level = 0; | ||
282 | bo.expiration_time = | ||
283 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); | ||
284 | sks_uri = GNUNET_FS_uri_sks_create (&nsid, "root"); | ||
285 | GNUNET_FS_publish_ksk (fs, | ||
286 | ksk_uri, meta, sks_uri, | ||
287 | &bo, GNUNET_FS_PUBLISH_OPTION_NONE, | ||
288 | &adv_cont, NULL); | ||
289 | GNUNET_FS_uri_destroy (sks_uri); | ||
290 | kill_task = | ||
291 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &do_timeout, | ||
292 | NULL); | ||
293 | GNUNET_FS_uri_destroy (ksk_uri); | ||
294 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
295 | } | ||
296 | |||
297 | |||
298 | static void | ||
299 | run (void *cls, | ||
300 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
301 | struct GNUNET_TESTING_Peer *peer) | ||
302 | { | ||
303 | fs = GNUNET_FS_start (cfg, "test-fs-namespace", &progress_cb, NULL, | ||
304 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
305 | testNamespace (); | ||
306 | } | ||
307 | |||
308 | |||
309 | int | ||
310 | main (int argc, char *argv[]) | ||
311 | { | ||
312 | if (0 != GNUNET_TESTING_peer_run ("test-fs-namespace", | ||
313 | "test_fs_namespace_data.conf", | ||
314 | &run, NULL)) | ||
315 | return 1; | ||
316 | return err; | ||
317 | } | ||
318 | |||
319 | |||
320 | /* end of test_fs_namespace.c */ | ||
diff --git a/src/fs/test_fs_namespace_data.conf b/src/fs/test_fs_namespace_data.conf deleted file mode 100644 index 70b954f7d..000000000 --- a/src/fs/test_fs_namespace_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-namespace/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
diff --git a/src/fs/test_fs_namespace_list_updateable.c b/src/fs/test_fs_namespace_list_updateable.c deleted file mode 100644 index 2132220fb..000000000 --- a/src/fs/test_fs_namespace_list_updateable.c +++ /dev/null | |||
@@ -1,175 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2005-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_namespace_list_updateable.c | ||
23 | * @brief Test for fs_namespace_list_updateable.c | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | |||
32 | static struct GNUNET_FS_Handle *fs; | ||
33 | |||
34 | static int err; | ||
35 | |||
36 | static struct GNUNET_CRYPTO_EcdsaPrivateKey ns; | ||
37 | |||
38 | static struct GNUNET_CONTAINER_MetaData *meta; | ||
39 | |||
40 | static struct GNUNET_FS_Uri *uri_this; | ||
41 | |||
42 | static struct GNUNET_FS_Uri *uri_next; | ||
43 | |||
44 | static struct GNUNET_FS_BlockOptions bo; | ||
45 | |||
46 | |||
47 | static void * | ||
48 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
49 | { | ||
50 | return NULL; | ||
51 | } | ||
52 | |||
53 | |||
54 | static void | ||
55 | do_shutdown () | ||
56 | { | ||
57 | if (uri_this != NULL) | ||
58 | GNUNET_FS_uri_destroy (uri_this); | ||
59 | if (uri_next != NULL) | ||
60 | GNUNET_FS_uri_destroy (uri_next); | ||
61 | if (meta != NULL) | ||
62 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
63 | } | ||
64 | |||
65 | |||
66 | static void | ||
67 | check_next (void *cls, const char *last_id, | ||
68 | const struct GNUNET_FS_Uri *last_uri, | ||
69 | const struct GNUNET_CONTAINER_MetaData *last_meta, | ||
70 | const char *next_id) | ||
71 | { | ||
72 | GNUNET_break (0 == strcmp (last_id, "next")); | ||
73 | GNUNET_break (0 == strcmp (next_id, "future")); | ||
74 | err -= 4; | ||
75 | } | ||
76 | |||
77 | |||
78 | static void | ||
79 | check_this_next (void *cls, const char *last_id, | ||
80 | const struct GNUNET_FS_Uri *last_uri, | ||
81 | const struct GNUNET_CONTAINER_MetaData *last_meta, | ||
82 | const char *next_id) | ||
83 | { | ||
84 | GNUNET_break (0 == strcmp (last_id, "this")); | ||
85 | GNUNET_break (0 == strcmp (next_id, "next")); | ||
86 | err -= 2; | ||
87 | err += 4; | ||
88 | GNUNET_FS_namespace_list_updateable (fs, &ns, next_id, &check_next, NULL); | ||
89 | } | ||
90 | |||
91 | |||
92 | static void | ||
93 | sks_cont_next (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) | ||
94 | { | ||
95 | GNUNET_assert (NULL == emsg); | ||
96 | err += 2; | ||
97 | GNUNET_FS_namespace_list_updateable (fs, &ns, NULL, &check_this_next, NULL); | ||
98 | } | ||
99 | |||
100 | |||
101 | static void | ||
102 | check_this (void *cls, const char *last_id, | ||
103 | const struct GNUNET_FS_Uri *last_uri, | ||
104 | const struct GNUNET_CONTAINER_MetaData *last_meta, | ||
105 | const char *next_id) | ||
106 | { | ||
107 | GNUNET_break (0 == strcmp (last_id, "this")); | ||
108 | GNUNET_break (0 == strcmp (next_id, "next")); | ||
109 | err -= 1; | ||
110 | } | ||
111 | |||
112 | |||
113 | static void | ||
114 | sks_cont_this (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) | ||
115 | { | ||
116 | GNUNET_assert (NULL == emsg); | ||
117 | err = 1; | ||
118 | GNUNET_FS_namespace_list_updateable (fs, &ns, NULL, &check_this, NULL); | ||
119 | GNUNET_FS_publish_sks (fs, | ||
120 | &ns, "next", "future", meta, uri_next, &bo, | ||
121 | GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont_next, NULL); | ||
122 | } | ||
123 | |||
124 | |||
125 | static void | ||
126 | testNamespace (void) | ||
127 | { | ||
128 | GNUNET_CRYPTO_ecdsa_key_create (&ns); | ||
129 | bo.content_priority = 1; | ||
130 | bo.anonymity_level = 1; | ||
131 | bo.replication_level = 0; | ||
132 | bo.expiration_time = | ||
133 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); | ||
134 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
135 | |||
136 | uri_this = | ||
137 | GNUNET_FS_uri_parse | ||
138 | ( | ||
139 | "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42", | ||
140 | NULL); | ||
141 | uri_next = | ||
142 | GNUNET_FS_uri_parse | ||
143 | ( | ||
144 | "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.43", | ||
145 | NULL); | ||
146 | GNUNET_FS_publish_sks (fs, | ||
147 | &ns, "this", "next", meta, uri_this, &bo, | ||
148 | GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont_this, NULL); | ||
149 | } | ||
150 | |||
151 | |||
152 | static void | ||
153 | run (void *cls, | ||
154 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
155 | struct GNUNET_TESTING_Peer *peer) | ||
156 | { | ||
157 | fs = GNUNET_FS_start (cfg, "test-fs-namespace", &progress_cb, NULL, | ||
158 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
159 | testNamespace (); | ||
160 | } | ||
161 | |||
162 | |||
163 | int | ||
164 | main (int argc, char *argv[]) | ||
165 | { | ||
166 | if (0 != GNUNET_TESTING_peer_run ("test-fs-namespace-list-updateable", | ||
167 | "test_fs_namespace_data.conf", | ||
168 | &run, NULL)) | ||
169 | return 1; | ||
170 | do_shutdown (); | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | |||
175 | /* end of test_fs_namespace_list_updateable.c */ | ||
diff --git a/src/fs/test_fs_publish.c b/src/fs/test_fs_publish.c deleted file mode 100644 index 2ffc722da..000000000 --- a/src/fs/test_fs_publish.c +++ /dev/null | |||
@@ -1,251 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_publish.c | ||
22 | * @brief simple testcase for publish operation (indexing, listing | ||
23 | * indexed, directory structure) | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE (1024 * 1024 * 2) | ||
35 | |||
36 | /** | ||
37 | * How long until we give up on transmitting the message? | ||
38 | */ | ||
39 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
40 | |||
41 | /** | ||
42 | * How long should our test-content live? | ||
43 | */ | ||
44 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
45 | |||
46 | |||
47 | static struct GNUNET_TIME_Absolute start; | ||
48 | |||
49 | static struct GNUNET_FS_Handle *fs; | ||
50 | |||
51 | static struct GNUNET_FS_PublishContext *publish; | ||
52 | |||
53 | static char *fn1; | ||
54 | |||
55 | static char *fn2; | ||
56 | |||
57 | static int err; | ||
58 | |||
59 | |||
60 | static void | ||
61 | abort_publish_task (void *cls) | ||
62 | { | ||
63 | GNUNET_FS_publish_stop (publish); | ||
64 | publish = NULL; | ||
65 | GNUNET_DISK_directory_remove (fn1); | ||
66 | GNUNET_free (fn1); | ||
67 | fn1 = NULL; | ||
68 | GNUNET_DISK_directory_remove (fn2); | ||
69 | GNUNET_free (fn2); | ||
70 | fn2 = NULL; | ||
71 | } | ||
72 | |||
73 | |||
74 | static void * | ||
75 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
76 | { | ||
77 | void *ret; | ||
78 | |||
79 | ret = NULL; | ||
80 | switch (event->status) | ||
81 | { | ||
82 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
83 | ret = event->value.publish.cctx; | ||
84 | printf ("Publish complete, %llu kbps.\n", | ||
85 | (unsigned long long) (FILESIZE * 1000000LL | ||
86 | / (1 | ||
87 | + GNUNET_TIME_absolute_get_duration | ||
88 | (start).rel_value_us) / 1024)); | ||
89 | if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) | ||
90 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
91 | break; | ||
92 | |||
93 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
94 | ret = event->value.publish.cctx; | ||
95 | GNUNET_assert (publish == event->value.publish.pc); | ||
96 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
97 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
98 | (unsigned long long) event->value.publish.completed, | ||
99 | (unsigned long long) event->value.publish.size, | ||
100 | event->value.publish.specifics.progress.depth, | ||
101 | (unsigned long long) event->value.publish.specifics. | ||
102 | progress.offset); | ||
103 | break; | ||
104 | |||
105 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
106 | ret = event->value.publish.cctx; | ||
107 | break; | ||
108 | |||
109 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
110 | ret = event->value.publish.cctx; | ||
111 | fprintf (stderr, "Error publishing file: %s\n", | ||
112 | event->value.publish.specifics.error.message); | ||
113 | err = 1; | ||
114 | if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) | ||
115 | { | ||
116 | fprintf (stderr, "Scheduling abort task for error on `%s'\n", | ||
117 | (const char *) event->value.publish.cctx); | ||
118 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
119 | } | ||
120 | break; | ||
121 | |||
122 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
123 | ret = event->value.publish.cctx; | ||
124 | if (0 == strcmp ("publish-context1", event->value.publish.cctx)) | ||
125 | { | ||
126 | GNUNET_assert (0 == | ||
127 | strcmp ("publish-context-dir", event->value.publish.pctx)); | ||
128 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
129 | GNUNET_assert (0 == event->value.publish.completed); | ||
130 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
131 | } | ||
132 | else if (0 == strcmp ("publish-context2", event->value.publish.cctx)) | ||
133 | { | ||
134 | GNUNET_assert (0 == | ||
135 | strcmp ("publish-context-dir", event->value.publish.pctx)); | ||
136 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
137 | GNUNET_assert (0 == event->value.publish.completed); | ||
138 | GNUNET_assert (2 == event->value.publish.anonymity); | ||
139 | } | ||
140 | else if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) | ||
141 | { | ||
142 | GNUNET_assert (0 == event->value.publish.completed); | ||
143 | GNUNET_assert (3 == event->value.publish.anonymity); | ||
144 | } | ||
145 | else | ||
146 | GNUNET_assert (0); | ||
147 | break; | ||
148 | |||
149 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
150 | if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) | ||
151 | GNUNET_assert (publish == event->value.publish.pc); | ||
152 | break; | ||
153 | |||
154 | default: | ||
155 | printf ("Unexpected event: %d\n", event->status); | ||
156 | break; | ||
157 | } | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | |||
162 | static void | ||
163 | run (void *cls, | ||
164 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
165 | struct GNUNET_TESTING_Peer *peer) | ||
166 | { | ||
167 | const char *keywords[] = { | ||
168 | "down_foo", | ||
169 | "down_bar", | ||
170 | }; | ||
171 | char *buf; | ||
172 | struct GNUNET_CONTAINER_MetaData *meta; | ||
173 | struct GNUNET_FS_Uri *kuri; | ||
174 | struct GNUNET_FS_FileInformation *fi1; | ||
175 | struct GNUNET_FS_FileInformation *fi2; | ||
176 | struct GNUNET_FS_FileInformation *fidir; | ||
177 | size_t i; | ||
178 | struct GNUNET_FS_BlockOptions bo; | ||
179 | |||
180 | fs = GNUNET_FS_start (cfg, "test-fs-publish", &progress_cb, NULL, | ||
181 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
182 | GNUNET_assert (NULL != fs); | ||
183 | fn1 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); | ||
184 | buf = GNUNET_malloc (FILESIZE); | ||
185 | for (i = 0; i < FILESIZE; i++) | ||
186 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
187 | (void) GNUNET_DISK_directory_remove (fn1); | ||
188 | GNUNET_assert (GNUNET_OK == | ||
189 | GNUNET_DISK_fn_write (fn1, buf, FILESIZE, | ||
190 | GNUNET_DISK_PERM_USER_READ | ||
191 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
192 | GNUNET_free (buf); | ||
193 | |||
194 | fn2 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); | ||
195 | buf = GNUNET_malloc (FILESIZE); | ||
196 | for (i = 0; i < FILESIZE; i++) | ||
197 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
198 | (void) GNUNET_DISK_directory_remove (fn2); | ||
199 | GNUNET_assert (GNUNET_OK == | ||
200 | GNUNET_DISK_fn_write (fn2, buf, FILESIZE, | ||
201 | GNUNET_DISK_PERM_USER_READ | ||
202 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
203 | GNUNET_free (buf); | ||
204 | |||
205 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
206 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
207 | bo.content_priority = 42; | ||
208 | bo.anonymity_level = 1; | ||
209 | bo.replication_level = 0; | ||
210 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
211 | |||
212 | fi1 = | ||
213 | GNUNET_FS_file_information_create_from_file (fs, "publish-context1", fn1, | ||
214 | kuri, meta, GNUNET_YES, &bo); | ||
215 | |||
216 | GNUNET_assert (NULL != fi1); | ||
217 | bo.anonymity_level = 2; | ||
218 | fi2 = | ||
219 | GNUNET_FS_file_information_create_from_file (fs, "publish-context2", fn2, | ||
220 | kuri, meta, GNUNET_YES, &bo); | ||
221 | GNUNET_assert (NULL != fi2); | ||
222 | bo.anonymity_level = 3; | ||
223 | fidir = | ||
224 | GNUNET_FS_file_information_create_empty_directory (fs, | ||
225 | "publish-context-dir", | ||
226 | kuri, meta, &bo, NULL); | ||
227 | GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); | ||
228 | GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); | ||
229 | GNUNET_FS_uri_destroy (kuri); | ||
230 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
231 | GNUNET_assert (NULL != fidir); | ||
232 | start = GNUNET_TIME_absolute_get (); | ||
233 | publish = | ||
234 | GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, | ||
235 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
236 | GNUNET_assert (publish != NULL); | ||
237 | } | ||
238 | |||
239 | |||
240 | int | ||
241 | main (int argc, char *argv[]) | ||
242 | { | ||
243 | if (0 != GNUNET_TESTING_peer_run ("test-fs-publish", | ||
244 | "test_fs_publish_data.conf", | ||
245 | &run, NULL)) | ||
246 | return 1; | ||
247 | return err; | ||
248 | } | ||
249 | |||
250 | |||
251 | /* end of test_fs_publish.c */ | ||
diff --git a/src/fs/test_fs_publish_data.conf b/src/fs/test_fs_publish_data.conf deleted file mode 100644 index 0930cdfed..000000000 --- a/src/fs/test_fs_publish_data.conf +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-publish/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
8 | [fs] | ||
9 | ACTIVEMIGRATION = NO | ||
10 | |||
diff --git a/src/fs/test_fs_publish_persistence.c b/src/fs/test_fs_publish_persistence.c deleted file mode 100644 index da0209793..000000000 --- a/src/fs/test_fs_publish_persistence.c +++ /dev/null | |||
@@ -1,322 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_publish_persistence.c | ||
22 | * @brief simple testcase for persistence of simple publish operation | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_testing_lib.h" | ||
28 | #include "gnunet_fs_service.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE (1024 * 1024 * 2) | ||
35 | |||
36 | /** | ||
37 | * How long until we give up on transmitting the message? | ||
38 | */ | ||
39 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
40 | |||
41 | /** | ||
42 | * How long should our test-content live? | ||
43 | */ | ||
44 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
45 | |||
46 | |||
47 | static struct GNUNET_TIME_Absolute start; | ||
48 | |||
49 | static struct GNUNET_FS_Handle *fs; | ||
50 | |||
51 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
52 | |||
53 | static struct GNUNET_FS_PublishContext *publish; | ||
54 | |||
55 | static struct GNUNET_FS_PublishContext *publish; | ||
56 | |||
57 | static char *fn1; | ||
58 | |||
59 | static char *fn2; | ||
60 | |||
61 | static int err; | ||
62 | |||
63 | static struct GNUNET_SCHEDULER_Task *rtask; | ||
64 | |||
65 | |||
66 | static void | ||
67 | abort_publish_task (void *cls) | ||
68 | { | ||
69 | GNUNET_FS_publish_stop (publish); | ||
70 | publish = NULL; | ||
71 | GNUNET_DISK_directory_remove (fn1); | ||
72 | GNUNET_free (fn1); | ||
73 | fn1 = NULL; | ||
74 | GNUNET_DISK_directory_remove (fn2); | ||
75 | GNUNET_free (fn2); | ||
76 | fn2 = NULL; | ||
77 | GNUNET_FS_stop (fs); | ||
78 | fs = NULL; | ||
79 | if (NULL != rtask) | ||
80 | { | ||
81 | GNUNET_SCHEDULER_cancel (rtask); | ||
82 | rtask = NULL; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | |||
87 | static void * | ||
88 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); | ||
89 | |||
90 | |||
91 | static void | ||
92 | restart_fs_task (void *cls) | ||
93 | { | ||
94 | rtask = NULL; | ||
95 | GNUNET_FS_stop (fs); | ||
96 | fs = GNUNET_FS_start (cfg, "test-fs-publish-persistence", | ||
97 | &progress_cb, NULL, | ||
98 | GNUNET_FS_FLAGS_PERSISTENCE, | ||
99 | GNUNET_FS_OPTIONS_END); | ||
100 | } | ||
101 | |||
102 | |||
103 | /** | ||
104 | * Consider scheduling the restart-task. | ||
105 | * Only runs the restart task once per event | ||
106 | * category. | ||
107 | * | ||
108 | * @param ev type of the event to consider | ||
109 | */ | ||
110 | static void | ||
111 | consider_restart (int ev) | ||
112 | { | ||
113 | static int prev[32]; | ||
114 | static int off; | ||
115 | int i; | ||
116 | |||
117 | for (i = 0; i < off; i++) | ||
118 | if (prev[i] == ev) | ||
119 | return; | ||
120 | prev[off++] = ev; | ||
121 | rtask = | ||
122 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, | ||
123 | &restart_fs_task, NULL); | ||
124 | } | ||
125 | |||
126 | |||
127 | static void * | ||
128 | progress_cb (void *cls, | ||
129 | const struct GNUNET_FS_ProgressInfo *event) | ||
130 | { | ||
131 | void *ret; | ||
132 | |||
133 | ret = NULL; | ||
134 | switch (event->status) | ||
135 | { | ||
136 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
137 | ret = event->value.publish.cctx; | ||
138 | printf ("Publish complete, %llu kbps.\n", | ||
139 | (unsigned long long) (FILESIZE * 1000000LL | ||
140 | / (1 | ||
141 | + GNUNET_TIME_absolute_get_duration | ||
142 | (start).rel_value_us) / 1024)); | ||
143 | if ((NULL != event->value.publish.cctx) && | ||
144 | (0 == strcmp ("publish-context-dir", event->value.publish.cctx))) | ||
145 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
146 | break; | ||
147 | |||
148 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
149 | ret = event->value.publish.cctx; | ||
150 | return ret; | ||
151 | |||
152 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
153 | consider_restart (event->status); | ||
154 | ret = event->value.publish.cctx; | ||
155 | GNUNET_assert (publish == event->value.publish.pc); | ||
156 | #if VERBOSE | ||
157 | printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
158 | (unsigned long long) event->value.publish.completed, | ||
159 | (unsigned long long) event->value.publish.size, | ||
160 | event->value.publish.specifics.progress.depth, | ||
161 | (unsigned long long) event->value.publish.specifics. | ||
162 | progress.offset); | ||
163 | #endif | ||
164 | break; | ||
165 | |||
166 | case GNUNET_FS_STATUS_PUBLISH_SUSPEND: | ||
167 | if (event->value.publish.pc == publish) | ||
168 | publish = NULL; | ||
169 | break; | ||
170 | |||
171 | case GNUNET_FS_STATUS_PUBLISH_RESUME: | ||
172 | if (NULL == publish) | ||
173 | { | ||
174 | GNUNET_assert (GNUNET_YES == | ||
175 | GNUNET_FS_file_information_is_directory (event-> | ||
176 | value.publish. | ||
177 | fi)); | ||
178 | publish = event->value.publish.pc; | ||
179 | return "publish-context-dir"; | ||
180 | } | ||
181 | break; | ||
182 | |||
183 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
184 | ret = event->value.publish.cctx; | ||
185 | fprintf (stderr, "Error publishing file: %s\n", | ||
186 | event->value.publish.specifics.error.message); | ||
187 | err = 1; | ||
188 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
189 | break; | ||
190 | |||
191 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
192 | consider_restart (event->status); | ||
193 | publish = event->value.publish.pc; | ||
194 | ret = event->value.publish.cctx; | ||
195 | if (0 == strcmp ("publish-context1", event->value.publish.cctx)) | ||
196 | { | ||
197 | GNUNET_assert (0 == | ||
198 | strcmp ("publish-context-dir", event->value.publish.pctx)); | ||
199 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
200 | GNUNET_assert (0 == event->value.publish.completed); | ||
201 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
202 | } | ||
203 | else if (0 == strcmp ("publish-context2", event->value.publish.cctx)) | ||
204 | { | ||
205 | GNUNET_assert (0 == | ||
206 | strcmp ("publish-context-dir", event->value.publish.pctx)); | ||
207 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
208 | GNUNET_assert (0 == event->value.publish.completed); | ||
209 | GNUNET_assert (2 == event->value.publish.anonymity); | ||
210 | } | ||
211 | else if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) | ||
212 | { | ||
213 | GNUNET_assert (0 == event->value.publish.completed); | ||
214 | GNUNET_assert (3 == event->value.publish.anonymity); | ||
215 | } | ||
216 | else | ||
217 | GNUNET_assert (0); | ||
218 | break; | ||
219 | |||
220 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
221 | consider_restart (event->status); | ||
222 | if ((NULL != event->value.publish.cctx) && | ||
223 | (0 == strcmp ("publish-context-dir", event->value.publish.cctx))) | ||
224 | GNUNET_assert (publish == event->value.publish.pc); | ||
225 | break; | ||
226 | |||
227 | default: | ||
228 | printf ("Unexpected event: %d\n", event->status); | ||
229 | break; | ||
230 | } | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | |||
235 | static void | ||
236 | run (void *cls, | ||
237 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
238 | struct GNUNET_TESTING_Peer *peer) | ||
239 | { | ||
240 | const char *keywords[] = { | ||
241 | "down_foo", | ||
242 | "down_bar", | ||
243 | }; | ||
244 | char *buf; | ||
245 | struct GNUNET_CONTAINER_MetaData *meta; | ||
246 | struct GNUNET_FS_Uri *kuri; | ||
247 | struct GNUNET_FS_FileInformation *fi1; | ||
248 | struct GNUNET_FS_FileInformation *fi2; | ||
249 | struct GNUNET_FS_FileInformation *fidir; | ||
250 | size_t i; | ||
251 | struct GNUNET_FS_BlockOptions bo; | ||
252 | |||
253 | cfg = c; | ||
254 | fs = GNUNET_FS_start (cfg, "test-fs-publish-persistence", &progress_cb, NULL, | ||
255 | GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); | ||
256 | GNUNET_assert (NULL != fs); | ||
257 | fn1 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); | ||
258 | buf = GNUNET_malloc (FILESIZE); | ||
259 | for (i = 0; i < FILESIZE; i++) | ||
260 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
261 | (void) GNUNET_DISK_directory_remove (fn1); | ||
262 | GNUNET_assert (GNUNET_OK == | ||
263 | GNUNET_DISK_fn_write (fn1, buf, FILESIZE, | ||
264 | GNUNET_DISK_PERM_USER_READ | ||
265 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
266 | GNUNET_free (buf); | ||
267 | |||
268 | fn2 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); | ||
269 | buf = GNUNET_malloc (FILESIZE); | ||
270 | for (i = 0; i < FILESIZE; i++) | ||
271 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
272 | (void) GNUNET_DISK_directory_remove (fn2); | ||
273 | GNUNET_assert (GNUNET_OK == | ||
274 | GNUNET_DISK_fn_write (fn2, buf, FILESIZE, | ||
275 | GNUNET_DISK_PERM_USER_READ | ||
276 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
277 | GNUNET_free (buf); | ||
278 | |||
279 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
280 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
281 | bo.content_priority = 42; | ||
282 | bo.anonymity_level = 1; | ||
283 | bo.replication_level = 0; | ||
284 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
285 | fi1 = | ||
286 | GNUNET_FS_file_information_create_from_file (fs, "publish-context1", fn1, | ||
287 | kuri, meta, GNUNET_YES, &bo); | ||
288 | GNUNET_assert (NULL != fi1); | ||
289 | bo.anonymity_level = 2; | ||
290 | fi2 = | ||
291 | GNUNET_FS_file_information_create_from_file (fs, "publish-context2", fn2, | ||
292 | kuri, meta, GNUNET_YES, &bo); | ||
293 | GNUNET_assert (NULL != fi2); | ||
294 | bo.anonymity_level = 3; | ||
295 | fidir = | ||
296 | GNUNET_FS_file_information_create_empty_directory (fs, | ||
297 | "publish-context-dir", | ||
298 | kuri, meta, &bo, NULL); | ||
299 | GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); | ||
300 | GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); | ||
301 | GNUNET_FS_uri_destroy (kuri); | ||
302 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
303 | GNUNET_assert (NULL != fidir); | ||
304 | start = GNUNET_TIME_absolute_get (); | ||
305 | GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, | ||
306 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
307 | GNUNET_assert (publish != NULL); | ||
308 | } | ||
309 | |||
310 | |||
311 | int | ||
312 | main (int argc, char *argv[]) | ||
313 | { | ||
314 | if (0 != GNUNET_TESTING_peer_run ("test-fs-publish-persistence", | ||
315 | "test_fs_publish_data.conf", | ||
316 | &run, NULL)) | ||
317 | return 1; | ||
318 | return err; | ||
319 | } | ||
320 | |||
321 | |||
322 | /* end of test_fs_publish_persistence.c */ | ||
diff --git a/src/fs/test_fs_search.c b/src/fs/test_fs_search.c deleted file mode 100644 index b392cc8ac..000000000 --- a/src/fs/test_fs_search.c +++ /dev/null | |||
@@ -1,252 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_search.c | ||
22 | * @brief simple testcase for simple publish + search operation | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_testing_lib.h" | ||
28 | #include "gnunet_fs_service.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE 1024 | ||
35 | |||
36 | /** | ||
37 | * How long until we give up on transmitting the message? | ||
38 | */ | ||
39 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
40 | |||
41 | /** | ||
42 | * How long should our test-content live? | ||
43 | */ | ||
44 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
45 | |||
46 | |||
47 | static struct GNUNET_TIME_Absolute start; | ||
48 | |||
49 | static struct GNUNET_FS_Handle *fs; | ||
50 | |||
51 | static struct GNUNET_FS_SearchContext *search; | ||
52 | |||
53 | static struct GNUNET_FS_PublishContext *publish; | ||
54 | |||
55 | static struct GNUNET_SCHEDULER_Task *timeout_task; | ||
56 | |||
57 | static int err; | ||
58 | |||
59 | |||
60 | static void | ||
61 | abort_publish_task (void *cls) | ||
62 | { | ||
63 | if (NULL != publish) | ||
64 | { | ||
65 | GNUNET_FS_publish_stop (publish); | ||
66 | publish = NULL; | ||
67 | } | ||
68 | if (NULL != timeout_task) | ||
69 | { | ||
70 | GNUNET_SCHEDULER_cancel (timeout_task); | ||
71 | timeout_task = NULL; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | |||
76 | static void | ||
77 | abort_error (void *cls) | ||
78 | { | ||
79 | fprintf (stderr, | ||
80 | "Timeout\n"); | ||
81 | timeout_task = NULL; | ||
82 | if (NULL != search) | ||
83 | { | ||
84 | GNUNET_FS_search_stop (search); | ||
85 | search = NULL; | ||
86 | } | ||
87 | if (NULL != publish) | ||
88 | { | ||
89 | GNUNET_FS_publish_stop (publish); | ||
90 | publish = NULL; | ||
91 | } | ||
92 | err = 1; | ||
93 | } | ||
94 | |||
95 | |||
96 | static void | ||
97 | abort_search_task (void *cls) | ||
98 | { | ||
99 | if (NULL != search) | ||
100 | { | ||
101 | GNUNET_FS_search_stop (search); | ||
102 | search = NULL; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | |||
107 | static void * | ||
108 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
109 | { | ||
110 | const char *keywords[] = { | ||
111 | "down_foo" | ||
112 | }; | ||
113 | struct GNUNET_FS_Uri *kuri; | ||
114 | |||
115 | switch (event->status) | ||
116 | { | ||
117 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
118 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
119 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
120 | (unsigned long long) event->value.publish.completed, | ||
121 | (unsigned long long) event->value.publish.size, | ||
122 | event->value.publish.specifics.progress.depth, | ||
123 | (unsigned long long) event->value.publish.specifics. | ||
124 | progress.offset); | ||
125 | break; | ||
126 | |||
127 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
128 | break; | ||
129 | |||
130 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
131 | kuri = GNUNET_FS_uri_ksk_create_from_args (1, keywords); | ||
132 | start = GNUNET_TIME_absolute_get (); | ||
133 | search = | ||
134 | GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, | ||
135 | "search"); | ||
136 | GNUNET_FS_uri_destroy (kuri); | ||
137 | GNUNET_assert (search != NULL); | ||
138 | break; | ||
139 | |||
140 | case GNUNET_FS_STATUS_SEARCH_RESULT: | ||
141 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
142 | "Search complete.\n"); | ||
143 | GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); | ||
144 | break; | ||
145 | |||
146 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
147 | fprintf (stderr, "Error publishing file: %s\n", | ||
148 | event->value.publish.specifics.error.message); | ||
149 | GNUNET_break (0); | ||
150 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
151 | break; | ||
152 | |||
153 | case GNUNET_FS_STATUS_SEARCH_ERROR: | ||
154 | fprintf (stderr, "Error searching file: %s\n", | ||
155 | event->value.search.specifics.error.message); | ||
156 | GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); | ||
157 | break; | ||
158 | |||
159 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
160 | GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); | ||
161 | GNUNET_assert (NULL == event->value.publish.pctx); | ||
162 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
163 | GNUNET_assert (0 == event->value.publish.completed); | ||
164 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
165 | break; | ||
166 | |||
167 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
168 | GNUNET_assert (publish == event->value.publish.pc); | ||
169 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
170 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
171 | GNUNET_FS_stop (fs); | ||
172 | fs = NULL; | ||
173 | break; | ||
174 | |||
175 | case GNUNET_FS_STATUS_SEARCH_START: | ||
176 | GNUNET_assert (search == NULL); | ||
177 | GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); | ||
178 | GNUNET_assert (1 == event->value.search.anonymity); | ||
179 | break; | ||
180 | |||
181 | case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: | ||
182 | break; | ||
183 | |||
184 | case GNUNET_FS_STATUS_SEARCH_STOPPED: | ||
185 | GNUNET_assert (search == event->value.search.sc); | ||
186 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
187 | break; | ||
188 | |||
189 | default: | ||
190 | fprintf (stderr, "Unexpected event: %d\n", event->status); | ||
191 | break; | ||
192 | } | ||
193 | return NULL; | ||
194 | } | ||
195 | |||
196 | |||
197 | static void | ||
198 | run (void *cls, | ||
199 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
200 | struct GNUNET_TESTING_Peer *peer) | ||
201 | { | ||
202 | const char *keywords[] = { | ||
203 | "down_foo", | ||
204 | "down_bar" | ||
205 | }; | ||
206 | char *buf; | ||
207 | struct GNUNET_CONTAINER_MetaData *meta; | ||
208 | struct GNUNET_FS_Uri *kuri; | ||
209 | struct GNUNET_FS_BlockOptions bo; | ||
210 | struct GNUNET_FS_FileInformation *fi; | ||
211 | size_t i; | ||
212 | |||
213 | fs = GNUNET_FS_start (cfg, "test-fs-search", &progress_cb, NULL, | ||
214 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
215 | GNUNET_assert (NULL != fs); | ||
216 | buf = GNUNET_malloc (FILESIZE); | ||
217 | for (i = 0; i < FILESIZE; i++) | ||
218 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
219 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
220 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
221 | bo.content_priority = 42; | ||
222 | bo.anonymity_level = 1; | ||
223 | bo.replication_level = 0; | ||
224 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
225 | fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", | ||
226 | FILESIZE, buf, kuri, meta, | ||
227 | GNUNET_NO, &bo); | ||
228 | GNUNET_FS_uri_destroy (kuri); | ||
229 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
230 | GNUNET_assert (NULL != fi); | ||
231 | start = GNUNET_TIME_absolute_get (); | ||
232 | publish = | ||
233 | GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, | ||
234 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
235 | GNUNET_assert (publish != NULL); | ||
236 | timeout_task = GNUNET_SCHEDULER_add_delayed (LIFETIME, | ||
237 | &abort_error, NULL); | ||
238 | } | ||
239 | |||
240 | |||
241 | int | ||
242 | main (int argc, char *argv[]) | ||
243 | { | ||
244 | if (0 != GNUNET_TESTING_peer_run ("test-fs-search", | ||
245 | "test_fs_search_data.conf", | ||
246 | &run, NULL)) | ||
247 | return 1; | ||
248 | return err; | ||
249 | } | ||
250 | |||
251 | |||
252 | /* end of test_fs_search.c */ | ||
diff --git a/src/fs/test_fs_search_data.conf b/src/fs/test_fs_search_data.conf deleted file mode 100644 index 8b24e328d..000000000 --- a/src/fs/test_fs_search_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-search/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
diff --git a/src/fs/test_fs_search_persistence.c b/src/fs/test_fs_search_persistence.c deleted file mode 100644 index d523a6404..000000000 --- a/src/fs/test_fs_search_persistence.c +++ /dev/null | |||
@@ -1,318 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_search_persistence.c | ||
22 | * @brief simple testcase for persistence of search operation | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_testing_lib.h" | ||
28 | #include "gnunet_fs_service.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE 1024 | ||
35 | |||
36 | /** | ||
37 | * How long until we give up on transmitting the message? | ||
38 | */ | ||
39 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
40 | |||
41 | /** | ||
42 | * How long should our test-content live? | ||
43 | */ | ||
44 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
45 | |||
46 | |||
47 | static struct GNUNET_TIME_Absolute start; | ||
48 | |||
49 | static struct GNUNET_FS_Handle *fs; | ||
50 | |||
51 | static struct GNUNET_FS_SearchContext *search; | ||
52 | |||
53 | static struct GNUNET_FS_PublishContext *publish; | ||
54 | |||
55 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
56 | |||
57 | static struct GNUNET_SCHEDULER_Task *timeout_task; | ||
58 | |||
59 | static int err; | ||
60 | |||
61 | |||
62 | static void | ||
63 | abort_error (void *cls) | ||
64 | { | ||
65 | timeout_task = NULL; | ||
66 | fprintf (stderr, | ||
67 | "Timeout\n"); | ||
68 | if (NULL != search) | ||
69 | { | ||
70 | GNUNET_FS_search_stop (search); | ||
71 | search = NULL; | ||
72 | } | ||
73 | if (NULL != publish) | ||
74 | { | ||
75 | GNUNET_FS_publish_stop (publish); | ||
76 | publish = NULL; | ||
77 | } | ||
78 | err = 1; | ||
79 | } | ||
80 | |||
81 | |||
82 | static void | ||
83 | abort_publish_task (void *cls) | ||
84 | { | ||
85 | if (NULL != publish) | ||
86 | { | ||
87 | GNUNET_FS_publish_stop (publish); | ||
88 | publish = NULL; | ||
89 | } | ||
90 | if (NULL != timeout_task) | ||
91 | { | ||
92 | GNUNET_SCHEDULER_cancel (timeout_task); | ||
93 | timeout_task = NULL; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | |||
98 | static void | ||
99 | abort_search_task (void *cls) | ||
100 | { | ||
101 | if (NULL != search) | ||
102 | { | ||
103 | GNUNET_FS_search_stop (search); | ||
104 | search = NULL; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | |||
109 | static void * | ||
110 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); | ||
111 | |||
112 | |||
113 | static void | ||
114 | restart_fs_task (void *cls) | ||
115 | { | ||
116 | GNUNET_FS_stop (fs); | ||
117 | fs = GNUNET_FS_start (cfg, "test-fs-search-persistence", &progress_cb, NULL, | ||
118 | GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); | ||
119 | } | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Consider scheduling the restart-task. | ||
124 | * Only runs the restart task once per event | ||
125 | * category. | ||
126 | * | ||
127 | * @param ev type of the event to consider | ||
128 | */ | ||
129 | static void | ||
130 | consider_restart (int ev) | ||
131 | { | ||
132 | static int prev[32]; | ||
133 | static int off; | ||
134 | int i; | ||
135 | |||
136 | for (i = 0; i < off; i++) | ||
137 | if (prev[i] == ev) | ||
138 | return; | ||
139 | prev[off++] = ev; | ||
140 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, | ||
141 | &restart_fs_task, NULL); | ||
142 | } | ||
143 | |||
144 | |||
145 | static void * | ||
146 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
147 | { | ||
148 | const char *keywords[] = { | ||
149 | "down_foo" | ||
150 | }; | ||
151 | struct GNUNET_FS_Uri *kuri; | ||
152 | |||
153 | switch (event->status) | ||
154 | { | ||
155 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
156 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
157 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
158 | (unsigned long long) event->value.publish.completed, | ||
159 | (unsigned long long) event->value.publish.size, | ||
160 | event->value.publish.specifics.progress.depth, | ||
161 | (unsigned long long) event->value.publish.specifics. | ||
162 | progress.offset); | ||
163 | break; | ||
164 | |||
165 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
166 | break; | ||
167 | |||
168 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
169 | kuri = GNUNET_FS_uri_ksk_create_from_args (1, keywords); | ||
170 | start = GNUNET_TIME_absolute_get (); | ||
171 | GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, | ||
172 | "search"); | ||
173 | GNUNET_FS_uri_destroy (kuri); | ||
174 | GNUNET_assert (search != NULL); | ||
175 | break; | ||
176 | |||
177 | case GNUNET_FS_STATUS_PUBLISH_SUSPEND: | ||
178 | if (event->value.publish.pc == publish) | ||
179 | publish = NULL; | ||
180 | break; | ||
181 | |||
182 | case GNUNET_FS_STATUS_PUBLISH_RESUME: | ||
183 | if (NULL == publish) | ||
184 | publish = event->value.publish.pc; | ||
185 | break; | ||
186 | |||
187 | case GNUNET_FS_STATUS_SEARCH_RESULT: | ||
188 | /* FIXME: consider_restart (event->status); cannot be tested with | ||
189 | * search result since we exit here after the first one... */ | ||
190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
191 | "Search complete.\n"); | ||
192 | GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); | ||
193 | break; | ||
194 | |||
195 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
196 | fprintf (stderr, "Error publishing file: %s\n", | ||
197 | event->value.publish.specifics.error.message); | ||
198 | GNUNET_break (0); | ||
199 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
200 | break; | ||
201 | |||
202 | case GNUNET_FS_STATUS_SEARCH_ERROR: | ||
203 | fprintf (stderr, "Error searching file: %s\n", | ||
204 | event->value.search.specifics.error.message); | ||
205 | GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); | ||
206 | break; | ||
207 | |||
208 | case GNUNET_FS_STATUS_SEARCH_SUSPEND: | ||
209 | if (event->value.search.sc == search) | ||
210 | search = NULL; | ||
211 | break; | ||
212 | |||
213 | case GNUNET_FS_STATUS_SEARCH_RESUME: | ||
214 | if (NULL == search) | ||
215 | { | ||
216 | search = event->value.search.sc; | ||
217 | return "search"; | ||
218 | } | ||
219 | break; | ||
220 | |||
221 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
222 | GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); | ||
223 | GNUNET_assert (NULL == event->value.publish.pctx); | ||
224 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
225 | GNUNET_assert (0 == event->value.publish.completed); | ||
226 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
227 | break; | ||
228 | |||
229 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
230 | GNUNET_assert (publish == event->value.publish.pc); | ||
231 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
232 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
233 | GNUNET_FS_stop (fs); | ||
234 | fs = NULL; | ||
235 | break; | ||
236 | |||
237 | case GNUNET_FS_STATUS_SEARCH_START: | ||
238 | consider_restart (event->status); | ||
239 | GNUNET_assert (search == NULL); | ||
240 | search = event->value.search.sc; | ||
241 | GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); | ||
242 | GNUNET_assert (1 == event->value.search.anonymity); | ||
243 | break; | ||
244 | |||
245 | case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: | ||
246 | break; | ||
247 | |||
248 | case GNUNET_FS_STATUS_SEARCH_STOPPED: | ||
249 | GNUNET_assert (search == event->value.search.sc); | ||
250 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
251 | search = NULL; | ||
252 | break; | ||
253 | |||
254 | default: | ||
255 | fprintf (stderr, "Unexpected event: %d\n", event->status); | ||
256 | break; | ||
257 | } | ||
258 | return NULL; | ||
259 | } | ||
260 | |||
261 | |||
262 | static void | ||
263 | run (void *cls, | ||
264 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
265 | struct GNUNET_TESTING_Peer *peer) | ||
266 | { | ||
267 | const char *keywords[] = { | ||
268 | "down_foo", | ||
269 | "down_bar" | ||
270 | }; | ||
271 | char *buf; | ||
272 | struct GNUNET_CONTAINER_MetaData *meta; | ||
273 | struct GNUNET_FS_Uri *kuri; | ||
274 | struct GNUNET_FS_FileInformation *fi; | ||
275 | size_t i; | ||
276 | struct GNUNET_FS_BlockOptions bo; | ||
277 | |||
278 | cfg = c; | ||
279 | fs = GNUNET_FS_start (cfg, "test-fs-search-persistence", &progress_cb, NULL, | ||
280 | GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); | ||
281 | GNUNET_assert (NULL != fs); | ||
282 | buf = GNUNET_malloc (FILESIZE); | ||
283 | for (i = 0; i < FILESIZE; i++) | ||
284 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
285 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
286 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
287 | bo.content_priority = 42; | ||
288 | bo.anonymity_level = 1; | ||
289 | bo.replication_level = 0; | ||
290 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
291 | fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", | ||
292 | FILESIZE, buf, kuri, meta, | ||
293 | GNUNET_NO, &bo); | ||
294 | GNUNET_FS_uri_destroy (kuri); | ||
295 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
296 | GNUNET_assert (NULL != fi); | ||
297 | start = GNUNET_TIME_absolute_get (); | ||
298 | publish = | ||
299 | GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, | ||
300 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
301 | GNUNET_assert (publish != NULL); | ||
302 | timeout_task = GNUNET_SCHEDULER_add_delayed (LIFETIME, | ||
303 | &abort_error, NULL); | ||
304 | } | ||
305 | |||
306 | |||
307 | int | ||
308 | main (int argc, char *argv[]) | ||
309 | { | ||
310 | if (0 != GNUNET_TESTING_peer_run ("test-fs-search-persistence", | ||
311 | "test_fs_search_data.conf", | ||
312 | &run, NULL)) | ||
313 | return 1; | ||
314 | return err; | ||
315 | } | ||
316 | |||
317 | |||
318 | /* end of test_fs_search_persistence.c */ | ||
diff --git a/src/fs/test_fs_search_probes.c b/src/fs/test_fs_search_probes.c deleted file mode 100644 index b3c717aa1..000000000 --- a/src/fs/test_fs_search_probes.c +++ /dev/null | |||
@@ -1,258 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_search_probes.c | ||
23 | * @brief simple testcase for publish + search operation with probes | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * File-size we use for testing. | ||
34 | */ | ||
35 | #define FILESIZE 1024 | ||
36 | |||
37 | /** | ||
38 | * How long until we give up on transmitting the message? | ||
39 | */ | ||
40 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
41 | |||
42 | /** | ||
43 | * How long should our test-content live? | ||
44 | */ | ||
45 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
46 | |||
47 | |||
48 | static struct GNUNET_TIME_Absolute start; | ||
49 | |||
50 | static struct GNUNET_FS_Handle *fs; | ||
51 | |||
52 | static struct GNUNET_FS_SearchContext *search; | ||
53 | |||
54 | static struct GNUNET_FS_PublishContext *publish; | ||
55 | |||
56 | static struct GNUNET_SCHEDULER_Task *timeout_task; | ||
57 | |||
58 | static int err; | ||
59 | |||
60 | |||
61 | static void | ||
62 | abort_error (void *cls) | ||
63 | { | ||
64 | timeout_task = NULL; | ||
65 | fprintf (stderr, | ||
66 | "Timeout\n"); | ||
67 | if (NULL != search) | ||
68 | { | ||
69 | GNUNET_FS_search_stop (search); | ||
70 | search = NULL; | ||
71 | } | ||
72 | if (NULL != publish) | ||
73 | { | ||
74 | GNUNET_FS_publish_stop (publish); | ||
75 | publish = NULL; | ||
76 | } | ||
77 | err = 1; | ||
78 | } | ||
79 | |||
80 | |||
81 | static void | ||
82 | abort_publish_task (void *cls) | ||
83 | { | ||
84 | if (NULL != publish) | ||
85 | { | ||
86 | GNUNET_FS_publish_stop (publish); | ||
87 | publish = NULL; | ||
88 | } | ||
89 | if (NULL != timeout_task) | ||
90 | { | ||
91 | GNUNET_SCHEDULER_cancel (timeout_task); | ||
92 | timeout_task = NULL; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | |||
97 | static void | ||
98 | abort_search_task (void *cls) | ||
99 | { | ||
100 | if (search != NULL) | ||
101 | GNUNET_FS_search_stop (search); | ||
102 | search = NULL; | ||
103 | } | ||
104 | |||
105 | |||
106 | static void * | ||
107 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
108 | { | ||
109 | const char *keywords[] = { | ||
110 | "down_foo" | ||
111 | }; | ||
112 | struct GNUNET_FS_Uri *kuri; | ||
113 | |||
114 | switch (event->status) | ||
115 | { | ||
116 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
117 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
118 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
119 | (unsigned long long) event->value.publish.completed, | ||
120 | (unsigned long long) event->value.publish.size, | ||
121 | event->value.publish.specifics.progress.depth, | ||
122 | (unsigned long long) event->value.publish.specifics. | ||
123 | progress.offset); | ||
124 | break; | ||
125 | |||
126 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
127 | break; | ||
128 | |||
129 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
130 | kuri = GNUNET_FS_uri_ksk_create_from_args (1, keywords); | ||
131 | start = GNUNET_TIME_absolute_get (); | ||
132 | search = | ||
133 | GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, | ||
134 | "search"); | ||
135 | GNUNET_FS_uri_destroy (kuri); | ||
136 | GNUNET_assert (search != NULL); | ||
137 | break; | ||
138 | |||
139 | case GNUNET_FS_STATUS_SEARCH_RESULT: | ||
140 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Search complete.\n"); | ||
141 | break; | ||
142 | |||
143 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
144 | fprintf (stderr, "Error publishing file: %s\n", | ||
145 | event->value.publish.specifics.error.message); | ||
146 | GNUNET_break (0); | ||
147 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
148 | break; | ||
149 | |||
150 | case GNUNET_FS_STATUS_SEARCH_ERROR: | ||
151 | fprintf (stderr, "Error searching file: %s\n", | ||
152 | event->value.search.specifics.error.message); | ||
153 | GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); | ||
154 | break; | ||
155 | |||
156 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
157 | GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); | ||
158 | GNUNET_assert (NULL == event->value.publish.pctx); | ||
159 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
160 | GNUNET_assert (0 == event->value.publish.completed); | ||
161 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
162 | break; | ||
163 | |||
164 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
165 | GNUNET_assert (publish == event->value.publish.pc); | ||
166 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
167 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
168 | GNUNET_FS_stop (fs); | ||
169 | fs = NULL; | ||
170 | break; | ||
171 | |||
172 | case GNUNET_FS_STATUS_SEARCH_UPDATE: | ||
173 | if ((0 < event->value.search.specifics.update.availability_rank) && | ||
174 | (0 < event->value.search.specifics.update.availability_certainty)) | ||
175 | GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); | ||
176 | break; | ||
177 | |||
178 | case GNUNET_FS_STATUS_SEARCH_START: | ||
179 | GNUNET_assert (search == NULL); | ||
180 | GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); | ||
181 | GNUNET_assert (1 == event->value.search.anonymity); | ||
182 | break; | ||
183 | |||
184 | case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: | ||
185 | break; | ||
186 | |||
187 | case GNUNET_FS_STATUS_SEARCH_STOPPED: | ||
188 | GNUNET_assert (search == event->value.search.sc); | ||
189 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
190 | break; | ||
191 | |||
192 | default: | ||
193 | fprintf (stderr, | ||
194 | "Unexpected event: %d\n", | ||
195 | event->status); | ||
196 | break; | ||
197 | } | ||
198 | return NULL; | ||
199 | } | ||
200 | |||
201 | |||
202 | static void | ||
203 | run (void *cls, | ||
204 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
205 | struct GNUNET_TESTING_Peer *peer) | ||
206 | { | ||
207 | const char *keywords[] = { | ||
208 | "down_foo", | ||
209 | "down_bar" | ||
210 | }; | ||
211 | char *buf; | ||
212 | struct GNUNET_CONTAINER_MetaData *meta; | ||
213 | struct GNUNET_FS_Uri *kuri; | ||
214 | struct GNUNET_FS_BlockOptions bo; | ||
215 | struct GNUNET_FS_FileInformation *fi; | ||
216 | size_t i; | ||
217 | |||
218 | fs = GNUNET_FS_start (cfg, "test-fs-search", &progress_cb, NULL, | ||
219 | GNUNET_FS_FLAGS_DO_PROBES, | ||
220 | GNUNET_FS_OPTIONS_END); | ||
221 | GNUNET_assert (NULL != fs); | ||
222 | buf = GNUNET_malloc (FILESIZE); | ||
223 | for (i = 0; i < FILESIZE; i++) | ||
224 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
225 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
226 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
227 | bo.content_priority = 42; | ||
228 | bo.anonymity_level = 1; | ||
229 | bo.replication_level = 0; | ||
230 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
231 | fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", | ||
232 | FILESIZE, buf, kuri, meta, | ||
233 | GNUNET_NO, &bo); | ||
234 | GNUNET_FS_uri_destroy (kuri); | ||
235 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
236 | GNUNET_assert (NULL != fi); | ||
237 | start = GNUNET_TIME_absolute_get (); | ||
238 | publish = | ||
239 | GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, | ||
240 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
241 | GNUNET_assert (publish != NULL); | ||
242 | timeout_task = GNUNET_SCHEDULER_add_delayed (LIFETIME, | ||
243 | &abort_error, NULL); | ||
244 | } | ||
245 | |||
246 | |||
247 | int | ||
248 | main (int argc, char *argv[]) | ||
249 | { | ||
250 | if (0 != GNUNET_TESTING_peer_run ("test-fs-search-probes", | ||
251 | "test_fs_search_data.conf", | ||
252 | &run, NULL)) | ||
253 | return 1; | ||
254 | return err; | ||
255 | } | ||
256 | |||
257 | |||
258 | /* end of test_fs_search_probes.c */ | ||
diff --git a/src/fs/test_fs_search_with_and.c b/src/fs/test_fs_search_with_and.c deleted file mode 100644 index 2187f4531..000000000 --- a/src/fs/test_fs_search_with_and.c +++ /dev/null | |||
@@ -1,272 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_search_with_and.c | ||
22 | * @brief testcase for publishing multiple files and search with a and operator | ||
23 | * @author Bruno Cabral - 99% based on Christian Grothoff code | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_testing_lib.h" | ||
28 | #include "gnunet_fs_service.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE 1024 | ||
35 | |||
36 | /** | ||
37 | * Number of files for testing. | ||
38 | */ | ||
39 | #define NUM_FILES 10 | ||
40 | |||
41 | |||
42 | /** | ||
43 | * How long until we give up on transmitting the message? | ||
44 | */ | ||
45 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
46 | |||
47 | /** | ||
48 | * How long should our test-content live? | ||
49 | */ | ||
50 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
51 | |||
52 | |||
53 | static struct GNUNET_TIME_Absolute start; | ||
54 | |||
55 | static struct GNUNET_FS_Handle *fs; | ||
56 | |||
57 | static struct GNUNET_FS_SearchContext *search; | ||
58 | |||
59 | static struct GNUNET_FS_PublishContext *publish; | ||
60 | |||
61 | static struct GNUNET_SCHEDULER_Task *timeout_task; | ||
62 | |||
63 | static int err; | ||
64 | |||
65 | static int processed_files; | ||
66 | |||
67 | |||
68 | static void | ||
69 | abort_publish_task (void *cls) | ||
70 | { | ||
71 | if (NULL != publish) | ||
72 | { | ||
73 | GNUNET_FS_publish_stop (publish); | ||
74 | publish = NULL; | ||
75 | } | ||
76 | if (NULL != timeout_task) | ||
77 | { | ||
78 | GNUNET_SCHEDULER_cancel (timeout_task); | ||
79 | timeout_task = NULL; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | |||
84 | static void | ||
85 | abort_error (void *cls) | ||
86 | { | ||
87 | fprintf (stderr, | ||
88 | "Timeout\n"); | ||
89 | timeout_task = NULL; | ||
90 | if (NULL != search) | ||
91 | { | ||
92 | GNUNET_FS_search_stop (search); | ||
93 | search = NULL; | ||
94 | } | ||
95 | if (NULL != publish) | ||
96 | { | ||
97 | GNUNET_FS_publish_stop (publish); | ||
98 | publish = NULL; | ||
99 | } | ||
100 | err = 1; | ||
101 | } | ||
102 | |||
103 | |||
104 | static void | ||
105 | abort_search_task (void *cls) | ||
106 | { | ||
107 | if (NULL != search) | ||
108 | { | ||
109 | GNUNET_FS_search_stop (search); | ||
110 | search = NULL; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | |||
115 | static void * | ||
116 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
117 | { | ||
118 | struct GNUNET_FS_Uri *kuri; | ||
119 | |||
120 | switch (event->status) | ||
121 | { | ||
122 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
123 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
124 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
125 | (unsigned long long) event->value.publish.completed, | ||
126 | (unsigned long long) event->value.publish.size, | ||
127 | event->value.publish.specifics.progress.depth, | ||
128 | (unsigned long long) event->value.publish.specifics. | ||
129 | progress.offset); | ||
130 | break; | ||
131 | |||
132 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
133 | break; | ||
134 | |||
135 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
136 | processed_files++; | ||
137 | if (processed_files == NUM_FILES) | ||
138 | { | ||
139 | char *emsg = NULL; | ||
140 | kuri = GNUNET_FS_uri_ksk_create ("+down_foo +down_bar", &emsg); | ||
141 | GNUNET_assert (kuri != NULL); | ||
142 | |||
143 | start = GNUNET_TIME_absolute_get (); | ||
144 | search = | ||
145 | GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, | ||
146 | "search"); | ||
147 | GNUNET_FS_uri_destroy (kuri); | ||
148 | GNUNET_assert (search != NULL); | ||
149 | } | ||
150 | break; | ||
151 | |||
152 | case GNUNET_FS_STATUS_SEARCH_RESULT: | ||
153 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
154 | "Search complete.\n"); | ||
155 | GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); | ||
156 | break; | ||
157 | |||
158 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
159 | fprintf (stderr, "Error publishing file: %s\n", | ||
160 | event->value.publish.specifics.error.message); | ||
161 | GNUNET_break (0); | ||
162 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
163 | break; | ||
164 | |||
165 | case GNUNET_FS_STATUS_SEARCH_ERROR: | ||
166 | fprintf (stderr, "Error searching file: %s\n", | ||
167 | event->value.search.specifics.error.message); | ||
168 | GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); | ||
169 | break; | ||
170 | |||
171 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
172 | GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); | ||
173 | GNUNET_assert (NULL == event->value.publish.pctx); | ||
174 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
175 | GNUNET_assert (0 == event->value.publish.completed); | ||
176 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
177 | break; | ||
178 | |||
179 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
180 | GNUNET_assert (publish == event->value.publish.pc); | ||
181 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
182 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
183 | GNUNET_FS_stop (fs); | ||
184 | fs = NULL; | ||
185 | break; | ||
186 | |||
187 | case GNUNET_FS_STATUS_SEARCH_START: | ||
188 | GNUNET_assert (search == NULL); | ||
189 | GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); | ||
190 | GNUNET_assert (1 == event->value.search.anonymity); | ||
191 | break; | ||
192 | |||
193 | case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: | ||
194 | break; | ||
195 | |||
196 | case GNUNET_FS_STATUS_SEARCH_STOPPED: | ||
197 | GNUNET_assert (search == event->value.search.sc); | ||
198 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
199 | break; | ||
200 | |||
201 | default: | ||
202 | fprintf (stderr, "Unexpected event: %d\n", event->status); | ||
203 | break; | ||
204 | } | ||
205 | return NULL; | ||
206 | } | ||
207 | |||
208 | |||
209 | static void | ||
210 | run (void *cls, | ||
211 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
212 | struct GNUNET_TESTING_Peer *peer) | ||
213 | { | ||
214 | const char *keywords[] = { | ||
215 | "down_foo", | ||
216 | "down_bar" | ||
217 | }; | ||
218 | char *buf; | ||
219 | struct GNUNET_CONTAINER_MetaData *meta; | ||
220 | struct GNUNET_FS_Uri *kuri; | ||
221 | struct GNUNET_FS_BlockOptions bo; | ||
222 | struct GNUNET_FS_FileInformation *fi; | ||
223 | size_t i; | ||
224 | size_t j; | ||
225 | |||
226 | fs = GNUNET_FS_start (cfg, "test-fs-search", &progress_cb, NULL, | ||
227 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
228 | GNUNET_assert (NULL != fs); | ||
229 | |||
230 | processed_files = 0; | ||
231 | for (j = 0; j < NUM_FILES; j++) | ||
232 | { | ||
233 | buf = GNUNET_malloc (FILESIZE); | ||
234 | for (i = 0; i < FILESIZE; i++) | ||
235 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
236 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
237 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
238 | bo.content_priority = 42; | ||
239 | bo.anonymity_level = 1; | ||
240 | bo.replication_level = 0; | ||
241 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
242 | fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", | ||
243 | FILESIZE, buf, kuri, meta, | ||
244 | GNUNET_NO, &bo); | ||
245 | GNUNET_FS_uri_destroy (kuri); | ||
246 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
247 | GNUNET_assert (NULL != fi); | ||
248 | start = GNUNET_TIME_absolute_get (); | ||
249 | publish = | ||
250 | GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, | ||
251 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
252 | GNUNET_assert (publish != NULL); | ||
253 | } | ||
254 | |||
255 | |||
256 | timeout_task = GNUNET_SCHEDULER_add_delayed (LIFETIME, | ||
257 | &abort_error, NULL); | ||
258 | } | ||
259 | |||
260 | |||
261 | int | ||
262 | main (int argc, char *argv[]) | ||
263 | { | ||
264 | if (0 != GNUNET_TESTING_peer_run ("test-fs-search-with-and", | ||
265 | "test_fs_search_data.conf", | ||
266 | &run, NULL)) | ||
267 | return 1; | ||
268 | return err; | ||
269 | } | ||
270 | |||
271 | |||
272 | /* end of test_fs_search.c */ | ||
diff --git a/src/fs/test_fs_start_stop.c b/src/fs/test_fs_start_stop.c deleted file mode 100644 index 509fbe76a..000000000 --- a/src/fs/test_fs_start_stop.c +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_start_stop.c | ||
22 | * @brief testcase for fs.c (start-stop only) | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | |||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | |||
32 | static void * | ||
33 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
34 | { | ||
35 | return NULL; | ||
36 | } | ||
37 | |||
38 | |||
39 | static void | ||
40 | run (void *cls, | ||
41 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
42 | struct GNUNET_TESTING_Peer *peer) | ||
43 | { | ||
44 | struct GNUNET_FS_Handle *fs; | ||
45 | |||
46 | fs = GNUNET_FS_start (cfg, "test-fs-start-stop", &progress_cb, NULL, | ||
47 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
48 | GNUNET_assert (NULL != fs); | ||
49 | GNUNET_FS_stop (fs); | ||
50 | } | ||
51 | |||
52 | |||
53 | int | ||
54 | main (int argc, char *argv[]) | ||
55 | { | ||
56 | if (0 != GNUNET_TESTING_peer_run ("test-fs-start-stop", | ||
57 | "test_fs_data.conf", | ||
58 | &run, NULL)) | ||
59 | return 1; | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | |||
64 | /* end of test_fs_start_stop.c */ | ||
diff --git a/src/fs/test_fs_test_lib.c b/src/fs/test_fs_test_lib.c deleted file mode 100644 index 7f0077bdd..000000000 --- a/src/fs/test_fs_test_lib.c +++ /dev/null | |||
@@ -1,179 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_test_lib.c | ||
23 | * @brief test fs test library | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "fs_test_lib.h" | ||
28 | |||
29 | #define VERBOSE GNUNET_NO | ||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE (1024 * 1024 * 2) | ||
35 | |||
36 | /** | ||
37 | * How long until we give up on transmitting the message? | ||
38 | */ | ||
39 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
40 | |||
41 | #define NUM_DAEMONS 2 | ||
42 | |||
43 | #define SEED 42 | ||
44 | |||
45 | static struct GNUNET_TESTBED_Peer *the_peers[NUM_DAEMONS]; | ||
46 | |||
47 | static struct GNUNET_TIME_Absolute start_time; | ||
48 | |||
49 | static int ret; | ||
50 | |||
51 | |||
52 | static void | ||
53 | do_stop (void *cls) | ||
54 | { | ||
55 | char *fn = cls; | ||
56 | |||
57 | if (0 == | ||
58 | GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (start_time, | ||
59 | TIMEOUT)). | ||
60 | rel_value_us) | ||
61 | { | ||
62 | GNUNET_break (0); | ||
63 | ret = 1; | ||
64 | } | ||
65 | else | ||
66 | { | ||
67 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
68 | "Finished download, shutting down\n"); | ||
69 | } | ||
70 | if (NULL != fn) | ||
71 | { | ||
72 | GNUNET_DISK_directory_remove (fn); | ||
73 | GNUNET_free (fn); | ||
74 | } | ||
75 | GNUNET_SCHEDULER_shutdown (); | ||
76 | } | ||
77 | |||
78 | |||
79 | static void | ||
80 | do_download (void *cls, | ||
81 | const struct GNUNET_FS_Uri *uri, | ||
82 | const char *fn) | ||
83 | { | ||
84 | if (NULL == uri) | ||
85 | { | ||
86 | GNUNET_break (0); | ||
87 | GNUNET_SCHEDULER_shutdown (); | ||
88 | ret = 1; | ||
89 | return; | ||
90 | } | ||
91 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
92 | "Downloading %llu bytes\n", | ||
93 | (unsigned long long) FILESIZE); | ||
94 | start_time = GNUNET_TIME_absolute_get (); | ||
95 | GNUNET_FS_TEST_download (the_peers[0], | ||
96 | TIMEOUT, 1, SEED, | ||
97 | uri, | ||
98 | VERBOSE, | ||
99 | &do_stop, | ||
100 | (NULL == fn) ? NULL : GNUNET_strdup (fn)); | ||
101 | } | ||
102 | |||
103 | |||
104 | static void | ||
105 | do_publish (void *cls, | ||
106 | struct GNUNET_TESTBED_Operation *op, | ||
107 | const char *emsg) | ||
108 | { | ||
109 | GNUNET_TESTBED_operation_done (op); | ||
110 | if (NULL != emsg) | ||
111 | { | ||
112 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to connect peers: %s\n", emsg); | ||
113 | GNUNET_break (0); | ||
114 | ret = 1; | ||
115 | GNUNET_SCHEDULER_shutdown (); | ||
116 | return; | ||
117 | } | ||
118 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", | ||
119 | (unsigned long long) FILESIZE); | ||
120 | GNUNET_FS_TEST_publish (the_peers[0], TIMEOUT, 1, GNUNET_NO, FILESIZE, SEED, | ||
121 | VERBOSE, &do_download, NULL); | ||
122 | } | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Actual main function for the test. | ||
127 | * | ||
128 | * @param cls closure | ||
129 | * @param h the run handle | ||
130 | * @param num_peers number of peers in 'peers' | ||
131 | * @param peers handle to peers run in the testbed | ||
132 | * @param links_succeeded the number of overlay link connection attempts that | ||
133 | * succeeded | ||
134 | * @param links_failed the number of overlay link connection attempts that | ||
135 | * failed | ||
136 | */ | ||
137 | static void | ||
138 | run (void *cls, | ||
139 | struct GNUNET_TESTBED_RunHandle *h, | ||
140 | unsigned int num_peers, | ||
141 | struct GNUNET_TESTBED_Peer **peers, | ||
142 | unsigned int links_succeeded, | ||
143 | unsigned int links_failed) | ||
144 | { | ||
145 | unsigned int i; | ||
146 | |||
147 | GNUNET_assert (NUM_DAEMONS == num_peers); | ||
148 | for (i = 0; i < num_peers; i++) | ||
149 | the_peers[i] = peers[i]; | ||
150 | GNUNET_TESTBED_overlay_connect (NULL, | ||
151 | &do_publish, | ||
152 | NULL, | ||
153 | peers[0], | ||
154 | peers[1]); | ||
155 | } | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Main function that initializes the testbed. | ||
160 | * | ||
161 | * @param argc ignored | ||
162 | * @param argv ignored | ||
163 | * @return 0 on success | ||
164 | */ | ||
165 | int | ||
166 | main (int argc, char *argv[]) | ||
167 | { | ||
168 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); | ||
169 | (void) GNUNET_TESTBED_test_run ("test_fs_test_lib", | ||
170 | "fs_test_lib_data.conf", | ||
171 | NUM_DAEMONS, | ||
172 | 0, NULL, NULL, | ||
173 | &run, NULL); | ||
174 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | |||
179 | /* end of test_fs_test_lib.c */ | ||
diff --git a/src/fs/test_fs_unindex.c b/src/fs/test_fs_unindex.c deleted file mode 100644 index 992672244..000000000 --- a/src/fs/test_fs_unindex.c +++ /dev/null | |||
@@ -1,237 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_unindex.c | ||
23 | * @brief simple testcase for simple publish + unindex operation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_fs_service.h" | ||
29 | #include "gnunet_testing_lib.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * File-size we use for testing. | ||
34 | */ | ||
35 | #define FILESIZE (1024 * 1024 * 2) | ||
36 | |||
37 | /** | ||
38 | * How long until we give up on transmitting the message? | ||
39 | */ | ||
40 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
41 | |||
42 | /** | ||
43 | * How long should our test-content live? | ||
44 | */ | ||
45 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
46 | |||
47 | |||
48 | static struct GNUNET_TIME_Absolute start; | ||
49 | |||
50 | static struct GNUNET_FS_Handle *fs; | ||
51 | |||
52 | static struct GNUNET_FS_UnindexContext *unindex; | ||
53 | |||
54 | static struct GNUNET_FS_PublishContext *publish; | ||
55 | |||
56 | static char *fn; | ||
57 | |||
58 | |||
59 | static void | ||
60 | abort_publish_task (void *cls) | ||
61 | { | ||
62 | GNUNET_FS_publish_stop (publish); | ||
63 | publish = NULL; | ||
64 | } | ||
65 | |||
66 | |||
67 | static void | ||
68 | abort_unindex_task (void *cls) | ||
69 | { | ||
70 | GNUNET_FS_unindex_stop (unindex); | ||
71 | unindex = NULL; | ||
72 | GNUNET_DISK_directory_remove (fn); | ||
73 | GNUNET_free (fn); | ||
74 | fn = NULL; | ||
75 | } | ||
76 | |||
77 | |||
78 | static void * | ||
79 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
80 | { | ||
81 | switch (event->status) | ||
82 | { | ||
83 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
84 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
85 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
86 | (unsigned long long) event->value.publish.completed, | ||
87 | (unsigned long long) event->value.publish.size, | ||
88 | event->value.publish.specifics.progress.depth, | ||
89 | (unsigned long long) event->value.publish.specifics. | ||
90 | progress.offset); | ||
91 | break; | ||
92 | |||
93 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
94 | break; | ||
95 | |||
96 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
97 | printf ("Publishing complete, %llu kbps.\n", | ||
98 | (unsigned long long) (FILESIZE * 1000000LL | ||
99 | / (1 | ||
100 | + GNUNET_TIME_absolute_get_duration | ||
101 | (start).rel_value_us) / 1024)); | ||
102 | start = GNUNET_TIME_absolute_get (); | ||
103 | unindex = GNUNET_FS_unindex_start (fs, fn, "unindex"); | ||
104 | GNUNET_assert (unindex != NULL); | ||
105 | break; | ||
106 | |||
107 | case GNUNET_FS_STATUS_UNINDEX_COMPLETED: | ||
108 | printf ("Unindex complete, %llu kbps.\n", | ||
109 | (unsigned long long) (FILESIZE * 1000000LL | ||
110 | / (1 | ||
111 | + GNUNET_TIME_absolute_get_duration | ||
112 | (start).rel_value_us) / 1024)); | ||
113 | GNUNET_SCHEDULER_add_now (&abort_unindex_task, NULL); | ||
114 | break; | ||
115 | |||
116 | case GNUNET_FS_STATUS_UNINDEX_PROGRESS: | ||
117 | GNUNET_assert (unindex == event->value.unindex.uc); | ||
118 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
119 | "Unindex is progressing (%llu/%llu at level %u off %llu)...\n", | ||
120 | (unsigned long long) event->value.unindex.completed, | ||
121 | (unsigned long long) event->value.unindex.size, | ||
122 | event->value.unindex.specifics.progress.depth, | ||
123 | (unsigned long long) event->value.unindex.specifics. | ||
124 | progress.offset); | ||
125 | break; | ||
126 | |||
127 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
128 | fprintf (stderr, "Error publishing file: %s\n", | ||
129 | event->value.publish.specifics.error.message); | ||
130 | GNUNET_break (0); | ||
131 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
132 | break; | ||
133 | |||
134 | case GNUNET_FS_STATUS_UNINDEX_ERROR: | ||
135 | fprintf (stderr, "Error unindexing file: %s\n", | ||
136 | event->value.unindex.specifics.error.message); | ||
137 | GNUNET_SCHEDULER_add_now (&abort_unindex_task, NULL); | ||
138 | break; | ||
139 | |||
140 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
141 | GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); | ||
142 | GNUNET_assert (NULL == event->value.publish.pctx); | ||
143 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
144 | GNUNET_assert (0 == event->value.publish.completed); | ||
145 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
146 | break; | ||
147 | |||
148 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
149 | GNUNET_assert (publish == event->value.publish.pc); | ||
150 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
151 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
152 | GNUNET_FS_stop (fs); | ||
153 | fs = NULL; | ||
154 | break; | ||
155 | |||
156 | case GNUNET_FS_STATUS_UNINDEX_START: | ||
157 | GNUNET_assert (unindex == NULL); | ||
158 | GNUNET_assert (0 == strcmp ("unindex", event->value.unindex.cctx)); | ||
159 | GNUNET_assert (0 == strcmp (fn, event->value.unindex.filename)); | ||
160 | GNUNET_assert (FILESIZE == event->value.unindex.size); | ||
161 | GNUNET_assert (0 == event->value.unindex.completed); | ||
162 | break; | ||
163 | |||
164 | case GNUNET_FS_STATUS_UNINDEX_STOPPED: | ||
165 | GNUNET_assert (unindex == event->value.unindex.uc); | ||
166 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
167 | break; | ||
168 | |||
169 | default: | ||
170 | printf ("Unexpected event: %d\n", event->status); | ||
171 | break; | ||
172 | } | ||
173 | return NULL; | ||
174 | } | ||
175 | |||
176 | |||
177 | static void | ||
178 | run (void *cls, | ||
179 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
180 | struct GNUNET_TESTING_Peer *peer) | ||
181 | { | ||
182 | const char *keywords[] = { | ||
183 | "down_foo", | ||
184 | "down_bar", | ||
185 | }; | ||
186 | char *buf; | ||
187 | struct GNUNET_CONTAINER_MetaData *meta; | ||
188 | struct GNUNET_FS_Uri *kuri; | ||
189 | struct GNUNET_FS_FileInformation *fi; | ||
190 | size_t i; | ||
191 | struct GNUNET_FS_BlockOptions bo; | ||
192 | |||
193 | fn = GNUNET_DISK_mktemp ("gnunet-unindex-test-dst"); | ||
194 | fs = GNUNET_FS_start (cfg, "test-fs-unindex", &progress_cb, NULL, | ||
195 | GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); | ||
196 | GNUNET_assert (NULL != fs); | ||
197 | buf = GNUNET_malloc (FILESIZE); | ||
198 | for (i = 0; i < FILESIZE; i++) | ||
199 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
200 | (void) GNUNET_DISK_directory_remove (fn); | ||
201 | GNUNET_assert (GNUNET_OK == | ||
202 | GNUNET_DISK_fn_write (fn, buf, FILESIZE, | ||
203 | GNUNET_DISK_PERM_USER_READ | ||
204 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
205 | GNUNET_free (buf); | ||
206 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
207 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
208 | bo.content_priority = 42; | ||
209 | bo.anonymity_level = 1; | ||
210 | bo.replication_level = 0; | ||
211 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
212 | fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", fn, | ||
213 | kuri, meta, GNUNET_YES, | ||
214 | &bo); | ||
215 | GNUNET_FS_uri_destroy (kuri); | ||
216 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
217 | GNUNET_assert (NULL != fi); | ||
218 | start = GNUNET_TIME_absolute_get (); | ||
219 | publish = | ||
220 | GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, | ||
221 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
222 | GNUNET_assert (publish != NULL); | ||
223 | } | ||
224 | |||
225 | |||
226 | int | ||
227 | main (int argc, char *argv[]) | ||
228 | { | ||
229 | if (0 != GNUNET_TESTING_peer_run ("test-fs-unindex", | ||
230 | "test_fs_unindex_data.conf", | ||
231 | &run, NULL)) | ||
232 | return 1; | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | |||
237 | /* end of test_fs_unindex.c */ | ||
diff --git a/src/fs/test_fs_unindex_data.conf b/src/fs/test_fs_unindex_data.conf deleted file mode 100644 index dde401857..000000000 --- a/src/fs/test_fs_unindex_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-unindex/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
diff --git a/src/fs/test_fs_unindex_persistence.c b/src/fs/test_fs_unindex_persistence.c deleted file mode 100644 index 802aaf7ca..000000000 --- a/src/fs/test_fs_unindex_persistence.c +++ /dev/null | |||
@@ -1,307 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_fs_unindex_persistence.c | ||
23 | * @brief simple testcase for simple publish + unindex operation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE (1024 * 1024 * 2) | ||
35 | |||
36 | /** | ||
37 | * How long until we give up on transmitting the message? | ||
38 | */ | ||
39 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
40 | |||
41 | /** | ||
42 | * How long should our test-content live? | ||
43 | */ | ||
44 | #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
45 | |||
46 | |||
47 | static struct GNUNET_TIME_Absolute start; | ||
48 | |||
49 | static struct GNUNET_FS_Handle *fs; | ||
50 | |||
51 | static struct GNUNET_FS_UnindexContext *unindex; | ||
52 | |||
53 | static struct GNUNET_FS_PublishContext *publish; | ||
54 | |||
55 | static char *fn; | ||
56 | |||
57 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
58 | |||
59 | |||
60 | static void | ||
61 | abort_publish_task (void *cls) | ||
62 | { | ||
63 | GNUNET_FS_publish_stop (publish); | ||
64 | publish = NULL; | ||
65 | } | ||
66 | |||
67 | |||
68 | static void | ||
69 | abort_unindex_task (void *cls) | ||
70 | { | ||
71 | if (unindex != NULL) | ||
72 | { | ||
73 | GNUNET_FS_unindex_stop (unindex); | ||
74 | unindex = NULL; | ||
75 | } | ||
76 | if (fn != NULL) | ||
77 | { | ||
78 | GNUNET_DISK_directory_remove (fn); | ||
79 | GNUNET_free (fn); | ||
80 | fn = NULL; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | |||
85 | static void * | ||
86 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); | ||
87 | |||
88 | |||
89 | static void | ||
90 | restart_fs_task (void *cls) | ||
91 | { | ||
92 | GNUNET_FS_stop (fs); | ||
93 | fs = GNUNET_FS_start (cfg, "test-fs-unindex-persistence", &progress_cb, NULL, | ||
94 | GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); | ||
95 | } | ||
96 | |||
97 | |||
98 | /** | ||
99 | * Consider scheduling the restart-task. | ||
100 | * Only runs the restart task once per event | ||
101 | * category. | ||
102 | * | ||
103 | * @param ev type of the event to consider | ||
104 | */ | ||
105 | static void | ||
106 | consider_restart (int ev) | ||
107 | { | ||
108 | static int prev[32]; | ||
109 | static int off; | ||
110 | int i; | ||
111 | |||
112 | for (i = 0; i < off; i++) | ||
113 | if (prev[i] == ev) | ||
114 | return; | ||
115 | prev[off++] = ev; | ||
116 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, | ||
117 | &restart_fs_task, NULL); | ||
118 | } | ||
119 | |||
120 | |||
121 | static void * | ||
122 | progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | ||
123 | { | ||
124 | switch (event->status) | ||
125 | { | ||
126 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS: | ||
127 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
128 | "Publish is progressing (%llu/%llu at level %u off %llu)...\n", | ||
129 | (unsigned long long) event->value.publish.completed, | ||
130 | (unsigned long long) event->value.publish.size, | ||
131 | event->value.publish.specifics.progress.depth, | ||
132 | (unsigned long long) event->value.publish.specifics. | ||
133 | progress.offset); | ||
134 | break; | ||
135 | |||
136 | case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY: | ||
137 | break; | ||
138 | |||
139 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | ||
140 | printf ("Publishing complete, %llu kbps.\n", | ||
141 | (unsigned long long) (FILESIZE * 1000000LL | ||
142 | / (1 | ||
143 | + GNUNET_TIME_absolute_get_duration | ||
144 | (start).rel_value_us) / 1024)); | ||
145 | start = GNUNET_TIME_absolute_get (); | ||
146 | unindex = GNUNET_FS_unindex_start (fs, fn, "unindex"); | ||
147 | GNUNET_assert (unindex != NULL); | ||
148 | break; | ||
149 | |||
150 | case GNUNET_FS_STATUS_UNINDEX_COMPLETED: | ||
151 | printf ("Unindex complete, %llu kbps.\n", | ||
152 | (unsigned long long) (FILESIZE * 1000000LL | ||
153 | / (1 | ||
154 | + GNUNET_TIME_absolute_get_duration | ||
155 | (start).rel_value_us) / 1024)); | ||
156 | GNUNET_SCHEDULER_add_now (&abort_unindex_task, NULL); | ||
157 | break; | ||
158 | |||
159 | case GNUNET_FS_STATUS_UNINDEX_PROGRESS: | ||
160 | consider_restart (event->status); | ||
161 | GNUNET_assert (unindex == event->value.unindex.uc); | ||
162 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
163 | "Unindex is progressing (%llu/%llu at level %u off %llu)...\n", | ||
164 | (unsigned long long) event->value.unindex.completed, | ||
165 | (unsigned long long) event->value.unindex.size, | ||
166 | event->value.unindex.specifics.progress.depth, | ||
167 | (unsigned long long) event->value.unindex.specifics. | ||
168 | progress.offset); | ||
169 | break; | ||
170 | |||
171 | case GNUNET_FS_STATUS_PUBLISH_SUSPEND: | ||
172 | if (event->value.publish.pc == publish) | ||
173 | publish = NULL; | ||
174 | break; | ||
175 | |||
176 | case GNUNET_FS_STATUS_PUBLISH_RESUME: | ||
177 | if (NULL == publish) | ||
178 | { | ||
179 | publish = event->value.publish.pc; | ||
180 | return "publish-context"; | ||
181 | } | ||
182 | break; | ||
183 | |||
184 | case GNUNET_FS_STATUS_UNINDEX_SUSPEND: | ||
185 | GNUNET_assert (event->value.unindex.uc == unindex); | ||
186 | unindex = NULL; | ||
187 | break; | ||
188 | |||
189 | case GNUNET_FS_STATUS_UNINDEX_RESUME: | ||
190 | GNUNET_assert (NULL == unindex); | ||
191 | unindex = event->value.unindex.uc; | ||
192 | return "unindex"; | ||
193 | |||
194 | case GNUNET_FS_STATUS_PUBLISH_ERROR: | ||
195 | fprintf (stderr, "Error publishing file: %s\n", | ||
196 | event->value.publish.specifics.error.message); | ||
197 | GNUNET_break (0); | ||
198 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
199 | break; | ||
200 | |||
201 | case GNUNET_FS_STATUS_UNINDEX_ERROR: | ||
202 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
203 | "Error unindexing file: %s\n", | ||
204 | event->value.unindex.specifics.error.message); | ||
205 | GNUNET_SCHEDULER_add_now (&abort_unindex_task, NULL); | ||
206 | break; | ||
207 | |||
208 | case GNUNET_FS_STATUS_PUBLISH_START: | ||
209 | GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); | ||
210 | GNUNET_assert (NULL == event->value.publish.pctx); | ||
211 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
212 | GNUNET_assert (0 == event->value.publish.completed); | ||
213 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
214 | break; | ||
215 | |||
216 | case GNUNET_FS_STATUS_PUBLISH_STOPPED: | ||
217 | GNUNET_assert (publish == event->value.publish.pc); | ||
218 | GNUNET_assert (FILESIZE == event->value.publish.size); | ||
219 | GNUNET_assert (1 == event->value.publish.anonymity); | ||
220 | GNUNET_FS_stop (fs); | ||
221 | fs = NULL; | ||
222 | break; | ||
223 | |||
224 | case GNUNET_FS_STATUS_UNINDEX_START: | ||
225 | consider_restart (event->status); | ||
226 | GNUNET_assert (unindex == NULL); | ||
227 | GNUNET_assert (0 == strcmp ("unindex", event->value.unindex.cctx)); | ||
228 | GNUNET_assert (0 == strcmp (fn, event->value.unindex.filename)); | ||
229 | GNUNET_assert (FILESIZE == event->value.unindex.size); | ||
230 | GNUNET_assert (0 == event->value.unindex.completed); | ||
231 | break; | ||
232 | |||
233 | case GNUNET_FS_STATUS_UNINDEX_STOPPED: | ||
234 | GNUNET_assert (unindex == event->value.unindex.uc); | ||
235 | GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); | ||
236 | break; | ||
237 | |||
238 | default: | ||
239 | printf ("Unexpected event: %d\n", event->status); | ||
240 | break; | ||
241 | } | ||
242 | return NULL; | ||
243 | } | ||
244 | |||
245 | |||
246 | static void | ||
247 | run (void *cls, | ||
248 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
249 | struct GNUNET_TESTING_Peer *peer) | ||
250 | { | ||
251 | const char *keywords[] = { | ||
252 | "down_foo", | ||
253 | "down_bar", | ||
254 | }; | ||
255 | char *buf; | ||
256 | struct GNUNET_CONTAINER_MetaData *meta; | ||
257 | struct GNUNET_FS_Uri *kuri; | ||
258 | struct GNUNET_FS_FileInformation *fi; | ||
259 | size_t i; | ||
260 | struct GNUNET_FS_BlockOptions bo; | ||
261 | |||
262 | cfg = c; | ||
263 | fn = GNUNET_DISK_mktemp ("gnunet-unindex-test-dst"); | ||
264 | fs = GNUNET_FS_start (cfg, "test-fs-unindex-persistence", &progress_cb, NULL, | ||
265 | GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); | ||
266 | GNUNET_assert (NULL != fs); | ||
267 | buf = GNUNET_malloc (FILESIZE); | ||
268 | for (i = 0; i < FILESIZE; i++) | ||
269 | buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); | ||
270 | (void) GNUNET_DISK_directory_remove (fn); | ||
271 | GNUNET_assert (GNUNET_OK == | ||
272 | GNUNET_DISK_fn_write (fn, buf, FILESIZE, | ||
273 | GNUNET_DISK_PERM_USER_READ | ||
274 | | GNUNET_DISK_PERM_USER_WRITE)); | ||
275 | GNUNET_free (buf); | ||
276 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
277 | kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); | ||
278 | bo.content_priority = 42; | ||
279 | bo.anonymity_level = 1; | ||
280 | bo.replication_level = 0; | ||
281 | bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); | ||
282 | fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", fn, | ||
283 | kuri, meta, GNUNET_YES, | ||
284 | &bo); | ||
285 | GNUNET_FS_uri_destroy (kuri); | ||
286 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
287 | GNUNET_assert (NULL != fi); | ||
288 | start = GNUNET_TIME_absolute_get (); | ||
289 | publish = | ||
290 | GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, | ||
291 | GNUNET_FS_PUBLISH_OPTION_NONE); | ||
292 | GNUNET_assert (publish != NULL); | ||
293 | } | ||
294 | |||
295 | |||
296 | int | ||
297 | main (int argc, char *argv[]) | ||
298 | { | ||
299 | if (0 != GNUNET_TESTING_peer_run ("test-fs-unindex-persistence", | ||
300 | "test_fs_unindex_data.conf", | ||
301 | &run, NULL)) | ||
302 | return 1; | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | |||
307 | /* end of test_fs_unindex_persistence.c */ | ||
diff --git a/src/fs/test_fs_uri.c b/src/fs/test_fs_uri.c deleted file mode 100644 index 30eafab9a..000000000 --- a/src/fs/test_fs_uri.c +++ /dev/null | |||
@@ -1,337 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003-2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_fs_uri.c | ||
22 | * @brief Test for fs_uri.c | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_fs_service.h" | ||
28 | #include "fs_api.h" | ||
29 | |||
30 | |||
31 | static int | ||
32 | testKeyword () | ||
33 | { | ||
34 | char *uri; | ||
35 | struct GNUNET_FS_Uri *ret; | ||
36 | char *emsg; | ||
37 | |||
38 | if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/ksk/++", &emsg))) | ||
39 | { | ||
40 | GNUNET_FS_uri_destroy (ret); | ||
41 | GNUNET_assert (0); | ||
42 | } | ||
43 | GNUNET_free (emsg); | ||
44 | ret = GNUNET_FS_uri_parse ("gnunet://fs/ksk/foo+bar", &emsg); | ||
45 | if (NULL == ret) | ||
46 | { | ||
47 | GNUNET_free (emsg); | ||
48 | GNUNET_assert (0); | ||
49 | } | ||
50 | if (! GNUNET_FS_uri_test_ksk (ret)) | ||
51 | { | ||
52 | GNUNET_FS_uri_destroy (ret); | ||
53 | GNUNET_assert (0); | ||
54 | } | ||
55 | if ((2 != ret->data.ksk.keywordCount) || | ||
56 | (0 != strcmp (" foo", ret->data.ksk.keywords[0])) || | ||
57 | (0 != strcmp (" bar", ret->data.ksk.keywords[1]))) | ||
58 | { | ||
59 | GNUNET_FS_uri_destroy (ret); | ||
60 | GNUNET_assert (0); | ||
61 | } | ||
62 | |||
63 | uri = GNUNET_FS_uri_to_string (ret); | ||
64 | if (0 != strcmp (uri, "gnunet://fs/ksk/foo+bar")) | ||
65 | { | ||
66 | GNUNET_free (uri); | ||
67 | GNUNET_FS_uri_destroy (ret); | ||
68 | GNUNET_assert (0); | ||
69 | } | ||
70 | GNUNET_free (uri); | ||
71 | GNUNET_FS_uri_destroy (ret); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | |||
76 | static int | ||
77 | testLocation () | ||
78 | { | ||
79 | struct GNUNET_FS_Uri *uri; | ||
80 | char *uric; | ||
81 | struct GNUNET_FS_Uri *uri2; | ||
82 | struct GNUNET_FS_Uri *baseURI; | ||
83 | char *emsg; | ||
84 | struct GNUNET_CRYPTO_EddsaPrivateKey pk; | ||
85 | |||
86 | baseURI = | ||
87 | GNUNET_FS_uri_parse | ||
88 | ( | ||
89 | "gnunet://fs/chk/4QZP479A9SKGFNMQ2ZBCYE71YV2QMTVGWTVPB6A10ASVCKXDHB05DKPSC7ZF6E9P9W1VE47394EQY7NXA47Q6R35M7P1MJPGP59D1Z8.D54QD1K5XCG5878T6YZ19AM60MQ6FC0YNVK7QY08KK0KM0FJJ3KQWYG112FN5T07KN7J0X35DF6WVBT9B8ZMZ3X2BXJ22X3KFQ6MV2G.15999", | ||
90 | &emsg); | ||
91 | GNUNET_assert (baseURI != NULL); | ||
92 | GNUNET_assert (emsg == NULL); | ||
93 | GNUNET_CRYPTO_eddsa_key_create (&pk); | ||
94 | uri = GNUNET_FS_uri_loc_create (baseURI, | ||
95 | &pk, | ||
96 | GNUNET_TIME_absolute_get ()); | ||
97 | if (NULL == uri) | ||
98 | { | ||
99 | GNUNET_break (0); | ||
100 | GNUNET_FS_uri_destroy (baseURI); | ||
101 | return 1; | ||
102 | } | ||
103 | if (! GNUNET_FS_uri_test_loc (uri)) | ||
104 | { | ||
105 | GNUNET_break (0); | ||
106 | GNUNET_FS_uri_destroy (uri); | ||
107 | GNUNET_FS_uri_destroy (baseURI); | ||
108 | return 1; | ||
109 | } | ||
110 | uri2 = GNUNET_FS_uri_loc_get_uri (uri); | ||
111 | if (! GNUNET_FS_uri_test_equal (baseURI, uri2)) | ||
112 | { | ||
113 | GNUNET_break (0); | ||
114 | GNUNET_FS_uri_destroy (uri); | ||
115 | GNUNET_FS_uri_destroy (uri2); | ||
116 | GNUNET_FS_uri_destroy (baseURI); | ||
117 | return 1; | ||
118 | } | ||
119 | GNUNET_FS_uri_destroy (uri2); | ||
120 | GNUNET_FS_uri_destroy (baseURI); | ||
121 | uric = GNUNET_FS_uri_to_string (uri); | ||
122 | #if 0 | ||
123 | /* not for the faint of heart: */ | ||
124 | printf ("URI: `%s'\n", uric); | ||
125 | #endif | ||
126 | uri2 = GNUNET_FS_uri_parse (uric, &emsg); | ||
127 | GNUNET_free (uric); | ||
128 | if (uri2 == NULL) | ||
129 | { | ||
130 | fprintf (stderr, "URI parsing failed: %s\n", emsg); | ||
131 | GNUNET_break (0); | ||
132 | GNUNET_FS_uri_destroy (uri); | ||
133 | GNUNET_free (emsg); | ||
134 | return 1; | ||
135 | } | ||
136 | GNUNET_assert (NULL == emsg); | ||
137 | if (GNUNET_YES != GNUNET_FS_uri_test_equal (uri, uri2)) | ||
138 | { | ||
139 | GNUNET_break (0); | ||
140 | GNUNET_FS_uri_destroy (uri); | ||
141 | GNUNET_FS_uri_destroy (uri2); | ||
142 | return 1; | ||
143 | } | ||
144 | GNUNET_FS_uri_destroy (uri2); | ||
145 | GNUNET_FS_uri_destroy (uri); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | |||
150 | static int | ||
151 | testNamespace (int i) | ||
152 | { | ||
153 | char *uri; | ||
154 | struct GNUNET_FS_Uri *ret; | ||
155 | char *emsg; | ||
156 | struct GNUNET_CRYPTO_EcdsaPrivateKey ph; | ||
157 | struct GNUNET_CRYPTO_EcdsaPublicKey id; | ||
158 | char buf[1024]; | ||
159 | char ubuf[1024]; | ||
160 | char *sret; | ||
161 | |||
162 | if (NULL != | ||
163 | (ret = | ||
164 | GNUNET_FS_uri_parse ( | ||
165 | "gnunet://fs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3VUK", | ||
166 | &emsg))) | ||
167 | { | ||
168 | GNUNET_FS_uri_destroy (ret); | ||
169 | GNUNET_assert (0); | ||
170 | } | ||
171 | GNUNET_free (emsg); | ||
172 | if (NULL != | ||
173 | (ret = | ||
174 | GNUNET_FS_uri_parse | ||
175 | ( | ||
176 | "gnunet://fs/sks/XQHH4R288W26EBV369F6RCE0PJVJTX2Y74Q2FJPMPGA31HJX2JG/this", | ||
177 | &emsg))) | ||
178 | { | ||
179 | GNUNET_FS_uri_destroy (ret); | ||
180 | GNUNET_assert (0); | ||
181 | } | ||
182 | GNUNET_free (emsg); | ||
183 | if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/sks/test", &emsg))) | ||
184 | { | ||
185 | GNUNET_FS_uri_destroy (ret); | ||
186 | GNUNET_assert (0); | ||
187 | } | ||
188 | GNUNET_free (emsg); | ||
189 | GNUNET_CRYPTO_ecdsa_key_create (&ph); | ||
190 | GNUNET_CRYPTO_ecdsa_key_get_public (&ph, | ||
191 | &id); | ||
192 | sret = GNUNET_STRINGS_data_to_string (&id, sizeof(id), | ||
193 | ubuf, sizeof(ubuf) - 1); | ||
194 | GNUNET_assert (NULL != sret); | ||
195 | sret[0] = '\0'; | ||
196 | GNUNET_snprintf (buf, sizeof(buf), | ||
197 | "gnunet://fs/sks/%s/test", | ||
198 | ubuf); | ||
199 | ret = GNUNET_FS_uri_parse (buf, &emsg); | ||
200 | if (NULL == ret) | ||
201 | { | ||
202 | GNUNET_free (emsg); | ||
203 | GNUNET_assert (0); | ||
204 | } | ||
205 | if (GNUNET_FS_uri_test_ksk (ret)) | ||
206 | { | ||
207 | GNUNET_FS_uri_destroy (ret); | ||
208 | GNUNET_assert (0); | ||
209 | } | ||
210 | if (! GNUNET_FS_uri_test_sks (ret)) | ||
211 | { | ||
212 | GNUNET_FS_uri_destroy (ret); | ||
213 | GNUNET_assert (0); | ||
214 | } | ||
215 | |||
216 | uri = GNUNET_FS_uri_to_string (ret); | ||
217 | if (0 != | ||
218 | strcmp (uri, | ||
219 | buf)) | ||
220 | { | ||
221 | GNUNET_FS_uri_destroy (ret); | ||
222 | GNUNET_free (uri); | ||
223 | GNUNET_assert (0); | ||
224 | } | ||
225 | GNUNET_free (uri); | ||
226 | GNUNET_FS_uri_destroy (ret); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | |||
231 | static int | ||
232 | testFile (int i) | ||
233 | { | ||
234 | char *uri; | ||
235 | struct GNUNET_FS_Uri *ret; | ||
236 | char *emsg; | ||
237 | |||
238 | if (NULL != | ||
239 | (ret = | ||
240 | GNUNET_FS_uri_parse | ||
241 | ( | ||
242 | "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H00000440000.42", | ||
243 | &emsg))) | ||
244 | { | ||
245 | GNUNET_FS_uri_destroy (ret); | ||
246 | GNUNET_assert (0); | ||
247 | } | ||
248 | GNUNET_free (emsg); | ||
249 | if (NULL != | ||
250 | (ret = | ||
251 | GNUNET_FS_uri_parse | ||
252 | ( | ||
253 | "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000", | ||
254 | &emsg))) | ||
255 | { | ||
256 | GNUNET_FS_uri_destroy (ret); | ||
257 | GNUNET_assert (0); | ||
258 | } | ||
259 | GNUNET_free (emsg); | ||
260 | if (NULL != | ||
261 | (ret = | ||
262 | GNUNET_FS_uri_parse | ||
263 | ( | ||
264 | "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.FGH", | ||
265 | &emsg))) | ||
266 | { | ||
267 | GNUNET_FS_uri_destroy (ret); | ||
268 | GNUNET_assert (0); | ||
269 | } | ||
270 | GNUNET_free (emsg); | ||
271 | ret = | ||
272 | GNUNET_FS_uri_parse | ||
273 | ( | ||
274 | "gnunet://fs/chk/4QZP479A9SKGFNMQ2ZBCYE71YV2QMTVGWTVPB6A10ASVCKXDHB05DKPSC7ZF6E9P9W1VE47394EQY7NXA47Q6R35M7P1MJPGP59D1Z8.D54QD1K5XCG5878T6YZ19AM60MQ6FC0YNVK7QY08KK0KM0FJJ3KQWYG112FN5T07KN7J0X35DF6WVBT9B8ZMZ3X2BXJ22X3KFQ6MV2G.42", | ||
275 | &emsg); | ||
276 | if (ret == NULL) | ||
277 | { | ||
278 | GNUNET_free (emsg); | ||
279 | GNUNET_assert (0); | ||
280 | } | ||
281 | if (GNUNET_FS_uri_test_ksk (ret)) | ||
282 | { | ||
283 | GNUNET_FS_uri_destroy (ret); | ||
284 | GNUNET_assert (0); | ||
285 | } | ||
286 | if (GNUNET_FS_uri_test_sks (ret)) | ||
287 | { | ||
288 | GNUNET_FS_uri_destroy (ret); | ||
289 | GNUNET_assert (0); | ||
290 | } | ||
291 | if (GNUNET_ntohll (ret->data.chk.file_length) != 42) | ||
292 | { | ||
293 | GNUNET_FS_uri_destroy (ret); | ||
294 | GNUNET_assert (0); | ||
295 | } | ||
296 | |||
297 | uri = GNUNET_FS_uri_to_string (ret); | ||
298 | if (0 != | ||
299 | strcmp (uri, | ||
300 | "gnunet://fs/chk/4QZP479A9SKGFNMQ2ZBCYE71YV2QMTVGWTVPB6A10ASVCKXDHB05DKPSC7ZF6E9P9W1VE47394EQY7NXA47Q6R35M7P1MJPGP59D1Z8.D54QD1K5XCG5878T6YZ19AM60MQ6FC0YNVK7QY08KK0KM0FJJ3KQWYG112FN5T07KN7J0X35DF6WVBT9B8ZMZ3X2BXJ22X3KFQ6MV2G.42")) | ||
301 | { | ||
302 | GNUNET_free (uri); | ||
303 | GNUNET_FS_uri_destroy (ret); | ||
304 | GNUNET_assert (0); | ||
305 | } | ||
306 | GNUNET_free (uri); | ||
307 | GNUNET_FS_uri_destroy (ret); | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | |||
312 | int | ||
313 | main (int argc, char *argv[]) | ||
314 | { | ||
315 | int failureCount = 0; | ||
316 | int i; | ||
317 | |||
318 | GNUNET_log_setup ("test_fs_uri", | ||
319 | "WARNING", | ||
320 | NULL); | ||
321 | failureCount += testKeyword (); | ||
322 | failureCount += testLocation (); | ||
323 | for (i = 0; i < 255; i++) | ||
324 | { | ||
325 | /* fprintf (stderr, "%s", "."); */ | ||
326 | failureCount += testNamespace (i); | ||
327 | failureCount += testFile (i); | ||
328 | } | ||
329 | /* fprintf (stderr, "%s", "\n"); */ | ||
330 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-uri"); | ||
331 | if (failureCount != 0) | ||
332 | return 1; | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | |||
337 | /* end of test_fs_uri.c */ | ||
diff --git a/src/fs/test_gnunet_fs_idx.py.in b/src/fs/test_gnunet_fs_idx.py.in deleted file mode 100755 index 564dd68f2..000000000 --- a/src/fs/test_gnunet_fs_idx.py.in +++ /dev/null | |||
@@ -1,113 +0,0 @@ | |||
1 | #!@PYTHONEXE@ | ||
2 | # This file is part of GNUnet. | ||
3 | # (C) 2010 Christian Grothoff (and other contributing authors) | ||
4 | # | ||
5 | # GNUnet is free software: you can redistribute it and/or modify it | ||
6 | # under the terms of the GNU Affero General Public License as published | ||
7 | # by the Free Software Foundation, either version 3 of the License, | ||
8 | # or (at your option) any later version. | ||
9 | # | ||
10 | # GNUnet is distributed in the hope that it will be useful, but | ||
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # Affero General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU Affero General Public License | ||
16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | # | ||
18 | # SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | # | ||
20 | # Testcase for file-sharing command-line tools (indexing and unindexing) | ||
21 | import sys | ||
22 | import os | ||
23 | import subprocess | ||
24 | import re | ||
25 | import shutil | ||
26 | |||
27 | srcdir = "../.." | ||
28 | gnunet_pyexpect_dir = os.path.join(srcdir, "contrib/scripts") | ||
29 | if gnunet_pyexpect_dir not in sys.path: | ||
30 | sys.path.append(gnunet_pyexpect_dir) | ||
31 | |||
32 | from gnunet_pyexpect import pexpect | ||
33 | |||
34 | if os.name == 'posix': | ||
35 | download = './gnunet-download' | ||
36 | gnunetarm = 'gnunet-arm' | ||
37 | publish = './gnunet-publish' | ||
38 | unindex = './gnunet-unindex' | ||
39 | elif os.name == 'nt': | ||
40 | download = './gnunet-download.exe' | ||
41 | gnunetarm = 'gnunet-arm.exe' | ||
42 | publish = './gnunet-publish.exe' | ||
43 | unindex = './gnunet-unindex.exe' | ||
44 | |||
45 | if os.name == "nt": | ||
46 | shutil.rmtree( | ||
47 | os.path.join(os.getenv("TEMP"), "gnunet-test-fs-py-idx"), True | ||
48 | ) | ||
49 | else: | ||
50 | shutil.rmtree("/tmp/gnunet-test-fs-py-idx", True) | ||
51 | |||
52 | arm = subprocess.Popen([gnunetarm, '-sq', '-c', 'test_gnunet_fs_idx_data.conf']) | ||
53 | arm.communicate() | ||
54 | |||
55 | try: | ||
56 | pub = pexpect() | ||
57 | |||
58 | pub.spawn( | ||
59 | None, [ | ||
60 | publish, '-c', 'test_gnunet_fs_idx_data.conf', '-m', | ||
61 | "description:Test archive", '-k', 'tst', | ||
62 | 'test_gnunet_fs_rec_data.tgz' | ||
63 | ], | ||
64 | stdout=subprocess.PIPE, | ||
65 | stderr=subprocess.STDOUT | ||
66 | ) | ||
67 | pub.expect( | ||
68 | "stdout", | ||
69 | re.compile( | ||
70 | r"URI is `gnunet://fs/chk/2ZMHKPV74CB6GB1GFKQRR95BXJQA2SER25FN48GAW7WSBPA0GDEM5Y74V1ZJHM0NA6919TVW376BHTFDRE3RYS0KRY92M1QJVKPHFCR\.49BT3V5C10KA1695JF71FCT8ZZG4JMJSH04BD9CT22R6KEM915A7CEST17RD0QYTHXV5M4HHEGJMEZSFRDB7JAYC0EMJAN2V781E9DG\.17822'\.\r?\n" | ||
71 | ) | ||
72 | ) | ||
73 | |||
74 | down = pexpect() | ||
75 | down.spawn( | ||
76 | None, [ | ||
77 | download, '-c', 'test_gnunet_fs_idx_data.conf', '-o', | ||
78 | 'test_gnunet_fs_rec_data.tar.gz', | ||
79 | 'gnunet://fs/chk/2ZMHKPV74CB6GB1GFKQRR95BXJQA2SER25FN48GAW7WSBPA0GDEM5Y74V1ZJHM0NA6919TVW376BHTFDRE3RYS0KRY92M1QJVKPHFCR.49BT3V5C10KA1695JF71FCT8ZZG4JMJSH04BD9CT22R6KEM915A7CEST17RD0QYTHXV5M4HHEGJMEZSFRDB7JAYC0EMJAN2V781E9DG.17822' | ||
80 | ], | ||
81 | stdout=subprocess.PIPE, | ||
82 | stderr=subprocess.STDOUT | ||
83 | ) | ||
84 | down.expect( | ||
85 | "stdout", | ||
86 | re.compile( | ||
87 | r"Downloading `test_gnunet_fs_rec_data.tar.gz' done (.*).\r?\n" | ||
88 | ) | ||
89 | ) | ||
90 | os.remove("test_gnunet_fs_rec_data.tar.gz") | ||
91 | |||
92 | un = pexpect() | ||
93 | un.spawn( | ||
94 | None, [ | ||
95 | unindex, '-c', 'test_gnunet_fs_idx_data.conf', | ||
96 | 'test_gnunet_fs_rec_data.tgz' | ||
97 | ], | ||
98 | stdout=subprocess.PIPE, | ||
99 | stderr=subprocess.STDOUT | ||
100 | ) | ||
101 | un.expect("stdout", re.compile(r'Unindexing done\.\r?\n')) | ||
102 | |||
103 | finally: | ||
104 | arm = subprocess.Popen([ | ||
105 | gnunetarm, '-eq', '-c', 'test_gnunet_fs_idx_data.conf' | ||
106 | ]) | ||
107 | arm.communicate() | ||
108 | if os.name == "nt": | ||
109 | shutil.rmtree( | ||
110 | os.path.join(os.getenv("TEMP"), "gnunet-test-fs-py-idx"), True | ||
111 | ) | ||
112 | else: | ||
113 | shutil.rmtree("/tmp/gnunet-test-fs-py-idx", True) | ||
diff --git a/src/fs/test_gnunet_fs_idx_data.conf b/src/fs/test_gnunet_fs_idx_data.conf deleted file mode 100644 index ba2a872dd..000000000 --- a/src/fs/test_gnunet_fs_idx_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-py-idx/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
diff --git a/src/fs/test_gnunet_fs_psd.py.in b/src/fs/test_gnunet_fs_psd.py.in deleted file mode 100755 index a25e4eaef..000000000 --- a/src/fs/test_gnunet_fs_psd.py.in +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
1 | #!@PYTHONEXE@ | ||
2 | # This file is part of GNUnet. | ||
3 | # (C) 2010, 2018 Christian Grothoff (and other contributing authors) | ||
4 | # | ||
5 | # GNUnet is free software: you can redistribute it and/or modify it | ||
6 | # under the terms of the GNU Affero General Public License as published | ||
7 | # by the Free Software Foundation, either version 3 of the License, | ||
8 | # or (at your option) any later version. | ||
9 | # | ||
10 | # GNUnet is distributed in the hope that it will be useful, but | ||
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # Affero General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU Affero General Public License | ||
16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | # | ||
18 | # SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | # | ||
20 | # Testcase for file-sharing command-line tools (publish, search, download) | ||
21 | |||
22 | import sys | ||
23 | import os | ||
24 | import subprocess | ||
25 | import re | ||
26 | import shutil | ||
27 | try: | ||
28 | # Python 2.7 | ||
29 | reload | ||
30 | except NameError: | ||
31 | try: | ||
32 | # Python 3.4+: | ||
33 | from importlib import reload | ||
34 | except ImportError: | ||
35 | # Python 3.0 - 3.3 | ||
36 | from imp import reload | ||
37 | |||
38 | reload(sys) | ||
39 | |||
40 | # Force encoding to utf-8, as this test otherwise fails | ||
41 | # on some systems (see #5094). In Python 3+ there is no attribute | ||
42 | # sys.setdefaultencoding anymore. | ||
43 | if (3 < sys.version_info[0]): | ||
44 | sys.setdefaultencoding('utf8') | ||
45 | |||
46 | srcdir = "../.." | ||
47 | gnunet_pyexpect_dir = os.path.join(srcdir, "contrib/scripts") | ||
48 | if gnunet_pyexpect_dir not in sys.path: | ||
49 | sys.path.append(gnunet_pyexpect_dir) | ||
50 | |||
51 | from gnunet_pyexpect import pexpect | ||
52 | |||
53 | if os.name == 'posix': | ||
54 | download = './gnunet-download' | ||
55 | gnunetarm = 'gnunet-arm' | ||
56 | publish = './gnunet-publish' | ||
57 | unindex = './gnunet-unindex' | ||
58 | search = './gnunet-search' | ||
59 | elif os.name == 'nt': | ||
60 | download = './gnunet-download.exe' | ||
61 | gnunetarm = 'gnunet-arm.exe' | ||
62 | publish = './gnunet-publish.exe' | ||
63 | unindex = './gnunet-unindex.exe' | ||
64 | search = './gnunet-search.exe' | ||
65 | |||
66 | if "GNUNET_PREFIX" in os.environ: | ||
67 | pass | ||
68 | else: | ||
69 | print("You need to export GNUNET_PREFIX") | ||
70 | sys.exit(1) | ||
71 | |||
72 | if os.name == "nt": | ||
73 | shutil.rmtree( | ||
74 | os.path.join(os.getenv("TEMP"), "gnunet-test-fs-py-psd"), True | ||
75 | ) | ||
76 | else: | ||
77 | shutil.rmtree("/tmp/gnunet-test-fs-py-psd", True) | ||
78 | |||
79 | arm = subprocess.Popen([gnunetarm, '-sq', '-c', 'test_gnunet_fs_psd_data.conf']) | ||
80 | arm.communicate() | ||
81 | |||
82 | # first, basic publish-search-download run | ||
83 | try: | ||
84 | pub = pexpect() | ||
85 | pub.spawn( | ||
86 | None, [ | ||
87 | publish, '-c', 'test_gnunet_fs_psd_data.conf', '-n', '-m', | ||
88 | "description:Test archive", '-k', 'tst', | ||
89 | 'test_gnunet_fs_rec_data.tgz' | ||
90 | ], | ||
91 | stdout=subprocess.PIPE, | ||
92 | stderr=subprocess.STDOUT | ||
93 | ) | ||
94 | pub.expect( | ||
95 | "stdout", | ||
96 | re.compile(r"Publishing `.+test_gnunet_fs_rec_data.tgz' done\.\r?\n") | ||
97 | ) | ||
98 | pub.expect( | ||
99 | "stdout", | ||
100 | re.compile( | ||
101 | r"URI is `gnunet://fs/chk/2ZMHKPV74CB6GB1GFKQRR95BXJQA2SER25FN48GAW7WSBPA0GDEM5Y74V1ZJHM0NA6919TVW376BHTFDRE3RYS0KRY92M1QJVKPHFCR\.49BT3V5C10KA1695JF71FCT8ZZG4JMJSH04BD9CT22R6KEM915A7CEST17RD0QYTHXV5M4HHEGJMEZSFRDB7JAYC0EMJAN2V781E9DG\.17822'\.\r?\n" | ||
102 | ) | ||
103 | ) | ||
104 | |||
105 | s = pexpect() | ||
106 | s.spawn( | ||
107 | None, [ | ||
108 | search, '-V', '-t', '1000 ms', '-N', '1', '-c', | ||
109 | 'test_gnunet_fs_psd_data.conf', 'tst' | ||
110 | ], | ||
111 | stdout=subprocess.PIPE, | ||
112 | stderr=subprocess.STDOUT | ||
113 | ) | ||
114 | s.expect( | ||
115 | "stdout", | ||
116 | re.compile( | ||
117 | r'gnunet-download -o "test_gnunet_fs_rec_data.tgz" gnunet://fs/chk/2ZMHKPV74CB6GB1GFKQRR95BXJQA2SER25FN48GAW7WSBPA0GDEM5Y74V1ZJHM0NA6919TVW376BHTFDRE3RYS0KRY92M1QJVKPHFCR\.49BT3V5C10KA1695JF71FCT8ZZG4JMJSH04BD9CT22R6KEM915A7CEST17RD0QYTHXV5M4HHEGJMEZSFRDB7JAYC0EMJAN2V781E9DG\.17822\r?\n' | ||
118 | ) | ||
119 | ) | ||
120 | |||
121 | down = pexpect() | ||
122 | down.spawn( | ||
123 | None, [ | ||
124 | download, '-c', 'test_gnunet_fs_psd_data.conf', '-o', | ||
125 | 'test_gnunet_fs_rec_data.tar.gz', | ||
126 | 'gnunet://fs/chk/2ZMHKPV74CB6GB1GFKQRR95BXJQA2SER25FN48GAW7WSBPA0GDEM5Y74V1ZJHM0NA6919TVW376BHTFDRE3RYS0KRY92M1QJVKPHFCR.49BT3V5C10KA1695JF71FCT8ZZG4JMJSH04BD9CT22R6KEM915A7CEST17RD0QYTHXV5M4HHEGJMEZSFRDB7JAYC0EMJAN2V781E9DG.17822' | ||
127 | ], | ||
128 | stdout=subprocess.PIPE, | ||
129 | stderr=subprocess.STDOUT | ||
130 | ) | ||
131 | down.expect( | ||
132 | "stdout", | ||
133 | re.compile( | ||
134 | r"Downloading `test_gnunet_fs_rec_data.tar.gz' done (.*).\r?\n" | ||
135 | ) | ||
136 | ) | ||
137 | os.remove("test_gnunet_fs_rec_data.tar.gz") | ||
138 | |||
139 | finally: | ||
140 | arm = subprocess.Popen([ | ||
141 | gnunetarm, '-eq', '-c', 'test_gnunet_fs_psd_data.conf' | ||
142 | ]) | ||
143 | arm.communicate() | ||
144 | if os.name == "nt": | ||
145 | shutil.rmtree( | ||
146 | os.path.join(os.getenv("TEMP"), "gnunet-test-fs-py-psd"), True | ||
147 | ) | ||
148 | else: | ||
149 | shutil.rmtree("/tmp/gnunet-test-fs-py-psd", True) | ||
diff --git a/src/fs/test_gnunet_fs_psd_data.conf b/src/fs/test_gnunet_fs_psd_data.conf deleted file mode 100644 index f6c05ecdd..000000000 --- a/src/fs/test_gnunet_fs_psd_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-py-psd/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
diff --git a/src/fs/test_gnunet_fs_rec.py.in b/src/fs/test_gnunet_fs_rec.py.in deleted file mode 100755 index f7e84e3da..000000000 --- a/src/fs/test_gnunet_fs_rec.py.in +++ /dev/null | |||
@@ -1,171 +0,0 @@ | |||
1 | #!@PYTHONEXE@ | ||
2 | # This file is part of GNUnet. | ||
3 | # (C) 2010 Christian Grothoff (and other contributing authors) | ||
4 | # | ||
5 | # GNUnet is free software: you can redistribute it and/or modify it | ||
6 | # under the terms of the GNU Affero General Public License as published | ||
7 | # by the Free Software Foundation, either version 3 of the License, | ||
8 | # or (at your option) any later version. | ||
9 | # | ||
10 | # GNUnet is distributed in the hope that it will be useful, but | ||
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # Affero General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU Affero General Public License | ||
16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | # | ||
18 | # SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | # | ||
20 | # Testcase for file-sharing command-line tools (recursive publishing & download) | ||
21 | import sys | ||
22 | import os | ||
23 | import subprocess | ||
24 | import re | ||
25 | import shutil | ||
26 | import tarfile | ||
27 | import filecmp | ||
28 | |||
29 | srcdir = "../.." | ||
30 | gnunet_pyexpect_dir = os.path.join(srcdir, "contrib/scripts") | ||
31 | if gnunet_pyexpect_dir not in sys.path: | ||
32 | sys.path.append(gnunet_pyexpect_dir) | ||
33 | |||
34 | from gnunet_pyexpect import pexpect | ||
35 | from pydiffer import dcdiff | ||
36 | |||
37 | if os.name == 'posix': | ||
38 | download = './gnunet-download' | ||
39 | gnunetarm = 'gnunet-arm' | ||
40 | publish = './gnunet-publish' | ||
41 | unindex = './gnunet-unindex' | ||
42 | search = './gnunet-search' | ||
43 | directory = './gnunet-directory' | ||
44 | elif os.name == 'nt': | ||
45 | download = './gnunet-download.exe' | ||
46 | gnunetarm = 'gnunet-arm.exe' | ||
47 | publish = './gnunet-publish.exe' | ||
48 | unindex = './gnunet-unindex.exe' | ||
49 | search = './gnunet-search.exe' | ||
50 | directory = './gnunet-directory.exe' | ||
51 | |||
52 | if os.name == "nt": | ||
53 | shutil.rmtree( | ||
54 | os.path.join(os.getenv("TEMP"), "gnunet-test-fs-py-rec"), True | ||
55 | ) | ||
56 | else: | ||
57 | shutil.rmtree("/tmp/gnunet-test-fs-py-rec", True) | ||
58 | |||
59 | arm = subprocess.Popen([gnunetarm, '-sq', '-c', 'test_gnunet_fs_rec_data.conf']) | ||
60 | arm.communicate() | ||
61 | |||
62 | tar = tarfile.open('test_gnunet_fs_rec_data.tgz') | ||
63 | tar.extractall() | ||
64 | # first, basic publish-search-download run | ||
65 | try: | ||
66 | pub = pexpect() | ||
67 | pub.spawn( | ||
68 | None, [ | ||
69 | publish, '-c', 'test_gnunet_fs_rec_data.conf', '-k', 'testdir', | ||
70 | 'dir/' | ||
71 | ], | ||
72 | stdout=subprocess.PIPE, | ||
73 | stderr=subprocess.STDOUT | ||
74 | ) | ||
75 | # Can't say much for publishing, except that the last one is the toplevel directory | ||
76 | pub.expect("stdout", re.compile(r"Publishing `.+' done\.\r?\n")) | ||
77 | pub.expect( | ||
78 | "stdout", | ||
79 | re.compile( | ||
80 | r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n" | ||
81 | ) | ||
82 | ) | ||
83 | pub.expect("stdout", re.compile(r"Publishing `.+' done\.\r?\n")) | ||
84 | pub.expect( | ||
85 | "stdout", | ||
86 | re.compile( | ||
87 | r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n" | ||
88 | ) | ||
89 | ) | ||
90 | pub.expect("stdout", re.compile(r"Publishing `.+' done\.\r?\n")) | ||
91 | pub.expect( | ||
92 | "stdout", | ||
93 | re.compile( | ||
94 | r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n" | ||
95 | ) | ||
96 | ) | ||
97 | pub.expect("stdout", re.compile(r"Publishing `.+' done\.\r?\n")) | ||
98 | pub.expect( | ||
99 | "stdout", | ||
100 | re.compile( | ||
101 | r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n" | ||
102 | ) | ||
103 | ) | ||
104 | pub.expect("stdout", re.compile(r"Publishing `.+' done\.\r?\n")) | ||
105 | pub.expect( | ||
106 | "stdout", | ||
107 | re.compile( | ||
108 | r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n" | ||
109 | ) | ||
110 | ) | ||
111 | pub.expect("stdout", re.compile(r"Publishing `.+' done\.\r?\n")) | ||
112 | pub.expect( | ||
113 | "stdout", | ||
114 | re.compile( | ||
115 | r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n" | ||
116 | ) | ||
117 | ) | ||
118 | pub.expect( | ||
119 | "stdout", re.compile(r"Publishing `.+[\\/]dir[\\/]' done\.\r?\n") | ||
120 | ) | ||
121 | m = pub.expect("stdout", re.compile(r".+\r?\n")) | ||
122 | if not m: | ||
123 | sys.exit(3) | ||
124 | output = m.string | ||
125 | url = output[output.find("`") + 1:output.find("'")] | ||
126 | |||
127 | down = pexpect() | ||
128 | down.spawn( | ||
129 | None, [ | ||
130 | download, '-c', 'test_gnunet_fs_rec_data.conf', '-R', '-o', | ||
131 | 'rdir.gnd', url | ||
132 | ], | ||
133 | stdout=subprocess.PIPE, | ||
134 | stderr=subprocess.STDOUT | ||
135 | ) | ||
136 | down.expect("stdout", re.compile(r"Downloading `rdir.gnd' done (.*).\r?\n")) | ||
137 | |||
138 | d = pexpect() | ||
139 | d.spawn( | ||
140 | None, [directory, '-c', 'test_gnunet_fs_rec_data.conf', 'rdir/a.gnd'], | ||
141 | stdout=subprocess.PIPE, | ||
142 | stderr=subprocess.STDOUT | ||
143 | ) | ||
144 | d.expect("stdout", re.compile(r"Directory `a/' meta data:\r?\n")) | ||
145 | d.expect("stdout", re.compile(r"Directory `a/' contents:\r?\n")) | ||
146 | d.expect("stdout", re.compile(r"COPYING (.*)\r?\n")) | ||
147 | d.expect("stdout", re.compile(r"INSTALL (.*)\r?\n")) | ||
148 | |||
149 | os.remove("rdir/b.gnd") | ||
150 | os.remove("rdir/a.gnd") | ||
151 | diff = dcdiff('dir', 'rdir') | ||
152 | if len(diff) != 0: | ||
153 | raise Exception( | ||
154 | "Unexpected difference between source directory and downloaded result:\n{}" | ||
155 | .format(diff) | ||
156 | ) | ||
157 | |||
158 | finally: | ||
159 | arm = subprocess.Popen([ | ||
160 | gnunetarm, '-eq', '-c', 'test_gnunet_fs_rec_data.conf' | ||
161 | ]) | ||
162 | arm.communicate() | ||
163 | if os.name == "nt": | ||
164 | shutil.rmtree( | ||
165 | os.path.join(os.getenv("TEMP"), "gnunet-test-fs-py-rec"), True | ||
166 | ) | ||
167 | else: | ||
168 | shutil.rmtree("/tmp/gnunet-test-fs-py-rec", True) | ||
169 | shutil.rmtree("dir", True) | ||
170 | shutil.rmtree("rdir", True) | ||
171 | shutil.rmtree("rdir.gnd", True) | ||
diff --git a/src/fs/test_gnunet_fs_rec_data.conf b/src/fs/test_gnunet_fs_rec_data.conf deleted file mode 100644 index 82ddb8f49..000000000 --- a/src/fs/test_gnunet_fs_rec_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-fs-py-rec/ | ||
4 | |||
5 | [transport] | ||
6 | PLUGINS = | ||
7 | |||
diff --git a/src/fs/test_gnunet_fs_rec_data.tgz b/src/fs/test_gnunet_fs_rec_data.tgz deleted file mode 100644 index 697794306..000000000 --- a/src/fs/test_gnunet_fs_rec_data.tgz +++ /dev/null | |||
Binary files differ | |||
diff --git a/src/fs/test_gnunet_service_fs_migration.c b/src/fs/test_gnunet_service_fs_migration.c deleted file mode 100644 index d4a1c38b5..000000000 --- a/src/fs/test_gnunet_service_fs_migration.c +++ /dev/null | |||
@@ -1,221 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2012, 2015 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_gnunet_service_fs_migration.c | ||
23 | * @brief test content migration between two peers | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "fs_test_lib.h" | ||
28 | #include "gnunet_testbed_service.h" | ||
29 | |||
30 | #define VERBOSE GNUNET_NO | ||
31 | |||
32 | /** | ||
33 | * File-size we use for testing. | ||
34 | */ | ||
35 | #define FILESIZE (2 * 32 * 1024) | ||
36 | |||
37 | /** | ||
38 | * How long until we give up on transmitting the message? | ||
39 | */ | ||
40 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) | ||
41 | |||
42 | /** | ||
43 | * How long do we give the peers for content migration? | ||
44 | */ | ||
45 | #define MIGRATION_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \ | ||
46 | 90) | ||
47 | |||
48 | #define SEED 42 | ||
49 | |||
50 | static struct GNUNET_TESTBED_Peer *daemons[2]; | ||
51 | |||
52 | static int ok; | ||
53 | |||
54 | static struct GNUNET_TIME_Absolute start_time; | ||
55 | |||
56 | static struct GNUNET_TESTBED_Operation *op; | ||
57 | |||
58 | |||
59 | struct DownloadContext | ||
60 | { | ||
61 | char *fn; | ||
62 | |||
63 | struct GNUNET_FS_Uri *uri; | ||
64 | }; | ||
65 | |||
66 | |||
67 | static void | ||
68 | do_stop (void *cls) | ||
69 | { | ||
70 | struct GNUNET_TIME_Relative del; | ||
71 | char *fancy; | ||
72 | |||
73 | GNUNET_SCHEDULER_shutdown (); | ||
74 | if (0 == | ||
75 | GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (start_time, | ||
76 | TIMEOUT)). | ||
77 | rel_value_us) | ||
78 | { | ||
79 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
80 | "Timeout during download, shutting down with error\n"); | ||
81 | ok = 1; | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | del = GNUNET_TIME_absolute_get_duration (start_time); | ||
86 | if (del.rel_value_us == 0) | ||
87 | del.rel_value_us = 1; | ||
88 | fancy = | ||
89 | GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) | ||
90 | * 1000000LL / del.rel_value_us); | ||
91 | fprintf (stdout, | ||
92 | "Download speed was %s/s\n", | ||
93 | fancy); | ||
94 | GNUNET_free (fancy); | ||
95 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
96 | "Finished download, shutting down\n"); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | |||
101 | static void | ||
102 | do_download (void *cls, | ||
103 | const char *emsg) | ||
104 | { | ||
105 | struct DownloadContext *dc = cls; | ||
106 | struct GNUNET_FS_Uri *uri = dc->uri; | ||
107 | |||
108 | GNUNET_TESTBED_operation_done (op); | ||
109 | op = NULL; | ||
110 | if (NULL != dc->fn) | ||
111 | { | ||
112 | GNUNET_DISK_directory_remove (dc->fn); | ||
113 | GNUNET_free (dc->fn); | ||
114 | } | ||
115 | GNUNET_free (dc); | ||
116 | if (NULL != emsg) | ||
117 | { | ||
118 | GNUNET_SCHEDULER_shutdown (); | ||
119 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
120 | "Failed to stop source daemon: %s\n", | ||
121 | emsg); | ||
122 | GNUNET_FS_uri_destroy (uri); | ||
123 | ok = 1; | ||
124 | return; | ||
125 | } | ||
126 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
127 | "Downloading %llu bytes\n", | ||
128 | (unsigned long long) FILESIZE); | ||
129 | start_time = GNUNET_TIME_absolute_get (); | ||
130 | GNUNET_FS_TEST_download (daemons[0], | ||
131 | TIMEOUT, | ||
132 | 1, | ||
133 | SEED, | ||
134 | uri, | ||
135 | VERBOSE, | ||
136 | &do_stop, | ||
137 | NULL); | ||
138 | GNUNET_FS_uri_destroy (uri); | ||
139 | } | ||
140 | |||
141 | |||
142 | static void | ||
143 | stop_source_peer (void *cls) | ||
144 | { | ||
145 | struct DownloadContext *dc = cls; | ||
146 | |||
147 | /* FIXME: We should not interact with testbed when shutting down */ | ||
148 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
149 | "Stopping source peer\n"); | ||
150 | op = GNUNET_TESTBED_peer_stop (NULL, | ||
151 | daemons[1], | ||
152 | &do_download, dc); | ||
153 | GNUNET_assert (NULL != op); | ||
154 | } | ||
155 | |||
156 | |||
157 | static void | ||
158 | do_wait (void *cls, | ||
159 | const struct GNUNET_FS_Uri *uri, | ||
160 | const char *fn) | ||
161 | { | ||
162 | struct DownloadContext *dc; | ||
163 | |||
164 | if (NULL == uri) | ||
165 | { | ||
166 | GNUNET_SCHEDULER_shutdown (); | ||
167 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
168 | "Timeout during upload attempt, shutting down with error\n"); | ||
169 | ok = 1; | ||
170 | return; | ||
171 | } | ||
172 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
173 | "Waiting to allow content to migrate\n"); | ||
174 | dc = GNUNET_new (struct DownloadContext); | ||
175 | dc->uri = GNUNET_FS_uri_dup (uri); | ||
176 | if (NULL != fn) | ||
177 | dc->fn = GNUNET_strdup (fn); | ||
178 | (void) GNUNET_SCHEDULER_add_delayed (MIGRATION_DELAY, | ||
179 | &stop_source_peer, | ||
180 | dc); | ||
181 | } | ||
182 | |||
183 | |||
184 | static void | ||
185 | do_publish (void *cls, | ||
186 | struct GNUNET_TESTBED_RunHandle *h, | ||
187 | unsigned int num_peers, | ||
188 | struct GNUNET_TESTBED_Peer **peers, | ||
189 | unsigned int links_succeeded, | ||
190 | unsigned int links_failed) | ||
191 | { | ||
192 | unsigned int i; | ||
193 | |||
194 | GNUNET_assert (2 == num_peers); | ||
195 | for (i = 0; i < num_peers; i++) | ||
196 | daemons[i] = peers[i]; | ||
197 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
198 | "Publishing %llu bytes\n", | ||
199 | (unsigned long long) FILESIZE); | ||
200 | GNUNET_FS_TEST_publish (daemons[1], TIMEOUT, 1, GNUNET_NO, | ||
201 | FILESIZE, SEED, | ||
202 | VERBOSE, &do_wait, NULL); | ||
203 | } | ||
204 | |||
205 | |||
206 | int | ||
207 | main (int argc, | ||
208 | char *argv[]) | ||
209 | { | ||
210 | (void) GNUNET_TESTBED_test_run ("test-gnunet-service-fs-migration", | ||
211 | "fs_test_lib_data.conf", | ||
212 | 2, | ||
213 | 0, NULL, NULL, | ||
214 | &do_publish, | ||
215 | NULL); | ||
216 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-service-fs-migration/"); | ||
217 | return ok; | ||
218 | } | ||
219 | |||
220 | |||
221 | /* end of test_gnunet_service_fs_migration.c */ | ||
diff --git a/src/fs/test_gnunet_service_fs_migration_data.conf b/src/fs/test_gnunet_service_fs_migration_data.conf deleted file mode 100644 index fca6c5a29..000000000 --- a/src/fs/test_gnunet_service_fs_migration_data.conf +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | @INLINE@ test_fs_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-service-fs-migration/ | ||
4 | |||
5 | [testbed] | ||
6 | OVERLAY_TOPOLOGY = CLIQUE | ||
7 | |||
8 | [ats] | ||
9 | WAN_QUOTA_IN = 3932160 | ||
10 | WAN_QUOTA_OUT = 3932160 | ||
diff --git a/src/fs/test_gnunet_service_fs_p2p.c b/src/fs/test_gnunet_service_fs_p2p.c deleted file mode 100644 index bedcb7173..000000000 --- a/src/fs/test_gnunet_service_fs_p2p.c +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/test_gnunet_service_fs_p2p.c | ||
23 | * @brief test P2P routing using simple publish + download operation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "fs_test_lib.h" | ||
28 | |||
29 | #define VERBOSE GNUNET_NO | ||
30 | |||
31 | /** | ||
32 | * File-size we use for testing. | ||
33 | */ | ||
34 | #define FILESIZE (1024 * 1024 * 1) | ||
35 | |||
36 | /** | ||
37 | * How long until we give up on the download? | ||
38 | */ | ||
39 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
40 | |||
41 | #define NUM_DAEMONS 2 | ||
42 | |||
43 | #define SEED 42 | ||
44 | |||
45 | static const char *progname; | ||
46 | |||
47 | static unsigned int anonymity_level; | ||
48 | |||
49 | static struct GNUNET_TESTBED_Peer *daemons[NUM_DAEMONS]; | ||
50 | |||
51 | static int ok; | ||
52 | |||
53 | static struct GNUNET_TIME_Absolute start_time; | ||
54 | |||
55 | |||
56 | static void | ||
57 | do_stop (void *cls) | ||
58 | { | ||
59 | char *fn = cls; | ||
60 | struct GNUNET_TIME_Relative del; | ||
61 | char *fancy; | ||
62 | |||
63 | GNUNET_SCHEDULER_shutdown (); | ||
64 | if (0 == | ||
65 | GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (start_time, | ||
66 | TIMEOUT)). | ||
67 | rel_value_us) | ||
68 | { | ||
69 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
70 | "Timeout during download, shutting down with error\n"); | ||
71 | ok = 1; | ||
72 | } | ||
73 | else | ||
74 | { | ||
75 | del = GNUNET_TIME_absolute_get_duration (start_time); | ||
76 | if (0 == del.rel_value_us) | ||
77 | del.rel_value_us = 1; | ||
78 | fancy = | ||
79 | GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) | ||
80 | * 1000000LL / del.rel_value_us); | ||
81 | fprintf (stdout, | ||
82 | "Download speed was %s/s\n", | ||
83 | fancy); | ||
84 | GNUNET_free (fancy); | ||
85 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
86 | "Finished download, shutting down\n"); | ||
87 | } | ||
88 | if (NULL != fn) | ||
89 | { | ||
90 | GNUNET_DISK_directory_remove (fn); | ||
91 | GNUNET_free (fn); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | |||
96 | static void | ||
97 | do_download (void *cls, const struct GNUNET_FS_Uri *uri, | ||
98 | const char *fn) | ||
99 | { | ||
100 | if (NULL == uri) | ||
101 | { | ||
102 | GNUNET_SCHEDULER_shutdown (); | ||
103 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
104 | "Timeout during upload attempt, shutting down with error\n"); | ||
105 | ok = 1; | ||
106 | return; | ||
107 | } | ||
108 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", | ||
109 | (unsigned long long) FILESIZE); | ||
110 | start_time = GNUNET_TIME_absolute_get (); | ||
111 | GNUNET_FS_TEST_download (daemons[0], TIMEOUT, | ||
112 | anonymity_level, SEED, uri, | ||
113 | VERBOSE, &do_stop, | ||
114 | (NULL == fn) | ||
115 | ? NULL | ||
116 | : GNUNET_strdup (fn)); | ||
117 | } | ||
118 | |||
119 | |||
120 | static void | ||
121 | do_publish (void *cls, | ||
122 | struct GNUNET_TESTBED_RunHandle *h, | ||
123 | unsigned int num_peers, | ||
124 | struct GNUNET_TESTBED_Peer **peers, | ||
125 | unsigned int links_succeeded, | ||
126 | unsigned int links_failed) | ||
127 | { | ||
128 | unsigned int i; | ||
129 | |||
130 | if (NULL != strstr (progname, "cadet")) | ||
131 | anonymity_level = 0; | ||
132 | else | ||
133 | anonymity_level = 1; | ||
134 | GNUNET_assert (NUM_DAEMONS == num_peers); | ||
135 | for (i = 0; i < num_peers; i++) | ||
136 | daemons[i] = peers[i]; | ||
137 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", | ||
138 | (unsigned long long) FILESIZE); | ||
139 | GNUNET_FS_TEST_publish (daemons[1], TIMEOUT, | ||
140 | anonymity_level, GNUNET_NO, | ||
141 | FILESIZE, SEED, | ||
142 | VERBOSE, &do_download, NULL); | ||
143 | } | ||
144 | |||
145 | |||
146 | int | ||
147 | main (int argc, char *argv[]) | ||
148 | { | ||
149 | const char *config; | ||
150 | |||
151 | progname = argv[0]; | ||
152 | if (NULL != strstr (progname, "cadet")) | ||
153 | config = "test_gnunet_service_fs_p2p_cadet.conf"; | ||
154 | else | ||
155 | config = "fs_test_lib_data.conf"; | ||
156 | (void) GNUNET_TESTBED_test_run ("test-gnunet-service-fs-p2p", | ||
157 | config, | ||
158 | NUM_DAEMONS, | ||
159 | 0, NULL, NULL, | ||
160 | &do_publish, NULL); | ||
161 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); | ||
162 | return ok; | ||
163 | } | ||
164 | |||
165 | |||
166 | /* end of test_gnunet_service_fs_p2p.c */ | ||
diff --git a/src/fs/test_gnunet_service_fs_p2p_cadet.conf b/src/fs/test_gnunet_service_fs_p2p_cadet.conf deleted file mode 100644 index 12e106968..000000000 --- a/src/fs/test_gnunet_service_fs_p2p_cadet.conf +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | @INLINE@ fs_test_lib_data.conf | ||
2 | |||
3 | [fs] | ||
4 | # FIXME: this option needs to be set for the | ||
5 | # testcase to truly work; however, as the code | ||
6 | # is not finished, not setting the option should | ||
7 | # allow the test to at least pass for now... | ||
8 | DISABLE_ANON_TRANSFER = YES | ||
9 | |||
10 | # Do we cache content from other nodes? (may improve anonymity) | ||
11 | CONTENT_CACHING = NO | ||
12 | |||
13 | # Do we send unsolicited data to other nodes if we have excess bandwidth? | ||
14 | # (may improve anonymity, probably not a good idea if content_caching is NO) | ||
15 | CONTENT_PUSHING = NO | ||
16 | |||
17 | #PREFIX = valgrind | ||
18 | |||
19 | [cadet] | ||
20 | #PREFIX = valgrind | ||
diff --git a/src/fs/test_plugin_block_fs.c b/src/fs/test_plugin_block_fs.c deleted file mode 100644 index 727cc37c2..000000000 --- a/src/fs/test_plugin_block_fs.c +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2010, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/test_plugin_block_fs.c | ||
22 | * @brief test for plugin_block_fs.c | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_block_lib.h" | ||
27 | |||
28 | |||
29 | static int | ||
30 | test_fs (struct GNUNET_BLOCK_Context *ctx) | ||
31 | { | ||
32 | struct GNUNET_HashCode key; | ||
33 | char block[4]; | ||
34 | |||
35 | memset (block, 1, sizeof(block)); | ||
36 | if (GNUNET_OK != | ||
37 | GNUNET_BLOCK_get_key (ctx, | ||
38 | GNUNET_BLOCK_TYPE_FS_DBLOCK, | ||
39 | block, | ||
40 | sizeof(block), | ||
41 | &key)) | ||
42 | return 1; | ||
43 | if (GNUNET_OK != | ||
44 | GNUNET_BLOCK_check_block (ctx, | ||
45 | GNUNET_BLOCK_TYPE_FS_DBLOCK, | ||
46 | &key, | ||
47 | block, | ||
48 | sizeof(block))) | ||
49 | return 2; | ||
50 | if (GNUNET_OK != | ||
51 | GNUNET_BLOCK_check_query (ctx, | ||
52 | GNUNET_BLOCK_TYPE_FS_DBLOCK, | ||
53 | &key, | ||
54 | NULL, 0)) | ||
55 | return 4; | ||
56 | GNUNET_log_skip (1, GNUNET_NO); | ||
57 | if (GNUNET_BLOCK_EVALUATION_REQUEST_INVALID != | ||
58 | GNUNET_BLOCK_check_query (ctx, | ||
59 | GNUNET_BLOCK_TYPE_FS_DBLOCK, | ||
60 | &key, | ||
61 | "bogus", 5)) | ||
62 | return 8; | ||
63 | GNUNET_log_skip (0, GNUNET_YES); | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | |||
68 | int | ||
69 | main (int argc, char *argv[]) | ||
70 | { | ||
71 | int ret; | ||
72 | struct GNUNET_BLOCK_Context *ctx; | ||
73 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
74 | |||
75 | GNUNET_log_setup ("test-block", "WARNING", NULL); | ||
76 | cfg = GNUNET_CONFIGURATION_create (); | ||
77 | ctx = GNUNET_BLOCK_context_create (cfg); | ||
78 | ret = test_fs (ctx); | ||
79 | GNUNET_BLOCK_context_destroy (ctx); | ||
80 | GNUNET_CONFIGURATION_destroy (cfg); | ||
81 | if (ret != 0) | ||
82 | fprintf (stderr, "Tests failed: %d\n", ret); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | |||
87 | /* end of test_plugin_block_fs.c */ | ||
diff --git a/src/fs/test_pseudonym_data.conf b/src/fs/test_pseudonym_data.conf deleted file mode 100644 index 5827721b8..000000000 --- a/src/fs/test_pseudonym_data.conf +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | # General settings | ||
2 | [fs] | ||
3 | |||
4 | [TESTING] | ||
5 | WEAKRANDOM = YES | ||
6 | |||